summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorChris Bieneman <chris.bieneman@me.com>2018-01-09 21:58:46 +0000
committerChris Bieneman <chris.bieneman@me.com>2018-01-09 21:58:46 +0000
commitabdea268c1ff58f159e3aaa59fb7ccc56c316004 (patch)
tree6d6a43cda874ed7c54a059ec3b2ccaca7f13f1ce /llvm
parent1712700842c03afcb9c3c758f95fa039f912ec02 (diff)
downloadbcm5719-llvm-abdea268c1ff58f159e3aaa59fb7ccc56c316004.tar.gz
bcm5719-llvm-abdea268c1ff58f159e3aaa59fb7ccc56c316004.zip
[IPSCCP] Remove calls without side effects
Summary: When performing constant propagation for call instructions we have historically replaced all uses of the return from a call, but not removed the call itself. This is required for correctness if the calls have side effects, however the compiler should be able to safely remove calls that don't have side effects. This allows the compiler to completely fold away calls to functions that have no side effects if the inputs are constant and the output can be determined at compile time. Reviewers: davide, sanjoy, bruno, dberlin Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38856 llvm-svn: 322125
Diffstat (limited to 'llvm')
-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