summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Analysis/ScalarEvolutionExpander.cpp15
-rw-r--r--llvm/unittests/Analysis/ScalarEvolutionTest.cpp104
2 files changed, 118 insertions, 1 deletions
diff --git a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp
index 86f714b930d..3ceda677ba6 100644
--- a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp
+++ b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp
@@ -187,8 +187,21 @@ Value *SCEVExpander::InsertBinop(Instruction::BinaryOps Opcode,
// generated code.
if (isa<DbgInfoIntrinsic>(IP))
ScanLimit++;
+
+ // Conservatively, do not use any instruction which has any of wrap/exact
+ // flags installed.
+ // TODO: Instead of simply disable poison instructions we can be clever
+ // here and match SCEV to this instruction.
+ auto canGeneratePoison = [](Instruction *I) {
+ if (isa<OverflowingBinaryOperator>(I) &&
+ (I->hasNoSignedWrap() || I->hasNoUnsignedWrap()))
+ return true;
+ if (isa<PossiblyExactOperator>(I) && I->isExact())
+ return true;
+ return false;
+ };
if (IP->getOpcode() == (unsigned)Opcode && IP->getOperand(0) == LHS &&
- IP->getOperand(1) == RHS)
+ IP->getOperand(1) == RHS && !canGeneratePoison(&*IP))
return &*IP;
if (IP == BlockBegin) break;
}
diff --git a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
index e438e8af7aa..dffb68ac94f 100644
--- a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
+++ b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
@@ -1184,5 +1184,109 @@ TEST_F(ScalarEvolutionsTest, SCEVExpanderIsSafeToExpandAt) {
EXPECT_TRUE(isSafeToExpandAt(AR, Post->getTerminator(), SE));
}
+// Check that SCEV expander does not use the nuw instruction
+// for expansion.
+TEST_F(ScalarEvolutionsTest, SCEVExpanderNUW) {
+ /*
+ * Create the following code:
+ * func(i64 %a)
+ * entry:
+ * br false, label %exit, label %body
+ * body:
+ * %s1 = add i64 %a, -1
+ * br label %exit
+ * exit:
+ * %s = add nuw i64 %a, -1
+ * ret %s
+ */
+
+ // Create a module.
+ Module M("SCEVExpanderNUW", Context);
+
+ Type *T_int64 = Type::getInt64Ty(Context);
+
+ FunctionType *FTy =
+ FunctionType::get(Type::getVoidTy(Context), { T_int64 }, false);
+ Function *F = cast<Function>(M.getOrInsertFunction("func", FTy));
+ Argument *Arg = &*F->arg_begin();
+ ConstantInt *C = ConstantInt::get(Context, APInt(64, -1));
+
+ BasicBlock *Entry = BasicBlock::Create(Context, "entry", F);
+ BasicBlock *Body = BasicBlock::Create(Context, "body", F);
+ BasicBlock *Exit = BasicBlock::Create(Context, "exit", F);
+
+ IRBuilder<> Builder(Entry);
+ ConstantInt *Cond = ConstantInt::get(Context, APInt(1, 0));
+ Builder.CreateCondBr(Cond, Exit, Body);
+
+ Builder.SetInsertPoint(Body);
+ auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add"));
+ Builder.CreateBr(Exit);
+
+ Builder.SetInsertPoint(Exit);
+ auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add"));
+ S2->setHasNoUnsignedWrap(true);
+ auto *R = cast<Instruction>(Builder.CreateRetVoid());
+
+ ScalarEvolution SE = buildSE(*F);
+ const SCEV *S = SE.getSCEV(S1);
+ EXPECT_TRUE(isa<SCEVAddExpr>(S));
+ SCEVExpander Exp(SE, M.getDataLayout(), "expander");
+ auto *I = cast<Instruction>(Exp.expandCodeFor(S, nullptr, R));
+ EXPECT_FALSE(I->hasNoUnsignedWrap());
+}
+
+// Check that SCEV expander does not use the nsw instruction
+// for expansion.
+TEST_F(ScalarEvolutionsTest, SCEVExpanderNSW) {
+ /*
+ * Create the following code:
+ * func(i64 %a)
+ * entry:
+ * br false, label %exit, label %body
+ * body:
+ * %s1 = add i64 %a, -1
+ * br label %exit
+ * exit:
+ * %s = add nsw i64 %a, -1
+ * ret %s
+ */
+
+ // Create a module.
+ Module M("SCEVExpanderNSW", Context);
+
+ Type *T_int64 = Type::getInt64Ty(Context);
+
+ FunctionType *FTy =
+ FunctionType::get(Type::getVoidTy(Context), { T_int64 }, false);
+ Function *F = cast<Function>(M.getOrInsertFunction("func", FTy));
+ Argument *Arg = &*F->arg_begin();
+ ConstantInt *C = ConstantInt::get(Context, APInt(64, -1));
+
+ BasicBlock *Entry = BasicBlock::Create(Context, "entry", F);
+ BasicBlock *Body = BasicBlock::Create(Context, "body", F);
+ BasicBlock *Exit = BasicBlock::Create(Context, "exit", F);
+
+ IRBuilder<> Builder(Entry);
+ ConstantInt *Cond = ConstantInt::get(Context, APInt(1, 0));
+ Builder.CreateCondBr(Cond, Exit, Body);
+
+ Builder.SetInsertPoint(Body);
+ auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add"));
+ Builder.CreateBr(Exit);
+
+ Builder.SetInsertPoint(Exit);
+ auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add"));
+ S2->setHasNoSignedWrap(true);
+ auto *R = cast<Instruction>(Builder.CreateRetVoid());
+
+ ScalarEvolution SE = buildSE(*F);
+ const SCEV *S = SE.getSCEV(S1);
+ EXPECT_TRUE(isa<SCEVAddExpr>(S));
+ SCEVExpander Exp(SE, M.getDataLayout(), "expander");
+ auto *I = cast<Instruction>(Exp.expandCodeFor(S, nullptr, R));
+ EXPECT_FALSE(I->hasNoSignedWrap());
+}
+
} // end anonymous namespace
} // end namespace llvm
OpenPOWER on IntegriCloud