llvm-project/llvm/test/Analysis/MemorySSA/phi-translation.ll
Lee Wei 1469d82e1c
Remove br i1 undef from some regression tests [NFC] (#115130)
As defined in LangRef, branching on `undef` is undefined behavior.
This PR aims to remove undefined behavior from tests. As UB tests break
Alive2 and may be the root cause of breaking future optimizations.

Here's an Alive2 proof for one of the examples:
https://alive2.llvm.org/ce/z/TncxhP
2024-11-07 08:11:15 +00:00

591 lines
19 KiB
LLVM

; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,NOLIMIT
; RUN: opt -memssa-check-limit=0 -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LIMIT
; %ptr can't alias %local, so we should be able to optimize the use of %local to
; point to the store to %local.
; CHECK-LABEL: define void @check
define void @check(ptr %ptr, i1 %bool) {
entry:
%local = alloca i8, align 1
; CHECK: 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i8 0, ptr %local, align 1
store i8 0, ptr %local, align 1
br i1 %bool, label %if.then, label %if.end
if.then:
%p2 = getelementptr inbounds i8, ptr %ptr, i32 1
; CHECK: 2 = MemoryDef(1)
; CHECK-NEXT: store i8 0, ptr %p2, align 1
store i8 0, ptr %p2, align 1
br label %if.end
if.end:
; CHECK: 3 = MemoryPhi({entry,1},{if.then,2})
; NOLIMIT: MemoryUse(1)
; NOLIMIT-NEXT: load i8, ptr %local, align 1
; LIMIT: MemoryUse(3)
; LIMIT-NEXT: load i8, ptr %local, align 1
load i8, ptr %local, align 1
ret void
}
; CHECK-LABEL: define void @check2
define void @check2(i1 %val1, i1 %val2, i1 %val3) {
entry:
%local = alloca i8, align 1
%local2 = alloca i8, align 1
; CHECK: 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i8 0, ptr %local
store i8 0, ptr %local
br i1 %val1, label %if.then, label %phi.3
if.then:
; CHECK: 2 = MemoryDef(1)
; CHECK-NEXT: store i8 2, ptr %local2
store i8 2, ptr %local2
br i1 %val2, label %phi.2, label %phi.3
phi.3:
; CHECK: 7 = MemoryPhi({entry,1},{if.then,2})
; CHECK: 3 = MemoryDef(7)
; CHECK-NEXT: store i8 3, ptr %local2
store i8 3, ptr %local2
br i1 %val3, label %phi.2, label %phi.1
phi.2:
; CHECK: 5 = MemoryPhi({if.then,2},{phi.3,3})
; CHECK: 4 = MemoryDef(5)
; CHECK-NEXT: store i8 4, ptr %local2
store i8 4, ptr %local2
br label %phi.1
phi.1:
; Order matters here; phi.2 needs to come before phi.3, because that's the order
; they're visited in.
; CHECK: 6 = MemoryPhi({phi.2,4},{phi.3,3})
; NOLIMIT: MemoryUse(1)
; NOLIMIT-NEXT: load i8, ptr %local
; LIMIT: MemoryUse(6)
; LIMIT-NEXT: load i8, ptr %local
load i8, ptr %local
ret void
}
; CHECK-LABEL: define void @cross_phi
define void @cross_phi(ptr noalias %p1, ptr noalias %p2, i1 %arg) {
; CHECK: 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i8 0, ptr %p1
store i8 0, ptr %p1
; NOLIMIT: MemoryUse(1)
; NOLIMIT-NEXT: load i8, ptr %p1
; LIMIT: MemoryUse(1)
; LIMIT-NEXT: load i8, ptr %p1
load i8, ptr %p1
br i1 %arg, label %a, label %b
a:
; CHECK: 2 = MemoryDef(1)
; CHECK-NEXT: store i8 0, ptr %p2
store i8 0, ptr %p2
br i1 %arg, label %c, label %d
b:
; CHECK: 3 = MemoryDef(1)
; CHECK-NEXT: store i8 1, ptr %p2
store i8 1, ptr %p2
br i1 %arg, label %c, label %d
c:
; CHECK: 6 = MemoryPhi({a,2},{b,3})
; CHECK: 4 = MemoryDef(6)
; CHECK-NEXT: store i8 2, ptr %p2
store i8 2, ptr %p2
br label %e
d:
; CHECK: 7 = MemoryPhi({a,2},{b,3})
; CHECK: 5 = MemoryDef(7)
; CHECK-NEXT: store i8 3, ptr %p2
store i8 3, ptr %p2
br label %e
e:
; 8 = MemoryPhi({c,4},{d,5})
; NOLIMIT: MemoryUse(1)
; NOLIMIT-NEXT: load i8, ptr %p1
; LIMIT: MemoryUse(8)
; LIMIT-NEXT: load i8, ptr %p1
load i8, ptr %p1
ret void
}
; CHECK-LABEL: define void @looped
define void @looped(ptr noalias %p1, ptr noalias %p2, i1 %arg) {
; CHECK: 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i8 0, ptr %p1
store i8 0, ptr %p1
br label %loop.1
loop.1:
; CHECK: 6 = MemoryPhi({%0,1},{loop.3,4})
; CHECK: 2 = MemoryDef(6)
; CHECK-NEXT: store i8 0, ptr %p2
store i8 0, ptr %p2
br i1 %arg, label %loop.2, label %loop.3
loop.2:
; CHECK: 5 = MemoryPhi({loop.1,2},{loop.3,4})
; CHECK: 3 = MemoryDef(5)
; CHECK-NEXT: store i8 1, ptr %p2
store i8 1, ptr %p2
br label %loop.3
loop.3:
; CHECK: 7 = MemoryPhi({loop.1,2},{loop.2,3})
; CHECK: 4 = MemoryDef(7)
; CHECK-NEXT: store i8 2, ptr %p2
store i8 2, ptr %p2
; NOLIMIT: MemoryUse(1)
; NOLIMIT-NEXT: load i8, ptr %p1
; LIMIT: MemoryUse(4)
; LIMIT-NEXT: load i8, ptr %p1
load i8, ptr %p1
br i1 %arg, label %loop.2, label %loop.1
}
; CHECK-LABEL: define void @looped_visitedonlyonce
define void @looped_visitedonlyonce(ptr noalias %p1, ptr noalias %p2, i1 %arg) {
br label %while.cond
while.cond:
; CHECK: 5 = MemoryPhi({%0,liveOnEntry},{if.end,3})
; CHECK-NEXT: br i1 %arg, label %if.then, label %if.end
br i1 %arg, label %if.then, label %if.end
if.then:
; CHECK: 1 = MemoryDef(5)
; CHECK-NEXT: store i8 0, ptr %p1
store i8 0, ptr %p1
br i1 %arg, label %if.end, label %if.then2
if.then2:
; CHECK: 2 = MemoryDef(1)
; CHECK-NEXT: store i8 1, ptr %p2
store i8 1, ptr %p2
br label %if.end
if.end:
; CHECK: 4 = MemoryPhi({while.cond,5},{if.then,1},{if.then2,2})
; CHECK: MemoryUse(4)
; CHECK-NEXT: load i8, ptr %p1
load i8, ptr %p1
; CHECK: 3 = MemoryDef(4)
; CHECK-NEXT: store i8 2, ptr %p2
store i8 2, ptr %p2
; NOLIMIT: MemoryUse(4)
; NOLIMIT-NEXT: load i8, ptr %p1
; LIMIT: MemoryUse(3)
; LIMIT-NEXT: load i8, ptr %p1
load i8, ptr %p1
br label %while.cond
}
; CHECK-LABEL: define i32 @use_not_optimized_due_to_backedge
define i32 @use_not_optimized_due_to_backedge(ptr nocapture %m_i_strides, ptr nocapture readonly %eval_left_dims) {
entry:
; CHECK: 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i32 1, ptr %m_i_strides, align 4
store i32 1, ptr %m_i_strides, align 4
br label %for.body
for.cond.cleanup: ; preds = %for.inc
ret i32 %m_i_size.1
for.body: ; preds = %entry, %for.inc
; CHECK: 4 = MemoryPhi({entry,1},{for.inc,3})
; CHECK-NEXT: %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.inc ]
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.inc ]
%m_i_size.022 = phi i32 [ 1, %entry ], [ %m_i_size.1, %for.inc ]
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%cmp1 = icmp eq i64 %indvars.iv, 0
%arrayidx2 = getelementptr inbounds i32, ptr %m_i_strides, i64 %indvars.iv
; CHECK: MemoryUse(4)
; CHECK-NEXT: %0 = load i32, ptr %arrayidx2, align 4
%0 = load i32, ptr %arrayidx2, align 4
%arrayidx4 = getelementptr inbounds i32, ptr %eval_left_dims, i64 %indvars.iv
; CHECK: MemoryUse(4)
; CHECK-NEXT: %1 = load i32, ptr %arrayidx4, align 4
%1 = load i32, ptr %arrayidx4, align 4
%mul = mul nsw i32 %1, %0
br i1 %cmp1, label %if.then, label %for.inc
if.then: ; preds = %for.body
%arrayidx7 = getelementptr inbounds i32, ptr %m_i_strides, i64 %indvars.iv.next
; CHECK: 2 = MemoryDef(4)
; CHECK-NEXT: store i32 %mul, ptr %arrayidx7, align 4
store i32 %mul, ptr %arrayidx7, align 4
br label %for.inc
for.inc: ; preds = %for.body, %if.then
; CHECK: 3 = MemoryPhi({for.body,4},{if.then,2})
; CHECK-NEXT: %m_i_size.1 = phi i32 [ %m_i_size.022, %if.then ], [ %mul, %for.body ]
%m_i_size.1 = phi i32 [ %m_i_size.022, %if.then ], [ %mul, %for.body ]
br i1 %cmp1, label %for.body, label %for.cond.cleanup
}
%ArrayType = type { [2 x i64] }
%StructOverArrayType = type { %ArrayType }
%BigStruct = type { i8, i8, i8, i8, i8, i8, i8, %ArrayType, %ArrayType}
; CHECK-LABEL: define void @use_not_optimized_due_to_backedge_unknown
define void @use_not_optimized_due_to_backedge_unknown(ptr %this) {
entry:
%eval_left_dims = alloca %StructOverArrayType, align 8
%eval_right_dims = alloca %StructOverArrayType, align 8
%lhs_strides = alloca %ArrayType, align 8
%rhs_strides = alloca %ArrayType, align 8
br label %for.body.preheader
for.body.preheader: ; preds = %entry
%arrayidx.i527 = getelementptr inbounds %BigStruct, ptr %this, i64 0, i32 7, i32 0, i64 0
; CHECK: 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i64 1, ptr %arrayidx.i527, align 8
store i64 1, ptr %arrayidx.i527, align 8
%arrayidx.i528 = getelementptr inbounds %BigStruct, ptr %this, i64 0, i32 8, i32 0, i64 0
; CHECK: 2 = MemoryDef(1)
; CHECK-NEXT: store i64 1, ptr %arrayidx.i528, align 8
store i64 1, ptr %arrayidx.i528, align 8
br label %for.main.body
for.main.body: ; preds = %if.end220.if.then185_crit_edge, %for.body.preheader
; CHECK: 4 = MemoryPhi({for.body.preheader,2},{if.end220.if.then185_crit_edge,3})
; CHECK-NEXT: %nocontract_idx.0656 = phi i64 [ 0, %for.body.preheader ], [ 1, %if.end220.if.then185_crit_edge ]
%nocontract_idx.0656 = phi i64 [ 0, %for.body.preheader ], [ 1, %if.end220.if.then185_crit_edge ]
%add199 = add nuw nsw i64 %nocontract_idx.0656, 1
%cmp200 = icmp eq i64 %nocontract_idx.0656, 0
%arrayidx.i559 = getelementptr inbounds %BigStruct, ptr %this, i64 0, i32 7, i32 0, i64 %nocontract_idx.0656
; CHECK: MemoryUse(4)
; CHECK-NEXT: %tmp21 = load i64, ptr %arrayidx.i559, align 8
%tmp21 = load i64, ptr %arrayidx.i559, align 8
%mul206 = mul nsw i64 %tmp21, %tmp21
br i1 %cmp200, label %if.end220.if.then185_crit_edge, label %the.end
if.end220.if.then185_crit_edge: ; preds = %for.main.body
%arrayidx.i571 = getelementptr inbounds %BigStruct, ptr %this, i64 0, i32 7, i32 0, i64 %add199
; CHECK: 3 = MemoryDef(4)
; CHECK-NEXT: store i64 %mul206, ptr %arrayidx.i571, align 8
store i64 %mul206, ptr %arrayidx.i571, align 8
br label %for.main.body
the.end: ; preds = %for.main.body
ret void
}
@c = local_unnamed_addr global [2 x i16] zeroinitializer, align 2
define i32 @dont_merge_noalias_simple(ptr noalias %ptr) {
; CHECK-LABEL: define i32 @dont_merge_noalias_simple
; CHECK-LABEL: entry:
; CHECK: ; 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i16 1, ptr @c, align 2
; CHECK-LABEL: %for.body
; NOLIMIT: ; MemoryUse(1)
; LIMIT: ; MemoryUse(4)
; CHECK-NEXT: %lv = load i16, ptr %arrayidx, align 2
entry:
store i16 1, ptr @c, align 2
br label %for.body
for.body: ; preds = %for.body, %entry
%storemerge2 = phi i32 [ 1, %entry ], [ %dec, %for.body ]
%idxprom1 = zext i32 %storemerge2 to i64
%arrayidx = getelementptr inbounds [2 x i16], ptr @c, i64 0, i64 %idxprom1
%lv = load i16, ptr %arrayidx, align 2
%conv = sext i16 %lv to i32
store i32 %conv, ptr %ptr, align 4
%dec = add nsw i32 %storemerge2, -1
%cmp = icmp sgt i32 %storemerge2, 0
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %for.body
store i16 0, ptr @c, align 2
ret i32 0
}
define i32 @dont_merge_noalias_complex(ptr noalias %ptr, ptr noalias %another) {
; CHECK-LABEL: define i32 @dont_merge_noalias_complex
; CHECK-LABEL: entry:
; CHECK: ; 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i16 1, ptr @c, align 2
; CHECK-LABEL: %for.body
; NOLIMIT: ; MemoryUse(1)
; LIMIT: ; MemoryUse(7)
; CHECK-NEXT: %lv = load i16, ptr %arrayidx, align 2
entry:
store i16 1, ptr @c, align 2
br label %for.body
for.body: ; preds = %for.body, %entry
%storemerge2 = phi i32 [ 1, %entry ], [ %dec, %merge.body ]
%idxprom1 = zext i32 %storemerge2 to i64
%arrayidx = getelementptr inbounds [2 x i16], ptr @c, i64 0, i64 %idxprom1
%lv = load i16, ptr %arrayidx, align 2
%conv = sext i16 %lv to i32
store i32 %conv, ptr %ptr, align 4
%dec = add nsw i32 %storemerge2, -1
%cmpif = icmp sgt i32 %storemerge2, 1
br i1 %cmpif, label %if.body, label %else.body
if.body:
store i32 %conv, ptr %another, align 4
br label %merge.body
else.body:
store i32 %conv, ptr %another, align 4
br label %merge.body
merge.body:
%cmp = icmp sgt i32 %storemerge2, 0
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %for.body
store i16 0, ptr @c, align 2
ret i32 0
}
declare i1 @should_exit(i32) readnone
declare void @init(ptr)
; Test case for PR47498.
; %l.1 may read the result of `store i32 10, ptr %p.1` in %storebb, because
; after %storebb has been executed, %loop.1.header might be executed again.
; Make sure %l.1's defining access is the MemoryPhi in the block.
define void @dont_merge_noalias_complex_2(i32 %arg, i32 %arg1) {
; CHECK-LABEL: define void @dont_merge_noalias_complex_2(
; CHECK-LABEL: entry:
; CHECK: ; 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: call void @init(ptr %tmp)
; CHECK-LABEL: loop.1.header:
; CHECK-NEXT: ; 4 = MemoryPhi({entry,1},{loop.1.latch,3})
; CHECK: ; MemoryUse(4)
; CHECK-NEXT: %l.1 = load i32, ptr %p.1, align 4
; CHECK-LABEL: loop.1.latch:
; CHECK-NEXT: ; 3 = MemoryPhi({loop.1.header,4},{storebb,2})
; CHECK-LABEL: storebb:
; CHECK-NEXT: %iv.add2 = add nuw nsw i64 %iv, 2
; CHECK-NEXT: %p.2 = getelementptr inbounds [32 x i32], ptr %tmp, i64 0, i64 %iv.add2
; CHECK-NEXT: ; MemoryUse(4)
; CHECK-NEXT: %l.2 = load i32, ptr %p.2, align 4
; CHECK-NEXT: ; 2 = MemoryDef(4)
; CHECK-NEXT: store i32 10, ptr %p.1, align 4
entry:
%tmp = alloca [32 x i32], align 16
call void @init(ptr %tmp)
br label %loop.1.header
loop.1.header:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.1.latch ]
%iv.next = add nuw nsw i64 %iv, 1
%p.1 = getelementptr inbounds [32 x i32], ptr %tmp, i64 0, i64 %iv.next
%l.1 = load i32, ptr %p.1, align 4
%tmp244 = icmp ult i64 %iv, 10
br i1 %tmp244, label %loop.1.latch, label %storebb
loop.1.latch:
%ec = call i1 @should_exit(i32 %l.1)
br i1 %ec, label %exit, label %loop.1.header
storebb:
%iv.add2 = add nuw nsw i64 %iv, 2
%p.2 = getelementptr inbounds [32 x i32], ptr %tmp, i64 0, i64 %iv.add2
%l.2 = load i32, ptr %p.2, align 4
store i32 10, ptr %p.1, align 4
br label %loop.1.latch
exit:
ret void
}
define i32 @phi_with_constant_values(i1 %cmp) {
; CHECK-LABEL: define i32 @phi_with_constant_values
; CHECK-LABEL: lhs:
; CHECK: ; 1 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i16 1, ptr @c, align 2
; CHECK-LABEL: rhs:
; CHECK: ; 2 = MemoryDef(liveOnEntry)
; CHECK-NEXT: store i16 1, ptr %s2.ptr, align 2
; CHECK-LABEL: merge:
; CHECK: ; 3 = MemoryPhi({lhs,1},{rhs,2})
; CHECK-NEXT: %storemerge2 = phi i32 [ 2, %lhs ], [ 3, %rhs ]
; LIMIT: ; MemoryUse(3)
; LIMIT-NEXT: %lv = load i16, ptr %arrayidx, align 2
; NOLIMIT: ; MemoryUse(liveOnEntry)
; NOLIMIT-NEXT: %lv = load i16, ptr %arrayidx, align 2
entry:
br i1 %cmp, label %lhs, label %rhs
lhs:
store i16 1, ptr @c, align 2
br label %merge
rhs:
%s2.ptr = getelementptr inbounds [2 x i16], ptr @c, i64 0, i64 1
store i16 1, ptr %s2.ptr, align 2
br label %merge
merge: ; preds = %for.body, %entry
%storemerge2 = phi i32 [ 2, %lhs ], [ 3, %rhs ]
%idxprom1 = zext i32 %storemerge2 to i64
%arrayidx = getelementptr inbounds [2 x i16], ptr @c, i64 0, i64 %idxprom1
%lv = load i16, ptr %arrayidx, align 2
br label %end
end: ; preds = %for.body
ret i32 0
}
; CHECK-LABEL: define void @use_clobbered_by_def_in_loop()
define void @use_clobbered_by_def_in_loop() {
entry:
%nodeStack = alloca [12 x i32], align 4
call void @llvm.lifetime.start.p0(i64 48, ptr nonnull %nodeStack)
br i1 false, label %cleanup, label %while.cond
; CHECK-LABEL: while.cond:
; CHECK-NEXT: ; [[NO6:.*]] = MemoryPhi({entry,1},{while.cond.backedge,5})
while.cond: ; preds = %entry, %while.cond.backedge
%depth.1 = phi i32 [ %depth.1.be, %while.cond.backedge ], [ 0, %entry ]
%cmp = icmp sgt i32 %depth.1, 0
br i1 %cmp, label %land.rhs, label %while.end
; CHECK-LABEL: land.rhs:
; CHECK-NEXT: %sub = add nsw i32 %depth.1, -1
; CHECK-NEXT: %arrayidx = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i32 %sub
; CHECK-NEXT: ; MemoryUse([[NO6]])
; CHECK-NEXT: %0 = load i32, ptr %arrayidx, align 4
land.rhs: ; preds = %while.cond
%sub = add nsw i32 %depth.1, -1
%arrayidx = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i32 %sub
%0 = load i32, ptr %arrayidx, align 4
br i1 true, label %while.body, label %while.end
while.body: ; preds = %land.rhs
br i1 true, label %cleanup, label %while.cond.backedge
while.cond.backedge: ; preds = %while.body, %while.end
%depth.1.be = phi i32 [ %sub, %while.body ], [ %inc, %while.end ]
br label %while.cond
while.end: ; preds = %while.cond, %land.rhs
%arrayidx10 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i32 %depth.1
store i32 %depth.1, ptr %arrayidx10, align 4
%inc = add nsw i32 %depth.1, 1
br i1 true, label %cleanup, label %while.cond.backedge
cleanup: ; preds = %while.body, %while.end, %entry
call void @llvm.lifetime.end.p0(i64 48, ptr nonnull %nodeStack)
ret void
}
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
define void @another_loop_clobber_inc() {
; CHECK-LABEL: void @another_loop_clobber_inc
; CHECK-LABEL: loop.header:
; CHECK-NEXT: ; 4 = MemoryPhi({entry,1},{cond.read,3})
; CHECK-LABEL: cond.read:
; CHECK: ; MemoryUse(4)
; CHECK-NEXT: %use = load i32, ptr %ptr.1, align 4
; CHECK-NEXT: ; 2 = MemoryDef(4)
; CHECK-NEXT: %c.2 = call i1 @cond(i32 %use)
; CHECK-NEXT: %ptr.10 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i32 %inc
; CHECK-NEXT: ; 3 = MemoryDef(2)
; CHECK-NEXT: store i32 10, ptr %ptr.2, align 4
entry:
%nodeStack = alloca [12 x i32], align 4
%c.1 = call i1 @cond(i32 1)
br i1 %c.1, label %cleanup, label %loop.header
loop.header: ; preds = %entry, %while.cond.backedge
%depth.1 = phi i32 [ %inc, %cond.read], [ 1, %entry ]
%cmp = icmp sgt i32 %depth.1, 0
%inc = add nsw i32 %depth.1, 3
%inc2 = add nsw i32 %depth.1, 6
br i1 %cmp, label %cond.read, label %cleanup
cond.read: ; preds = %while.cond
%ptr.1 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i32 %depth.1
%ptr.2 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i32 %inc2
%use = load i32, ptr %ptr.1, align 4
%c.2 = call i1 @cond(i32 %use)
%ptr.10 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i32 %inc
store i32 10, ptr %ptr.2, align 4
br i1 %c.2, label %loop.header, label %cleanup
cleanup:
ret void
}
define void @another_loop_clobber_dec() {
; CHECK-LABEL: void @another_loop_clobber_dec
; CHECK-LABEL: loop.header:
; CHECK-NEXT: ; 4 = MemoryPhi({entry,1},{cond.read,3})
; CHECK-LABEL: cond.read:
; CHECK: ; MemoryUse(4)
; CHECK-NEXT: %use = load i32, ptr %ptr.1, align 4
; CHECK-NEXT: ; 2 = MemoryDef(4)
; CHECK-NEXT: %c.2 = call i1 @cond(i32 %use)
; CHECK-NEXT: %ptr.10 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i64 %sub
; CHECK-NEXT: ; 3 = MemoryDef(2)
; CHECK-NEXT: store i32 10, ptr %ptr.2, align 4
entry:
%nodeStack = alloca [12 x i32], align 4
%c.1 = call i1 @cond(i32 1)
br i1 %c.1, label %cleanup, label %loop.header
loop.header: ; preds = %entry, %while.cond.backedge
%depth.1 = phi i64 [ %sub, %cond.read], [ 20, %entry ]
%cmp = icmp sgt i64 %depth.1, 6
%sub = sub nsw nuw i64 %depth.1, 3
%sub2 = sub nsw nuw i64 %depth.1, 6
br i1 %cmp, label %cond.read, label %cleanup
cond.read: ; preds = %while.cond
%ptr.1 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i64 %depth.1
%ptr.2 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i64 %sub2
%use = load i32, ptr %ptr.1, align 4
%c.2 = call i1 @cond(i32 %use)
%ptr.10 = getelementptr inbounds [12 x i32], ptr %nodeStack, i32 0, i64 %sub
store i32 10, ptr %ptr.2, align 4
br i1 %c.2, label %loop.header, label %cleanup
cleanup:
ret void
}
declare i1 @cond(i32)