Skip to content

Commit

Permalink
[InstCombine] Sink instructions with multiple users in a successor bl…
Browse files Browse the repository at this point in the history
…ock.

This patch tries to sink instructions when they are only used in a successor block.

This is a further enhancement patch based on Anna's commit:
D109700, which allows sinking an instruction having multiple uses in a single user.

In this patch, sink instructions with multiple users in a single successor block will be supported.
It could fix a known issue from rust:
  rust-lang/rust#51346 (comment)

Reviewed By: nikic, reames

Differential Revision: https://reviews.llvm.org/D121585
  • Loading branch information
wweiandrew committed Mar 18, 2022
1 parent c236b41 commit 0af3e6a
Show file tree
Hide file tree
Showing 17 changed files with 205 additions and 181 deletions.
91 changes: 57 additions & 34 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ static cl::opt<bool>
EnableCodeSinking("instcombine-code-sinking", cl::desc("Enable code sinking"),
cl::init(true));

static cl::opt<unsigned> MaxSinkNumUsers(
"instcombine-max-sink-users", cl::init(32),
cl::desc("Maximum number of undroppable users for instruction sinking"));

static cl::opt<unsigned> LimitMaxIterations(
"instcombine-max-iterations",
cl::desc("Limit the maximum number of instruction combining iterations"),
Expand Down Expand Up @@ -3859,7 +3863,6 @@ static bool SoleWriteToDeadLocal(Instruction *I, TargetLibraryInfo &TLI) {
/// block.
static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock,
TargetLibraryInfo &TLI) {
assert(I->getUniqueUndroppableUser() && "Invariants didn't hold!");
BasicBlock *SrcBlock = I->getParent();

// Cannot move control-flow-involving, volatile loads, vaarg, etc.
Expand Down Expand Up @@ -4026,48 +4029,68 @@ bool InstCombinerImpl::run() {
[this](Instruction *I) -> Optional<BasicBlock *> {
if (!EnableCodeSinking)
return None;
auto *UserInst = cast_or_null<Instruction>(I->getUniqueUndroppableUser());
if (!UserInst)
return None;

BasicBlock *BB = I->getParent();
BasicBlock *UserParent = nullptr;
unsigned NumUsers = 0;

// Special handling for Phi nodes - get the block the use occurs in.
if (PHINode *PN = dyn_cast<PHINode>(UserInst)) {
for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
if (PN->getIncomingValue(i) == I) {
// Bail out if we have uses in different blocks. We don't do any
// sophisticated analysis (i.e finding NearestCommonDominator of these
// use blocks).
if (UserParent && UserParent != PN->getIncomingBlock(i))
return None;
UserParent = PN->getIncomingBlock(i);
for (auto *U : I->users()) {
if (U->isDroppable())
continue;
if (NumUsers > MaxSinkNumUsers)
return None;

Instruction *UserInst = cast<Instruction>(U);
// Special handling for Phi nodes - get the block the use occurs in.
if (PHINode *PN = dyn_cast<PHINode>(UserInst)) {
for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
if (PN->getIncomingValue(i) == I) {
// Bail out if we have uses in different blocks. We don't do any
// sophisticated analysis (i.e finding NearestCommonDominator of
// these use blocks).
if (UserParent && UserParent != PN->getIncomingBlock(i))
return None;
UserParent = PN->getIncomingBlock(i);
}
}
assert(UserParent && "expected to find user block!");
} else {
if (UserParent && UserParent != UserInst->getParent())
return None;
UserParent = UserInst->getParent();
}
assert(UserParent && "expected to find user block!");
} else
UserParent = UserInst->getParent();

// Try sinking to another block. If that block is unreachable, then do
// not bother. SimplifyCFG should handle it.
if (UserParent == BB || !DT.isReachableFromEntry(UserParent))
return None;
// Make sure these checks are done only once, naturally we do the checks
// the first time we get the userparent, this will save compile time.
if (NumUsers == 0) {
// Try sinking to another block. If that block is unreachable, then do
// not bother. SimplifyCFG should handle it.
if (UserParent == BB || !DT.isReachableFromEntry(UserParent))
return None;

auto *Term = UserParent->getTerminator();
// See if the user is one of our successors that has only one
// predecessor, so that we don't have to split the critical edge.
// Another option where we can sink is a block that ends with a
// terminator that does not pass control to other block (such as
// return or unreachable or resume). In this case:
// - I dominates the User (by SSA form);
// - the User will be executed at most once.
// So sinking I down to User is always profitable or neutral.
if (UserParent->getUniquePredecessor() != BB && !succ_empty(Term))
return None;

assert(DT.dominates(BB, UserParent) && "Dominance relation broken?");
}

auto *Term = UserParent->getTerminator();
// See if the user is one of our successors that has only one
// predecessor, so that we don't have to split the critical edge.
// Another option where we can sink is a block that ends with a
// terminator that does not pass control to other block (such as
// return or unreachable or resume). In this case:
// - I dominates the User (by SSA form);
// - the User will be executed at most once.
// So sinking I down to User is always profitable or neutral.
if (UserParent->getUniquePredecessor() == BB || succ_empty(Term)) {
assert(DT.dominates(BB, UserParent) && "Dominance relation broken?");
return UserParent;
NumUsers++;
}
return None;

// No user or only has droppable users.
if (!UserParent)
return None;

return UserParent;
};

auto OptBB = getOptionalSinkBlockForInst(I);
Expand Down
40 changes: 21 additions & 19 deletions llvm/test/Transforms/InstCombine/intptr7.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
define void @matching_phi(i64 %a, float* %b, i1 %cond) {
; CHECK-LABEL: @matching_phi(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB2:%.*]], label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[ADDB:%.*]] = getelementptr inbounds float, float* [[B:%.*]], i64 2
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[ADD_INT:%.*]] = add i64 [[A:%.*]], 1
; CHECK-NEXT: [[ADD:%.*]] = inttoptr i64 [[ADD_INT]] to float*
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BBB:%.*]], label [[A:%.*]]
; CHECK: A:
; CHECK-NEXT: [[ADDB:%.*]] = getelementptr inbounds float, float* [[B:%.*]], i64 2
; CHECK-NEXT: br label [[C:%.*]]
; CHECK: Bbb:
; CHECK-NEXT: store float 1.000000e+01, float* [[ADD]], align 4
; CHECK-NEXT: br label [[C]]
; CHECK: C:
; CHECK-NEXT: [[A_ADDR_03:%.*]] = phi float* [ [[ADDB]], [[A]] ], [ [[ADD]], [[BBB]] ]
; CHECK-NEXT: br label [[BB3]]
; CHECK: bb3:
; CHECK-NEXT: [[A_ADDR_03:%.*]] = phi float* [ [[ADDB]], [[BB1]] ], [ [[ADD]], [[BB2]] ]
; CHECK-NEXT: [[I1:%.*]] = load float, float* [[A_ADDR_03]], align 4
; CHECK-NEXT: [[MUL_I:%.*]] = fmul float [[I1]], 4.200000e+01
; CHECK-NEXT: store float [[MUL_I]], float* [[A_ADDR_03]], align 4
Expand All @@ -27,16 +27,16 @@ entry:

