summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/IR/Instruction.h8
-rw-r--r--llvm/lib/IR/Instruction.cpp5
-rw-r--r--llvm/lib/Transforms/Scalar/SCCP.cpp2
-rw-r--r--llvm/test/Transforms/IPConstantProp/remove-call-inst.ll33
-rw-r--r--llvm/test/Transforms/IPConstantProp/user-with-multiple-uses.ll5
5 files changed, 49 insertions, 4 deletions
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 6af9cbfae5d..76bc4010d8c 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -535,6 +535,14 @@ public:
/// matters, isSafeToSpeculativelyExecute may be more appropriate.
bool mayHaveSideEffects() const { return mayWriteToMemory() || mayThrow(); }
+ /// Return true if the instruction can be removed if the result is unused.
+ ///
+ /// When constant folding some instructions cannot be removed even if their
+ /// results are unused. Specifically terminator instructions and calls that
+ /// may have side effects cannot be removed without semantically changing the
+ /// generated program.
+ bool isSafeToRemove() const;
+
/// Return true if the instruction is a variety of EH-block.
bool isEHPad() const {
switch (getOpcode()) {
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 5f2a6146ad8..215c6907256 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -589,6 +589,11 @@ bool Instruction::mayThrow() const {
return isa<ResumeInst>(this);
}
+bool Instruction::isSafeToRemove() const {
+ return (!isa<CallInst>(this) || !this->mayHaveSideEffects()) &&
+ !isa<TerminatorInst>(this);
+}
+
bool Instruction::isAssociative() const {
unsigned Opcode = getOpcode();
if (isAssociative(Opcode))
diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index df6053ac201..b6d034e9fb9 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -1900,7 +1900,7 @@ static bool runIPSCCP(Module &M, const DataLayout &DL,
if (Inst->getType()->isVoidTy())
continue;
if (tryToReplaceWithConstant(Solver, Inst)) {
- if (!isa<CallInst>(Inst) && !isa<TerminatorInst>(Inst))
+ if (Inst->isSafeToRemove())
Inst->eraseFromParent();
// Hey, we just changed something!
MadeChanges = true;
diff --git a/llvm/test/Transforms/IPConstantProp/remove-call-inst.ll b/llvm/test/Transforms/IPConstantProp/remove-call-inst.ll
new file mode 100644
index 00000000000..943086ab466
--- /dev/null
+++ b/llvm/test/Transforms/IPConstantProp/remove-call-inst.ll
@@ -0,0 +1,33 @@
+; RUN: opt < %s -S -ipsccp | FileCheck %s
+; PR5596
+
+; IPSCCP should propagate the 0 argument, eliminate the switch, and propagate
+; the result.
+
+; CHECK: define i32 @main() #0 {
+; CHECK-NEXT: entry:
+; CHECK-NOT: call
+; CHECK-NEXT: ret i32 123
+
+define i32 @main() noreturn nounwind {
+entry:
+ %call2 = tail call i32 @wwrite(i64 0) nounwind
+ ret i32 %call2
+}
+
+define internal i32 @wwrite(i64 %i) nounwind readnone {
+entry:
+ switch i64 %i, label %sw.default [
+ i64 3, label %return
+ i64 10, label %return
+ ]
+
+sw.default:
+ ret i32 123
+
+return:
+ ret i32 0
+}
+
+; CHECK: attributes #0 = { noreturn nounwind }
+; CHECK: attributes #1 = { nounwind readnone }
diff --git a/llvm/test/Transforms/IPConstantProp/user-with-multiple-uses.ll b/llvm/test/Transforms/IPConstantProp/user-with-multiple-uses.ll
index 968718084e4..3146709aec6 100644
--- a/llvm/test/Transforms/IPConstantProp/user-with-multiple-uses.ll
+++ b/llvm/test/Transforms/IPConstantProp/user-with-multiple-uses.ll
@@ -15,7 +15,7 @@ entry:
ret i32 %call2
}
-define internal i32 @wwrite(i64 %i) nounwind readnone {
+define internal i32 @wwrite(i64 %i) nounwind {
entry:
switch i64 %i, label %sw.default [
i64 3, label %return
@@ -30,5 +30,4 @@ return:
}
; CHECK: attributes #0 = { noreturn nounwind }
-; CHECK: attributes #1 = { nounwind readnone }
-; CHECK: attributes [[NUW]] = { nounwind }
+; CHECK: attributes #1 = { nounwind }
OpenPOWER on IntegriCloud