[llvm] r298329 - Revert "[Hexagon] Recognize polynomial-modulo loop idiom again"
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 20 17:59:52 PDT 2017
Author: vitalybuka
Date: Mon Mar 20 19:59:51 2017
New Revision: 298329
URL: http://llvm.org/viewvc/llvm-project?rev=298329&view=rev
Log:
Revert "[Hexagon] Recognize polynomial-modulo loop idiom again"
Fix memory leaks on check-llvm tests detected by Asan.
This reverts commit r298282.
Removed:
llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll
Modified:
llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp
Modified: llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp?rev=298329&r1=298328&r2=298329&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp Mon Mar 20 19:59:51 2017
@@ -129,342 +129,6 @@ INITIALIZE_PASS_END(HexagonLoopIdiomReco
"Recognize Hexagon-specific loop idioms", false, false)
-namespace {
- struct Simplifier {
- typedef std::function<Value* (Instruction*, LLVMContext&)> Rule;
-
- void addRule(const Rule &R) { Rules.push_back(R); }
-
- private:
- typedef std::deque<Value*> WorkListType;
- typedef std::set<Value*> ValueSetType;
- std::vector<Rule> Rules;
-
- public:
- struct Context {
- typedef DenseMap<Value*,Value*> ValueMapType;
-
- Value *Root;
- ValueSetType Used;
- ValueMapType Clones, Orig;
- LLVMContext &Ctx;
-
- Context(Instruction *Exp)
- : Ctx(Exp->getParent()->getParent()->getContext()) {
- initialize(Exp);
- reset();
- }
- ~Context() { cleanup(); }
- void print(raw_ostream &OS, const Value *V) const;
-
- Value *materialize(BasicBlock *B, BasicBlock::iterator At);
-
- private:
- void initialize(Instruction *Exp);
- void reset();
- void cleanup();
- void cleanup(Value *V);
-
- bool equal(const Instruction *I, const Instruction *J) const;
- Value *find(Value *Tree, Value *Sub) const;
- Value *subst(Value *Tree, Value *OldV, Value *NewV);
- void replace(Value *OldV, Value *NewV);
- void link(Instruction *I, BasicBlock *B, BasicBlock::iterator At);
-
- friend struct Simplifier;
- };
-
- Value *simplify(Context &C);
- };
-
- struct PE {
- PE(const Simplifier::Context &c, Value *v = nullptr) : C(c), V(v) {}
- const Simplifier::Context &C;
- const Value *V;
- };
-
- raw_ostream &operator<< (raw_ostream &OS, const PE &P) LLVM_ATTRIBUTE_USED;
- raw_ostream &operator<< (raw_ostream &OS, const PE &P) {
- P.C.print(OS, P.V ? P.V : P.C.Root);
- return OS;
- }
-}
-
-
-void Simplifier::Context::print(raw_ostream &OS, const Value *V) const {
- const auto *U = dyn_cast<const Instruction>(V);
- if (!U) {
- OS << V << '(' << *V << ')';
- return;
- }
-
- if (U->getParent()) {
- OS << U << '(';
- U->printAsOperand(OS, true);
- OS << ')';
- return;
- }
-
- unsigned N = U->getNumOperands();
- if (N != 0)
- OS << U << '(';
- OS << U->getOpcodeName();
- for (const Value *Op : U->operands()) {
- OS << ' ';
- print(OS, Op);
- }
- if (N != 0)
- OS << ')';
-}
-
-
-void Simplifier::Context::initialize(Instruction *Exp) {
- // Perform a deep clone of the expression, set Root to the root
- // of the clone, and build a map from the cloned values to the
- // original ones.
- BasicBlock *Block = Exp->getParent();
- WorkListType Q;
- Q.push_back(Exp);
-
- while (!Q.empty()) {
- Value *V = Q.front();
- Q.pop_front();
- if (Clones.find(V) != Clones.end())
- continue;
- if (Instruction *U = dyn_cast<Instruction>(V)) {
- if (isa<PHINode>(U) || U->getParent() != Block)
- continue;
- for (Value *Op : U->operands())
- Q.push_back(Op);
- Clones.insert({U, U->clone()});
- }
- }
-
- for (std::pair<Value*,Value*> P : Clones) {
- Instruction *U = cast<Instruction>(P.second);
- for (unsigned i = 0, n = U->getNumOperands(); i != n; ++i) {
- auto F = Clones.find(U->getOperand(i));
- if (F != Clones.end())
- U->setOperand(i, F->second);
- }
- Orig.insert({P.second, P.first});
- }
-
- auto R = Clones.find(Exp);
- assert(R != Clones.end());
- Root = R->second;
-}
-
-
-void Simplifier::Context::reset() {
- ValueSetType NewUsed;
- WorkListType Q;
- Q.push_back(Root);
-
- while (!Q.empty()) {
- Instruction *U = dyn_cast<Instruction>(Q.front());
- Q.pop_front();
- if (!U || U->getParent())
- continue;
- NewUsed.insert(U);
- for (Value *Op : U->operands())
- Q.push_back(Op);
- }
- for (Value *V : Used)
- if (!NewUsed.count(V))
- cast<Instruction>(V)->dropAllReferences();
- Used = NewUsed;
-}
-
-
-Value *Simplifier::Context::subst(Value *Tree, Value *OldV, Value *NewV) {
- if (Tree == OldV) {
- cleanup(OldV);
- return NewV;
- }
-
- WorkListType Q;
- Q.push_back(Tree);
- while (!Q.empty()) {
- Instruction *U = dyn_cast<Instruction>(Q.front());
- Q.pop_front();
- // If U is not an instruction, or it's not a clone, skip it.
- if (!U || U->getParent())
- continue;
- for (unsigned i = 0, n = U->getNumOperands(); i != n; ++i) {
- Value *Op = U->getOperand(i);
- if (Op == OldV) {
- cleanup(OldV);
- U->setOperand(i, NewV);
- } else {
- Q.push_back(Op);
- }
- }
- }
- return Tree;
-}
-
-
-void Simplifier::Context::replace(Value *OldV, Value *NewV) {
- if (Root == OldV) {
- Root = NewV;
- reset();
- return;
- }
-
- // NewV may be a complex tree that has just been created by one of the
- // transformation rules. We need to make sure that it is commoned with
- // the existing Root to the maximum extent possible.
- // Identify all subtrees of NewV (including NewV itself) that have
- // equivalent counterparts in Root, and replace those subtrees with
- // these counterparts.
- WorkListType Q;
- Q.push_back(NewV);
- while (!Q.empty()) {
- Value *V = Q.front();
- Q.pop_front();
- Instruction *U = dyn_cast<Instruction>(V);
- if (!U || U->getParent())
- continue;
- if (Value *DupV = find(Root, V)) {
- if (DupV != V)
- NewV = subst(NewV, V, DupV);
- } else {
- for (Value *Op : U->operands())
- Q.push_back(Op);
- }
- }
-
- // Now, simply replace OldV with NewV in Root.
- Root = subst(Root, OldV, NewV);
- reset();
-}
-
-
-void Simplifier::Context::cleanup() {
- for (Value *V : Used) {
- Instruction *U = cast<Instruction>(V);
- if (!U->getParent())
- U->dropAllReferences();
- }
-}
-
-
-void Simplifier::Context::cleanup(Value *V) {
- if (!isa<Instruction>(V) || cast<Instruction>(V)->getParent() != nullptr)
- return;
- WorkListType Q;
- Q.push_back(V);
- while (!Q.empty()) {
- Instruction *U = dyn_cast<Instruction>(Q.front());
- Q.pop_front();
- if (!U || U->getParent() || Used.count(U))
- continue;
- for (Value *Op : U->operands())
- Q.push_back(Op);
- U->dropAllReferences();
- }
-}
-
-
-bool Simplifier::Context::equal(const Instruction *I,
- const Instruction *J) const {
- if (I == J)
- return true;
- if (!I->isSameOperationAs(J))
- return false;
- if (isa<PHINode>(I))
- return I->isIdenticalTo(J);
-
- for (unsigned i = 0, n = I->getNumOperands(); i != n; ++i) {
- Value *OpI = I->getOperand(i), *OpJ = J->getOperand(i);
- if (OpI == OpJ)
- continue;
- auto *InI = dyn_cast<const Instruction>(OpI);
- auto *InJ = dyn_cast<const Instruction>(OpJ);
- if (InI && InJ) {
- if (!equal(InI, InJ))
- return false;
- } else if (InI != InJ || !InI)
- return false;
- }
- return true;
-}
-
-
-Value *Simplifier::Context::find(Value *Tree, Value *Sub) const {
- Instruction *SubI = dyn_cast<Instruction>(Sub);
- WorkListType Q;
- Q.push_back(Tree);
-
- while (!Q.empty()) {
- Value *V = Q.front();
- Q.pop_front();
- if (V == Sub)
- return V;
- Instruction *U = dyn_cast<Instruction>(V);
- if (!U || U->getParent())
- continue;
- if (SubI && equal(SubI, U))
- return U;
- assert(!isa<PHINode>(U));
- for (Value *Op : U->operands())
- Q.push_back(Op);
- }
- return nullptr;
-}
-
-
-void Simplifier::Context::link(Instruction *I, BasicBlock *B,
- BasicBlock::iterator At) {
- if (I->getParent())
- return;
-
- for (Value *Op : I->operands()) {
- if (Instruction *OpI = dyn_cast<Instruction>(Op))
- link(OpI, B, At);
- }
-
- B->getInstList().insert(At, I);
-}
-
-
-Value *Simplifier::Context::materialize(BasicBlock *B,
- BasicBlock::iterator At) {
- if (Instruction *RootI = dyn_cast<Instruction>(Root))
- link(RootI, B, At);
- return Root;
-}
-
-
-Value *Simplifier::simplify(Context &C) {
- WorkListType Q;
- Q.push_back(C.Root);
-
- while (!Q.empty()) {
- Instruction *U = dyn_cast<Instruction>(Q.front());
- Q.pop_front();
- if (!U || U->getParent() || !C.Used.count(U))
- continue;
- bool Changed = false;
- for (Rule &R : Rules) {
- Value *W = R(U, C.Ctx);
- if (!W)
- continue;
- Changed = true;
- C.replace(U, W);
- Q.push_back(C.Root);
- break;
- }
- if (!Changed) {
- for (Value *Op : U->operands())
- Q.push_back(Op);
- }
- }
- return C.Root;
-}
-
-
//===----------------------------------------------------------------------===//
//
// Implementation of PolynomialMultiplyRecognize
@@ -483,14 +147,6 @@ namespace {
private:
typedef SetVector<Value*> ValueSeq;
- IntegerType *getPmpyType() const {
- LLVMContext &Ctx = CurLoop->getHeader()->getParent()->getContext();
- return IntegerType::get(Ctx, 32);
- }
- bool isPromotableTo(Value *V, IntegerType *Ty);
- void promoteTo(Instruction *In, IntegerType *DestTy, BasicBlock *LoopB);
- bool promoteTypes(BasicBlock *LoopB, BasicBlock *ExitB);
-
Value *getCountIV(BasicBlock *BB);
bool findCycle(Value *Out, Value *In, ValueSeq &Cycle);
void classifyCycle(Instruction *DivI, ValueSeq &Cycle, ValueSeq &Early,
@@ -520,9 +176,6 @@ namespace {
unsigned getInverseMxN(unsigned QP);
Value *generate(BasicBlock::iterator At, ParsedValues &PV);
- void setupSimplifier();
-
- Simplifier Simp;
Loop *CurLoop;
const DataLayout &DL;
const DominatorTree &DT;
@@ -772,6 +425,7 @@ bool PolynomialMultiplyRecognize::scanSe
BasicBlock *LoopB, BasicBlock *PrehB, Value *CIV, ParsedValues &PV,
bool PreScan) {
using namespace PatternMatch;
+
// The basic pattern for R = P.Q is:
// for i = 0..31
// R = phi (0, R')
@@ -875,150 +529,6 @@ bool PolynomialMultiplyRecognize::scanSe
}
-bool PolynomialMultiplyRecognize::isPromotableTo(Value *Val,
- IntegerType *DestTy) {
- IntegerType *T = dyn_cast<IntegerType>(Val->getType());
- if (!T || T->getBitWidth() > DestTy->getBitWidth())
- return false;
- if (T->getBitWidth() == DestTy->getBitWidth())
- return true;
- // Non-instructions are promotable. The reason why an instruction may not
- // be promotable is that it may produce a different result if its operands
- // and the result are promoted, for example, it may produce more non-zero
- // bits. While it would still be possible to represent the proper result
- // in a wider type, it may require adding additional instructions (which
- // we don't want to do).
- Instruction *In = dyn_cast<Instruction>(Val);
- if (!In)
- return true;
- // The bitwidth of the source type is smaller than the destination.
- // Check if the individual operation can be promoted.
- switch (In->getOpcode()) {
- case Instruction::PHI:
- case Instruction::ZExt:
- case Instruction::And:
- case Instruction::Or:
- case Instruction::Xor:
- case Instruction::LShr: // Shift right is ok.
- case Instruction::Select:
- return true;
- case Instruction::ICmp:
- if (CmpInst *CI = cast<CmpInst>(In))
- return CI->isEquality() || CI->isUnsigned();
- llvm_unreachable("Cast failed unexpectedly");
- case Instruction::Add:
- return In->hasNoSignedWrap() && In->hasNoUnsignedWrap();
- }
- return false;
-}
-
-
-void PolynomialMultiplyRecognize::promoteTo(Instruction *In,
- IntegerType *DestTy, BasicBlock *LoopB) {
- // Leave boolean values alone.
- if (!In->getType()->isIntegerTy(1))
- In->mutateType(DestTy);
- unsigned DestBW = DestTy->getBitWidth();
-
- // Handle PHIs.
- if (PHINode *P = dyn_cast<PHINode>(In)) {
- unsigned N = P->getNumIncomingValues();
- for (unsigned i = 0; i != N; ++i) {
- BasicBlock *InB = P->getIncomingBlock(i);
- if (InB == LoopB)
- continue;
- Value *InV = P->getIncomingValue(i);
- IntegerType *Ty = cast<IntegerType>(InV->getType());
- // Do not promote values in PHI nodes of type i1.
- if (Ty != P->getType()) {
- // If the value type does not match the PHI type, the PHI type
- // must have been promoted.
- assert(Ty->getBitWidth() < DestBW);
- InV = IRBuilder<>(InB->getTerminator()).CreateZExt(InV, DestTy);
- P->setIncomingValue(i, InV);
- }
- }
- } else if (ZExtInst *Z = dyn_cast<ZExtInst>(In)) {
- Value *Op = Z->getOperand(0);
- if (Op->getType() == Z->getType())
- Z->replaceAllUsesWith(Op);
- Z->eraseFromParent();
- return;
- }
-
- // Promote immediates.
- for (unsigned i = 0, n = In->getNumOperands(); i != n; ++i) {
- if (ConstantInt *CI = dyn_cast<ConstantInt>(In->getOperand(i)))
- if (CI->getType()->getBitWidth() < DestBW)
- In->setOperand(i, ConstantInt::get(DestTy, CI->getZExtValue()));
- }
-}
-
-
-bool PolynomialMultiplyRecognize::promoteTypes(BasicBlock *LoopB,
- BasicBlock *ExitB) {
- assert(LoopB);
- // Skip loops where the exit block has more than one predecessor. The values
- // coming from the loop block will be promoted to another type, and so the
- // values coming into the exit block from other predecessors would also have
- // to be promoted.
- if (!ExitB || (ExitB->getSinglePredecessor() != LoopB))
- return false;
- IntegerType *DestTy = getPmpyType();
- // Check if the exit values have types that are no wider than the type
- // that we want to promote to.
- unsigned DestBW = DestTy->getBitWidth();
- for (Instruction &In : *ExitB) {
- PHINode *P = dyn_cast<PHINode>(&In);
- if (!P)
- break;
- if (P->getNumIncomingValues() != 1)
- return false;
- assert(P->getIncomingBlock(0) == LoopB);
- IntegerType *T = dyn_cast<IntegerType>(P->getType());
- if (!T || T->getBitWidth() > DestBW)
- return false;
- }
-
- // Check all instructions in the loop.
- for (Instruction &In : *LoopB)
- if (!In.isTerminator() && !isPromotableTo(&In, DestTy))
- return false;
-
- // Perform the promotion.
- std::vector<Instruction*> LoopIns;
- std::transform(LoopB->begin(), LoopB->end(), std::back_inserter(LoopIns),
- [](Instruction &In) { return &In; });
- for (Instruction *In : LoopIns)
- promoteTo(In, DestTy, LoopB);
-
- // Fix up the PHI nodes in the exit block.
- Instruction *EndI = ExitB->getFirstNonPHI();
- BasicBlock::iterator End = EndI ? EndI->getIterator() : ExitB->end();
- for (auto I = ExitB->begin(); I != End; ++I) {
- PHINode *P = dyn_cast<PHINode>(I);
- if (!P)
- break;
- Type *Ty0 = P->getIncomingValue(0)->getType();
- Type *PTy = P->getType();
- if (PTy != Ty0) {
- assert(Ty0 == DestTy);
- // In order to create the trunc, P must have the promoted type.
- P->mutateType(Ty0);
- Value *T = IRBuilder<>(ExitB, End).CreateTrunc(P, PTy);
- // In order for the RAUW to work, the types of P and T must match.
- P->mutateType(PTy);
- P->replaceAllUsesWith(T);
- // Final update of the P's type.
- P->mutateType(Ty0);
- cast<Instruction>(T)->setOperand(0, P);
- }
- }
-
- return true;
-}
-
-
bool PolynomialMultiplyRecognize::findCycle(Value *Out, Value *In,
ValueSeq &Cycle) {
// Out = ..., In, ...
@@ -1189,7 +699,6 @@ bool PolynomialMultiplyRecognize::keepsH
case Instruction::Select:
case Instruction::ICmp:
case Instruction::PHI:
- case Instruction::ZExt:
return true;
}
}
@@ -1476,170 +985,13 @@ Value *PolynomialMultiplyRecognize::gene
}
-void PolynomialMultiplyRecognize::setupSimplifier() {
- Simp.addRule(
- // Sink zext past bitwise operations.
- [](Instruction *I, LLVMContext &Ctx) -> Value* {
- if (I->getOpcode() != Instruction::ZExt)
- return nullptr;
- Instruction *T = dyn_cast<Instruction>(I->getOperand(0));
- if (!T)
- return nullptr;
- switch (T->getOpcode()) {
- case Instruction::And:
- case Instruction::Or:
- case Instruction::Xor:
- break;
- default:
- return nullptr;
- }
- IRBuilder<> B(Ctx);
- return B.CreateBinOp(cast<BinaryOperator>(T)->getOpcode(),
- B.CreateZExt(T->getOperand(0), I->getType()),
- B.CreateZExt(T->getOperand(1), I->getType()));
- });
- Simp.addRule(
- // (xor (and x a) (and y a)) -> (and (xor x y) a)
- [](Instruction *I, LLVMContext &Ctx) -> Value* {
- if (I->getOpcode() != Instruction::Xor)
- return nullptr;
- Instruction *And0 = dyn_cast<Instruction>(I->getOperand(0));
- Instruction *And1 = dyn_cast<Instruction>(I->getOperand(1));
- if (!And0 || !And1)
- return nullptr;
- if (And0->getOpcode() != Instruction::And ||
- And1->getOpcode() != Instruction::And)
- return nullptr;
- if (And0->getOperand(1) != And1->getOperand(1))
- return nullptr;
- IRBuilder<> B(Ctx);
- return B.CreateAnd(B.CreateXor(And0->getOperand(0), And1->getOperand(0)),
- And0->getOperand(1));
- });
- Simp.addRule(
- // (Op (select c x y) z) -> (select c (Op x z) (Op y z))
- // (Op x (select c y z)) -> (select c (Op x y) (Op x z))
- [](Instruction *I, LLVMContext &Ctx) -> Value* {
- BinaryOperator *BO = dyn_cast<BinaryOperator>(I);
- if (!BO)
- return nullptr;
- Instruction::BinaryOps Op = BO->getOpcode();
- if (SelectInst *Sel = dyn_cast<SelectInst>(BO->getOperand(0))) {
- IRBuilder<> B(Ctx);
- Value *X = Sel->getTrueValue(), *Y = Sel->getFalseValue();
- Value *Z = BO->getOperand(1);
- return B.CreateSelect(Sel->getCondition(),
- B.CreateBinOp(Op, X, Z),
- B.CreateBinOp(Op, Y, Z));
- }
- if (SelectInst *Sel = dyn_cast<SelectInst>(BO->getOperand(1))) {
- IRBuilder<> B(Ctx);
- Value *X = BO->getOperand(0);
- Value *Y = Sel->getTrueValue(), *Z = Sel->getFalseValue();
- return B.CreateSelect(Sel->getCondition(),
- B.CreateBinOp(Op, X, Y),
- B.CreateBinOp(Op, X, Z));
- }
- return nullptr;
- });
- Simp.addRule(
- // (select c (select c x y) z) -> (select c x z)
- // (select c x (select c y z)) -> (select c x z)
- [](Instruction *I, LLVMContext &Ctx) -> Value* {
- SelectInst *Sel = dyn_cast<SelectInst>(I);
- if (!Sel)
- return nullptr;
- IRBuilder<> B(Ctx);
- Value *C = Sel->getCondition();
- if (SelectInst *Sel0 = dyn_cast<SelectInst>(Sel->getTrueValue())) {
- if (Sel0->getCondition() == C)
- return B.CreateSelect(C, Sel0->getTrueValue(), Sel->getFalseValue());
- }
- if (SelectInst *Sel1 = dyn_cast<SelectInst>(Sel->getFalseValue())) {
- if (Sel1->getCondition() == C)
- return B.CreateSelect(C, Sel->getTrueValue(), Sel1->getFalseValue());
- }
- return nullptr;
- });
- Simp.addRule(
- // (or (lshr x 1) 0x800.0) -> (xor (lshr x 1) 0x800.0)
- [](Instruction *I, LLVMContext &Ctx) -> Value* {
- if (I->getOpcode() != Instruction::Or)
- return nullptr;
- Instruction *LShr = dyn_cast<Instruction>(I->getOperand(0));
- if (!LShr || LShr->getOpcode() != Instruction::LShr)
- return nullptr;
- ConstantInt *One = dyn_cast<ConstantInt>(LShr->getOperand(1));
- if (!One || One->getZExtValue() != 1)
- return nullptr;
- ConstantInt *Msb = dyn_cast<ConstantInt>(I->getOperand(1));
- if (!Msb || Msb->getZExtValue() != Msb->getType()->getSignBit())
- return nullptr;
- return IRBuilder<>(Ctx).CreateXor(LShr, Msb);
- });
- Simp.addRule(
- // (lshr (BitOp x y) c) -> (BitOp (lshr x c) (lshr y c))
- [](Instruction *I, LLVMContext &Ctx) -> Value* {
- if (I->getOpcode() != Instruction::LShr)
- return nullptr;
- BinaryOperator *BitOp = dyn_cast<BinaryOperator>(I->getOperand(0));
- if (!BitOp)
- return nullptr;
- switch (BitOp->getOpcode()) {
- case Instruction::And:
- case Instruction::Or:
- case Instruction::Xor:
- break;
- default:
- return nullptr;
- }
- IRBuilder<> B(Ctx);
- Value *S = I->getOperand(1);
- return B.CreateBinOp(BitOp->getOpcode(),
- B.CreateLShr(BitOp->getOperand(0), S),
- B.CreateLShr(BitOp->getOperand(1), S));
- });
- Simp.addRule(
- // (BitOp1 (BitOp2 x a) b) -> (BitOp2 x (BitOp1 a b))
- [](Instruction *I, LLVMContext &Ctx) -> Value* {
- auto IsBitOp = [](unsigned Op) -> bool {
- switch (Op) {
- case Instruction::And:
- case Instruction::Or:
- case Instruction::Xor:
- return true;
- }
- return false;
- };
- BinaryOperator *BitOp1 = dyn_cast<BinaryOperator>(I);
- if (!BitOp1 || !IsBitOp(BitOp1->getOpcode()))
- return nullptr;
- BinaryOperator *BitOp2 = dyn_cast<BinaryOperator>(BitOp1->getOperand(0));
- if (!BitOp2 || !IsBitOp(BitOp2->getOpcode()))
- return nullptr;
- ConstantInt *CA = dyn_cast<ConstantInt>(BitOp2->getOperand(1));
- ConstantInt *CB = dyn_cast<ConstantInt>(BitOp1->getOperand(1));
- if (!CA || !CB)
- return nullptr;
- IRBuilder<> B(Ctx);
- Value *X = BitOp2->getOperand(0);
- return B.CreateBinOp(BitOp2->getOpcode(), X,
- B.CreateBinOp(BitOp1->getOpcode(), CA, CB));
- });
-}
-
-
bool PolynomialMultiplyRecognize::recognize() {
- DEBUG(dbgs() << "Starting PolynomialMultiplyRecognize on loop\n"
- << *CurLoop << '\n');
// Restrictions:
// - The loop must consist of a single block.
// - The iteration count must be known at compile-time.
// - The loop must have an induction variable starting from 0, and
// incremented in each iteration of the loop.
BasicBlock *LoopB = CurLoop->getHeader();
- DEBUG(dbgs() << "Loop header:\n" << *LoopB);
-
if (LoopB != CurLoop->getLoopLatch())
return false;
BasicBlock *ExitB = CurLoop->getExitBlock();
@@ -1659,65 +1011,30 @@ bool PolynomialMultiplyRecognize::recogn
Value *CIV = getCountIV(LoopB);
ParsedValues PV;
PV.IterCount = IterCount;
- DEBUG(dbgs() << "Loop IV: " << *CIV << "\nIterCount: " << IterCount << '\n');
-
- setupSimplifier();
- // Perform a preliminary scan of select instructions to see if any of them
- // looks like a generator of the polynomial multiply steps. Assume that a
- // loop can only contain a single transformable operation, so stop the
- // traversal after the first reasonable candidate was found.
- // XXX: Currently this approach can modify the loop before being 100% sure
- // that the transformation can be carried out.
- bool FoundPreScan = false;
- for (Instruction &In : *LoopB) {
- SelectInst *SI = dyn_cast<SelectInst>(&In);
- if (!SI)
- continue;
-
- Simplifier::Context C(SI);
- Value *T = Simp.simplify(C);
- SelectInst *SelI = (T && isa<SelectInst>(T)) ? cast<SelectInst>(T) : SI;
- DEBUG(dbgs() << "scanSelect(pre-scan): " << PE(C, SelI) << '\n');
- if (scanSelect(SelI, LoopB, EntryB, CIV, PV, true)) {
- FoundPreScan = true;
- if (SelI != SI) {
- Value *NewSel = C.materialize(LoopB, SI->getIterator());
- SI->replaceAllUsesWith(NewSel);
- RecursivelyDeleteTriviallyDeadInstructions(SI, &TLI);
- }
- break;
- }
- }
-
- if (!FoundPreScan) {
- DEBUG(dbgs() << "Have not found candidates for pmpy\n");
+ // Test function to see if a given select instruction is a part of the
+ // pmpy pattern. The argument PreScan set to "true" indicates that only
+ // a preliminary scan is needed, "false" indicated an exact match.
+ auto CouldBePmpy = [this, LoopB, EntryB, CIV, &PV] (bool PreScan)
+ -> std::function<bool (Instruction &I)> {
+ return [this, LoopB, EntryB, CIV, &PV, PreScan] (Instruction &I) -> bool {
+ if (auto *SelI = dyn_cast<SelectInst>(&I))
+ return scanSelect(SelI, LoopB, EntryB, CIV, PV, PreScan);
+ return false;
+ };
+ };
+ auto PreF = std::find_if(LoopB->begin(), LoopB->end(), CouldBePmpy(true));
+ if (PreF == LoopB->end())
return false;
- }
if (!PV.Left) {
- // The right shift version actually only returns the higher bits of
- // the result (each iteration discards the LSB). If we want to convert it
- // to a left-shifting loop, the working data type must be at least as
- // wide as the target's pmpy instruction.
- if (!promoteTypes(LoopB, ExitB))
- return false;
convertShiftsToLeft(LoopB, ExitB, IterCount);
cleanupLoopBody(LoopB);
}
- // Scan the loop again, find the generating select instruction.
- bool FoundScan = false;
- for (Instruction &In : *LoopB) {
- SelectInst *SelI = dyn_cast<SelectInst>(&In);
- if (!SelI)
- continue;
- DEBUG(dbgs() << "scanSelect: " << *SelI << '\n');
- FoundScan = scanSelect(SelI, LoopB, EntryB, CIV, PV, false);
- if (FoundScan)
- break;
- }
- assert(FoundScan);
+ auto PostF = std::find_if(LoopB->begin(), LoopB->end(), CouldBePmpy(false));
+ if (PostF == LoopB->end())
+ return false;
DEBUG({
StringRef PP = (PV.M ? "(P+M)" : "P");
Removed: llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll?rev=298328&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll (original)
+++ llvm/trunk/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll (removed)
@@ -1,84 +0,0 @@
-; Run -O2 to make sure that all the usual optimizations do happen before
-; the Hexagon loop idiom recognition runs. This is to check that we still
-; get this opportunity regardless of what happens before.
-
-; RUN: opt -O2 -march=hexagon -S < %s | FileCheck %s
-
-target triple = "hexagon"
-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"
-
-; CHECK-LABEL: define zeroext i16 @pmpy_mod_lsr
-; There need to be two pmpy instructions.
-; CHECK: call i64 @llvm.hexagon.M4.pmpyw
-; CHECK: call i64 @llvm.hexagon.M4.pmpyw
-
-define zeroext i16 @pmpy_mod_lsr(i8 zeroext %a0, i16 zeroext %a1) #0 {
-b2:
- br label %b3
-
-b3: ; preds = %b44, %b2
- %v4 = phi i8 [ %a0, %b2 ], [ %v19, %b44 ]
- %v5 = phi i16 [ %a1, %b2 ], [ %v43, %b44 ]
- %v6 = phi i8 [ 0, %b2 ], [ %v45, %b44 ]
- %v7 = zext i8 %v6 to i32
- %v8 = icmp slt i32 %v7, 8
- br i1 %v8, label %b9, label %b46
-
-b9: ; preds = %b3
- %v10 = zext i8 %v4 to i32
- %v11 = and i32 %v10, 1
- %v12 = trunc i16 %v5 to i8
- %v13 = zext i8 %v12 to i32
- %v14 = and i32 %v13, 1
- %v15 = xor i32 %v11, %v14
- %v16 = trunc i32 %v15 to i8
- %v17 = zext i8 %v4 to i32
- %v18 = ashr i32 %v17, 1
- %v19 = trunc i32 %v18 to i8
- %v20 = zext i8 %v16 to i32
- %v21 = icmp eq i32 %v20, 1
- br i1 %v21, label %b22, label %b26
-
-b22: ; preds = %b9
- %v23 = zext i16 %v5 to i32
- %v24 = xor i32 %v23, 16386
- %v25 = trunc i32 %v24 to i16
- br label %b27
-
-b26: ; preds = %b9
- br label %b27
-
-b27: ; preds = %b26, %b22
- %v28 = phi i16 [ %v25, %b22 ], [ %v5, %b26 ]
- %v29 = phi i8 [ 1, %b22 ], [ 0, %b26 ]
- %v30 = zext i16 %v28 to i32
- %v31 = ashr i32 %v30, 1
- %v32 = trunc i32 %v31 to i16
- %v33 = icmp ne i8 %v29, 0
- br i1 %v33, label %b34, label %b38
-
-b34: ; preds = %b27
- %v35 = zext i16 %v32 to i32
- %v36 = or i32 %v35, 32768
- %v37 = trunc i32 %v36 to i16
- br label %b42
-
-b38: ; preds = %b27
- %v39 = zext i16 %v32 to i32
- %v40 = and i32 %v39, 32767
- %v41 = trunc i32 %v40 to i16
- br label %b42
-
-b42: ; preds = %b38, %b34
- %v43 = phi i16 [ %v37, %b34 ], [ %v41, %b38 ]
- br label %b44
-
-b44: ; preds = %b42
- %v45 = add i8 %v6, 1
- br label %b3
-
-b46: ; preds = %b3
- ret i16 %v5
-}
-
-attributes #0 = { noinline nounwind "target-cpu"="hexagonv5" "target-features"="-hvx,-hvx-double,-long-calls" }
More information about the llvm-commits
mailing list