<div dir="ltr">Could you please take a look?<div><a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/3574/steps/check-llvm%20asan/logs/stdio">http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/3574/steps/check-llvm%20asan/logs/stdio</a><br></div><div><br></div><div><pre style="font-family:"courier new",courier,monotype,monospace;font-size:medium"><span class="inbox-inbox-stdout">Direct leak of 136 byte(s) in 1 object(s) allocated from:
    #0 0x98a100 in operator new(unsigned long) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:82
    #1 0x3d355e5 in allocateFixedOperandUser /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/User.cpp:128:7
    #2 0x3d355e5 in llvm::User::operator new(unsigned long, unsigned int) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/User.cpp:146
    #3 0x3c3422a in Create /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/IR/Instructions.h:1962:23
    #4 0x3c3422a in llvm::SelectInst::cloneImpl() const /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/Instructions.cpp:3929
    #5 0x3c01f42 in llvm::Instruction::clone() const /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/IR/Instruction.def:187:1
    #6 0x1921b77 in initialize /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:239:28
    #7 0x1921b77 in Context /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:154
    #8 0x1921b77 in (anonymous namespace)::PolynomialMultiplyRecognize::recognize() /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:1678
    #9 0x191e5b0 in runOnCountableLoop /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:2234:11
    #10 0x191e5b0 in (anonymous namespace)::HexagonLoopIdiomRecognize::runOnLoop(llvm::Loop*, llvm::LPPassManager&) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:2291
    #11 0x2dcf8bc in llvm::LPPassManager::runOnFunction(llvm::Function&) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Analysis/LoopPass.cpp:203:23
    #12 0x3c7b90d in llvm::FPPassManager::runOnFunction(llvm::Function&) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/LegacyPassManager.cpp:1513:27
    #13 0x3c7beb2 in llvm::FPPassManager::runOnModule(llvm::Module&) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/LegacyPassManager.cpp:1534:16
    #14 0x3c7cd4a in runOnModule /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/LegacyPassManager.cpp:1590:27
    #15 0x3c7cd4a in llvm::legacy::PassManagerImpl::run(llvm::Module&) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/LegacyPassManager.cpp:1693
    #16 0x9b4feb in main /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/tools/opt/opt.cpp:722:10
    #17 0x7f9b7820482f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)</span></pre></div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Mar 20, 2017 at 11:25 AM Krzysztof Parzyszek via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: kparzysz<br class="gmail_msg">
Date: Mon Mar 20 13:12:58 2017<br class="gmail_msg">
New Revision: 298282<br class="gmail_msg">
<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=298282&view=rev" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project?rev=298282&view=rev</a><br class="gmail_msg">
Log:<br class="gmail_msg">
[Hexagon] Recognize polynomial-modulo loop idiom again<br class="gmail_msg">
<br class="gmail_msg">
Regain the ability to recognize loops calculating polynomial modulo<br class="gmail_msg">
operation. This ability has been lost due to some changes in the<br class="gmail_msg">
preceding optimizations. Add code to preprocess the IR to a form<br class="gmail_msg">
that the pattern matching code can recognize.<br class="gmail_msg">
<br class="gmail_msg">
Added:<br class="gmail_msg">
    llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll<br class="gmail_msg">
Modified:<br class="gmail_msg">
    llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp<br class="gmail_msg">
<br class="gmail_msg">
Modified: llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp?rev=298282&r1=298281&r2=298282&view=diff" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp?rev=298282&r1=298281&r2=298282&view=diff</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp (original)<br class="gmail_msg">
+++ llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp Mon Mar 20 13:12:58 2017<br class="gmail_msg">
@@ -129,6 +129,342 @@ INITIALIZE_PASS_END(HexagonLoopIdiomReco<br class="gmail_msg">
     "Recognize Hexagon-specific loop idioms", false, false)<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
