<div dir="ltr">Should we just revert this?</div><br><div class="gmail_quote"><div dir="ltr">On Mon, Mar 20, 2017 at 3:05 PM Krzysztof Parzyszek <<a href="mailto:kparzysz@codeaurora.org">kparzysz@codeaurora.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Sure. Checking...<br class="gmail_msg">
<br class="gmail_msg">
-Krzysztof<br class="gmail_msg">
<br class="gmail_msg">
On 3/20/2017 4:58 PM, Vitaly Buka wrote:<br class="gmail_msg">
> Could you please take a look?<br class="gmail_msg">
> <a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/3574/steps/check-llvm%20asan/logs/stdio" rel="noreferrer" class="gmail_msg" target="_blank">http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/3574/steps/check-llvm%20asan/logs/stdio</a><br class="gmail_msg">
><br class="gmail_msg">
> Direct leak of 136 byte(s) in 1 object(s) allocated from: #0 0x98a100 in<br class="gmail_msg">
> operator new(unsigned long)<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:82<br class="gmail_msg">
> #1 0x3d355e5 in allocateFixedOperandUser<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/User.cpp:128:7<br class="gmail_msg">
> #2 0x3d355e5 in llvm::User::operator new(unsigned long, unsigned int)<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/User.cpp:146<br class="gmail_msg">
> #3 0x3c3422a in Create<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/IR/Instructions.h:1962:23<br class="gmail_msg">
> #4 0x3c3422a in llvm::SelectInst::cloneImpl() const<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/Instructions.cpp:3929<br class="gmail_msg">
> #5 0x3c01f42 in llvm::Instruction::clone() const<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/IR/Instruction.def:187:1<br class="gmail_msg">
> #6 0x1921b77 in initialize<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:239:28<br class="gmail_msg">
> #7 0x1921b77 in Context<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:154<br class="gmail_msg">
> #8 0x1921b77 in (anonymous<br class="gmail_msg">
> namespace)::PolynomialMultiplyRecognize::recognize()<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:1678<br class="gmail_msg">
> #9 0x191e5b0 in runOnCountableLoop<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:2234:11<br class="gmail_msg">
> #10 0x191e5b0 in (anonymous<br class="gmail_msg">
> namespace)::HexagonLoopIdiomRecognize::runOnLoop(llvm::Loop*,<br class="gmail_msg">
> llvm::LPPassManager&)<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp:2291<br class="gmail_msg">
> #11 0x2dcf8bc in llvm::LPPassManager::runOnFunction(llvm::Function&)<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/Analysis/LoopPass.cpp:203:23<br class="gmail_msg">
> #12 0x3c7b90d in llvm::FPPassManager::runOnFunction(llvm::Function&)<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/LegacyPassManager.cpp:1513:27<br class="gmail_msg">
> #13 0x3c7beb2 in llvm::FPPassManager::runOnModule(llvm::Module&)<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/LegacyPassManager.cpp:1534:16<br class="gmail_msg">
> #14 0x3c7cd4a in runOnModule<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/LegacyPassManager.cpp:1590:27<br class="gmail_msg">
> #15 0x3c7cd4a in llvm::legacy::PassManagerImpl::run(llvm::Module&)<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/lib/IR/LegacyPassManager.cpp:1693<br class="gmail_msg">
> #16 0x9b4feb in main<br class="gmail_msg">
> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/tools/opt/opt.cpp:722:10<br class="gmail_msg">
> #17 0x7f9b7820482f in __libc_start_main<br class="gmail_msg">
> (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)<br class="gmail_msg">
><br class="gmail_msg">
><br class="gmail_msg">
> On Mon, Mar 20, 2017 at 11:25 AM Krzysztof Parzyszek via llvm-commits<br class="gmail_msg">
> <<a href="mailto:llvm-commits@lists.llvm.org" class="gmail_msg" target="_blank">llvm-commits@lists.llvm.org</a> <mailto:<a href="mailto:llvm-commits@lists.llvm.org" class="gmail_msg" target="_blank">llvm-commits@lists.llvm.org</a>>> wrote:<br class="gmail_msg">
><br class="gmail_msg">
> 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:<br class="gmail_msg">
> <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<br class="gmail_msg">
> (original)<br class="gmail_msg">
> +++ llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp<br class="gmail_msg">
> 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<br class="gmail_msg">
> 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),<br class="gmail_msg">
> 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)<br class="gmail_msg">
> 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)<br class="gmail_msg">
> 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<br class="gmail_msg">
> *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<br class="gmail_msg">
> of the<br class="gmail_msg">
> + // transformation rules. We need to make sure that it is commoned<br class="gmail_msg">
> 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() !=<br class="gmail_msg">
> 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 =<br class="gmail_msg">
> 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<br class="gmail_msg">
> *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<br class="gmail_msg">
> &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,<br class="gmail_msg">
> 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<br class="gmail_msg">
> may not<br class="gmail_msg">
> + // be promotable is that it may produce a different result if its<br class="gmail_msg">
> operands<br class="gmail_msg">
> + // and the result are promoted, for example, it may produce more<br class="gmail_msg">
> non-zero<br class="gmail_msg">
> + // bits. While it would still be possible to represent the proper<br class="gmail_msg">
> result<br class="gmail_msg">
> + // in a wider type, it may require adding additional instructions<br class="gmail_msg">
> (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,<br class="gmail_msg">
> 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,<br class="gmail_msg">
> 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.<br class="gmail_msg">
> The values<br class="gmail_msg">
> + // coming from the loop block will be promoted to another type,<br class="gmail_msg">
> and so the<br class="gmail_msg">
> + // values coming into the exit block from other predecessors<br class="gmail_msg">
> 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<br class="gmail_msg">
> 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(),<br class="gmail_msg">
> 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<br class="gmail_msg">
> 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),<br class="gmail_msg">
> I->getType()),<br class="gmail_msg">
> + B.CreateZExt(T->getOperand(1),<br class="gmail_msg">
> 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),<br class="gmail_msg">
> 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 =<br class="gmail_msg">
> dyn_cast<SelectInst>(Sel->getTrueValue())) {<br class="gmail_msg">
> + if (Sel0->getCondition() == C)<br class="gmail_msg">
> + return B.CreateSelect(C, Sel0->getTrueValue(),<br class="gmail_msg">
> Sel->getFalseValue());<br class="gmail_msg">
> + }<br class="gmail_msg">
> + if (SelectInst *Sel1 =<br class="gmail_msg">
> dyn_cast<SelectInst>(Sel->getFalseValue())) {<br class="gmail_msg">
> + if (Sel1->getCondition() == C)<br class="gmail_msg">
> + return B.CreateSelect(C, Sel->getTrueValue(),<br class="gmail_msg">
> 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 =<br class="gmail_msg">
> 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 =<br class="gmail_msg">
> 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: " <<<br class="gmail_msg">
> IterCount << '\n');<br class="gmail_msg">
><br class="gmail_msg">
> - // Test function to see if a given select instruction is a part<br class="gmail_msg">
> of the<br class="gmail_msg">
> - // pmpy pattern. The argument PreScan set to "true" indicates<br class="gmail_msg">
> 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<br class="gmail_msg">
> &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(),<br class="gmail_msg">
> 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<br class="gmail_msg">
> any of them<br class="gmail_msg">
> + // looks like a generator of the polynomial multiply steps.<br class="gmail_msg">
> Assume that a<br class="gmail_msg">
> + // loop can only contain a single transformable operation, so<br class="gmail_msg">
> 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<br class="gmail_msg">
> 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)) ?<br class="gmail_msg">
> 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<br class="gmail_msg">
> convert it<br class="gmail_msg">
> + // to a left-shifting loop, the working data type must be at<br class="gmail_msg">
> 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(),<br class="gmail_msg">
> 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:<br class="gmail_msg">
> <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<br class="gmail_msg">
> 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<br class="gmail_msg">
> before<br class="gmail_msg">
> +; the Hexagon loop idiom recognition runs. This is to check that we<br class="gmail_msg">
> 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 =<br class="gmail_msg">
> "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"<br class="gmail_msg">
> "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> <mailto:<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">
><br class="gmail_msg">
<br class="gmail_msg">
--<br class="gmail_msg">
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,<br class="gmail_msg">
hosted by The Linux Foundation<br class="gmail_msg">
</blockquote></div>