summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kazantsev <max.kazantsev@azul.com>2017-11-28 07:07:55 +0000
committerMax Kazantsev <max.kazantsev@azul.com>2017-11-28 07:07:55 +0000
commit115607226a12f6dbaa2b9e32a36089a9685daa7e (patch)
tree3846ff78cbc20a0d337dd3d4bc00935865f69074
parentbf74f64e6718b73f48da255c7331d6d5ab3c601e (diff)
downloadbcm5719-llvm-115607226a12f6dbaa2b9e32a36089a9685daa7e.tar.gz
bcm5719-llvm-115607226a12f6dbaa2b9e32a36089a9685daa7e.zip
[GVN] Prevent ScalarPRE from hoisting across instructions that don't pass control flow to successors
This is to address a problem similar to those in D37460 for Scalar PRE. We should not PRE across an instruction that may not pass execution to its successor unless it is safe to speculatively execute it. Differential Revision: https://reviews.llvm.org/D38619 llvm-svn: 319147
-rw-r--r--llvm/lib/Transforms/Scalar/GVN.cpp14
-rw-r--r--llvm/test/Transforms/GVN/PRE/local-pre.ll125
2 files changed, 139 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index b031f905eba..76e295c1ad2 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -2255,6 +2255,20 @@ bool GVN::performScalarPRE(Instruction *CurInst) {
Instruction *PREInstr = nullptr;
if (NumWithout != 0) {
+ if (!isSafeToSpeculativelyExecute(CurInst)) {
+ // It is only valid to insert a new instruction if the current instruction
+ // is always executed. An instruction with implicit control flow could
+ // prevent us from doing it. If we cannot speculate the execution, then
+ // PRE should be prohibited.
+ auto It = FirstImplicitControlFlowInsts.find(CurrentBlock);
+ if (It != FirstImplicitControlFlowInsts.end()) {
+ assert(It->second->getParent() == CurrentBlock &&
+ "Implicit control flow map broken?");
+ if (OI->dominates(It->second, CurInst))
+ return false;
+ }
+ }
+
// Don't do PRE across indirect branch.
if (isa<IndirectBrInst>(PREPred->getTerminator()))
return false;
diff --git a/llvm/test/Transforms/GVN/PRE/local-pre.ll b/llvm/test/Transforms/GVN/PRE/local-pre.ll
index 943f351f17a..22d9b506644 100644
--- a/llvm/test/Transforms/GVN/PRE/local-pre.ll
+++ b/llvm/test/Transforms/GVN/PRE/local-pre.ll
@@ -1,6 +1,13 @@
; RUN: opt < %s -gvn -enable-pre -S | FileCheck %s
+declare void @may_exit() nounwind
+
+declare void @may_exit_1(i32) nounwind
+
define i32 @main(i32 %p, i32 %q) {
+
+; CHECK-LABEL: @main(
+
block1:
%cmp = icmp eq i32 %p, %q
br i1 %cmp, label %block2, label %block3
@@ -20,3 +27,121 @@ block4:
; CHECK: %b.pre-phi = phi i32 [ %.pre, %block3 ], [ %a, %block2 ]
; CHECK-NEXT: ret i32 %b.pre-phi
}
+
+; Don't PRE across implicit control flow.
+define i32 @test2(i32 %p, i32 %q) {
+
+; CHECK-LABEL: @test2
+; CHECK: block1:
+
+block1:
+ %cmp = icmp eq i32 %p, %q
+ br i1 %cmp, label %block2, label %block3
+
+block2:
+ %a = sdiv i32 %p, %q
+ br label %block4
+
+block3:
+ br label %block4
+
+; CHECK: block4:
+; CHECK-NEXT: call void @may_exit(
+; CHECK-NEXT: %b = sdiv
+; CHECK-NEXT: ret i32 %b
+
+block4:
+ call void @may_exit() nounwind
+ %b = sdiv i32 %p, %q
+ ret i32 %b
+}
+
+; Don't PRE across implicit control flow.
+define i32 @test3(i32 %p, i32 %q, i1 %r) {
+
+; CHECK-LABEL: @test3
+; CHECK: block1:
+
+block1:
+ br i1 %r, label %block2, label %block3
+
+block2:
+ %a = sdiv i32 %p, %q
+ br label %block4
+
+block3:
+ br label %block4
+
+block4:
+
+; CHECK: block4:
+; CHECK-NEXT: phi i32
+; CHECK-NEXT: call void @may_exit_1(
+; CHECK-NEXT: %b = sdiv
+; CHECK-NEXT: ret i32 %b
+
+ %phi = phi i32 [ 0, %block3 ], [ %a, %block2 ]
+ call void @may_exit_1(i32 %phi) nounwind
+ %b = sdiv i32 %p, %q
+ ret i32 %b
+
+}
+
+; It's OK to PRE an instruction that is guaranteed to be safe to execute
+; speculatively.
+; TODO: Does it make any sense in this case?
+define i32 @test4(i32 %p, i32 %q) {
+
+; CHECK-LABEL: @test4
+; CHECK: block1:
+
+block1:
+ %cmp = icmp eq i32 %p, %q
+ br i1 %cmp, label %block2, label %block3
+
+block2:
+ %a = sdiv i32 %p, 6
+ br label %block4
+
+block3:
+ br label %block4
+
+; CHECK: block4:
+; CHECK-NEXT: %b.pre-phi = phi i32
+; CHECK-NEXT: call void @may_exit(
+; CHECK-NEXT: ret i32 %b
+
+block4:
+ call void @may_exit() nounwind
+ %b = sdiv i32 %p, 6
+ ret i32 %b
+}
+
+; It is OK to PRE across implicit control flow if we don't insert new
+; instructions.
+define i32 @test5(i1 %cond, i32 %p, i32 %q) {
+
+; CHECK-LABEL: @test5
+; CHECK: block1:
+
+block1:
+ br i1 %cond, label %block2, label %block3
+
+block2:
+ %a = sdiv i32 %p, %q
+ br label %block4
+
+block3:
+ %b = sdiv i32 %p, %q
+ br label %block4
+
+; CHECK: block4:
+; CHECK-NEXT: %c.pre-phi = phi i32 [ %b, %block3 ], [ %a, %block2 ]
+; CHECK-NEXT: call void @may_exit()
+; CHECK-NEXT: ret i32 %c.pre-phi
+
+block4:
+ call void @may_exit() nounwind
+ %c = sdiv i32 %p, %q
+ ret i32 %c
+}
OpenPOWER on IntegriCloud