forked from OSchip/llvm-project
[SimpleLoopUnswitch] Fix introduction of UB when hoisted condition may be undef or poison
Summary: Loop unswitch hoists branches on loop-invariant conditions. However, if this condition is poison/undef and the branch wasn't originally reachable, loop unswitch introduces UB (since the optimized code will branch on poison/undef and the original one didn't)). We fix this problem by freezing the condition to ensure we don't introduce UB. We will now transform the following: while (...) { if (C) { A } else { B } } Into: C' = freeze(C) if (C') { while (...) { A } } else { while (...) { B } } This patch fixes the root cause of the following bug reports (which use the old loop unswitch, but can be reproduced with minor changes in the code and -enable-nontrivial-unswitch): - https://llvm.org/bugs/show_bug.cgi?id=27506 - https://llvm.org/bugs/show_bug.cgi?id=31652 Reviewers: reames, majnemer, chenli, sanjoy, hfinkel Reviewed By: reames Subscribers: hiraditya, jvesely, nhaehnle, filcab, regehr, trentxintong, nlopes, llvm-commits, mzolotukhin Tags: #llvm Differential Revision: https://reviews.llvm.org/D29015
This commit is contained in:
parent
b083d7a346
commit
181628b52d
|
@ -26,7 +26,9 @@
|
|||
#include "llvm/Analysis/LoopPass.h"
|
||||
#include "llvm/Analysis/MemorySSA.h"
|
||||
#include "llvm/Analysis/MemorySSAUpdater.h"
|
||||
#include "llvm/Analysis/MustExecute.h"
|
||||
#include "llvm/Analysis/Utils/Local.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
|
@ -180,11 +182,14 @@ static void buildPartialUnswitchConditionalBranch(BasicBlock &BB,
|
|||
ArrayRef<Value *> Invariants,
|
||||
bool Direction,
|
||||
BasicBlock &UnswitchedSucc,
|
||||
BasicBlock &NormalSucc) {
|
||||
BasicBlock &NormalSucc,
|
||||
bool insertFreeze) {
|
||||
IRBuilder<> IRB(&BB);
|
||||
|
||||
|
||||
Value *Cond = Direction ? IRB.CreateOr(Invariants) :
|
||||
IRB.CreateAnd(Invariants);
|
||||
if (insertFreeze)
|
||||
Cond = IRB.CreateFreeze(Cond, Cond->getName() + ".fr");
|
||||
IRB.CreateCondBr(Cond, Direction ? &UnswitchedSucc : &NormalSucc,
|
||||
Direction ? &NormalSucc : &UnswitchedSucc);
|
||||
}
|
||||
|
@ -498,7 +503,7 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|||
Instruction::And &&
|
||||
"Must have an `and` of `i1`s for the condition!");
|
||||
buildPartialUnswitchConditionalBranch(*OldPH, Invariants, ExitDirection,
|
||||
*UnswitchedBB, *NewPH);
|
||||
*UnswitchedBB, *NewPH, false);
|
||||
}
|
||||
|
||||
// Update the dominator tree with the added edge.
|
||||
|
@ -2009,6 +2014,10 @@ static void unswitchNontrivialInvariants(
|
|||
SE->forgetTopmostLoop(&L);
|
||||
}
|
||||
|
||||
ICFLoopSafetyInfo SafetyInfo(&DT);
|
||||
SafetyInfo.computeLoopSafetyInfo(&L);
|
||||
bool insertFreeze = !SafetyInfo.isGuaranteedToExecute(TI, &DT, &L);
|
||||
|
||||
// If the edge from this terminator to a successor dominates that successor,
|
||||
// store a map from each block in its dominator subtree to it. This lets us
|
||||
// tell when cloning for a particular successor if a block is dominated by
|
||||
|
@ -2066,6 +2075,12 @@ static void unswitchNontrivialInvariants(
|
|||
BasicBlock *ClonedPH = ClonedPHs.begin()->second;
|
||||
BI->setSuccessor(ClonedSucc, ClonedPH);
|
||||
BI->setSuccessor(1 - ClonedSucc, LoopPH);
|
||||
if (insertFreeze) {
|
||||
auto Cond = BI->getCondition();
|
||||
if (!isGuaranteedNotToBeUndefOrPoison(Cond))
|
||||
BI->setCondition(new FreezeInst(Cond, Cond->getName() + ".fr", BI));
|
||||
}
|
||||
|
||||
DTUpdates.push_back({DominatorTree::Insert, SplitBB, ClonedPH});
|
||||
} else {
|
||||
assert(SI && "Must either be a branch or switch!");
|
||||
|
@ -2080,6 +2095,12 @@ static void unswitchNontrivialInvariants(
|
|||
else
|
||||
Case.setSuccessor(ClonedPHs.find(Case.getCaseSuccessor())->second);
|
||||
|
||||
if (insertFreeze) {
|
||||
auto Cond = SI->getCondition();
|
||||
if (!isGuaranteedNotToBeUndefOrPoison(Cond))
|
||||
SI->setCondition(new FreezeInst(Cond, Cond->getName() + ".fr", SI));
|
||||
}
|
||||
|
||||
// We need to use the set to populate domtree updates as even when there
|
||||
// are multiple cases pointing at the same successor we only want to
|
||||
// remove and insert one edge in the domtree.
|
||||
|
@ -2156,7 +2177,7 @@ static void unswitchNontrivialInvariants(
|
|||
// When doing a partial unswitch, we have to do a bit more work to build up
|
||||
// the branch in the split block.
|
||||
buildPartialUnswitchConditionalBranch(*SplitBB, Invariants, Direction,
|
||||
*ClonedPH, *LoopPH);
|
||||
*ClonedPH, *LoopPH, insertFreeze);
|
||||
DTUpdates.push_back({DominatorTree::Insert, SplitBB, ClonedPH});
|
||||
|
||||
if (MSSAU) {
|
||||
|
|
|
@ -85,8 +85,14 @@
|
|||
|
||||
declare void @bar()
|
||||
|
||||
define void @loop_nested3_conds5(i32* %addr, i1 %c1, i1 %c2, i1 %c3, i1 %c4, i1 %c5) {
|
||||
define void @loop_nested3_conds5(i32* %addr, i1 %c1i, i1 %c2i, i1 %c3i, i1 %c4i, i1 %c5i) {
|
||||
entry:
|
||||
; c1 ~ c5 are guaranteed to be never undef or poison.
|
||||
%c1 = freeze i1 %c1i
|
||||
%c2 = freeze i1 %c2i
|
||||
%c3 = freeze i1 %c3i
|
||||
%c4 = freeze i1 %c4i
|
||||
%c5 = freeze i1 %c5i
|
||||
%addr1 = getelementptr i32, i32* %addr, i64 0
|
||||
%addr2 = getelementptr i32, i32* %addr, i64 1
|
||||
%addr3 = getelementptr i32, i32* %addr, i64 2
|
||||
|
|
|
@ -97,8 +97,14 @@
|
|||
|
||||
declare void @bar()
|
||||
|
||||
define void @loop_nested3_conds5(i32* %addr, i1 %c1, i1 %c2, i1 %c3, i1 %c4, i1 %c5) {
|
||||
define void @loop_nested3_conds5(i32* %addr, i1 %c1i, i1 %c2i, i1 %c3i, i1 %c4i, i1 %c5i) {
|
||||
entry:
|
||||
; c1 ~ c5 are guaranteed to be never undef or poison.
|
||||
%c1 = freeze i1 %c1i
|
||||
%c2 = freeze i1 %c2i
|
||||
%c3 = freeze i1 %c3i
|
||||
%c4 = freeze i1 %c4i
|
||||
%c5 = freeze i1 %c5i
|
||||
%addr1 = getelementptr i32, i32* %addr, i64 0
|
||||
%addr2 = getelementptr i32, i32* %addr, i64 1
|
||||
%addr3 = getelementptr i32, i32* %addr, i64 2
|
||||
|
|
|
@ -86,8 +86,11 @@
|
|||
; LOOP-MAX-COUNT-111: Loop at depth 2 containing:
|
||||
; LOOP-MAX-NOT: Loop at depth 2 containing:
|
||||
|
||||
define i32 @loop_switch(i32* %addr, i32 %c1, i32 %c2) {
|
||||
define i32 @loop_switch(i32* %addr, i32 %c1i, i32 %c2i) {
|
||||
entry:
|
||||
; c1, c2 are guaranteed to be never undef or poison.
|
||||
%c1 = freeze i32 %c1i
|
||||
%c2 = freeze i32 %c2i
|
||||
%addr1 = getelementptr i32, i32* %addr, i64 0
|
||||
%addr2 = getelementptr i32, i32* %addr, i64 1
|
||||
%check0 = icmp eq i32 %c2, 0
|
||||
|
|
|
@ -81,7 +81,8 @@ exit:
|
|||
define void @test_conditional_guards(i1 %cond, i32 %N) {
|
||||
; CHECK-LABEL: @test_conditional_guards(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]]
|
||||
; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK: entry.split.us:
|
||||
; CHECK-NEXT: br label [[LOOP_US:%.*]]
|
||||
; CHECK: loop.us:
|
||||
|
|
|
@ -57,7 +57,8 @@ define void @test_unswitch(i1* %ptr, i1 %cond) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
call void @x()
|
||||
|
@ -127,7 +128,8 @@ define void @test_unswitch_non_dup_code(i1* %ptr, i1 %cond) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
call void @x()
|
||||
|
@ -208,7 +210,8 @@ define void @test_unswitch_non_dup_code_in_cfg(i1* %ptr, i1 %cond) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
call void @x()
|
||||
|
@ -364,7 +367,8 @@ define void @test_unswitch_large_exit(i1* %ptr, i1 %cond) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
call void @x()
|
||||
|
@ -441,7 +445,8 @@ define void @test_unswitch_dedicated_exiting(i1* %ptr, i1 %cond) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
call void @x()
|
||||
|
|
|
@ -814,7 +814,8 @@ inner_loop_begin:
|
|||
; CHECK-NEXT: %[[A_INNER_PHI:.*]] = phi i32 [ %[[A]], %loop_begin ], [ %[[A2:.*]], %inner_inner_loop_exit ]
|
||||
; CHECK-NEXT: %[[COND:.*]] = load i1, i1* %cond.ptr
|
||||
; CHECK-NEXT: %[[B:.*]] = load i32, i32* %b.ptr
|
||||
; CHECK-NEXT: br i1 %[[COND]], label %inner_loop_begin.split.us, label %inner_loop_begin.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %[[COND]]
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %inner_loop_begin.split.us, label %inner_loop_begin.split
|
||||
|
||||
inner_inner_loop_begin:
|
||||
%v1 = load i1, i1* %ptr
|
||||
|
@ -967,7 +968,8 @@ inner_loop_begin:
|
|||
; CHECK-NEXT: %[[A_INNER_PHI:.*]] = phi i32 [ %[[A]], %loop_begin ], [ %[[A2:.*]], %inner_inner_loop_exit ]
|
||||
; CHECK-NEXT: %[[COND:.*]] = load i1, i1* %cond.ptr
|
||||
; CHECK-NEXT: %[[B:.*]] = load i32, i32* %b.ptr
|
||||
; CHECK-NEXT: br i1 %[[COND]], label %inner_loop_begin.split.us, label %inner_loop_begin.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %[[COND]]
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %inner_loop_begin.split.us, label %inner_loop_begin.split
|
||||
|
||||
inner_inner_loop_begin:
|
||||
%v1 = load i1, i1* %ptr
|
||||
|
@ -1120,7 +1122,8 @@ inner_loop_begin:
|
|||
; CHECK-NEXT: %[[A_INNER_PHI:.*]] = phi i32 [ %[[A]], %loop_begin ], [ %[[A2:.*]], %inner_inner_loop_exit ]
|
||||
; CHECK-NEXT: %[[COND:.*]] = load i1, i1* %cond.ptr
|
||||
; CHECK-NEXT: %[[B:.*]] = load i32, i32* %b.ptr
|
||||
; CHECK-NEXT: br i1 %[[COND]], label %inner_loop_begin.split.us, label %inner_loop_begin.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %[[COND]]
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %inner_loop_begin.split.us, label %inner_loop_begin.split
|
||||
|
||||
inner_inner_loop_begin:
|
||||
%v1 = load i1, i1* %ptr
|
||||
|
@ -1240,7 +1243,8 @@ inner_loop_begin:
|
|||
; CHECK-NEXT: %[[A_INNER_PHI:.*]] = phi i32 [ %[[A]], %loop_begin ], [ %[[A2:.*]], %inner_inner_loop_exit ]
|
||||
; CHECK-NEXT: %[[COND:.*]] = load i1, i1* %cond.ptr
|
||||
; CHECK-NEXT: %[[B:.*]] = load i32, i32* %b.ptr
|
||||
; CHECK-NEXT: br i1 %[[COND]], label %inner_loop_begin.split.us, label %inner_loop_begin.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %[[COND]]
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %inner_loop_begin.split.us, label %inner_loop_begin.split
|
||||
|
||||
inner_inner_loop_begin:
|
||||
%v1 = load i1, i1* %ptr
|
||||
|
@ -1482,7 +1486,8 @@ define i32 @test10a(i1* %ptr, i1 %cond, i32* %a.ptr) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
%a = load i32, i32* %a.ptr
|
||||
|
@ -1562,7 +1567,8 @@ define i32 @test10b(i1* %ptr, i1 %cond, i32* %a.ptr) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
%a = load i32, i32* %a.ptr
|
||||
|
@ -1661,7 +1667,8 @@ inner_loop_ph:
|
|||
br label %inner_loop_begin
|
||||
; CHECK: inner_loop_ph:
|
||||
; CHECK-NEXT: %[[COND:.*]] = load i1, i1* %cond.ptr
|
||||
; CHECK-NEXT: br i1 %[[COND]], label %inner_loop_ph.split.us, label %inner_loop_ph.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %[[COND]]
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %inner_loop_ph.split.us, label %inner_loop_ph.split
|
||||
|
||||
inner_loop_begin:
|
||||
call void @sink1(i32 %b)
|
||||
|
@ -1755,7 +1762,8 @@ inner_loop_ph:
|
|||
br label %inner_loop_begin
|
||||
; CHECK: inner_loop_ph:
|
||||
; CHECK-NEXT: %[[COND:.*]] = load i1, i1* %cond.ptr
|
||||
; CHECK-NEXT: br i1 %[[COND]], label %inner_loop_ph.split.us, label %inner_loop_ph.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %[[COND]]
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %inner_loop_ph.split.us, label %inner_loop_ph.split
|
||||
|
||||
inner_loop_begin:
|
||||
call void @sink1(i32 %b)
|
||||
|
@ -1853,7 +1861,8 @@ inner_inner_loop_ph:
|
|||
br label %inner_inner_loop_begin
|
||||
; CHECK: inner_inner_loop_ph:
|
||||
; CHECK-NEXT: %[[COND:.*]] = load i1, i1* %cond.ptr
|
||||
; CHECK-NEXT: br i1 %[[COND]], label %inner_inner_loop_ph.split.us, label %inner_inner_loop_ph.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %[[COND]]
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %inner_inner_loop_ph.split.us, label %inner_inner_loop_ph.split
|
||||
|
||||
inner_inner_loop_begin:
|
||||
call void @sink1(i32 %b)
|
||||
|
@ -1961,7 +1970,8 @@ inner_inner_loop_ph:
|
|||
br label %inner_inner_loop_begin
|
||||
; CHECK: inner_inner_loop_ph:
|
||||
; CHECK-NEXT: %[[COND:.*]] = load i1, i1* %cond.ptr
|
||||
; CHECK-NEXT: br i1 %[[COND]], label %inner_inner_loop_ph.split.us, label %inner_inner_loop_ph.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %[[COND]]
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %inner_inner_loop_ph.split.us, label %inner_inner_loop_ph.split
|
||||
|
||||
inner_inner_loop_begin:
|
||||
call void @sink1(i32 %b)
|
||||
|
@ -2048,7 +2058,8 @@ define i32 @test13a(i1* %ptr, i1 %cond, i32* %a.ptr, i32* %b.ptr) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
%a = load i32, i32* %a.ptr
|
||||
|
@ -2172,7 +2183,8 @@ define i32 @test13b(i1* %ptr, i1 %cond, i32* %a.ptr, i32* %b.ptr) {
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 %cond, label %entry.split.us, label %entry.split
|
||||
; CHECK-NEXT: %[[COND_FR:.*]] = freeze i1 %cond
|
||||
; CHECK-NEXT: br i1 %[[COND_FR]], label %entry.split.us, label %entry.split
|
||||
|
||||
loop_begin:
|
||||
%a = load i32, i32* %a.ptr
|
||||
|
@ -2420,9 +2432,10 @@ loop_exit:
|
|||
; paths to reach an inner loop after unswitching, and one of them is via the
|
||||
; predecessors of the unswitched loop header. That can allow us to find the loop
|
||||
; through multiple different paths.
|
||||
define void @test21(i1 %a, i1 %b) {
|
||||
define void @test21(i1 %a0, i1 %b) {
|
||||
; CHECK-LABEL: @test21(
|
||||
bb:
|
||||
%a = freeze i1 %a0
|
||||
br label %bb3
|
||||
; CHECK-NOT: br i1 %a
|
||||
;
|
||||
|
@ -2553,7 +2566,8 @@ define void @test23(i1 %arg, i1* %ptr) {
|
|||
entry:
|
||||
br label %outer.header
|
||||
; CHECK: entry:
|
||||
; CHECK-NEXT: br i1 %arg,
|
||||
; CHECK-NEXT: %[[ARG_FR:.*]] = freeze i1 %arg
|
||||
; CHECK-NEXT: br i1 %[[ARG_FR]],
|
||||
;
|
||||
; Just verify that we unswitched the correct bits. We should call `@f` twice in
|
||||
; one unswitch and `@f` and then `@g` in the other.
|
||||
|
@ -3064,7 +3078,8 @@ define i32 @test29(i32 %arg) {
|
|||
entry:
|
||||
br label %header
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: switch i32 %arg, label %[[ENTRY_SPLIT_C:.*]] [
|
||||
; CHECK-NEXT: %arg.fr = freeze i32 %arg
|
||||
; CHECK-NEXT: switch i32 %arg.fr, label %[[ENTRY_SPLIT_C:.*]] [
|
||||
; CHECK-NEXT: i32 0, label %[[ENTRY_SPLIT_A:.*]]
|
||||
; CHECK-NEXT: i32 1, label %[[ENTRY_SPLIT_A]]
|
||||
; CHECK-NEXT: i32 2, label %[[ENTRY_SPLIT_B:.*]]
|
||||
|
@ -3242,11 +3257,13 @@ exit:
|
|||
; a loop exit edge as those can in some cases be special. Among other things,
|
||||
; this includes an LCSSA phi with multiple entries despite being a dedicated
|
||||
; exit block.
|
||||
define i32 @test30(i32 %arg) {
|
||||
define i32 @test30(i32 %arg0) {
|
||||
; CHECK-LABEL: define i32 @test30(
|
||||
entry:
|
||||
%arg = freeze i32 %arg0
|
||||
br label %header
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: %arg = freeze i32 %arg0
|
||||
; CHECK-NEXT: switch i32 %arg, label %[[ENTRY_SPLIT_EXIT:.*]] [
|
||||
; CHECK-NEXT: i32 -1, label %[[ENTRY_SPLIT_EXIT]]
|
||||
; CHECK-NEXT: i32 0, label %[[ENTRY_SPLIT_A:.*]]
|
||||
|
@ -3426,7 +3443,8 @@ b.header:
|
|||
br label %c.header
|
||||
; CHECK: b.header:
|
||||
; CHECK-NEXT: %v1 = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 %v1, label %[[B_HEADER_SPLIT_US:.*]], label %[[B_HEADER_SPLIT:.*]]
|
||||
; CHECK-NEXT: %[[V1_FR:.*]] = freeze i1 %v1
|
||||
; CHECK-NEXT: br i1 %[[V1_FR]], label %[[B_HEADER_SPLIT_US:.*]], label %[[B_HEADER_SPLIT:.*]]
|
||||
;
|
||||
; CHECK: [[B_HEADER_SPLIT_US]]:
|
||||
; CHECK-NEXT: br label %[[C_HEADER_US:.*]]
|
||||
|
@ -3501,7 +3519,8 @@ b.header:
|
|||
; CHECK: b.header:
|
||||
; CHECK-NEXT: %x.b = load i32, i32* %ptr
|
||||
; CHECK-NEXT: %v1 = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 %v1, label %[[B_HEADER_SPLIT_US:.*]], label %[[B_HEADER_SPLIT:.*]]
|
||||
; CHECK-NEXT: %[[V1_FR:.*]] = freeze i1 %v1
|
||||
; CHECK-NEXT: br i1 %[[V1_FR]], label %[[B_HEADER_SPLIT_US:.*]], label %[[B_HEADER_SPLIT:.*]]
|
||||
;
|
||||
; CHECK: [[B_HEADER_SPLIT_US]]:
|
||||
; CHECK-NEXT: br label %[[C_HEADER_US:.*]]
|
||||
|
@ -3589,7 +3608,8 @@ b.header:
|
|||
; CHECK: b.header:
|
||||
; CHECK-NEXT: %x.b = load i32, i32* %ptr
|
||||
; CHECK-NEXT: %v1 = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 %v1, label %[[B_HEADER_SPLIT_US:.*]], label %[[B_HEADER_SPLIT:.*]]
|
||||
; CHECK-NEXT: %[[V1_FR:.*]] = freeze i1 %v1
|
||||
; CHECK-NEXT: br i1 %[[V1_FR]], label %[[B_HEADER_SPLIT_US:.*]], label %[[B_HEADER_SPLIT:.*]]
|
||||
;
|
||||
; CHECK: [[B_HEADER_SPLIT_US]]:
|
||||
; CHECK-NEXT: br label %[[C_HEADER_US:.*]]
|
||||
|
@ -3669,7 +3689,8 @@ b.header:
|
|||
; CHECK: b.header:
|
||||
; CHECK-NEXT: %x.b = load i32, i32* %ptr
|
||||
; CHECK-NEXT: %v1 = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 %v1, label %[[B_HEADER_SPLIT_US:.*]], label %[[B_HEADER_SPLIT:.*]]
|
||||
; CHECK-NEXT: %[[V1_FR:.*]] = freeze i1 %v1
|
||||
; CHECK-NEXT: br i1 %[[V1_FR]], label %[[B_HEADER_SPLIT_US:.*]], label %[[B_HEADER_SPLIT:.*]]
|
||||
;
|
||||
; CHECK: [[B_HEADER_SPLIT_US]]:
|
||||
; CHECK-NEXT: br label %[[C_HEADER_US:.*]]
|
||||
|
@ -3767,7 +3788,8 @@ c.header:
|
|||
br label %d.header
|
||||
; CHECK: c.header:
|
||||
; CHECK-NEXT: %v1 = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 %v1, label %[[C_HEADER_SPLIT_US:.*]], label %[[C_HEADER_SPLIT:.*]]
|
||||
; CHECK-NEXT: %[[V1_FR:.*]] = freeze i1 %v1
|
||||
; CHECK-NEXT: br i1 %[[V1_FR]], label %[[C_HEADER_SPLIT_US:.*]], label %[[C_HEADER_SPLIT:.*]]
|
||||
;
|
||||
; CHECK: [[C_HEADER_SPLIT_US]]:
|
||||
; CHECK-NEXT: br label %[[D_HEADER_US:.*]]
|
||||
|
@ -3880,7 +3902,8 @@ c.header:
|
|||
; CHECK: c.header:
|
||||
; CHECK-NEXT: %x.c = load i32, i32* %ptr
|
||||
; CHECK-NEXT: %v1 = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 %v1, label %[[C_HEADER_SPLIT_US:.*]], label %[[C_HEADER_SPLIT:.*]]
|
||||
; CHECK-NEXT: %[[V1_FR:.*]] = freeze i1 %v1
|
||||
; CHECK-NEXT: br i1 %[[V1_FR]], label %[[C_HEADER_SPLIT_US:.*]], label %[[C_HEADER_SPLIT:.*]]
|
||||
;
|
||||
; CHECK: [[C_HEADER_SPLIT_US]]:
|
||||
; CHECK-NEXT: br label %[[D_HEADER_US:.*]]
|
||||
|
@ -3962,7 +3985,8 @@ b.header:
|
|||
; CHECK: b.header:
|
||||
; CHECK-NEXT: %x.b = load i32, i32* %ptr
|
||||
; CHECK-NEXT: %v1 = call i32 @cond.i32()
|
||||
; CHECK-NEXT: switch i32 %v1, label %[[B_HEADER_SPLIT:.*]] [
|
||||
; CHECK-NEXT: %[[V1_FR]] = freeze i32 %v1
|
||||
; CHECK-NEXT: switch i32 %[[V1_FR]], label %[[B_HEADER_SPLIT:.*]] [
|
||||
; CHECK-NEXT: i32 1, label %[[B_HEADER_SPLIT_US:.*]]
|
||||
; CHECK-NEXT: i32 2, label %[[B_HEADER_SPLIT_US]]
|
||||
; CHECK-NEXT: i32 3, label %[[B_HEADER_SPLIT_US]]
|
||||
|
|
Loading…
Reference in New Issue