forked from OSchip/llvm-project
2029 lines
68 KiB
LLVM
2029 lines
68 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes --check-attributes
|
|
; RUN: opt -attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=17 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=17 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
|
|
; TODO: The old pass manager cgscc run is disabled as it causes a crash on windows which is under investigation: http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/23151
|
|
; opt -attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
|
|
|
|
; NOT_CGSCC_OPM: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)]
|
|
; IS__CGSCC_OPM: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* blockaddress(@dead_with_blockaddress_users, %lab0), i8* blockaddress(@dead_with_blockaddress_users, %end)]
|
|
@dead_with_blockaddress_users.l = constant [2 x i8*] [i8* blockaddress(@dead_with_blockaddress_users, %lab0), i8* blockaddress(@dead_with_blockaddress_users, %end)]
|
|
|
|
declare void @no_return_call() nofree noreturn nounwind nosync
|
|
|
|
declare void @normal_call() readnone
|
|
|
|
declare i32 @foo()
|
|
|
|
declare i32 @foo_nounwind() nounwind
|
|
|
|
declare i32 @foo_noreturn_nounwind() noreturn nounwind
|
|
|
|
declare i32 @foo_noreturn() noreturn
|
|
|
|
declare i32 @bar() nosync readnone
|
|
|
|
; This internal function has no live call sites, so all its BBs are considered dead,
|
|
; and nothing should be deduced for it.
|
|
|
|
define internal i32 @dead_internal_func(i32 %0) {
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@dead_internal_func()
|
|
; IS__CGSCC____-NEXT: br label [[TMP2:%.*]]
|
|
; IS__CGSCC____: 1:
|
|
; IS__CGSCC____-NEXT: ret i32 undef
|
|
; IS__CGSCC____: 2:
|
|
; IS__CGSCC____-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP6:%.*]], [[TMP2]] ], [ 1, [[TMP0:%.*]] ]
|
|
; IS__CGSCC____-NEXT: [[TMP4:%.*]] = phi i32 [ [[TMP5:%.*]], [[TMP2]] ], [ 1, [[TMP0]] ]
|
|
; IS__CGSCC____-NEXT: [[TMP5]] = mul nsw i32 [[TMP3]], [[TMP4]]
|
|
; IS__CGSCC____-NEXT: [[TMP6]] = add nuw nsw i32 [[TMP3]], 1
|
|
; IS__CGSCC____-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP3]], 10
|
|
; IS__CGSCC____-NEXT: br i1 [[TMP7]], label [[TMP1:%.*]], label [[TMP2]]
|
|
;
|
|
%2 = icmp slt i32 %0, 1
|
|
br i1 %2, label %3, label %5
|
|
|
|
; <label>:3: ; preds = %5, %1
|
|
%4 = phi i32 [ 1, %1 ], [ %8, %5 ]
|
|
ret i32 %4
|
|
|
|
; <label>:5: ; preds = %1, %5
|
|
%6 = phi i32 [ %9, %5 ], [ 1, %1 ]
|
|
%7 = phi i32 [ %8, %5 ], [ 1, %1 ]
|
|
%8 = mul nsw i32 %6, %7
|
|
%9 = add nuw nsw i32 %6, 1
|
|
%10 = icmp eq i32 %6, %0
|
|
br i1 %10, label %3, label %5
|
|
}
|
|
|
|
define i32 @volatile_load(i32*) norecurse nounwind uwtable {
|
|
; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@volatile_load
|
|
; CHECK-SAME: (i32* nofree align 4 [[TMP0:%.*]])
|
|
; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, i32* [[TMP0]], align 4
|
|
; CHECK-NEXT: ret i32 [[TMP2]]
|
|
;
|
|
%2 = load volatile i32, i32* %0, align 4
|
|
ret i32 %2
|
|
}
|
|
|
|
define internal i32 @internal_load(i32*) norecurse nounwind uwtable {
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone uwtable willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@internal_load()
|
|
; IS__CGSCC____-NEXT: ret i32 undef
|
|
;
|
|
%2 = load i32, i32* %0, align 4
|
|
ret i32 %2
|
|
}
|
|
; TEST 1: Only first block is live.
|
|
|
|
define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2) #0 {
|
|
; CHECK: Function Attrs: nofree noreturn nosync nounwind
|
|
; CHECK-LABEL: define {{[^@]+}}@first_block_no_return
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32* nocapture nofree nonnull readnone [[PTR1:%.*]], i32* nocapture nofree readnone [[PTR2:%.*]])
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: call void @no_return_call()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
call i32 @internal_load(i32* %ptr1)
|
|
call void @no_return_call()
|
|
call i32 @dead_internal_func(i32 10)
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call i32 @internal_load(i32* %ptr2)
|
|
%load = call i32 @volatile_load(i32* %ptr1)
|
|
call void @normal_call()
|
|
%call = call i32 @foo()
|
|
br label %cond.end
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @normal_call()
|
|
%call1 = call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.false, %cond.true
|
|
%cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; TEST 2: cond.true is dead, but cond.end is not, since cond.false is live
|
|
|
|
; This is just an example. For example we can put a sync call in a
|
|
; dead block and check if it is deduced.
|
|
|
|
define i32 @dead_block_present(i32 %a, i32* %ptr1) #0 {
|
|
; CHECK: Function Attrs: nosync
|
|
; CHECK-LABEL: define {{[^@]+}}@dead_block_present
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32* nocapture nofree readnone [[PTR1:%.*]])
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: call void @no_return_call()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar()
|
|
; CHECK-NEXT: br label [[COND_END:%.*]]
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: ret i32 [[CALL1]]
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call void @no_return_call()
|
|
%call = call i32 @volatile_load(i32* %ptr1)
|
|
br label %cond.end
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @normal_call()
|
|
%call1 = call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.false, %cond.true
|
|
%cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; TEST 3: both cond.true and cond.false are dead, therfore cond.end is dead as well.
|
|
|
|
define i32 @all_dead(i32 %a) #0 {
|
|
; CHECK: Function Attrs: nofree noreturn nosync nounwind
|
|
; CHECK-LABEL: define {{[^@]+}}@all_dead
|
|
; CHECK-SAME: (i32 [[A:%.*]])
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: call void @no_return_call()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: call void @no_return_call()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call void @no_return_call()
|
|
call i32 @dead_internal_func(i32 10)
|
|
%call = call i32 @foo()
|
|
br label %cond.end
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @no_return_call()
|
|
call i32 @dead_internal_func(i32 10)
|
|
%call1 = call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.false, %cond.true
|
|
%cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
declare i32 @__gxx_personality_v0(...)
|
|
|
|
; TEST 4: All blocks are live.
|
|
|
|
define i32 @all_live(i32 %a) #0 {
|
|
; CHECK-LABEL: define {{[^@]+}}@all_live
|
|
; CHECK-SAME: (i32 [[A:%.*]])
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_noreturn()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar()
|
|
; CHECK-NEXT: br label [[COND_END:%.*]]
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: ret i32 [[CALL1]]
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call void @normal_call()
|
|
%call = call i32 @foo_noreturn()
|
|
br label %cond.end
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @normal_call()
|
|
%call1 = call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.false, %cond.true
|
|
%cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ]
|
|
ret i32 %cond
|
|
}
|
|
|
|
; TEST 5.1 noreturn invoke instruction with a unreachable normal successor block.
|
|
|
|
define i32 @invoke_noreturn(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
|
; CHECK-LABEL: define {{[^@]+}}@invoke_noreturn
|
|
; CHECK-SAME: (i32 [[A:%.*]]) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL:%.*]] = invoke i32 @foo_noreturn()
|
|
; CHECK-NEXT: to label [[CONTINUE:%.*]] unwind label [[CLEANUP:%.*]]
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar()
|
|
; CHECK-NEXT: br label [[COND_END:%.*]]
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: ret i32 [[CALL1]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cleanup:
|
|
; CHECK-NEXT: [[RES:%.*]] = landingpad { i8*, i32 }
|
|
; CHECK-NEXT: catch i8* null
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call void @normal_call()
|
|
%call = invoke i32 @foo_noreturn() to label %continue
|
|
unwind label %cleanup
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @normal_call()
|
|
%call1 = call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.false, %continue
|
|
%cond = phi i32 [ %call, %continue ], [ %call1, %cond.false ]
|
|
ret i32 %cond
|
|
|
|
continue:
|
|
br label %cond.end
|
|
|
|
cleanup:
|
|
%res = landingpad { i8*, i32 }
|
|
catch i8* null
|
|
ret i32 0
|
|
}
|
|
|
|
; TEST 5.2 noreturn invoke instruction replaced by a call and an unreachable instruction
|
|
; put after it.
|
|
|
|
define i32 @invoke_noreturn_nounwind(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
|
; CHECK-LABEL: define {{[^@]+}}@invoke_noreturn_nounwind
|
|
; CHECK-SAME: (i32 [[A:%.*]]) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_noreturn_nounwind()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar()
|
|
; CHECK-NEXT: br label [[COND_END:%.*]]
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: ret i32 [[CALL1]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cleanup:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call void @normal_call()
|
|
%call = invoke i32 @foo_noreturn_nounwind() to label %continue
|
|
unwind label %cleanup
|
|
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @normal_call()
|
|
%call1 = call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.false, %continue
|
|
%cond = phi i32 [ %call, %continue ], [ %call1, %cond.false ]
|
|
ret i32 %cond
|
|
|
|
continue:
|
|
br label %cond.end
|
|
|
|
cleanup:
|
|
%res = landingpad { i8*, i32 }
|
|
catch i8* null
|
|
ret i32 0
|
|
}
|
|
|
|
; TEST 5.3 unounwind invoke instruction replaced by a call and a branch instruction put after it.
|
|
define i32 @invoke_nounwind(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
|
; CHECK-LABEL: define {{[^@]+}}@invoke_nounwind
|
|
; CHECK-SAME: (i32 [[A:%.*]]) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_nounwind()
|
|
; CHECK-NEXT: br label [[CONTINUE:%.*]]
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar()
|
|
; CHECK-NEXT: br label [[COND_END:%.*]]
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[CALL]], [[CONTINUE]] ], [ [[CALL1]], [[COND_FALSE]] ]
|
|
; CHECK-NEXT: ret i32 [[COND]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: br label [[COND_END]]
|
|
; CHECK: cleanup:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call void @normal_call()
|
|
%call = invoke i32 @foo_nounwind() to label %continue
|
|
unwind label %cleanup
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @normal_call()
|
|
%call1 = call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.false, %continue
|
|
%cond = phi i32 [ %call, %continue ], [ %call1, %cond.false ]
|
|
ret i32 %cond
|
|
|
|
continue:
|
|
br label %cond.end
|
|
|
|
cleanup:
|
|
%res = landingpad { i8*, i32 }
|
|
catch i8* null
|
|
ret i32 0
|
|
}
|
|
|
|
; TEST 5.4 unounwind invoke instruction replaced by a call and a branch instruction put after it.
|
|
define i32 @invoke_nounwind_phi(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
|
; CHECK-LABEL: define {{[^@]+}}@invoke_nounwind_phi
|
|
; CHECK-SAME: (i32 [[A:%.*]]) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_nounwind()
|
|
; CHECK-NEXT: br label [[CONTINUE:%.*]]
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar()
|
|
; CHECK-NEXT: br label [[CONTINUE]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[COND_TRUE]] ], [ 1, [[COND_FALSE]] ]
|
|
; CHECK-NEXT: ret i32 [[P]]
|
|
; CHECK: cleanup:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call void @normal_call()
|
|
%call = invoke i32 @foo_nounwind() to label %continue
|
|
unwind label %cleanup
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @normal_call()
|
|
%call1 = call i32 @bar()
|
|
br label %continue
|
|
|
|
continue:
|
|
%p = phi i32 [ 0, %cond.true ], [ 1, %cond.false ]
|
|
ret i32 %p
|
|
|
|
cleanup:
|
|
%res = landingpad { i8*, i32 } catch i8* null
|
|
ret i32 0
|
|
}
|
|
|
|
; TEST 5.5 unounwind invoke instruction replaced by a call and a branch instruction put after it.
|
|
define i32 @invoke_nounwind_phi_dom(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
|
; CHECK-LABEL: define {{[^@]+}}@invoke_nounwind_phi_dom
|
|
; CHECK-SAME: (i32 [[A:%.*]]) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.true:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_nounwind()
|
|
; CHECK-NEXT: br label [[CONTINUE:%.*]]
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: call void @normal_call()
|
|
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar()
|
|
; CHECK-NEXT: br label [[CONTINUE]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[CALL]], [[COND_TRUE]] ], [ [[CALL1]], [[COND_FALSE]] ]
|
|
; CHECK-NEXT: ret i32 [[P]]
|
|
; CHECK: cleanup:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %a, 0
|
|
br i1 %cmp, label %cond.true, label %cond.false
|
|
|
|
cond.true: ; preds = %entry
|
|
call void @normal_call()
|
|
%call = invoke i32 @foo_nounwind() to label %continue
|
|
unwind label %cleanup
|
|
|
|
cond.false: ; preds = %entry
|
|
call void @normal_call()
|
|
%call1 = call i32 @bar()
|
|
br label %continue
|
|
|
|
continue:
|
|
%p = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ]
|
|
ret i32 %p
|
|
|
|
cleanup:
|
|
%res = landingpad { i8*, i32 } catch i8* null
|
|
ret i32 0
|
|
}
|
|
|
|
; TEST 6: Undefined behvior, taken from LangRef.
|
|
; FIXME: Should be able to detect undefined behavior.
|
|
|
|
define void @ub(i32* %0) {
|
|
; NOT_CGSCC_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@ub
|
|
; NOT_CGSCC_NPM-SAME: (i32* nocapture nofree writeonly [[TMP0:%.*]])
|
|
; NOT_CGSCC_NPM-NEXT: [[POISON:%.*]] = sub nuw i32 0, 1
|
|
; NOT_CGSCC_NPM-NEXT: [[STILL_POISON:%.*]] = and i32 [[POISON]], 0
|
|
; NOT_CGSCC_NPM-NEXT: [[POISON_YET_AGAIN:%.*]] = getelementptr i32, i32* [[TMP0]], i32 [[STILL_POISON]]
|
|
; NOT_CGSCC_NPM-NEXT: store i32 0, i32* [[POISON_YET_AGAIN]], align 4
|
|
; NOT_CGSCC_NPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@ub
|
|
; IS__CGSCC____-SAME: (i32* nocapture nofree writeonly [[TMP0:%.*]])
|
|
; IS__CGSCC____-NEXT: [[POISON:%.*]] = sub nuw i32 0, 1
|
|
; IS__CGSCC____-NEXT: [[STILL_POISON:%.*]] = and i32 [[POISON]], 0
|
|
; IS__CGSCC____-NEXT: [[POISON_YET_AGAIN:%.*]] = getelementptr i32, i32* [[TMP0]], i32 [[STILL_POISON]]
|
|
; IS__CGSCC____-NEXT: store i32 0, i32* [[POISON_YET_AGAIN]], align 4
|
|
; IS__CGSCC____-NEXT: ret void
|
|
;
|
|
%poison = sub nuw i32 0, 1 ; Results in a poison value.
|
|
%still_poison = and i32 %poison, 0 ; 0, but also poison.
|
|
%poison_yet_again = getelementptr i32, i32* %0, i32 %still_poison
|
|
store i32 0, i32* %poison_yet_again ; Undefined behavior due to store to poison.
|
|
ret void
|
|
}
|
|
|
|
define void @inf_loop() #0 {
|
|
; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@inf_loop()
|
|
; NOT_CGSCC_NPM-NEXT: entry:
|
|
; NOT_CGSCC_NPM-NEXT: br label [[WHILE_BODY:%.*]]
|
|
; NOT_CGSCC_NPM: while.body:
|
|
; NOT_CGSCC_NPM-NEXT: br label [[WHILE_BODY]]
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readnone
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@inf_loop()
|
|
; IS__CGSCC____-NEXT: entry:
|
|
; IS__CGSCC____-NEXT: br label [[WHILE_BODY:%.*]]
|
|
; IS__CGSCC____: while.body:
|
|
; IS__CGSCC____-NEXT: br label [[WHILE_BODY]]
|
|
;
|
|
entry:
|
|
br label %while.body
|
|
|
|
while.body: ; preds = %entry, %while.body
|
|
br label %while.body
|
|
}
|
|
|
|
; TEST 7: Infinite loop.
|
|
; FIXME: Detect infloops, and mark affected blocks dead.
|
|
|
|
define i32 @test5(i32, i32) #0 {
|
|
; CHECK: Function Attrs: nosync readnone
|
|
; CHECK-LABEL: define {{[^@]+}}@test5
|
|
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], [[TMP1]]
|
|
; CHECK-NEXT: br i1 [[TMP3]], label [[COND_IF:%.*]], label [[COND_ELSEIF:%.*]]
|
|
; CHECK: cond.if:
|
|
; CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @bar()
|
|
; CHECK-NEXT: br label [[COND_END:%.*]]
|
|
; CHECK: cond.elseif:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.else:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%3 = icmp sgt i32 %0, %1
|
|
br i1 %3, label %cond.if, label %cond.elseif
|
|
|
|
cond.if: ; preds = %2
|
|
%4 = tail call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.elseif: ; preds = %2
|
|
call void @inf_loop()
|
|
%5 = icmp slt i32 %0, %1
|
|
br i1 %5, label %cond.end, label %cond.else
|
|
|
|
cond.else: ; preds = %cond.elseif
|
|
%6 = tail call i32 @foo()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.if, %cond.else, %cond.elseif
|
|
%7 = phi i32 [ %1, %cond.elseif ], [ 0, %cond.else ], [ 0, %cond.if ]
|
|
ret i32 %7
|
|
}
|
|
|
|
define void @rec() #0 {
|
|
; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone willreturn
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@rec()
|
|
; NOT_CGSCC_NPM-NEXT: entry:
|
|
; NOT_CGSCC_NPM-NEXT: unreachable
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@rec()
|
|
; IS__CGSCC____-NEXT: entry:
|
|
; IS__CGSCC____-NEXT: unreachable
|
|
;
|
|
entry:
|
|
call void @rec()
|
|
ret void
|
|
}
|
|
|
|
; TEST 8: Recursion
|
|
; FIXME: everything after first block should be marked dead
|
|
; and unreachable should be put after call to @rec().
|
|
|
|
define i32 @test6(i32, i32) #0 {
|
|
; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone willreturn
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test6
|
|
; NOT_CGSCC_NPM-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
|
|
; NOT_CGSCC_NPM-NEXT: unreachable
|
|
; NOT_CGSCC_NPM: cond.if:
|
|
; NOT_CGSCC_NPM-NEXT: unreachable
|
|
; NOT_CGSCC_NPM: cond.elseif:
|
|
; NOT_CGSCC_NPM-NEXT: unreachable
|
|
; NOT_CGSCC_NPM: cond.else:
|
|
; NOT_CGSCC_NPM-NEXT: unreachable
|
|
; NOT_CGSCC_NPM: cond.end:
|
|
; NOT_CGSCC_NPM-NEXT: unreachable
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test6
|
|
; IS__CGSCC____-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
|
|
; IS__CGSCC____-NEXT: unreachable
|
|
; IS__CGSCC____: cond.if:
|
|
; IS__CGSCC____-NEXT: unreachable
|
|
; IS__CGSCC____: cond.elseif:
|
|
; IS__CGSCC____-NEXT: unreachable
|
|
; IS__CGSCC____: cond.else:
|
|
; IS__CGSCC____-NEXT: unreachable
|
|
; IS__CGSCC____: cond.end:
|
|
; IS__CGSCC____-NEXT: unreachable
|
|
;
|
|
call void @rec()
|
|
%3 = icmp sgt i32 %0, %1
|
|
br i1 %3, label %cond.if, label %cond.elseif
|
|
|
|
cond.if: ; preds = %2
|
|
%4 = tail call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.elseif: ; preds = %2
|
|
call void @rec()
|
|
%5 = icmp slt i32 %0, %1
|
|
br i1 %5, label %cond.end, label %cond.else
|
|
|
|
cond.else: ; preds = %cond.elseif
|
|
%6 = tail call i32 @foo()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.if, %cond.else, %cond.elseif
|
|
%7 = phi i32 [ %1, %cond.elseif ], [ 0, %cond.else ], [ 0, %cond.if ]
|
|
ret i32 %7
|
|
}
|
|
; TEST 9: Recursion
|
|
; FIXME: contains recursive call to itself in cond.elseif block
|
|
|
|
define i32 @test7(i32, i32) #0 {
|
|
; CHECK-LABEL: define {{[^@]+}}@test7
|
|
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
|
|
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], [[TMP1]]
|
|
; CHECK-NEXT: br i1 [[TMP3]], label [[COND_IF:%.*]], label [[COND_ELSEIF:%.*]]
|
|
; CHECK: cond.if:
|
|
; CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @bar()
|
|
; CHECK-NEXT: br label [[COND_END:%.*]]
|
|
; CHECK: cond.elseif:
|
|
; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @test7(i32 [[TMP0]], i32 [[TMP1]])
|
|
; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP0]], [[TMP1]]
|
|
; CHECK-NEXT: br i1 [[TMP6]], label [[COND_END]], label [[COND_ELSE:%.*]]
|
|
; CHECK: cond.else:
|
|
; CHECK-NEXT: [[TMP7:%.*]] = tail call i32 @foo()
|
|
; CHECK-NEXT: br label [[COND_END]]
|
|
; CHECK: cond.end:
|
|
; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP1]], [[COND_ELSEIF]] ], [ 0, [[COND_ELSE]] ], [ 0, [[COND_IF]] ]
|
|
; CHECK-NEXT: ret i32 [[TMP8]]
|
|
;
|
|
%3 = icmp sgt i32 %0, %1
|
|
br i1 %3, label %cond.if, label %cond.elseif
|
|
|
|
cond.if: ; preds = %2
|
|
%4 = tail call i32 @bar()
|
|
br label %cond.end
|
|
|
|
cond.elseif: ; preds = %2
|
|
%5 = tail call i32 @test7(i32 %0, i32 %1)
|
|
%6 = icmp slt i32 %0, %1
|
|
br i1 %6, label %cond.end, label %cond.else
|
|
|
|
cond.else: ; preds = %cond.elseif
|
|
%7 = tail call i32 @foo()
|
|
br label %cond.end
|
|
|
|
cond.end: ; preds = %cond.if, %cond.else, %cond.elseif
|
|
%8 = phi i32 [ %1, %cond.elseif ], [ 0, %cond.else ], [ 0, %cond.if ]
|
|
ret i32 %8
|
|
}
|
|
|
|
; SCC test
|
|
;
|
|
; char a1 __attribute__((aligned(8)));
|
|
; char a2 __attribute__((aligned(16)));
|
|
;
|
|
; char* f1(char* a ){
|
|
; return a?a:f2(&a1);
|
|
; }
|
|
; char* f2(char* a){
|
|
; return a?f1(a):f3(&a2);
|
|
; }
|
|
;
|
|
; char* f3(char* a){
|
|
; return a?&a1: f1(&a2);
|
|
; }
|
|
|
|
@a1 = common global i8 0, align 8
|
|
@a2 = common global i8 0, align 16
|
|
|
|
define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: define {{[^@]+}}@f1
|
|
; CHECK-SAME: (i8* readnone [[TMP0:%.*]]) local_unnamed_addr
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
|
|
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
|
|
; CHECK: 3:
|
|
; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* @f2(i8* nonnull @a1)
|
|
; CHECK-NEXT: br label [[TMP5]]
|
|
; CHECK: 5:
|
|
; CHECK-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
|
|
; CHECK-NEXT: ret i8* [[TMP6]]
|
|
;
|
|
%2 = icmp eq i8* %0, null
|
|
br i1 %2, label %3, label %5
|
|
|
|
; <label>:3: ; preds = %1
|
|
%4 = tail call i8* @f2(i8* nonnull @a1)
|
|
br label %5
|
|
|
|
; <label>:5: ; preds = %1, %3
|
|
%6 = phi i8* [ %4, %3 ], [ %0, %1 ]
|
|
ret i8* %6
|
|
}
|
|
|
|
define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: define {{[^@]+}}@f2
|
|
; CHECK-SAME: (i8* readnone [[TMP0:%.*]]) local_unnamed_addr
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
|
|
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
|
|
; CHECK: 3:
|
|
; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* @f1(i8* nonnull [[TMP0]])
|
|
; CHECK-NEXT: br label [[TMP7:%.*]]
|
|
; CHECK: 5:
|
|
; CHECK-NEXT: [[TMP6:%.*]] = tail call i8* @f3(i8* nonnull @a2)
|
|
; CHECK-NEXT: br label [[TMP7]]
|
|
; CHECK: 7:
|
|
; CHECK-NEXT: [[TMP8:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ]
|
|
; CHECK-NEXT: ret i8* [[TMP8]]
|
|
;
|
|
%2 = icmp eq i8* %0, null
|
|
br i1 %2, label %5, label %3
|
|
|
|
; <label>:3: ; preds = %1
|
|
|
|
%4 = tail call i8* @f1(i8* nonnull %0)
|
|
br label %7
|
|
|
|
; <label>:5: ; preds = %1
|
|
%6 = tail call i8* @f3(i8* nonnull @a2)
|
|
br label %7
|
|
|
|
; <label>:7: ; preds = %5, %3
|
|
%8 = phi i8* [ %4, %3 ], [ %6, %5 ]
|
|
ret i8* %8
|
|
}
|
|
|
|
define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: define {{[^@]+}}@f3
|
|
; CHECK-SAME: (i8* readnone [[TMP0:%.*]]) local_unnamed_addr
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
|
|
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
|
|
; CHECK: 3:
|
|
; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* @f1(i8* nonnull @a2)
|
|
; CHECK-NEXT: br label [[TMP5]]
|
|
; CHECK: 5:
|
|
; CHECK-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ @a1, [[TMP1:%.*]] ]
|
|
; CHECK-NEXT: ret i8* [[TMP6]]
|
|
;
|
|
%2 = icmp eq i8* %0, null
|
|
br i1 %2, label %3, label %5
|
|
|
|
; <label>:3: ; preds = %1
|
|
%4 = tail call i8* @f1(i8* nonnull @a2)
|
|
br label %5
|
|
|
|
; <label>:5: ; preds = %1, %3
|
|
%6 = phi i8* [ %4, %3 ], [ @a1, %1 ]
|
|
ret i8* %6
|
|
}
|
|
|
|
declare void @sink() nofree nosync nounwind willreturn
|
|
define void @test_unreachable() {
|
|
; CHECK: Function Attrs: nofree noreturn nosync nounwind
|
|
; CHECK-LABEL: define {{[^@]+}}@test_unreachable()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: call void @test_unreachable()
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
call void @sink()
|
|
call void @test_unreachable()
|
|
unreachable
|
|
}
|
|
|
|
define linkonce_odr void @non_exact1() {
|
|
; CHECK-LABEL: define {{[^@]+}}@non_exact1()
|
|
; CHECK-NEXT: call void @non_dead_a0()
|
|
; CHECK-NEXT: call void @non_dead_a1()
|
|
; CHECK-NEXT: call void @non_dead_a2()
|
|
; CHECK-NEXT: call void @non_dead_a3()
|
|
; CHECK-NEXT: call void @non_dead_a4()
|
|
; CHECK-NEXT: call void @non_dead_a5()
|
|
; CHECK-NEXT: call void @non_dead_a6()
|
|
; CHECK-NEXT: call void @non_dead_a7()
|
|
; CHECK-NEXT: call void @non_dead_a8()
|
|
; CHECK-NEXT: call void @non_dead_a9()
|
|
; CHECK-NEXT: call void @non_dead_a10()
|
|
; CHECK-NEXT: call void @non_dead_a11()
|
|
; CHECK-NEXT: call void @non_dead_a12()
|
|
; CHECK-NEXT: call void @non_dead_a13()
|
|
; CHECK-NEXT: call void @non_dead_a14()
|
|
; CHECK-NEXT: call void @non_dead_a15()
|
|
; CHECK-NEXT: call void @middle()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @non_dead_a0()
|
|
call void @non_dead_a1()
|
|
call void @non_dead_a2()
|
|
call void @non_dead_a3()
|
|
call void @non_dead_a4()
|
|
call void @non_dead_a5()
|
|
call void @non_dead_a6()
|
|
call void @non_dead_a7()
|
|
call void @non_dead_a8()
|
|
call void @non_dead_a9()
|
|
call void @non_dead_a10()
|
|
call void @non_dead_a11()
|
|
call void @non_dead_a12()
|
|
call void @non_dead_a13()
|
|
call void @non_dead_a14()
|
|
call void @non_dead_a15()
|
|
call void @middle()
|
|
ret void
|
|
}
|
|
define internal void @middle() {
|
|
; CHECK-LABEL: define {{[^@]+}}@middle()
|
|
; CHECK-NEXT: bb0:
|
|
; CHECK-NEXT: call void @non_dead_b0()
|
|
; CHECK-NEXT: call void @non_dead_b1()
|
|
; CHECK-NEXT: call void @non_dead_b2()
|
|
; CHECK-NEXT: call void @non_dead_b3()
|
|
; CHECK-NEXT: br label [[BB1:%.*]]
|
|
; CHECK: bb1:
|
|
; CHECK-NEXT: call void @non_dead_b4()
|
|
; CHECK-NEXT: call void @non_dead_b5()
|
|
; CHECK-NEXT: call void @non_dead_b6()
|
|
; CHECK-NEXT: call void @non_dead_b7()
|
|
; CHECK-NEXT: br label [[BB2:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: call void @non_dead_b8()
|
|
; CHECK-NEXT: call void @non_dead_b9()
|
|
; CHECK-NEXT: call void @non_dead_b10()
|
|
; CHECK-NEXT: call void @non_dead_b11()
|
|
; CHECK-NEXT: br label [[BB3:%.*]]
|
|
; CHECK: bb3:
|
|
; CHECK-NEXT: call void @non_dead_b12()
|
|
; CHECK-NEXT: call void @non_dead_b13()
|
|
; CHECK-NEXT: call void @non_dead_b14()
|
|
; CHECK-NEXT: call void @non_dead_b15()
|
|
; CHECK-NEXT: br label [[BB4:%.*]]
|
|
; CHECK: bb4:
|
|
; CHECK-NEXT: call void @non_exact2()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
bb0:
|
|
call void @non_dead_b0()
|
|
call void @non_dead_b1()
|
|
call void @non_dead_b2()
|
|
call void @non_dead_b3()
|
|
br label %bb1
|
|
bb1:
|
|
call void @non_dead_b4()
|
|
call void @non_dead_b5()
|
|
call void @non_dead_b6()
|
|
call void @non_dead_b7()
|
|
br label %bb2
|
|
bb2:
|
|
call void @non_dead_b8()
|
|
call void @non_dead_b9()
|
|
call void @non_dead_b10()
|
|
call void @non_dead_b11()
|
|
br label %bb3
|
|
bb3:
|
|
call void @non_dead_b12()
|
|
call void @non_dead_b13()
|
|
call void @non_dead_b14()
|
|
call void @non_dead_b15()
|
|
br label %bb4
|
|
bb4:
|
|
call void @non_exact2()
|
|
ret void
|
|
}
|
|
define linkonce_odr void @non_exact2() {
|
|
; CHECK-LABEL: define {{[^@]+}}@non_exact2()
|
|
; CHECK-NEXT: call void @non_dead_c0()
|
|
; CHECK-NEXT: call void @non_dead_c1()
|
|
; CHECK-NEXT: call void @non_dead_c2()
|
|
; CHECK-NEXT: call void @non_dead_c3()
|
|
; CHECK-NEXT: call void @non_dead_c4()
|
|
; CHECK-NEXT: call void @non_dead_c5()
|
|
; CHECK-NEXT: call void @non_dead_c6()
|
|
; CHECK-NEXT: call void @non_dead_c7()
|
|
; CHECK-NEXT: call void @non_dead_c8()
|
|
; CHECK-NEXT: call void @non_dead_c9()
|
|
; CHECK-NEXT: call void @non_dead_c10()
|
|
; CHECK-NEXT: call void @non_dead_c11()
|
|
; CHECK-NEXT: call void @non_dead_c12()
|
|
; CHECK-NEXT: call void @non_dead_c13()
|
|
; CHECK-NEXT: call void @non_dead_c14()
|
|
; CHECK-NEXT: call void @non_dead_c15()
|
|
; CHECK-NEXT: call void @non_exact3()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @non_dead_c0()
|
|
call void @non_dead_c1()
|
|
call void @non_dead_c2()
|
|
call void @non_dead_c3()
|
|
call void @non_dead_c4()
|
|
call void @non_dead_c5()
|
|
call void @non_dead_c6()
|
|
call void @non_dead_c7()
|
|
call void @non_dead_c8()
|
|
call void @non_dead_c9()
|
|
call void @non_dead_c10()
|
|
call void @non_dead_c11()
|
|
call void @non_dead_c12()
|
|
call void @non_dead_c13()
|
|
call void @non_dead_c14()
|
|
call void @non_dead_c15()
|
|
call void @non_exact3()
|
|
ret void
|
|
}
|
|
define linkonce_odr void @non_exact3() {
|
|
; CHECK-LABEL: define {{[^@]+}}@non_exact3()
|
|
; CHECK-NEXT: call void @non_dead_d0()
|
|
; CHECK-NEXT: call void @non_dead_d1()
|
|
; CHECK-NEXT: call void @non_dead_d2()
|
|
; CHECK-NEXT: call void @non_dead_d3()
|
|
; CHECK-NEXT: call void @non_dead_d4()
|
|
; CHECK-NEXT: call void @non_dead_d5()
|
|
; CHECK-NEXT: call void @non_dead_d6()
|
|
; CHECK-NEXT: call void @non_dead_d7()
|
|
; CHECK-NEXT: call void @non_dead_d8()
|
|
; CHECK-NEXT: call void @non_dead_d9()
|
|
; CHECK-NEXT: call void @non_dead_d10()
|
|
; CHECK-NEXT: call void @non_dead_d11()
|
|
; CHECK-NEXT: call void @non_dead_d12()
|
|
; CHECK-NEXT: call void @non_dead_d13()
|
|
; CHECK-NEXT: call void @non_dead_d14()
|
|
; CHECK-NEXT: call void @non_dead_d15()
|
|
; CHECK-NEXT: [[NR:%.*]] = call i32 @foo_noreturn()
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
call void @non_dead_d0()
|
|
call void @non_dead_d1()
|
|
call void @non_dead_d2()
|
|
call void @non_dead_d3()
|
|
call void @non_dead_d4()
|
|
call void @non_dead_d5()
|
|
call void @non_dead_d6()
|
|
call void @non_dead_d7()
|
|
call void @non_dead_d8()
|
|
call void @non_dead_d9()
|
|
call void @non_dead_d10()
|
|
call void @non_dead_d11()
|
|
call void @non_dead_d12()
|
|
call void @non_dead_d13()
|
|
call void @non_dead_d14()
|
|
call void @non_dead_d15()
|
|
%nr = call i32 @foo_noreturn()
|
|
call void @dead_e1()
|
|
ret void
|
|
}
|
|
|
|
define internal void @non_dead_a0() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a0()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a1() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a1()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a2() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a2()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a3() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a3()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a4() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a4()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a5() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a5()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a6() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a6()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a7() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a7()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a8() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a8()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a9() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a9()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a10() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a10()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a11() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a11()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a12() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a12()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a13() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a13()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a14() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a14()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_a15() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_a15()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b0() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b0()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b1() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b1()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b2() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b2()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b3() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b3()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b4() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b4()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b5() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b5()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b6() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b6()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b7() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b7()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b8() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b8()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b9() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b9()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b10() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b10()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b11() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b11()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b12() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b12()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b13() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b13()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b14() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b14()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_b15() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_b15()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c0() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c0()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c1() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c1()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c2() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c2()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c3() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c3()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c4() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c4()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c5() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c5()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c6() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c6()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c7() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c7()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c8() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c8()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c9() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c9()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c10() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c10()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c11() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c11()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c12() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c12()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c13() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c13()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c14() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c14()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_c15() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_c15()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d0() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d0()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d1() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d1()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d2() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d2()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d3() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d3()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d4() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d4()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d5() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d5()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d6() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d6()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d7() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d7()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d8() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d8()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d9() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d9()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d10() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d10()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d11() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d11()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d12() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d12()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d13() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d13()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d14() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d14()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @non_dead_d15() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@non_dead_d15()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
define internal void @dead_e0() { call void @dead_e1() ret void }
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@dead_e0()
|
|
; IS__CGSCC____-NEXT: call void @dead_e1()
|
|
; IS__CGSCC____-NEXT: ret void
|
|
;
|
|
define internal void @dead_e1() { call void @dead_e2() ret void }
|
|
define internal void @dead_e2() { ret void }
|
|
|
|
; Verify we actually deduce information for these functions.
|
|
|
|
declare void @blowup() noreturn
|
|
define void @live_with_dead_entry() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
|
entry:
|
|
invoke void @blowup() to label %live_with_dead_entry unwind label %lpad
|
|
lpad:
|
|
%0 = landingpad { i8*, i32 } catch i8* null
|
|
br label %live_with_dead_entry
|
|
live_with_dead_entry:
|
|
ret void
|
|
}
|
|
|
|
define void @live_with_dead_entry_lp() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
|
; CHECK: Function Attrs: nounwind
|
|
; CHECK-LABEL: define {{[^@]+}}@live_with_dead_entry_lp() #2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: invoke void @blowup()
|
|
; CHECK-NEXT: to label [[LIVE_WITH_DEAD_ENTRY_DEAD:%.*]] unwind label [[LP1:%.*]]
|
|
; CHECK: lp1:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { i8*, i32 }
|
|
; CHECK-NEXT: catch i8* null
|
|
; CHECK-NEXT: invoke void @blowup()
|
|
; CHECK-NEXT: to label [[LIVE_WITH_DEAD_ENTRY_DEAD1:%.*]] unwind label [[LP2:%.*]]
|
|
; CHECK: lp2:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 }
|
|
; CHECK-NEXT: catch i8* null
|
|
; CHECK-NEXT: br label [[LIVE_WITH_DEAD_ENTRY:%.*]]
|
|
; CHECK: live_with_dead_entry.dead:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: live_with_dead_entry.dead1:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: live_with_dead_entry:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
invoke void @blowup() to label %live_with_dead_entry unwind label %lp1
|
|
lp1:
|
|
%lp = landingpad { i8*, i32 } catch i8* null
|
|
invoke void @blowup() to label %live_with_dead_entry unwind label %lp2
|
|
lp2:
|
|
%0 = landingpad { i8*, i32 } catch i8* null
|
|
br label %live_with_dead_entry
|
|
live_with_dead_entry:
|
|
ret void
|
|
}
|
|
|
|
define internal void @useless_arg_sink(i32* %a) {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@useless_arg_sink()
|
|
; CHECK-NEXT: call void @sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @sink()
|
|
ret void
|
|
}
|
|
|
|
define internal void @useless_arg_almost_sink(i32* %a) {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@useless_arg_almost_sink()
|
|
; CHECK-NEXT: call void @useless_arg_sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @useless_arg_sink(i32* %a)
|
|
ret void
|
|
}
|
|
|
|
; Check we do not annotate the function interface of this weak function.
|
|
define weak_odr void @useless_arg_ext(i32* %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@useless_arg_ext
|
|
; CHECK-SAME: (i32* [[A:%.*]])
|
|
; CHECK-NEXT: call void @useless_arg_almost_sink()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @useless_arg_almost_sink(i32* %a)
|
|
ret void
|
|
}
|
|
|
|
define internal void @useless_arg_ext_int(i32* %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@useless_arg_ext_int
|
|
; CHECK-SAME: (i32* [[A:%.*]])
|
|
; CHECK-NEXT: call void @useless_arg_ext(i32* [[A]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @useless_arg_ext(i32* %a)
|
|
ret void
|
|
}
|
|
|
|
define void @useless_arg_ext_int_ext(i32* %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@useless_arg_ext_int_ext
|
|
; CHECK-SAME: (i32* [[A:%.*]])
|
|
; CHECK-NEXT: call void @useless_arg_ext_int(i32* [[A]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @useless_arg_ext_int(i32* %a)
|
|
ret void
|
|
}
|
|
|
|
; FIXME: We should fold terminators.
|
|
|
|
define internal i32 @switch_default(i64 %i) nounwind {
|
|
; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind willreturn
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@switch_default()
|
|
; NOT_CGSCC_NPM-NEXT: entry:
|
|
; NOT_CGSCC_NPM-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [
|
|
; NOT_CGSCC_NPM-NEXT: i64 3, label [[RETURN:%.*]]
|
|
; NOT_CGSCC_NPM-NEXT: i64 10, label [[RETURN]]
|
|
; NOT_CGSCC_NPM-NEXT: ]
|
|
; NOT_CGSCC_NPM: sw.default:
|
|
; NOT_CGSCC_NPM-NEXT: call void @sink()
|
|
; NOT_CGSCC_NPM-NEXT: ret i32 undef
|
|
; NOT_CGSCC_NPM: return:
|
|
; NOT_CGSCC_NPM-NEXT: unreachable
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree nosync nounwind willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@switch_default()
|
|
; IS__CGSCC____-NEXT: entry:
|
|
; IS__CGSCC____-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [
|
|
; IS__CGSCC____-NEXT: i64 3, label [[RETURN:%.*]]
|
|
; IS__CGSCC____-NEXT: i64 10, label [[RETURN]]
|
|
; IS__CGSCC____-NEXT: ]
|
|
; IS__CGSCC____: sw.default:
|
|
; IS__CGSCC____-NEXT: call void @sink()
|
|
; IS__CGSCC____-NEXT: ret i32 123
|
|
; IS__CGSCC____: return:
|
|
; IS__CGSCC____-NEXT: unreachable
|
|
;
|
|
entry:
|
|
switch i64 %i, label %sw.default [
|
|
i64 3, label %return
|
|
i64 10, label %return
|
|
]
|
|
|
|
sw.default:
|
|
call void @sink()
|
|
ret i32 123
|
|
|
|
return:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @switch_default_caller() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@switch_default_caller()
|
|
; CHECK-NEXT: [[CALL2:%.*]] = tail call i32 @switch_default()
|
|
; CHECK-NEXT: ret i32 123
|
|
;
|
|
%call2 = tail call i32 @switch_default(i64 0)
|
|
ret i32 %call2
|
|
}
|
|
|
|
define internal i32 @switch_default_dead(i64 %i) nounwind {
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@switch_default_dead()
|
|
; IS__CGSCC____-NEXT: entry:
|
|
; IS__CGSCC____-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [
|
|
; IS__CGSCC____-NEXT: i64 3, label [[RETURN:%.*]]
|
|
; IS__CGSCC____-NEXT: i64 10, label [[RETURN]]
|
|
; IS__CGSCC____-NEXT: ]
|
|
; IS__CGSCC____: sw.default:
|
|
; IS__CGSCC____-NEXT: ret i32 123
|
|
; IS__CGSCC____: return:
|
|
; IS__CGSCC____-NEXT: unreachable
|
|
;
|
|
entry:
|
|
switch i64 %i, label %sw.default [
|
|
i64 3, label %return
|
|
i64 10, label %return
|
|
]
|
|
|
|
sw.default:
|
|
ret i32 123
|
|
|
|
return:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @switch_default_dead_caller() {
|
|
; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@switch_default_dead_caller()
|
|
; NOT_CGSCC_NPM-NEXT: ret i32 123
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@switch_default_dead_caller()
|
|
; IS__CGSCC____-NEXT: ret i32 123
|
|
;
|
|
%call2 = tail call i32 @switch_default_dead(i64 0)
|
|
ret i32 %call2
|
|
}
|
|
|
|
define void @call_via_pointer_with_dead_args(i32* %a, i32* %b, void (i32*, i32*, i32*, i64, i32**)* %fp) {
|
|
; CHECK-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args
|
|
; CHECK-SAME: (i32* [[A:%.*]], i32* [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]])
|
|
; CHECK-NEXT: call void [[FP]](i32* [[A]], i32* [[B]], i32* [[A]], i64 -1, i32** null)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void %fp(i32* %a, i32* %b, i32* %a, i64 -1, i32** null)
|
|
ret void
|
|
}
|
|
; FIXME: We have to prevent the propagation of %fp in the new pm CGSCC pass until the CallGraphUpdater can handle the new call edge.
|
|
define internal void @call_via_pointer_with_dead_args_internal_a(i32* %a, i32* %b, void (i32*, i32*, i32*, i64, i32**)* %fp) {
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a
|
|
; NOT_CGSCC_NPM-SAME: (i32* [[A:%.*]], i32* nonnull align 128 dereferenceable(4) [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]])
|
|
; NOT_CGSCC_NPM-NEXT: call void @called_via_pointer(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[B]], i32* [[A]], i64 -1, i32** null)
|
|
; NOT_CGSCC_NPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a
|
|
; IS__CGSCC____-SAME: (i32* [[A:%.*]], i32* nonnull align 128 dereferenceable(4) [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]])
|
|
; IS__CGSCC____-NEXT: call void [[FP]](i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[B]], i32* [[A]], i64 -1, i32** null)
|
|
; IS__CGSCC____-NEXT: ret void
|
|
;
|
|
call void %fp(i32* %a, i32* %b, i32* %a, i64 -1, i32** null)
|
|
ret void
|
|
}
|
|
define internal void @call_via_pointer_with_dead_args_internal_b(i32* %a, i32* %b, void (i32*, i32*, i32*, i64, i32**)* %fp) {
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b
|
|
; NOT_CGSCC_NPM-SAME: (i32* [[A:%.*]], i32* nonnull align 128 dereferenceable(4) [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]])
|
|
; NOT_CGSCC_NPM-NEXT: call void @called_via_pointer_internal_2(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[B]], i32* [[A]], i64 -1, i32** null)
|
|
; NOT_CGSCC_NPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b
|
|
; IS__CGSCC____-SAME: (i32* [[A:%.*]], i32* nonnull align 128 dereferenceable(4) [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]])
|
|
; IS__CGSCC____-NEXT: call void [[FP]](i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[B]], i32* [[A]], i64 -1, i32** null)
|
|
; IS__CGSCC____-NEXT: ret void
|
|
;
|
|
call void %fp(i32* %a, i32* %b, i32* %a, i64 -1, i32** null)
|
|
ret void
|
|
}
|
|
define void @call_via_pointer_with_dead_args_caller(i32* %a, i32* %b) {
|
|
; CHECK-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_caller
|
|
; CHECK-SAME: (i32* [[A:%.*]], i32* [[B:%.*]])
|
|
; CHECK-NEXT: [[PTR1:%.*]] = alloca i32, align 128
|
|
; CHECK-NEXT: [[PTR2:%.*]] = alloca i32, align 128
|
|
; CHECK-NEXT: [[PTR3:%.*]] = alloca i32, align 128
|
|
; CHECK-NEXT: [[PTR4:%.*]] = alloca i32, align 128
|
|
; CHECK-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR1]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull @called_via_pointer)
|
|
; CHECK-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR2]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull @called_via_pointer_internal_1)
|
|
; CHECK-NEXT: call void @call_via_pointer_with_dead_args_internal_a(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR3]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull @called_via_pointer)
|
|
; CHECK-NEXT: call void @call_via_pointer_with_dead_args_internal_b(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR4]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull @called_via_pointer_internal_2)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%ptr1 = alloca i32, align 128
|
|
%ptr2 = alloca i32, align 128
|
|
%ptr3 = alloca i32, align 128
|
|
%ptr4 = alloca i32, align 128
|
|
call void @call_via_pointer_with_dead_args(i32* %a, i32* %ptr1, void (i32*, i32*, i32*, i64, i32**)* @called_via_pointer)
|
|
call void @call_via_pointer_with_dead_args(i32* %a, i32* %ptr2, void (i32*, i32*, i32*, i64, i32**)* @called_via_pointer_internal_1)
|
|
call void @call_via_pointer_with_dead_args_internal_a(i32* %b, i32* %ptr3, void (i32*, i32*, i32*, i64, i32**)* @called_via_pointer)
|
|
call void @call_via_pointer_with_dead_args_internal_b(i32* %b, i32* %ptr4, void (i32*, i32*, i32*, i64, i32**)* @called_via_pointer_internal_2)
|
|
ret void
|
|
}
|
|
define void @called_via_pointer(i32* %a, i32* %b, i32* %c, i64 %d, i32** %e) {
|
|
; CHECK-LABEL: define {{[^@]+}}@called_via_pointer
|
|
; CHECK-SAME: (i32* [[A:%.*]], i32* nocapture nofree readnone [[B:%.*]], i32* nocapture nofree readnone [[C:%.*]], i64 [[D:%.*]], i32** nocapture nofree readnone [[E:%.*]])
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: tail call void @use_i32p(i32* [[A]])
|
|
; CHECK-NEXT: tail call void @use_i32p(i32* [[A]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
tail call void @use_i32p(i32* %a)
|
|
tail call void @use_i32p(i32* %a)
|
|
ret void
|
|
}
|
|
define internal void @called_via_pointer_internal_1(i32* %a, i32* %b, i32* %c, i64 %d, i32** %e) {
|
|
; CHECK-LABEL: define {{[^@]+}}@called_via_pointer_internal_1
|
|
; CHECK-SAME: (i32* [[A:%.*]], i32* nocapture nofree readnone [[B:%.*]], i32* nocapture nofree readnone [[C:%.*]], i64 [[D:%.*]], i32** nocapture nofree readnone [[E:%.*]])
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: tail call void @use_i32p(i32* [[A]])
|
|
; CHECK-NEXT: tail call void @use_i32p(i32* [[A]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
tail call void @use_i32p(i32* %a)
|
|
tail call void @use_i32p(i32* %a)
|
|
ret void
|
|
}
|
|
; FIXME: Figure out why the MODULE has the unused arguments still
|
|
define internal void @called_via_pointer_internal_2(i32* %a, i32* %b, i32* %c, i64 %d, i32** %e) {
|
|
; CHECK-LABEL: define {{[^@]+}}@called_via_pointer_internal_2
|
|
; CHECK-SAME: (i32* [[A:%.*]], i32* nocapture nofree readnone [[B:%.*]], i32* nocapture nofree readnone [[C:%.*]], i64 [[D:%.*]], i32** nocapture nofree readnone [[E:%.*]])
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: tail call void @use_i32p(i32* [[A]])
|
|
; CHECK-NEXT: tail call void @use_i32p(i32* [[A]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
tail call void @use_i32p(i32* %a)
|
|
tail call void @use_i32p(i32* %a)
|
|
ret void
|
|
}
|
|
declare void @use_i32p(i32*)
|
|
|
|
; Allow blockaddress users
|
|
; NOT_CGSCC_OPM-NOT: @dead_with_blockaddress_users
|
|
define internal void @dead_with_blockaddress_users(i32* nocapture %pc) nounwind readonly {
|
|
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@dead_with_blockaddress_users
|
|
; IS__CGSCC_OPM-SAME: (i32* nocapture [[PC:%.*]])
|
|
; IS__CGSCC_OPM-NEXT: entry:
|
|
; IS__CGSCC_OPM-NEXT: br label [[INDIRECTGOTO:%.*]]
|
|
; IS__CGSCC_OPM: lab0:
|
|
; IS__CGSCC_OPM-NEXT: [[INDVAR_NEXT:%.*]] = add i32 [[INDVAR:%.*]], 1
|
|
; IS__CGSCC_OPM-NEXT: br label [[INDIRECTGOTO]]
|
|
; IS__CGSCC_OPM: end:
|
|
; IS__CGSCC_OPM-NEXT: ret void
|
|
; IS__CGSCC_OPM: indirectgoto:
|
|
; IS__CGSCC_OPM-NEXT: [[INDVAR]] = phi i32 [ [[INDVAR_NEXT]], [[LAB0:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; IS__CGSCC_OPM-NEXT: [[PC_ADDR_0:%.*]] = getelementptr i32, i32* [[PC]], i32 [[INDVAR]]
|
|
; IS__CGSCC_OPM-NEXT: [[TMP1_PN:%.*]] = load i32, i32* [[PC_ADDR_0]]
|
|
; IS__CGSCC_OPM-NEXT: [[INDIRECT_GOTO_DEST_IN:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @dead_with_blockaddress_users.l, i32 0, i32 [[TMP1_PN]]
|
|
; IS__CGSCC_OPM-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = load i8*, i8** [[INDIRECT_GOTO_DEST_IN]]
|
|
; IS__CGSCC_OPM-NEXT: indirectbr i8* [[INDIRECT_GOTO_DEST]], [label [[LAB0]], label %end]
|
|
;
|
|
entry:
|
|
br label %indirectgoto
|
|
|
|
lab0: ; preds = %indirectgoto
|
|
%indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1]
|
|
br label %indirectgoto
|
|
|
|
end: ; preds = %indirectgoto
|
|
ret void
|
|
|
|
indirectgoto: ; preds = %lab0, %entry
|
|
%indvar = phi i32 [ %indvar.next, %lab0 ], [ 0, %entry ] ; <i32> [#uses=2]
|
|
%pc.addr.0 = getelementptr i32, i32* %pc, i32 %indvar ; <i32*> [#uses=1]
|
|
%tmp1.pn = load i32, i32* %pc.addr.0 ; <i32> [#uses=1]
|
|
%indirect.goto.dest.in = getelementptr inbounds [2 x i8*], [2 x i8*]* @dead_with_blockaddress_users.l, i32 0, i32 %tmp1.pn ; <i8**> [#uses=1]
|
|
%indirect.goto.dest = load i8*, i8** %indirect.goto.dest.in ; <i8*> [#uses=1]
|
|
indirectbr i8* %indirect.goto.dest, [label %lab0, label %end]
|
|
}
|
|
|
|
|
|
; The code below exposed a bug that caused %call to be replaced with `undef`.
|
|
|
|
%struct.a = type { %struct.a* }
|
|
|
|
@e = global %struct.a* null
|
|
|
|
define i32 @main() {
|
|
; CHECK-LABEL: define {{[^@]+}}@main()
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[F:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: br label [[FOR_COND_0:%.*]]
|
|
; CHECK: for.cond.0:
|
|
; CHECK-NEXT: [[G_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY_0:%.*]] ]
|
|
; CHECK-NEXT: [[CMP_0:%.*]] = icmp ult i32 [[G_0]], 100
|
|
; CHECK-NEXT: br i1 [[CMP_0]], label [[FOR_BODY_0]], label [[FOR_END_0:%.*]]
|
|
; CHECK: for.body.0:
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[G_0]], 1
|
|
; CHECK-NEXT: br label [[FOR_COND_0]]
|
|
; CHECK: for.end.0:
|
|
; CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @malloc(i64 8)
|
|
; CHECK-NEXT: store i8* [[CALL]], i8** bitcast (%struct.a** @e to i8**), align 8
|
|
; CHECK-NEXT: [[B:%.*]] = bitcast i8* [[CALL]] to %struct.a**
|
|
; CHECK-NEXT: store %struct.a* null, %struct.a** [[B]], align 8
|
|
; CHECK-NEXT: br label [[FOR_COND_1:%.*]]
|
|
; CHECK: for.cond.1:
|
|
; CHECK-NEXT: [[G_1:%.*]] = phi i32 [ 0, [[FOR_END_0]] ], [ [[INC6:%.*]], [[FOR_BODY_1:%.*]] ]
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[G_1]], 100
|
|
; CHECK-NEXT: br i1 [[CMP_1]], label [[FOR_BODY_1]], label [[FOR_END_1:%.*]]
|
|
; CHECK: for.body.1:
|
|
; CHECK-NEXT: [[CALL4:%.*]] = call i32 (i32*, ...) bitcast (i32 (i32)* @h to i32 (i32*, ...)*)(i32* nonnull [[F]])
|
|
; CHECK-NEXT: [[INC6]] = add nuw nsw i32 [[G_1]], 1
|
|
; CHECK-NEXT: br label [[FOR_COND_1]]
|
|
; CHECK: for.end.1:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%f = alloca i32
|
|
br label %for.cond.0
|
|
|
|
for.cond.0:
|
|
%g.0 = phi i32 [ 0, %entry ], [ %inc, %for.body.0 ]
|
|
%cmp.0 = icmp ult i32 %g.0, 100
|
|
br i1 %cmp.0, label %for.body.0, label %for.end.0
|
|
|
|
for.body.0:
|
|
%inc = add nuw nsw i32 %g.0, 1
|
|
br label %for.cond.0
|
|
|
|
for.end.0:
|
|
%call = call i8* @malloc(i64 8)
|
|
store i8* %call, i8** bitcast (%struct.a** @e to i8**)
|
|
%b = bitcast i8* %call to %struct.a**
|
|
store %struct.a* null, %struct.a** %b
|
|
br label %for.cond.1
|
|
|
|
for.cond.1:
|
|
%g.1 = phi i32 [ 0, %for.end.0 ], [ %inc6, %for.body.1 ]
|
|
%cmp.1 = icmp ult i32 %g.1, 100
|
|
br i1 %cmp.1, label %for.body.1, label %for.end.1
|
|
|
|
for.body.1:
|
|
%call4 = call i32 (i32*, ...) bitcast (i32 (i32)* @h to i32 (i32*, ...)*)(i32* nonnull %f)
|
|
%inc6 = add nuw nsw i32 %g.1, 1
|
|
br label %for.cond.1
|
|
|
|
for.end.1:
|
|
ret i32 0
|
|
}
|
|
|
|
declare noalias i8* @malloc(i64)
|
|
|
|
define i32 @h(i32 %i) {
|
|
; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
|
|
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@h
|
|
; NOT_CGSCC_NPM-SAME: (i32 [[I:%.*]])
|
|
; NOT_CGSCC_NPM-NEXT: ret i32 0
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@h
|
|
; IS__CGSCC____-SAME: (i32 [[I:%.*]])
|
|
; IS__CGSCC____-NEXT: ret i32 0
|
|
;
|
|
ret i32 0
|
|
}
|
|
|
|
|
|
; Verify we do not choke on the GEP in the unreachable block.
|
|
|
|
@p = global i8 0
|
|
|
|
define void @bad_gep() {
|
|
; CHECK: Function Attrs: nounwind readnone willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@bad_gep()
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[N:%.*]] = alloca i8, align 1
|
|
; CHECK-NEXT: [[M:%.*]] = alloca i8, align 1
|
|
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* noalias nocapture nonnull dereferenceable(1) [[N]])
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: while.body:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* noalias nocapture nonnull dereferenceable(1) [[N]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%n = alloca i8
|
|
%m = alloca i8
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %n)
|
|
br label %exit
|
|
|
|
while.body:
|
|
%call = call i1 @bad_gep_helper1(i8* %n, i8* %ptr, i8* %m)
|
|
br i1 %call, label %if.then, label %if.end
|
|
|
|
if.then:
|
|
%0 = load i8, i8* %ptr
|
|
call void @bad_gep_helper2(i8 %0)
|
|
br label %if.end
|
|
|
|
if.end:
|
|
%ptr = getelementptr inbounds i8, i8* %ptr, i64 1
|
|
%cmp = icmp eq i8* %ptr, @p
|
|
br i1 %cmp, label %exit, label %while.body
|
|
|
|
exit:
|
|
call void @llvm.lifetime.end.p0i8(i64 1, i8* %n)
|
|
ret void
|
|
}
|
|
|
|
declare i1 @bad_gep_helper1(i8*, i8*, i8*)
|
|
declare void @bad_gep_helper2(i8)
|
|
|
|
declare void @llvm.lifetime.start.p0i8(i64 %0, i8* %1)
|
|
declare void @llvm.lifetime.end.p0i8(i64 %0, i8* %1)
|