%addb = getelementptr inbounds float, float* %b, i64 2
%addb.int = ptrtoint float* %addb to i64
br i1 %cmp1, label %A, label %Bbb
A:
br label %C
Bbb:
br i1 %cmp1, label %bb1, label %bb2
bb1:
br label %bb3
bb2:
store float 1.0e+01, float* %add, align 4
br label %C
br label %bb3

C:
%a.addr.03 = phi float* [ %addb, %A ], [ %add, %Bbb ]
%b.addr.02 = phi i64 [ %addb.int, %A ], [ %add.int, %Bbb ]
bb3:
%a.addr.03 = phi float* [ %addb, %bb1 ], [ %add, %bb2 ]
%b.addr.02 = phi i64 [ %addb.int, %bb1 ], [ %add.int, %bb2 ]
%i0 = inttoptr i64 %b.addr.02 to float*
%i1 = load float, float* %i0, align 4
%mul.i = fmul float %i1, 4.200000e+01
Expand All @@ -48,18 +48,20 @@ define void @no_matching_phi(i64 %a, float* %b, i1 %cond) {
; CHECK-LABEL: @no_matching_phi(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD_INT:%.*]] = add i64 [[A:%.*]], 1
; CHECK-NEXT: [[ADD:%.*]] = inttoptr i64 [[ADD_INT]] to float*
; CHECK-NEXT: [[ADDB:%.*]] = getelementptr inbounds float, float* [[B:%.*]], i64 2
; CHECK-NEXT: br i1 [[COND:%.*]], label [[B:%.*]], label [[A:%.*]]
; CHECK: A:
; CHECK-NEXT: br label [[C:%.*]]
; CHECK: B:
; CHECK-NEXT: [[ADDB_INT:%.*]] = ptrtoint float* [[ADDB]] to i64
; CHECK-NEXT: [[ADD:%.*]] = inttoptr i64 [[ADD_INT]] to float*
; CHECK-NEXT: store float 1.000000e+01, float* [[ADD]], align 4
; CHECK-NEXT: br label [[C]]
; CHECK: C:
; CHECK-NEXT: [[A_ADDR_03:%.*]] = phi float* [ [[ADDB]], [[A]] ], [ [[ADD]], [[B]] ]
; CHECK-NEXT: [[B_ADDR_02_PTR:%.*]] = phi float* [ [[ADD]], [[A]] ], [ [[ADDB]], [[B]] ]
; CHECK-NEXT: [[I1:%.*]] = load float, float* [[B_ADDR_02_PTR]], align 4
; CHECK-NEXT: [[B_ADDR_02:%.*]] = phi i64 [ [[ADD_INT]], [[A]] ], [ [[ADDB_INT]], [[B]] ]
; CHECK-NEXT: [[I0:%.*]] = inttoptr i64 [[B_ADDR_02]] to float*
; CHECK-NEXT: [[I1:%.*]] = load float, float* [[I0]], align 4
; CHECK-NEXT: [[MUL_I:%.*]] = fmul float [[I1]], 4.200000e+01
; CHECK-NEXT: store float [[MUL_I]], float* [[A_ADDR_03]], align 4
; CHECK-NEXT: ret void
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/Transforms/InstCombine/lifetime-no-null-opt.ll
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ define void @bar(i1 %flag) #0 !dbg !4 {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TEXT:%.*]] = alloca [1 x i8], align 1
; CHECK-NEXT: [[BUFF:%.*]] = alloca [1 x i8], align 1
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [1 x i8], [1 x i8]* [[TEXT]], i64 0, i64 0
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [1 x i8], [1 x i8]* [[BUFF]], i64 0, i64 0
; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb3:
; CHECK-NEXT: call void @llvm.dbg.declare(metadata [1 x i8]* [[TEXT]], [[META16:metadata !.*]], metadata !DIExpression()), [[DBG24:!dbg !.*]]
; CHECK-NEXT: call void @llvm.dbg.declare(metadata [1 x i8]* [[TEXT]], metadata [[META16:![0-9]+]], metadata !DIExpression()), !dbg [[DBG24:![0-9]+]]
; CHECK-NEXT: br label [[FIN:%.*]]
; CHECK: else:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [1 x i8], [1 x i8]* [[TEXT]], i64 0, i64 0
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [1 x i8], [1 x i8]* [[BUFF]], i64 0, i64 0
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP0]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]])
; CHECK-NEXT: call void @foo(i8* [[TMP1]], i8* [[TMP0]])
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/Transforms/InstCombine/lifetime.ll
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ define void @bar(i1 %flag) !dbg !4 {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TEXT:%.*]] = alloca [1 x i8], align 1
; CHECK-NEXT: [[BUFF:%.*]] = alloca [1 x i8], align 1
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [1 x i8], [1 x i8]* [[TEXT]], i64 0, i64 0
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [1 x i8], [1 x i8]* [[BUFF]], i64 0, i64 0
; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb3:
; CHECK-NEXT: call void @llvm.dbg.declare(metadata [1 x i8]* [[TEXT]], [[META16:metadata !.*]], metadata !DIExpression()), [[DBG24:!dbg !.*]]
; CHECK-NEXT: call void @llvm.dbg.declare(metadata [1 x i8]* [[TEXT]], metadata [[META16:![0-9]+]], metadata !DIExpression()), !dbg [[DBG24:![0-9]+]]
; CHECK-NEXT: br label [[FIN:%.*]]
; CHECK: else:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [1 x i8], [1 x i8]* [[TEXT]], i64 0, i64 0
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [1 x i8], [1 x i8]* [[BUFF]], i64 0, i64 0
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]])
; CHECK-NEXT: call void @foo(i8* nonnull [[TMP1]], i8* nonnull [[TMP0]])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ define void @_Z4testv() {
; CHECK-NEXT: [[I:%.*]] = load i8, i8* @var_7, align 1
; CHECK-NEXT: [[I1:%.*]] = icmp eq i8 [[I]], -1
; CHECK-NEXT: [[I4:%.*]] = load i16, i16* @var_0, align 2
; CHECK-NEXT: [[I8:%.*]] = sext i16 [[I4]] to i32
; CHECK-NEXT: br i1 [[I1]], label [[BB10:%.*]], label [[BB9:%.*]]
; CHECK: bb9:
; CHECK-NEXT: br label [[BB12:%.*]]
Expand All @@ -31,6 +30,7 @@ define void @_Z4testv() {
; CHECK-NEXT: [[STOREMERGE1:%.*]] = phi i32 [ [[I11]], [[BB10]] ], [ 1, [[BB9]] ]
; CHECK-NEXT: store i32 [[STOREMERGE1]], i32* getelementptr inbounds ([0 x i32], [0 x i32]* @arr_2, i64 0, i64 0), align 4
; CHECK-NEXT: store i16 [[I4]], i16* getelementptr inbounds ([0 x i16], [0 x i16]* @arr_4, i64 0, i64 0), align 2
; CHECK-NEXT: [[I8:%.*]] = sext i16 [[I4]] to i32
; CHECK-NEXT: store i32 [[I8]], i32* getelementptr inbounds ([8 x i32], [8 x i32]* @arr_3, i64 0, i64 0), align 16
; CHECK-NEXT: store i32 [[STOREMERGE1]], i32* getelementptr inbounds ([0 x i32], [0 x i32]* @arr_2, i64 0, i64 1), align 4
; CHECK-NEXT: store i16 [[I4]], i16* getelementptr inbounds ([0 x i16], [0 x i16]* @arr_4, i64 0, i64 1), align 2
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/InstCombine/pr33689_same_bitwidth.ll
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ define void @f(i1 %cond) {
; CHECK-LABEL: @f(
; CHECK-NEXT: bb0:
; CHECK-NEXT: [[T12:%.*]] = alloca [2 x i32], align 8
; CHECK-NEXT: [[T12_SUB:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[T12]], i16 0, i16 0
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
; CHECK-NEXT: unreachable
; CHECK: bb2:
; CHECK-NEXT: [[T12_SUB:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[T12]], i16 0, i16 0
; CHECK-NEXT: [[T9:%.*]] = load i16*, i16** @b, align 2
; CHECK-NEXT: store i16 0, i16* [[T9]], align 2
; CHECK-NEXT: [[T10:%.*]] = load i32, i32* [[T12_SUB]], align 8
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/InstCombine/shift-by-signext.ll
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ define <2 x i32> @t5_vec_ashr(<2 x i32> %x, <2 x i8> %shamt) {
define i32 @t6_twoshifts(i32 %x, i8 %shamt) {
; CHECK-LABEL: @t6_twoshifts(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i8 [[SHAMT:%.*]] to i32
; CHECK-NEXT: br label [[WORK:%.*]]
; CHECK: work:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: end:
; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i8 [[SHAMT:%.*]] to i32
; CHECK-NEXT: [[N0:%.*]] = shl i32 [[X:%.*]], [[SHAMT_WIDE]]
; CHECK-NEXT: [[R:%.*]] = ashr i32 [[N0]], [[SHAMT_WIDE]]
; CHECK-NEXT: ret i32 [[R]]
Expand Down Expand Up @@ -151,11 +151,11 @@ define i32 @n11_extrause(i32 %x, i8 %shamt) {
}
define i32 @n12_twoshifts_and_extrause(i32 %x, i8 %shamt) {
; CHECK-LABEL: @n12_twoshifts_and_extrause(
; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i8 [[SHAMT:%.*]] to i32
; CHECK-NEXT: br label [[WORK:%.*]]
; CHECK: work:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: end:
; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i8 [[SHAMT:%.*]] to i32
; CHECK-NEXT: [[N0:%.*]] = shl i32 [[X:%.*]], [[SHAMT_WIDE]]
; CHECK-NEXT: [[R:%.*]] = ashr i32 [[N0]], [[SHAMT_WIDE]]
; CHECK-NEXT: call void @use32(i32 [[SHAMT_WIDE]])
Expand Down
7 changes: 3 additions & 4 deletions llvm/test/Transforms/InstCombine/sink_instruction.ll
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,15 @@ else:
declare void @abort()
declare { i64, i1 } @llvm.umul.with.overflow.i64(i64, i64)
declare void @dummy(i64)
; Todo: Two uses in two different users of a single successor block. We can sink.
; Two uses in two different users of a single successor block. We can sink.
define i64 @test8(i64 %c) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp ugt i64 [[C:%.*]], 2305843009213693951
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[OVERFLOW]], i64 0, i64 8
; CHECK-NEXT: br i1 [[OVERFLOW]], label [[ABORT:%.*]], label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: call void @dummy(i64 [[SELECT]])
; CHECK-NEXT: ret i64 [[SELECT]]
; CHECK-NEXT: call void @dummy(i64 8)
; CHECK-NEXT: ret i64 8
; CHECK: abort:
; CHECK-NEXT: call void @abort()
; CHECK-NEXT: unreachable
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/LoopUnroll/runtime-unroll-remainder.ll
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ define i32 @unroll(i32* nocapture readonly %a, i32* nocapture readonly %b, i32 %
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[ARRAYIDX2_EPIL]], align 4
; CHECK-NEXT: [[MUL_EPIL:%.*]] = mul nsw i32 [[TMP3]], [[TMP2]]
; CHECK-NEXT: [[ADD_EPIL:%.*]] = add nsw i32 [[MUL_EPIL]], [[C_010_UNR]]
; CHECK-NEXT: [[INDVARS_IV_NEXT_EPIL:%.*]] = add nuw nsw i64 [[INDVARS_IV_UNR]], 1
; CHECK-NEXT: [[EPIL_ITER_CMP_NOT:%.*]] = icmp eq i64 [[XTRAITER]], 1
; CHECK-NEXT: br i1 [[EPIL_ITER_CMP_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_EPILOG_LCSSA:%.*]], label [[FOR_BODY_EPIL_1:%.*]]
; CHECK: for.body.epil.1:
; CHECK-NEXT: [[INDVARS_IV_NEXT_EPIL:%.*]] = add nuw nsw i64 [[INDVARS_IV_UNR]], 1
; CHECK-NEXT: [[ARRAYIDX_EPIL_1:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INDVARS_IV_NEXT_EPIL]]
; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[ARRAYIDX_EPIL_1]], align 4
; CHECK-NEXT: [[ARRAYIDX2_EPIL_1:%.*]] = getelementptr inbounds i32, i32* [[B]], i64 [[INDVARS_IV_NEXT_EPIL]]
; CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* [[ARRAYIDX2_EPIL_1]], align 4
; CHECK-NEXT: [[MUL_EPIL_1:%.*]] = mul nsw i32 [[TMP5]], [[TMP4]]
; CHECK-NEXT: [[ADD_EPIL_1:%.*]] = add nsw i32 [[MUL_EPIL_1]], [[ADD_EPIL]]
; CHECK-NEXT: [[INDVARS_IV_NEXT_EPIL_1:%.*]] = add nuw nsw i64 [[INDVARS_IV_UNR]], 2
; CHECK-NEXT: [[EPIL_ITER_CMP_1_NOT:%.*]] = icmp eq i64 [[XTRAITER]], 2
; CHECK-NEXT: br i1 [[EPIL_ITER_CMP_1_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_EPILOG_LCSSA]], label [[FOR_BODY_EPIL_2:%.*]]
; CHECK: for.body.epil.2:
; CHECK-NEXT: [[INDVARS_IV_NEXT_EPIL_1:%.*]] = add nuw nsw i64 [[INDVARS_IV_UNR]], 2
; CHECK-NEXT: [[ARRAYIDX_EPIL_2:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INDVARS_IV_NEXT_EPIL_1]]
; CHECK-NEXT: [[TMP6:%.*]] = load i32, i32* [[ARRAYIDX_EPIL_2]], align 4
; CHECK-NEXT: [[ARRAYIDX2_EPIL_2:%.*]] = getelementptr inbounds i32, i32* [[B]], i64 [[INDVARS_IV_NEXT_EPIL_1]]
Expand Down
Loading

0 comments on commit 0af3e6a

Please sign in to comment.