+namespace {<br class="gmail_msg">
+  struct Simplifier {<br class="gmail_msg">
+    typedef std::function<Value* (Instruction*, LLVMContext&)> Rule;<br class="gmail_msg">
+<br class="gmail_msg">
+    void addRule(const Rule &R) { Rules.push_back(R); }<br class="gmail_msg">
+<br class="gmail_msg">
+  private:<br class="gmail_msg">
+    typedef std::deque<Value*> WorkListType;<br class="gmail_msg">
+    typedef std::set<Value*> ValueSetType;<br class="gmail_msg">
+    std::vector<Rule> Rules;<br class="gmail_msg">
+<br class="gmail_msg">
+  public:<br class="gmail_msg">
+    struct Context {<br class="gmail_msg">
+      typedef DenseMap<Value*,Value*> ValueMapType;<br class="gmail_msg">
+<br class="gmail_msg">
+      Value *Root;<br class="gmail_msg">
+      ValueSetType Used;<br class="gmail_msg">
+      ValueMapType Clones, Orig;<br class="gmail_msg">
+      LLVMContext &Ctx;<br class="gmail_msg">
+<br class="gmail_msg">
+      Context(Instruction *Exp)<br class="gmail_msg">
+        : Ctx(Exp->getParent()->getParent()->getContext()) {<br class="gmail_msg">
+        initialize(Exp);<br class="gmail_msg">
+        reset();<br class="gmail_msg">
+      }<br class="gmail_msg">
+      ~Context() { cleanup(); }<br class="gmail_msg">
+      void print(raw_ostream &OS, const Value *V) const;<br class="gmail_msg">
+<br class="gmail_msg">
+      Value *materialize(BasicBlock *B, BasicBlock::iterator At);<br class="gmail_msg">
+<br class="gmail_msg">
+    private:<br class="gmail_msg">
+      void initialize(Instruction *Exp);<br class="gmail_msg">
+      void reset();<br class="gmail_msg">
+      void cleanup();<br class="gmail_msg">
+      void cleanup(Value *V);<br class="gmail_msg">
+<br class="gmail_msg">
+      bool equal(const Instruction *I, const Instruction *J) const;<br class="gmail_msg">
+      Value *find(Value *Tree, Value *Sub) const;<br class="gmail_msg">
+      Value *subst(Value *Tree, Value *OldV, Value *NewV);<br class="gmail_msg">
+      void replace(Value *OldV, Value *NewV);<br class="gmail_msg">
+      void link(Instruction *I, BasicBlock *B, BasicBlock::iterator At);<br class="gmail_msg">
+<br class="gmail_msg">
+      friend struct Simplifier;<br class="gmail_msg">
+    };<br class="gmail_msg">
+<br class="gmail_msg">
+    Value *simplify(Context &C);<br class="gmail_msg">
+  };<br class="gmail_msg">
+<br class="gmail_msg">
+  struct PE {<br class="gmail_msg">
+    PE(const Simplifier::Context &c, Value *v = nullptr) : C(c), V(v) {}<br class="gmail_msg">
+    const Simplifier::Context &C;<br class="gmail_msg">
+    const Value *V;<br class="gmail_msg">
+  };<br class="gmail_msg">
+<br class="gmail_msg">
+  raw_ostream &operator<< (raw_ostream &OS, const PE &P) LLVM_ATTRIBUTE_USED;<br class="gmail_msg">
+  raw_ostream &operator<< (raw_ostream &OS, const PE &P) {<br class="gmail_msg">
+    P.C.print(OS, P.V ? P.V : P.C.Root);<br class="gmail_msg">
+    return OS;<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+void Simplifier::Context::print(raw_ostream &OS, const Value *V) const {<br class="gmail_msg">
+  const auto *U = dyn_cast<const Instruction>(V);<br class="gmail_msg">
+  if (!U) {<br class="gmail_msg">
+    OS << V << '(' << *V << ')';<br class="gmail_msg">
+    return;<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  if (U->getParent()) {<br class="gmail_msg">
+    OS << U << '(';<br class="gmail_msg">
+    U->printAsOperand(OS, true);<br class="gmail_msg">
+    OS << ')';<br class="gmail_msg">
+    return;<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  unsigned N = U->getNumOperands();<br class="gmail_msg">
+  if (N != 0)<br class="gmail_msg">
+    OS << U << '(';<br class="gmail_msg">
+  OS << U->getOpcodeName();<br class="gmail_msg">
+  for (const Value *Op : U->operands()) {<br class="gmail_msg">
+    OS << ' ';<br class="gmail_msg">
+    print(OS, Op);<br class="gmail_msg">
+  }<br class="gmail_msg">
+  if (N != 0)<br class="gmail_msg">
+    OS << ')';<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+void Simplifier::Context::initialize(Instruction *Exp) {<br class="gmail_msg">
+  // Perform a deep clone of the expression, set Root to the root<br class="gmail_msg">
+  // of the clone, and build a map from the cloned values to the<br class="gmail_msg">
+  // original ones.<br class="gmail_msg">
+  BasicBlock *Block = Exp->getParent();<br class="gmail_msg">
+  WorkListType Q;<br class="gmail_msg">
+  Q.push_back(Exp);<br class="gmail_msg">
+<br class="gmail_msg">
+  while (!Q.empty()) {<br class="gmail_msg">
+    Value *V = Q.front();<br class="gmail_msg">
+    Q.pop_front();<br class="gmail_msg">
+    if (Clones.find(V) != Clones.end())<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    if (Instruction *U = dyn_cast<Instruction>(V)) {<br class="gmail_msg">
+      if (isa<PHINode>(U) || U->getParent() != Block)<br class="gmail_msg">
+        continue;<br class="gmail_msg">
+      for (Value *Op : U->operands())<br class="gmail_msg">
+        Q.push_back(Op);<br class="gmail_msg">
+      Clones.insert({U, U->clone()});<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  for (std::pair<Value*,Value*> P : Clones) {<br class="gmail_msg">
+    Instruction *U = cast<Instruction>(P.second);<br class="gmail_msg">
+    for (unsigned i = 0, n = U->getNumOperands(); i != n; ++i) {<br class="gmail_msg">
+      auto F = Clones.find(U->getOperand(i));<br class="gmail_msg">
+      if (F != Clones.end())<br class="gmail_msg">
+        U->setOperand(i, F->second);<br class="gmail_msg">
+    }<br class="gmail_msg">
+    Orig.insert({P.second, P.first});<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  auto R = Clones.find(Exp);<br class="gmail_msg">
+  assert(R != Clones.end());<br class="gmail_msg">
+  Root = R->second;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+void Simplifier::Context::reset() {<br class="gmail_msg">
+  ValueSetType NewUsed;<br class="gmail_msg">
+  WorkListType Q;<br class="gmail_msg">
+  Q.push_back(Root);<br class="gmail_msg">
+<br class="gmail_msg">
+  while (!Q.empty()) {<br class="gmail_msg">
+    Instruction *U = dyn_cast<Instruction>(Q.front());<br class="gmail_msg">
+    Q.pop_front();<br class="gmail_msg">
+    if (!U || U->getParent())<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    NewUsed.insert(U);<br class="gmail_msg">
+    for (Value *Op : U->operands())<br class="gmail_msg">
+      Q.push_back(Op);<br class="gmail_msg">
+  }<br class="gmail_msg">
+  for (Value *V : Used)<br class="gmail_msg">
+    if (!NewUsed.count(V))<br class="gmail_msg">
+      cast<Instruction>(V)->dropAllReferences();<br class="gmail_msg">
+  Used = NewUsed;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+Value *Simplifier::Context::subst(Value *Tree, Value *OldV, Value *NewV) {<br class="gmail_msg">
+  if (Tree == OldV) {<br class="gmail_msg">
+    cleanup(OldV);<br class="gmail_msg">
+    return NewV;<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  WorkListType Q;<br class="gmail_msg">
+  Q.push_back(Tree);<br class="gmail_msg">
+  while (!Q.empty()) {<br class="gmail_msg">
+    Instruction *U = dyn_cast<Instruction>(Q.front());<br class="gmail_msg">
+    Q.pop_front();<br class="gmail_msg">
+    // If U is not an instruction, or it's not a clone, skip it.<br class="gmail_msg">
+    if (!U || U->getParent())<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    for (unsigned i = 0, n = U->getNumOperands(); i != n; ++i) {<br class="gmail_msg">
+      Value *Op = U->getOperand(i);<br class="gmail_msg">
+      if (Op == OldV) {<br class="gmail_msg">
+        cleanup(OldV);<br class="gmail_msg">
+        U->setOperand(i, NewV);<br class="gmail_msg">
+      } else {<br class="gmail_msg">
+        Q.push_back(Op);<br class="gmail_msg">
+      }<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+  return Tree;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+void Simplifier::Context::replace(Value *OldV, Value *NewV) {<br class="gmail_msg">
+  if (Root == OldV) {<br class="gmail_msg">
+    Root = NewV;<br class="gmail_msg">
+    reset();<br class="gmail_msg">
+    return;<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  // NewV may be a complex tree that has just been created by one of the<br class="gmail_msg">
+  // transformation rules. We need to make sure that it is commoned with<br class="gmail_msg">
+  // the existing Root to the maximum extent possible.<br class="gmail_msg">
+  // Identify all subtrees of NewV (including NewV itself) that have<br class="gmail_msg">
+  // equivalent counterparts in Root, and replace those subtrees with<br class="gmail_msg">
+  // these counterparts.<br class="gmail_msg">
+  WorkListType Q;<br class="gmail_msg">
+  Q.push_back(NewV);<br class="gmail_msg">
+  while (!Q.empty()) {<br class="gmail_msg">
+    Value *V = Q.front();<br class="gmail_msg">
+    Q.pop_front();<br class="gmail_msg">
+    Instruction *U = dyn_cast<Instruction>(V);<br class="gmail_msg">
+    if (!U || U->getParent())<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    if (Value *DupV = find(Root, V)) {<br class="gmail_msg">
+      if (DupV != V)<br class="gmail_msg">
+        NewV = subst(NewV, V, DupV);<br class="gmail_msg">
+    } else {<br class="gmail_msg">
+      for (Value *Op : U->operands())<br class="gmail_msg">
+        Q.push_back(Op);<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  // Now, simply replace OldV with NewV in Root.<br class="gmail_msg">
+  Root = subst(Root, OldV, NewV);<br class="gmail_msg">
+  reset();<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+void Simplifier::Context::cleanup() {<br class="gmail_msg">
+  for (Value *V : Used) {<br class="gmail_msg">
+    Instruction *U = cast<Instruction>(V);<br class="gmail_msg">
+    if (!U->getParent())<br class="gmail_msg">
+      U->dropAllReferences();<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+void Simplifier::Context::cleanup(Value *V) {<br class="gmail_msg">
+  if (!isa<Instruction>(V) || cast<Instruction>(V)->getParent() != nullptr)<br class="gmail_msg">
+    return;<br class="gmail_msg">
+  WorkListType Q;<br class="gmail_msg">
+  Q.push_back(V);<br class="gmail_msg">
+  while (!Q.empty()) {<br class="gmail_msg">
+    Instruction *U = dyn_cast<Instruction>(Q.front());<br class="gmail_msg">
+    Q.pop_front();<br class="gmail_msg">
+    if (!U || U->getParent() || Used.count(U))<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    for (Value *Op : U->operands())<br class="gmail_msg">
+      Q.push_back(Op);<br class="gmail_msg">
+    U->dropAllReferences();<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+bool Simplifier::Context::equal(const Instruction *I,<br class="gmail_msg">
+                                const Instruction *J) const {<br class="gmail_msg">
+  if (I == J)<br class="gmail_msg">
+    return true;<br class="gmail_msg">
+  if (!I->isSameOperationAs(J))<br class="gmail_msg">
+    return false;<br class="gmail_msg">
+  if (isa<PHINode>(I))<br class="gmail_msg">
+    return I->isIdenticalTo(J);<br class="gmail_msg">
+<br class="gmail_msg">
+  for (unsigned i = 0, n = I->getNumOperands(); i != n; ++i) {<br class="gmail_msg">
+    Value *OpI = I->getOperand(i), *OpJ = J->getOperand(i);<br class="gmail_msg">
+    if (OpI == OpJ)<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    auto *InI = dyn_cast<const Instruction>(OpI);<br class="gmail_msg">
+    auto *InJ = dyn_cast<const Instruction>(OpJ);<br class="gmail_msg">
+    if (InI && InJ) {<br class="gmail_msg">
+      if (!equal(InI, InJ))<br class="gmail_msg">
+        return false;<br class="gmail_msg">
+    } else if (InI != InJ || !InI)<br class="gmail_msg">
+      return false;<br class="gmail_msg">
+  }<br class="gmail_msg">
+  return true;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+Value *Simplifier::Context::find(Value *Tree, Value *Sub) const {<br class="gmail_msg">
+  Instruction *SubI = dyn_cast<Instruction>(Sub);<br class="gmail_msg">
+  WorkListType Q;<br class="gmail_msg">
+  Q.push_back(Tree);<br class="gmail_msg">
+<br class="gmail_msg">
+  while (!Q.empty()) {<br class="gmail_msg">
+    Value *V = Q.front();<br class="gmail_msg">
+    Q.pop_front();<br class="gmail_msg">
+    if (V == Sub)<br class="gmail_msg">
+      return V;<br class="gmail_msg">
+    Instruction *U = dyn_cast<Instruction>(V);<br class="gmail_msg">
+    if (!U || U->getParent())<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    if (SubI && equal(SubI, U))<br class="gmail_msg">
+      return U;<br class="gmail_msg">
+    assert(!isa<PHINode>(U));<br class="gmail_msg">
+    for (Value *Op : U->operands())<br class="gmail_msg">
+      Q.push_back(Op);<br class="gmail_msg">
+  }<br class="gmail_msg">
+  return nullptr;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+void Simplifier::Context::link(Instruction *I, BasicBlock *B,<br class="gmail_msg">
+      BasicBlock::iterator At) {<br class="gmail_msg">
+  if (I->getParent())<br class="gmail_msg">
+    return;<br class="gmail_msg">
+<br class="gmail_msg">
+  for (Value *Op : I->operands()) {<br class="gmail_msg">
+    if (Instruction *OpI = dyn_cast<Instruction>(Op))<br class="gmail_msg">
+      link(OpI, B, At);<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  B->getInstList().insert(At, I);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+Value *Simplifier::Context::materialize(BasicBlock *B,<br class="gmail_msg">
+      BasicBlock::iterator At) {<br class="gmail_msg">
+  if (Instruction *RootI = dyn_cast<Instruction>(Root))<br class="gmail_msg">
+    link(RootI, B, At);<br class="gmail_msg">
+  return Root;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+Value *Simplifier::simplify(Context &C) {<br class="gmail_msg">
+  WorkListType Q;<br class="gmail_msg">
+  Q.push_back(C.Root);<br class="gmail_msg">
+<br class="gmail_msg">
+  while (!Q.empty()) {<br class="gmail_msg">
+    Instruction *U = dyn_cast<Instruction>(Q.front());<br class="gmail_msg">
+    Q.pop_front();<br class="gmail_msg">
+    if (!U || U->getParent() || !C.Used.count(U))<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    bool Changed = false;<br class="gmail_msg">
+    for (Rule &R : Rules) {<br class="gmail_msg">
+      Value *W = R(U, C.Ctx);<br class="gmail_msg">
+      if (!W)<br class="gmail_msg">
+        continue;<br class="gmail_msg">
+      Changed = true;<br class="gmail_msg">
+      C.replace(U, W);<br class="gmail_msg">
+      Q.push_back(C.Root);<br class="gmail_msg">
+      break;<br class="gmail_msg">
+    }<br class="gmail_msg">
+    if (!Changed) {<br class="gmail_msg">
+      for (Value *Op : U->operands())<br class="gmail_msg">
+        Q.push_back(Op);<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+  return C.Root;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
 //===----------------------------------------------------------------------===//<br class="gmail_msg">
 //<br class="gmail_msg">
 //          Implementation of PolynomialMultiplyRecognize<br class="gmail_msg">
@@ -147,6 +483,14 @@ namespace {<br class="gmail_msg">
   private:<br class="gmail_msg">
     typedef SetVector<Value*> ValueSeq;<br class="gmail_msg">
<br class="gmail_msg">
+    IntegerType *getPmpyType() const {<br class="gmail_msg">
+      LLVMContext &Ctx = CurLoop->getHeader()->getParent()->getContext();<br class="gmail_msg">
+      return IntegerType::get(Ctx, 32);<br class="gmail_msg">
+    }<br class="gmail_msg">
+    bool isPromotableTo(Value *V, IntegerType *Ty);<br class="gmail_msg">
+    void promoteTo(Instruction *In, IntegerType *DestTy, BasicBlock *LoopB);<br class="gmail_msg">
+    bool promoteTypes(BasicBlock *LoopB, BasicBlock *ExitB);<br class="gmail_msg">
+<br class="gmail_msg">
     Value *getCountIV(BasicBlock *BB);<br class="gmail_msg">
     bool findCycle(Value *Out, Value *In, ValueSeq &Cycle);<br class="gmail_msg">
     void classifyCycle(Instruction *DivI, ValueSeq &Cycle, ValueSeq &Early,<br class="gmail_msg">
@@ -176,6 +520,9 @@ namespace {<br class="gmail_msg">
     unsigned getInverseMxN(unsigned QP);<br class="gmail_msg">
     Value *generate(BasicBlock::iterator At, ParsedValues &PV);<br class="gmail_msg">
<br class="gmail_msg">
+    void setupSimplifier();<br class="gmail_msg">
+<br class="gmail_msg">
+    Simplifier Simp;<br class="gmail_msg">
     Loop *CurLoop;<br class="gmail_msg">
     const DataLayout &DL;<br class="gmail_msg">
     const DominatorTree &DT;<br class="gmail_msg">
@@ -425,7 +772,6 @@ bool PolynomialMultiplyRecognize::scanSe<br class="gmail_msg">
       BasicBlock *LoopB, BasicBlock *PrehB, Value *CIV, ParsedValues &PV,<br class="gmail_msg">
       bool PreScan) {<br class="gmail_msg">
   using namespace PatternMatch;<br class="gmail_msg">
-<br class="gmail_msg">
   // The basic pattern for R = P.Q is:<br class="gmail_msg">
   // for i = 0..31<br class="gmail_msg">
   //   R = phi (0, R')<br class="gmail_msg">
@@ -529,6 +875,150 @@ bool PolynomialMultiplyRecognize::scanSe<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
+bool PolynomialMultiplyRecognize::isPromotableTo(Value *Val,<br class="gmail_msg">
+      IntegerType *DestTy) {<br class="gmail_msg">
+  IntegerType *T = dyn_cast<IntegerType>(Val->getType());<br class="gmail_msg">
+  if (!T || T->getBitWidth() > DestTy->getBitWidth())<br class="gmail_msg">
+    return false;<br class="gmail_msg">
+  if (T->getBitWidth() == DestTy->getBitWidth())<br class="gmail_msg">
+    return true;<br class="gmail_msg">
+  // Non-instructions are promotable. The reason why an instruction may not<br class="gmail_msg">
+  // be promotable is that it may produce a different result if its operands<br class="gmail_msg">
+  // and the result are promoted, for example, it may produce more non-zero<br class="gmail_msg">
+  // bits. While it would still be possible to represent the proper result<br class="gmail_msg">
+  // in a wider type, it may require adding additional instructions (which<br class="gmail_msg">
+  // we don't want to do).<br class="gmail_msg">
+  Instruction *In = dyn_cast<Instruction>(Val);<br class="gmail_msg">
+  if (!In)<br class="gmail_msg">
+    return true;<br class="gmail_msg">
+  // The bitwidth of the source type is smaller than the destination.<br class="gmail_msg">
+  // Check if the individual operation can be promoted.<br class="gmail_msg">
+  switch (In->getOpcode()) {<br class="gmail_msg">
+    case Instruction::PHI:<br class="gmail_msg">
+    case Instruction::ZExt:<br class="gmail_msg">
+    case Instruction::And:<br class="gmail_msg">
+    case Instruction::Or:<br class="gmail_msg">
+    case Instruction::Xor:<br class="gmail_msg">
+    case Instruction::LShr: // Shift right is ok.<br class="gmail_msg">
+    case Instruction::Select:<br class="gmail_msg">
+      return true;<br class="gmail_msg">
+    case Instruction::ICmp:<br class="gmail_msg">
+      if (CmpInst *CI = cast<CmpInst>(In))<br class="gmail_msg">
+        return CI->isEquality() || CI->isUnsigned();<br class="gmail_msg">
+      llvm_unreachable("Cast failed unexpectedly");<br class="gmail_msg">
+    case Instruction::Add:<br class="gmail_msg">
+      return In->hasNoSignedWrap() && In->hasNoUnsignedWrap();<br class="gmail_msg">
+  }<br class="gmail_msg">
+  return false;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+void PolynomialMultiplyRecognize::promoteTo(Instruction *In,<br class="gmail_msg">
+      IntegerType *DestTy, BasicBlock *LoopB) {<br class="gmail_msg">
+  // Leave boolean values alone.<br class="gmail_msg">
+  if (!In->getType()->isIntegerTy(1))<br class="gmail_msg">
+    In->mutateType(DestTy);<br class="gmail_msg">
+  unsigned DestBW = DestTy->getBitWidth();<br class="gmail_msg">
+<br class="gmail_msg">
+  // Handle PHIs.<br class="gmail_msg">
+  if (PHINode *P = dyn_cast<PHINode>(In)) {<br class="gmail_msg">
+    unsigned N = P->getNumIncomingValues();<br class="gmail_msg">
+    for (unsigned i = 0; i != N; ++i) {<br class="gmail_msg">
+      BasicBlock *InB = P->getIncomingBlock(i);<br class="gmail_msg">
+      if (InB == LoopB)<br class="gmail_msg">
+        continue;<br class="gmail_msg">
+      Value *InV = P->getIncomingValue(i);<br class="gmail_msg">
+      IntegerType *Ty = cast<IntegerType>(InV->getType());<br class="gmail_msg">
+      // Do not promote values in PHI nodes of type i1.<br class="gmail_msg">
+      if (Ty != P->getType()) {<br class="gmail_msg">
+        // If the value type does not match the PHI type, the PHI type<br class="gmail_msg">
+        // must have been promoted.<br class="gmail_msg">
+        assert(Ty->getBitWidth() < DestBW);<br class="gmail_msg">
+        InV = IRBuilder<>(InB->getTerminator()).CreateZExt(InV, DestTy);<br class="gmail_msg">
+        P->setIncomingValue(i, InV);<br class="gmail_msg">
+      }<br class="gmail_msg">
+    }<br class="gmail_msg">
+  } else if (ZExtInst *Z = dyn_cast<ZExtInst>(In)) {<br class="gmail_msg">
+    Value *Op = Z->getOperand(0);<br class="gmail_msg">
+    if (Op->getType() == Z->getType())<br class="gmail_msg">
+      Z->replaceAllUsesWith(Op);<br class="gmail_msg">
+    Z->eraseFromParent();<br class="gmail_msg">
+    return;<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  // Promote immediates.<br class="gmail_msg">
+  for (unsigned i = 0, n = In->getNumOperands(); i != n; ++i) {<br class="gmail_msg">
+    if (ConstantInt *CI = dyn_cast<ConstantInt>(In->getOperand(i)))<br class="gmail_msg">
+      if (CI->getType()->getBitWidth() < DestBW)<br class="gmail_msg">
+        In->setOperand(i, ConstantInt::get(DestTy, CI->getZExtValue()));<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+bool PolynomialMultiplyRecognize::promoteTypes(BasicBlock *LoopB,<br class="gmail_msg">
+      BasicBlock *ExitB) {<br class="gmail_msg">
+  assert(LoopB);<br class="gmail_msg">
+  // Skip loops where the exit block has more than one predecessor. The values<br class="gmail_msg">
+  // coming from the loop block will be promoted to another type, and so the<br class="gmail_msg">
+  // values coming into the exit block from other predecessors would also have<br class="gmail_msg">
+  // to be promoted.<br class="gmail_msg">
+  if (!ExitB || (ExitB->getSinglePredecessor() != LoopB))<br class="gmail_msg">
+    return false;<br class="gmail_msg">
+  IntegerType *DestTy = getPmpyType();<br class="gmail_msg">
+  // Check if the exit values have types that are no wider than the type<br class="gmail_msg">
+  // that we want to promote to.<br class="gmail_msg">
+  unsigned DestBW = DestTy->getBitWidth();<br class="gmail_msg">
+  for (Instruction &In : *ExitB) {<br class="gmail_msg">
+    PHINode *P = dyn_cast<PHINode>(&In);<br class="gmail_msg">
+    if (!P)<br class="gmail_msg">
+      break;<br class="gmail_msg">
+    if (P->getNumIncomingValues() != 1)<br class="gmail_msg">
+      return false;<br class="gmail_msg">
+    assert(P->getIncomingBlock(0) == LoopB);<br class="gmail_msg">
+    IntegerType *T = dyn_cast<IntegerType>(P->getType());<br class="gmail_msg">
+    if (!T || T->getBitWidth() > DestBW)<br class="gmail_msg">
+      return false;<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  // Check all instructions in the loop.<br class="gmail_msg">
+  for (Instruction &In : *LoopB)<br class="gmail_msg">
+    if (!In.isTerminator() && !isPromotableTo(&In, DestTy))<br class="gmail_msg">
+      return false;<br class="gmail_msg">
+<br class="gmail_msg">
+  // Perform the promotion.<br class="gmail_msg">
+  std::vector<Instruction*> LoopIns;<br class="gmail_msg">
+  std::transform(LoopB->begin(), LoopB->end(), std::back_inserter(LoopIns),<br class="gmail_msg">
+                 [](Instruction &In) { return &In; });<br class="gmail_msg">
+  for (Instruction *In : LoopIns)<br class="gmail_msg">
+    promoteTo(In, DestTy, LoopB);<br class="gmail_msg">
+<br class="gmail_msg">
+  // Fix up the PHI nodes in the exit block.<br class="gmail_msg">
+  Instruction *EndI = ExitB->getFirstNonPHI();<br class="gmail_msg">
+  BasicBlock::iterator End = EndI ? EndI->getIterator() : ExitB->end();<br class="gmail_msg">
+  for (auto I = ExitB->begin(); I != End; ++I) {<br class="gmail_msg">
+    PHINode *P = dyn_cast<PHINode>(I);<br class="gmail_msg">
+    if (!P)<br class="gmail_msg">
+      break;<br class="gmail_msg">
+    Type *Ty0 = P->getIncomingValue(0)->getType();<br class="gmail_msg">
+    Type *PTy = P->getType();<br class="gmail_msg">
+    if (PTy != Ty0) {<br class="gmail_msg">
+      assert(Ty0 == DestTy);<br class="gmail_msg">
+      // In order to create the trunc, P must have the promoted type.<br class="gmail_msg">
+      P->mutateType(Ty0);<br class="gmail_msg">
+      Value *T = IRBuilder<>(ExitB, End).CreateTrunc(P, PTy);<br class="gmail_msg">
+      // In order for the RAUW to work, the types of P and T must match.<br class="gmail_msg">
+      P->mutateType(PTy);<br class="gmail_msg">
+      P->replaceAllUsesWith(T);<br class="gmail_msg">
+      // Final update of the P's type.<br class="gmail_msg">
+      P->mutateType(Ty0);<br class="gmail_msg">
+      cast<Instruction>(T)->setOperand(0, P);<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  return true;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
 bool PolynomialMultiplyRecognize::findCycle(Value *Out, Value *In,<br class="gmail_msg">
       ValueSeq &Cycle) {<br class="gmail_msg">
   // Out = ..., In, ...<br class="gmail_msg">
@@ -699,6 +1189,7 @@ bool PolynomialMultiplyRecognize::keepsH<br class="gmail_msg">
       case Instruction::Select:<br class="gmail_msg">
       case Instruction::ICmp:<br class="gmail_msg">
       case Instruction::PHI:<br class="gmail_msg">
+      case Instruction::ZExt:<br class="gmail_msg">
         return true;<br class="gmail_msg">
     }<br class="gmail_msg">
   }<br class="gmail_msg">
@@ -985,13 +1476,170 @@ Value *PolynomialMultiplyRecognize::gene<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
+void PolynomialMultiplyRecognize::setupSimplifier() {<br class="gmail_msg">
+  Simp.addRule(<br class="gmail_msg">
+    // Sink zext past bitwise operations.<br class="gmail_msg">
+    [](Instruction *I, LLVMContext &Ctx) -> Value* {<br class="gmail_msg">
+      if (I->getOpcode() != Instruction::ZExt)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      Instruction *T = dyn_cast<Instruction>(I->getOperand(0));<br class="gmail_msg">
+      if (!T)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      switch (T->getOpcode()) {<br class="gmail_msg">
+        case Instruction::And:<br class="gmail_msg">
+        case Instruction::Or:<br class="gmail_msg">
+        case Instruction::Xor:<br class="gmail_msg">
+          break;<br class="gmail_msg">
+        default:<br class="gmail_msg">
+          return nullptr;<br class="gmail_msg">
+      }<br class="gmail_msg">
+      IRBuilder<> B(Ctx);<br class="gmail_msg">
+      return B.CreateBinOp(cast<BinaryOperator>(T)->getOpcode(),<br class="gmail_msg">
+                           B.CreateZExt(T->getOperand(0), I->getType()),<br class="gmail_msg">
+                           B.CreateZExt(T->getOperand(1), I->getType()));<br class="gmail_msg">
+    });<br class="gmail_msg">
+  Simp.addRule(<br class="gmail_msg">
+    // (xor (and x a) (and y a)) -> (and (xor x y) a)<br class="gmail_msg">
+    [](Instruction *I, LLVMContext &Ctx) -> Value* {<br class="gmail_msg">
+      if (I->getOpcode() != Instruction::Xor)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      Instruction *And0 = dyn_cast<Instruction>(I->getOperand(0));<br class="gmail_msg">
+      Instruction *And1 = dyn_cast<Instruction>(I->getOperand(1));<br class="gmail_msg">
+      if (!And0 || !And1)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      if (And0->getOpcode() != Instruction::And ||<br class="gmail_msg">
+          And1->getOpcode() != Instruction::And)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      if (And0->getOperand(1) != And1->getOperand(1))<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      IRBuilder<> B(Ctx);<br class="gmail_msg">
+      return B.CreateAnd(B.CreateXor(And0->getOperand(0), And1->getOperand(0)),<br class="gmail_msg">
+                         And0->getOperand(1));<br class="gmail_msg">
+    });<br class="gmail_msg">
+  Simp.addRule(<br class="gmail_msg">
+    // (Op (select c x y) z) -> (select c (Op x z) (Op y z))<br class="gmail_msg">
+    // (Op x (select c y z)) -> (select c (Op x y) (Op x z))<br class="gmail_msg">
+    [](Instruction *I, LLVMContext &Ctx) -> Value* {<br class="gmail_msg">
+      BinaryOperator *BO = dyn_cast<BinaryOperator>(I);<br class="gmail_msg">
+      if (!BO)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      Instruction::BinaryOps Op = BO->getOpcode();<br class="gmail_msg">
+      if (SelectInst *Sel = dyn_cast<SelectInst>(BO->getOperand(0))) {<br class="gmail_msg">
+        IRBuilder<> B(Ctx);<br class="gmail_msg">
+        Value *X = Sel->getTrueValue(), *Y = Sel->getFalseValue();<br class="gmail_msg">
+        Value *Z = BO->getOperand(1);<br class="gmail_msg">
+        return B.CreateSelect(Sel->getCondition(),<br class="gmail_msg">
+                              B.CreateBinOp(Op, X, Z),<br class="gmail_msg">
+                              B.CreateBinOp(Op, Y, Z));<br class="gmail_msg">
+      }<br class="gmail_msg">
+      if (SelectInst *Sel = dyn_cast<SelectInst>(BO->getOperand(1))) {<br class="gmail_msg">
+        IRBuilder<> B(Ctx);<br class="gmail_msg">
+        Value *X = BO->getOperand(0);<br class="gmail_msg">
+        Value *Y = Sel->getTrueValue(), *Z = Sel->getFalseValue();<br class="gmail_msg">
+        return B.CreateSelect(Sel->getCondition(),<br class="gmail_msg">
+                              B.CreateBinOp(Op, X, Y),<br class="gmail_msg">
+                              B.CreateBinOp(Op, X, Z));<br class="gmail_msg">
+      }<br class="gmail_msg">
+      return nullptr;<br class="gmail_msg">
+    });<br class="gmail_msg">
+  Simp.addRule(<br class="gmail_msg">
+    // (select c (select c x y) z) -> (select c x z)<br class="gmail_msg">
+    // (select c x (select c y z)) -> (select c x z)<br class="gmail_msg">
+    [](Instruction *I, LLVMContext &Ctx) -> Value* {<br class="gmail_msg">
+      SelectInst *Sel = dyn_cast<SelectInst>(I);<br class="gmail_msg">
+      if (!Sel)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      IRBuilder<> B(Ctx);<br class="gmail_msg">
+      Value *C = Sel->getCondition();<br class="gmail_msg">
+      if (SelectInst *Sel0 = dyn_cast<SelectInst>(Sel->getTrueValue())) {<br class="gmail_msg">
+        if (Sel0->getCondition() == C)<br class="gmail_msg">
+          return B.CreateSelect(C, Sel0->getTrueValue(), Sel->getFalseValue());<br class="gmail_msg">
+      }<br class="gmail_msg">
+      if (SelectInst *Sel1 = dyn_cast<SelectInst>(Sel->getFalseValue())) {<br class="gmail_msg">
+        if (Sel1->getCondition() == C)<br class="gmail_msg">
+          return B.CreateSelect(C, Sel->getTrueValue(), Sel1->getFalseValue());<br class="gmail_msg">
+      }<br class="gmail_msg">
+      return nullptr;<br class="gmail_msg">
+    });<br class="gmail_msg">
+  Simp.addRule(<br class="gmail_msg">
+    // (or (lshr x 1) 0x800.0) -> (xor (lshr x 1) 0x800.0)<br class="gmail_msg">
+    [](Instruction *I, LLVMContext &Ctx) -> Value* {<br class="gmail_msg">
+      if (I->getOpcode() != Instruction::Or)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      Instruction *LShr = dyn_cast<Instruction>(I->getOperand(0));<br class="gmail_msg">
+      if (!LShr || LShr->getOpcode() != Instruction::LShr)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      ConstantInt *One = dyn_cast<ConstantInt>(LShr->getOperand(1));<br class="gmail_msg">
+      if (!One || One->getZExtValue() != 1)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      ConstantInt *Msb = dyn_cast<ConstantInt>(I->getOperand(1));<br class="gmail_msg">
+      if (!Msb || Msb->getZExtValue() != Msb->getType()->getSignBit())<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      return IRBuilder<>(Ctx).CreateXor(LShr, Msb);<br class="gmail_msg">
+    });<br class="gmail_msg">
+  Simp.addRule(<br class="gmail_msg">
+    // (lshr (BitOp x y) c) -> (BitOp (lshr x c) (lshr y c))<br class="gmail_msg">
+    [](Instruction *I, LLVMContext &Ctx) -> Value* {<br class="gmail_msg">
+      if (I->getOpcode() != Instruction::LShr)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      BinaryOperator *BitOp = dyn_cast<BinaryOperator>(I->getOperand(0));<br class="gmail_msg">
+      if (!BitOp)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      switch (BitOp->getOpcode()) {<br class="gmail_msg">
+        case Instruction::And:<br class="gmail_msg">
+        case Instruction::Or:<br class="gmail_msg">
+        case Instruction::Xor:<br class="gmail_msg">
+          break;<br class="gmail_msg">
+        default:<br class="gmail_msg">
+          return nullptr;<br class="gmail_msg">
+      }<br class="gmail_msg">
+      IRBuilder<> B(Ctx);<br class="gmail_msg">
+      Value *S = I->getOperand(1);<br class="gmail_msg">
+      return B.CreateBinOp(BitOp->getOpcode(),<br class="gmail_msg">
+                B.CreateLShr(BitOp->getOperand(0), S),<br class="gmail_msg">
+                B.CreateLShr(BitOp->getOperand(1), S));<br class="gmail_msg">
+    });<br class="gmail_msg">
+  Simp.addRule(<br class="gmail_msg">
+    // (BitOp1 (BitOp2 x a) b) -> (BitOp2 x (BitOp1 a b))<br class="gmail_msg">
+    [](Instruction *I, LLVMContext &Ctx) -> Value* {<br class="gmail_msg">
+      auto IsBitOp = [](unsigned Op) -> bool {<br class="gmail_msg">
+        switch (Op) {<br class="gmail_msg">
+          case Instruction::And:<br class="gmail_msg">
+          case Instruction::Or:<br class="gmail_msg">
+          case Instruction::Xor:<br class="gmail_msg">
+            return true;<br class="gmail_msg">
+        }<br class="gmail_msg">
+        return false;<br class="gmail_msg">
+      };<br class="gmail_msg">
+      BinaryOperator *BitOp1 = dyn_cast<BinaryOperator>(I);<br class="gmail_msg">
+      if (!BitOp1 || !IsBitOp(BitOp1->getOpcode()))<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      BinaryOperator *BitOp2 = dyn_cast<BinaryOperator>(BitOp1->getOperand(0));<br class="gmail_msg">
+      if (!BitOp2 || !IsBitOp(BitOp2->getOpcode()))<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      ConstantInt *CA = dyn_cast<ConstantInt>(BitOp2->getOperand(1));<br class="gmail_msg">
+      ConstantInt *CB = dyn_cast<ConstantInt>(BitOp1->getOperand(1));<br class="gmail_msg">
+      if (!CA || !CB)<br class="gmail_msg">
+        return nullptr;<br class="gmail_msg">
+      IRBuilder<> B(Ctx);<br class="gmail_msg">
+      Value *X = BitOp2->getOperand(0);<br class="gmail_msg">
+      return B.CreateBinOp(BitOp2->getOpcode(), X,<br class="gmail_msg">
+                B.CreateBinOp(BitOp1->getOpcode(), CA, CB));<br class="gmail_msg">
+    });<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
 bool PolynomialMultiplyRecognize::recognize() {<br class="gmail_msg">
+  DEBUG(dbgs() << "Starting PolynomialMultiplyRecognize on loop\n"<br class="gmail_msg">
+               << *CurLoop << '\n');<br class="gmail_msg">
   // Restrictions:<br class="gmail_msg">
   // - The loop must consist of a single block.<br class="gmail_msg">
   // - The iteration count must be known at compile-time.<br class="gmail_msg">
   // - The loop must have an induction variable starting from 0, and<br class="gmail_msg">
   //   incremented in each iteration of the loop.<br class="gmail_msg">
   BasicBlock *LoopB = CurLoop->getHeader();<br class="gmail_msg">
+  DEBUG(dbgs() << "Loop header:\n" << *LoopB);<br class="gmail_msg">
+<br class="gmail_msg">
   if (LoopB != CurLoop->getLoopLatch())<br class="gmail_msg">
     return false;<br class="gmail_msg">
   BasicBlock *ExitB = CurLoop->getExitBlock();<br class="gmail_msg">
@@ -1011,30 +1659,65 @@ bool PolynomialMultiplyRecognize::recogn<br class="gmail_msg">
   Value *CIV = getCountIV(LoopB);<br class="gmail_msg">
   ParsedValues PV;<br class="gmail_msg">
   PV.IterCount = IterCount;<br class="gmail_msg">
+  DEBUG(dbgs() << "Loop IV: " << *CIV << "\nIterCount: " << IterCount << '\n');<br class="gmail_msg">
<br class="gmail_msg">
-  // Test function to see if a given select instruction is a part of the<br class="gmail_msg">
-  // pmpy pattern. The argument PreScan set to "true" indicates that only<br class="gmail_msg">
-  // a preliminary scan is needed, "false" indicated an exact match.<br class="gmail_msg">
-  auto CouldBePmpy = [this, LoopB, EntryB, CIV, &PV] (bool PreScan)<br class="gmail_msg">
-      -> std::function<bool (Instruction &I)> {<br class="gmail_msg">
-    return [this, LoopB, EntryB, CIV, &PV, PreScan] (Instruction &I) -> bool {<br class="gmail_msg">
-      if (auto *SelI = dyn_cast<SelectInst>(&I))<br class="gmail_msg">
-        return scanSelect(SelI, LoopB, EntryB, CIV, PV, PreScan);<br class="gmail_msg">
-      return false;<br class="gmail_msg">
-    };<br class="gmail_msg">
-  };<br class="gmail_msg">
-  auto PreF = std::find_if(LoopB->begin(), LoopB->end(), CouldBePmpy(true));<br class="gmail_msg">
-  if (PreF == LoopB->end())<br class="gmail_msg">
+  setupSimplifier();<br class="gmail_msg">
+<br class="gmail_msg">
+  // Perform a preliminary scan of select instructions to see if any of them<br class="gmail_msg">
+  // looks like a generator of the polynomial multiply steps. Assume that a<br class="gmail_msg">
+  // loop can only contain a single transformable operation, so stop the<br class="gmail_msg">
+  // traversal after the first reasonable candidate was found.<br class="gmail_msg">
+  // XXX: Currently this approach can modify the loop before being 100% sure<br class="gmail_msg">
+  // that the transformation can be carried out.<br class="gmail_msg">
+  bool FoundPreScan = false;<br class="gmail_msg">
+  for (Instruction &In : *LoopB) {<br class="gmail_msg">
+    SelectInst *SI = dyn_cast<SelectInst>(&In);<br class="gmail_msg">
+    if (!SI)<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+<br class="gmail_msg">
+    Simplifier::Context C(SI);<br class="gmail_msg">
+    Value *T = Simp.simplify(C);<br class="gmail_msg">
+    SelectInst *SelI = (T && isa<SelectInst>(T)) ? cast<SelectInst>(T) : SI;<br class="gmail_msg">
+    DEBUG(dbgs() << "scanSelect(pre-scan): " << PE(C, SelI) << '\n');<br class="gmail_msg">
+    if (scanSelect(SelI, LoopB, EntryB, CIV, PV, true)) {<br class="gmail_msg">
+      FoundPreScan = true;<br class="gmail_msg">
+      if (SelI != SI) {<br class="gmail_msg">
+        Value *NewSel = C.materialize(LoopB, SI->getIterator());<br class="gmail_msg">
+        SI->replaceAllUsesWith(NewSel);<br class="gmail_msg">
+        RecursivelyDeleteTriviallyDeadInstructions(SI, &TLI);<br class="gmail_msg">
+      }<br class="gmail_msg">
+      break;<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  if (!FoundPreScan) {<br class="gmail_msg">
+    DEBUG(dbgs() << "Have not found candidates for pmpy\n");<br class="gmail_msg">
     return false;<br class="gmail_msg">
+  }<br class="gmail_msg">
<br class="gmail_msg">
   if (!PV.Left) {<br class="gmail_msg">
+    // The right shift version actually only returns the higher bits of<br class="gmail_msg">
+    // the result (each iteration discards the LSB). If we want to convert it<br class="gmail_msg">
+    // to a left-shifting loop, the working data type must be at least as<br class="gmail_msg">
+    // wide as the target's pmpy instruction.<br class="gmail_msg">
+    if (!promoteTypes(LoopB, ExitB))<br class="gmail_msg">
+      return false;<br class="gmail_msg">
     convertShiftsToLeft(LoopB, ExitB, IterCount);<br class="gmail_msg">
     cleanupLoopBody(LoopB);<br class="gmail_msg">
   }<br class="gmail_msg">
<br class="gmail_msg">
-  auto PostF = std::find_if(LoopB->begin(), LoopB->end(), CouldBePmpy(false));<br class="gmail_msg">
-  if (PostF == LoopB->end())<br class="gmail_msg">
-    return false;<br class="gmail_msg">
+  // Scan the loop again, find the generating select instruction.<br class="gmail_msg">
+  bool FoundScan = false;<br class="gmail_msg">
+  for (Instruction &In : *LoopB) {<br class="gmail_msg">
+    SelectInst *SelI = dyn_cast<SelectInst>(&In);<br class="gmail_msg">
+    if (!SelI)<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    DEBUG(dbgs() << "scanSelect: " << *SelI << '\n');<br class="gmail_msg">
+    FoundScan = scanSelect(SelI, LoopB, EntryB, CIV, PV, false);<br class="gmail_msg">
+    if (FoundScan)<br class="gmail_msg">
+      break;<br class="gmail_msg">
+  }<br class="gmail_msg">
+  assert(FoundScan);<br class="gmail_msg">
<br class="gmail_msg">
   DEBUG({<br class="gmail_msg">
     StringRef PP = (PV.M ? "(P+M)" : "P");<br class="gmail_msg">
<br class="gmail_msg">
Added: llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll?rev=298282&view=auto" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll?rev=298282&view=auto</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll (added)<br class="gmail_msg">
+++ llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll Mon Mar 20 13:12:58 2017<br class="gmail_msg">
@@ -0,0 +1,84 @@<br class="gmail_msg">
+; Run -O2 to make sure that all the usual optimizations do happen before<br class="gmail_msg">
+; the Hexagon loop idiom recognition runs. This is to check that we still<br class="gmail_msg">
+; get this opportunity regardless of what happens before.<br class="gmail_msg">
+<br class="gmail_msg">
+; RUN: opt -O2 -march=hexagon -S < %s | FileCheck %s<br class="gmail_msg">
+<br class="gmail_msg">
+target triple = "hexagon"<br class="gmail_msg">
+target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"<br class="gmail_msg">
+<br class="gmail_msg">
+; CHECK-LABEL: define zeroext i16 @pmpy_mod_lsr<br class="gmail_msg">
+; There need to be two pmpy instructions.<br class="gmail_msg">
+; CHECK: call i64 @llvm.hexagon.M4.pmpyw<br class="gmail_msg">
+; CHECK: call i64 @llvm.hexagon.M4.pmpyw<br class="gmail_msg">
+<br class="gmail_msg">
+define zeroext i16 @pmpy_mod_lsr(i8 zeroext %a0, i16 zeroext %a1) #0 {<br class="gmail_msg">
+b2:<br class="gmail_msg">
+  br label %b3<br class="gmail_msg">
+<br class="gmail_msg">
+b3:                                               ; preds = %b44, %b2<br class="gmail_msg">
+  %v4 = phi i8 [ %a0, %b2 ], [ %v19, %b44 ]<br class="gmail_msg">
+  %v5 = phi i16 [ %a1, %b2 ], [ %v43, %b44 ]<br class="gmail_msg">
+  %v6 = phi i8 [ 0, %b2 ], [ %v45, %b44 ]<br class="gmail_msg">
+  %v7 = zext i8 %v6 to i32<br class="gmail_msg">
+  %v8 = icmp slt i32 %v7, 8<br class="gmail_msg">
+  br i1 %v8, label %b9, label %b46<br class="gmail_msg">
+<br class="gmail_msg">
+b9:                                               ; preds = %b3<br class="gmail_msg">
+  %v10 = zext i8 %v4 to i32<br class="gmail_msg">
+  %v11 = and i32 %v10, 1<br class="gmail_msg">
+  %v12 = trunc i16 %v5 to i8<br class="gmail_msg">
+  %v13 = zext i8 %v12 to i32<br class="gmail_msg">
+  %v14 = and i32 %v13, 1<br class="gmail_msg">
+  %v15 = xor i32 %v11, %v14<br class="gmail_msg">
+  %v16 = trunc i32 %v15 to i8<br class="gmail_msg">
+  %v17 = zext i8 %v4 to i32<br class="gmail_msg">
+  %v18 = ashr i32 %v17, 1<br class="gmail_msg">
+  %v19 = trunc i32 %v18 to i8<br class="gmail_msg">
+  %v20 = zext i8 %v16 to i32<br class="gmail_msg">
+  %v21 = icmp eq i32 %v20, 1<br class="gmail_msg">
+  br i1 %v21, label %b22, label %b26<br class="gmail_msg">
+<br class="gmail_msg">
+b22:                                              ; preds = %b9<br class="gmail_msg">
+  %v23 = zext i16 %v5 to i32<br class="gmail_msg">
+  %v24 = xor i32 %v23, 16386<br class="gmail_msg">
+  %v25 = trunc i32 %v24 to i16<br class="gmail_msg">
+  br label %b27<br class="gmail_msg">
+<br class="gmail_msg">
+b26:                                              ; preds = %b9<br class="gmail_msg">
+  br label %b27<br class="gmail_msg">
+<br class="gmail_msg">
+b27:                                              ; preds = %b26, %b22<br class="gmail_msg">
+  %v28 = phi i16 [ %v25, %b22 ], [ %v5, %b26 ]<br class="gmail_msg">
+  %v29 = phi i8 [ 1, %b22 ], [ 0, %b26 ]<br class="gmail_msg">
+  %v30 = zext i16 %v28 to i32<br class="gmail_msg">
+  %v31 = ashr i32 %v30, 1<br class="gmail_msg">
+  %v32 = trunc i32 %v31 to i16<br class="gmail_msg">
+  %v33 = icmp ne i8 %v29, 0<br class="gmail_msg">
+  br i1 %v33, label %b34, label %b38<br class="gmail_msg">
+<br class="gmail_msg">
+b34:                                              ; preds = %b27<br class="gmail_msg">
+  %v35 = zext i16 %v32 to i32<br class="gmail_msg">
+  %v36 = or i32 %v35, 32768<br class="gmail_msg">
+  %v37 = trunc i32 %v36 to i16<br class="gmail_msg">
+  br label %b42<br class="gmail_msg">
+<br class="gmail_msg">
+b38:                                              ; preds = %b27<br class="gmail_msg">
+  %v39 = zext i16 %v32 to i32<br class="gmail_msg">
+  %v40 = and i32 %v39, 32767<br class="gmail_msg">
+  %v41 = trunc i32 %v40 to i16<br class="gmail_msg">
+  br label %b42<br class="gmail_msg">
+<br class="gmail_msg">
+b42:                                              ; preds = %b38, %b34<br class="gmail_msg">
+  %v43 = phi i16 [ %v37, %b34 ], [ %v41, %b38 ]<br class="gmail_msg">
+  br label %b44<br class="gmail_msg">
+<br class="gmail_msg">
+b44:                                              ; preds = %b42<br class="gmail_msg">
+  %v45 = add i8 %v6, 1<br class="gmail_msg">
+  br label %b3<br class="gmail_msg">
+<br class="gmail_msg">
+b46:                                              ; preds = %b3<br class="gmail_msg">
+  ret i16 %v5<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+attributes #0 = { noinline nounwind "target-cpu"="hexagonv5" "target-features"="-hvx,-hvx-double,-long-calls" }<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
_______________________________________________<br class="gmail_msg">
llvm-commits mailing list<br class="gmail_msg">
<a href="mailto:llvm-commits@lists.llvm.org" class="gmail_msg" target="_blank">llvm-commits@lists.llvm.org</a><br class="gmail_msg">
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" class="gmail_msg" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br class="gmail_msg">
</blockquote></div>