summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombine.h1
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp77
-rw-r--r--llvm/test/Transforms/InstCombine/vec_phi_extract.ll27
3 files changed, 105 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombine.h b/llvm/lib/Transforms/InstCombine/InstCombine.h
index 1f6a3a5e335..2a360747500 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombine.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombine.h
@@ -233,6 +233,7 @@ private:
Instruction *transformSExtICmp(ICmpInst *ICI, Instruction &CI);
bool WillNotOverflowSignedAdd(Value *LHS, Value *RHS);
Value *EmitGEPOffset(User *GEP);
+ Instruction *scalarizePHI(ExtractElementInst &EI, PHINode *PN);
public:
// InsertNewInstBefore - insert an instruction New before instruction Old
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
index bbfad8693eb..d13c2af4727 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
@@ -105,6 +105,75 @@ static Value *FindScalarElement(Value *V, unsigned EltNo) {
return 0;
}
+// If we have a PHI node with a vector type that has only 2 uses: feed
+// itself and be an operand of extractelemnt at a constant location,
+// try to replace the PHI of the vector type with a PHI of a scalar type
+Instruction *InstCombiner::scalarizePHI(ExtractElementInst &EI, PHINode *PN) {
+ // Verify that the PHI node has exactly 2 uses. Otherwise return NULL.
+ if (!PN->hasNUses(2))
+ return NULL;
+
+ // If so, it's known at this point that one operand is PHI and the other is
+ // an extractelement node. Find the PHI user that is not the extractelement
+ // node.
+ Value::use_iterator iu = PN->use_begin();
+ Instruction *PHIUser = dyn_cast<Instruction>(*iu);
+ if (PHIUser == cast<Instruction>(&EI))
+ PHIUser = cast<Instruction>(*(++iu));
+
+ // Verify that this PHI user has one use, which is the PHI itself,
+ // and that it is a binary operation which is cheap to scalarize.
+ // otherwise return NULL.
+ if (!PHIUser->hasOneUse() || !(PHIUser->use_back() == PN) ||
+ !(isa<BinaryOperator>(PHIUser)) ||
+ !CheapToScalarize(PHIUser, true))
+ return NULL;
+
+ // Create a scalar PHI node that will replace the vector PHI node
+ // just before the current PHI node.
+ PHINode * scalarPHI = cast<PHINode>(
+ InsertNewInstWith(PHINode::Create(EI.getType(),
+ PN->getNumIncomingValues(), ""), *PN));
+ // Scalarize each PHI operand.
+ for (unsigned i=0; i < PN->getNumIncomingValues(); i++) {
+ Value *PHIInVal = PN->getIncomingValue(i);
+ BasicBlock *inBB = PN->getIncomingBlock(i);
+ Value *Elt = EI.getIndexOperand();
+ // If the operand is the PHI induction variable:
+ if (PHIInVal == PHIUser) {
+ // Scalarize the binary operation. Its first operand is the
+ // scalar PHI and the second operand is extracted from the other
+ // vector operand.
+ BinaryOperator *B0 = cast<BinaryOperator>(PHIUser);
+ unsigned opId = (B0->getOperand(0) == PN) ? 1: 0;
+ Value *Op = Builder->CreateExtractElement(
+ B0->getOperand(opId), Elt, B0->getOperand(opId)->getName()+".Elt");
+ Value *newPHIUser = InsertNewInstWith(
+ BinaryOperator::Create(B0->getOpcode(), scalarPHI,Op),
+ *B0);
+ scalarPHI->addIncoming(newPHIUser, inBB);
+ } else {
+ // Scalarize PHI input:
+ Instruction *newEI =
+ ExtractElementInst::Create(PHIInVal, Elt, "");
+ // Insert the new instruction into the predecessor basic block.
+ Instruction *pos = dyn_cast<Instruction>(PHIInVal);
+ BasicBlock::iterator InsertPos;
+ if (pos && !isa<PHINode>(pos)) {
+ InsertPos = pos;
+ ++InsertPos;
+ } else {
+ InsertPos = inBB->getFirstInsertionPt();
+ }
+
+ InsertNewInstWith(newEI, *InsertPos);
+
+ scalarPHI->addIncoming(newEI, inBB);
+ }
+ }
+ return ReplaceInstUsesWith(EI, scalarPHI);
+}
+
Instruction *InstCombiner::visitExtractElementInst(ExtractElementInst &EI) {
// If vector val is constant with all elements the same, replace EI with
// that element. We handle a known element # below.
@@ -149,6 +218,14 @@ Instruction *InstCombiner::visitExtractElementInst(ExtractElementInst &EI) {
if (Value *Elt = FindScalarElement(BCI->getOperand(0), IndexVal))
return new BitCastInst(Elt, EI.getType());
}
+
+ // If there's a vector PHI feeding a scalar use through this extractelement
+ // instruction, try to scalarize the PHI.
+ if (PHINode *PN = dyn_cast<PHINode>(EI.getOperand(0))) {
+ Instruction *scalarPHI = scalarizePHI(EI, PN);
+ if (scalarPHI)
+ return (scalarPHI);
+ }
}
if (Instruction *I = dyn_cast<Instruction>(EI.getOperand(0))) {
diff --git a/llvm/test/Transforms/InstCombine/vec_phi_extract.ll b/llvm/test/Transforms/InstCombine/vec_phi_extract.ll
new file mode 100644
index 00000000000..2f10fc2c1ed
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/vec_phi_extract.ll
@@ -0,0 +1,27 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define void @f(i64 %val, i32 %limit, i32 *%ptr) {
+;CHECK: %0 = trunc i64
+;CHECK: %1 = phi i32
+entry:
+ %tempvector = insertelement <16 x i64> undef, i64 %val, i32 0
+ %vector = shufflevector <16 x i64> %tempvector, <16 x i64> undef, <16 x i32> zeroinitializer
+ %0 = add <16 x i64> %vector, <i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12, i64 13, i64 14, i64 15>
+ %1 = trunc <16 x i64> %0 to <16 x i32>
+ br label %loop
+
+loop:
+ %2 = phi <16 x i32> [ %1, %entry ], [ %inc, %loop ]
+ %elt = extractelement <16 x i32> %2, i32 0
+ %end = icmp ult i32 %elt, %limit
+ %3 = add i32 10, %elt
+ %4 = sext i32 %elt to i64
+ %5 = getelementptr i32* %ptr, i64 %4
+ store i32 %3, i32* %5
+ %inc = add <16 x i32> %2, <i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16>
+ br i1 %end, label %loop, label %ret
+
+ret:
+ ret void
+}
+
OpenPOWER on IntegriCloud