bool onlyReadsMemory() const {
return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly);
}
+
+ /// Returns true if this function is guaranteed to return.
+ bool willReturn() const { return hasFnAttr(Attribute::WillReturn); }
+
void setOnlyReadsMemory() {
addAttribute(AttributeList::FunctionIndex, Attribute::ReadOnly);
}
return true;
}
+ if (auto *CB = dyn_cast<CallBase>(I)) {
+ // Treat calls that may not return as alive.
+ // TODO: Remove the intrinsic escape hatch once all intrinsics set
+ // willreturn properly.
+ if (!CB->willReturn() && !isa<IntrinsicInst>(I))
+ return false;
+ }
+
if (!I->mayHaveSideEffects())
return true;
; they're carrying unknown operand bundles since the presence of
; unknown operand bundles implies arbitrary memory effects.
-declare void @readonly_function() readonly nounwind
-declare void @readnone_function() readnone nounwind
+declare void @readonly_function() readonly nounwind willreturn
+declare void @readnone_function() readnone nounwind willreturn
define i32 @test0(i32* %x) {
; CHECK-LABEL: @test0(
@a = internal global %struct.Foo { i32 1, i64 2 }, align 8
define void @run() {
-; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@run
-; NOT_CGSCC_NPM-SAME: () [[ATTR0:#.*]] {
-; NOT_CGSCC_NPM-NEXT: entry:
-; NOT_CGSCC_NPM-NEXT: unreachable
+; IS________OPM: Function Attrs: nofree noreturn nosync nounwind readnone
+; IS________OPM-LABEL: define {{[^@]+}}@run
+; IS________OPM-SAME: () [[ATTR0:#.*]] {
+; IS________OPM-NEXT: entry:
+; IS________OPM-NEXT: [[TMP0:%.*]] = call i64 @CaptureAStruct(%struct.Foo* nocapture nofree noundef nonnull readonly align 8 dereferenceable(16) @a) [[ATTR0]]
+; IS________OPM-NEXT: unreachable
+;
+; IS__TUNIT_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@run
+; IS__TUNIT_NPM-SAME: () [[ATTR0:#.*]] {
+; IS__TUNIT_NPM-NEXT: entry:
+; IS__TUNIT_NPM-NEXT: [[A_CAST:%.*]] = bitcast %struct.Foo* @a to i32*
+; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_CAST]], align 8
+; IS__TUNIT_NPM-NEXT: [[A_0_1:%.*]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* @a, i32 0, i32 1
+; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[A_0_1]], align 8
+; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = call i64 @CaptureAStruct(i32 [[TMP0]], i64 [[TMP1]]) [[ATTR0]]
+; IS__TUNIT_NPM-NEXT: unreachable
;
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readonly willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@run
; IS__CGSCC____-SAME: () [[ATTR0:#.*]] {
; IS__CGSCC____-NEXT: entry:
+; IS__CGSCC____-NEXT: [[A_CAST:%.*]] = bitcast %struct.Foo* @a to i32*
+; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_CAST]], align 8
+; IS__CGSCC____-NEXT: [[A_0_1:%.*]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* @a, i32 0, i32 1
+; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i64, i64* [[A_0_1]], align 8
; IS__CGSCC____-NEXT: unreachable
;
entry:
; IS__CGSCC_OPM-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* [[A]], i64 0
; IS__CGSCC_OPM-NEXT: br label [[LOOP]]
;
+; IS________OPM: Function Attrs: nofree noreturn nosync nounwind readnone
+; IS________OPM-LABEL: define {{[^@]+}}@CaptureAStruct
+; IS________OPM-SAME: (%struct.Foo* noalias nofree noundef nonnull byval(%struct.Foo) align 8 dereferenceable(16) [[A:%.*]]) [[ATTR0]] {
+; IS________OPM-NEXT: entry:
+; IS________OPM-NEXT: [[A_PTR:%.*]] = alloca %struct.Foo*, align 8
+; IS________OPM-NEXT: br label [[LOOP:%.*]]
+; IS________OPM: loop:
+; IS________OPM-NEXT: [[PHI:%.*]] = phi %struct.Foo* [ null, [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ]
+; IS________OPM-NEXT: [[TMP0:%.*]] = phi %struct.Foo* [ [[A]], [[ENTRY]] ], [ [[TMP0]], [[LOOP]] ]
+; IS________OPM-NEXT: store %struct.Foo* [[PHI]], %struct.Foo** [[A_PTR]], align 8
+; IS________OPM-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* [[A]], i64 0
+; IS________OPM-NEXT: br label [[LOOP]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@CaptureAStruct
+; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]]) [[ATTR0]] {
+; IS__TUNIT_NPM-NEXT: entry:
+; IS__TUNIT_NPM-NEXT: [[A_PRIV:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8
+; IS__TUNIT_NPM-NEXT: [[A_PRIV_CAST:%.*]] = bitcast %struct.Foo* [[A_PRIV]] to i32*
+; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[A_PRIV_CAST]], align 4
+; IS__TUNIT_NPM-NEXT: [[A_PRIV_0_1:%.*]] = getelementptr [[STRUCT_FOO]], %struct.Foo* [[A_PRIV]], i32 0, i32 1
+; IS__TUNIT_NPM-NEXT: store i64 [[TMP1]], i64* [[A_PRIV_0_1]], align 8
+; IS__TUNIT_NPM-NEXT: [[A_PTR:%.*]] = alloca %struct.Foo*, align 8
+; IS__TUNIT_NPM-NEXT: br label [[LOOP:%.*]]
+; IS__TUNIT_NPM: loop:
+; IS__TUNIT_NPM-NEXT: [[PHI:%.*]] = phi %struct.Foo* [ null, [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ]
+; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = phi %struct.Foo* [ [[A_PRIV]], [[ENTRY]] ], [ [[TMP2]], [[LOOP]] ]
+; IS__TUNIT_NPM-NEXT: store %struct.Foo* [[PHI]], %struct.Foo** [[A_PTR]], align 8
+; IS__TUNIT_NPM-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO]], %struct.Foo* [[A_PRIV]], i64 0
+; IS__TUNIT_NPM-NEXT: br label [[LOOP]]
+;
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readnone
; IS__CGSCC____-LABEL: define {{[^@]+}}@CaptureAStruct
; IS__CGSCC____-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]]) [[ATTR2:#.*]] {
; TEST 6
; SCC
define i32* @test6_1() #0 {
-; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test6_1
-; NOT_CGSCC_NPM-SAME: () [[ATTR1:#.*]] {
-; NOT_CGSCC_NPM-NEXT: unreachable
-;
-; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test6_1
-; IS__CGSCC_NPM-SAME: () [[ATTR1:#.*]] {
-; IS__CGSCC_NPM-NEXT: unreachable
+; NOT_CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
+; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@test6_1
+; NOT_CGSCC_OPM-SAME: () [[ATTR1:#.*]] {
+; NOT_CGSCC_OPM-NEXT: [[RET:%.*]] = tail call i32* @test6_2() [[ATTR11:#.*]]
+; NOT_CGSCC_OPM-NEXT: unreachable
+;
+; IS__CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test6_1
+; IS__CGSCC_OPM-SAME: () [[ATTR1:#.*]] {
+; IS__CGSCC_OPM-NEXT: [[RET:%.*]] = tail call i32* @test6_2() [[ATTR12:#.*]]
+; IS__CGSCC_OPM-NEXT: unreachable
;
%ret = tail call i32* @test6_2()
ret i32* %ret
}
define i32* @test6_2() #0 {
-; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test6_2
-; NOT_CGSCC_NPM-SAME: () [[ATTR1]] {
-; NOT_CGSCC_NPM-NEXT: unreachable
-;
-; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test6_2
-; IS__CGSCC_NPM-SAME: () [[ATTR1]] {
-; IS__CGSCC_NPM-NEXT: unreachable
+; NOT_CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
+; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@test6_2
+; NOT_CGSCC_OPM-SAME: () [[ATTR1]] {
+; NOT_CGSCC_OPM-NEXT: [[RET:%.*]] = tail call i32* @test6_1() [[ATTR11]]
+; NOT_CGSCC_OPM-NEXT: unreachable
+;
+; IS__CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test6_2
+; IS__CGSCC_OPM-SAME: () [[ATTR1]] {
+; IS__CGSCC_OPM-NEXT: [[RET:%.*]] = tail call i32* @test6_1() [[ATTR12]]
+; IS__CGSCC_OPM-NEXT: unreachable
;
%ret = tail call i32* @test6_1()
ret i32* %ret
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = load i1, i1* @cnd, align 1
; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[MT:%.*]], label [[EXIT:%.*]]
; IS__CGSCC_OPM: mt:
-; IS__CGSCC_OPM-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]]) [[ATTR12:#.*]]
+; IS__CGSCC_OPM-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]]) [[ATTR13:#.*]]
; IS__CGSCC_OPM-NEXT: ret i32 [[V]]
; IS__CGSCC_OPM: exit:
; IS__CGSCC_OPM-NEXT: ret i32 0
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = load i1, i1* @cnd, align 1
; IS__CGSCC_NPM-NEXT: br i1 [[C]], label [[MT:%.*]], label [[EXIT:%.*]]
; IS__CGSCC_NPM: mt:
-; IS__CGSCC_NPM-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]]) [[ATTR11:#.*]]
+; IS__CGSCC_NPM-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]]) [[ATTR12:#.*]]
; IS__CGSCC_NPM-NEXT: ret i32 [[V]]
; IS__CGSCC_NPM: exit:
; IS__CGSCC_NPM-NEXT: ret i32 0
; CHECK: Function Attrs: nounwind
; CHECK-LABEL: define {{[^@]+}}@ptr_uses
; CHECK-SAME: (i8* [[PTR:%.*]], i8* nocapture nonnull writeonly dereferenceable(1) [[WPTR:%.*]]) [[ATTR13:#.*]] {
+; CHECK-NEXT: [[CALL_PTR:%.*]] = call i8* @maybe_returned_ptr(i8* readonly [[PTR]]) [[ATTR4]]
+; CHECK-NEXT: [[CALL_VAL:%.*]] = call i8 @maybe_returned_val(i8* readonly [[CALL_PTR]]) [[ATTR4]]
; CHECK-NEXT: store i8 0, i8* [[WPTR]], align 1
; CHECK-NEXT: ret void
;
; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either3
; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) [[ATTR8]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1b(i32* nocapture readonly [[B]], i32* readonly [[R]]) [[ATTR6]]
+; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1b(i32* nocapture readonly [[B]], i32* readonly [[R]]) [[ATTR8]]
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test4_helper
; NOT_CGSCC_NPM-SAME: () [[ATTR2:#.*]] {
+; NOT_CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4()
; NOT_CGSCC_NPM-NEXT: unreachable
;
-; IS__CGSCC_NPM: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
+; IS__CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test4_helper
; IS__CGSCC_NPM-SAME: () [[ATTR2:#.*]] {
+; IS__CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4()
; IS__CGSCC_NPM-NEXT: unreachable
;
%ret = call i8* @test4()
; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test4
; NOT_CGSCC_NPM-SAME: () [[ATTR2]] {
+; NOT_CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4_helper()
; NOT_CGSCC_NPM-NEXT: unreachable
;
-; IS__CGSCC_NPM: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
+; IS__CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test4
; IS__CGSCC_NPM-SAME: () [[ATTR2]] {
+; IS__CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4_helper()
; IS__CGSCC_NPM-NEXT: unreachable
;
%ret = call i8* @test4_helper()
}
define i32 @indirect_rec() {
-; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@indirect_rec
-; NOT_CGSCC_NPM-SAME: () [[ATTR2:#.*]] {
-; NOT_CGSCC_NPM-NEXT: unreachable
-;
-; IS__CGSCC_NPM: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@indirect_rec
-; IS__CGSCC_NPM-SAME: () [[ATTR1:#.*]] {
-; IS__CGSCC_NPM-NEXT: unreachable
+; CHECK: Function Attrs: nofree noreturn nosync nounwind readnone
+; CHECK-LABEL: define {{[^@]+}}@indirect_rec
+; CHECK-SAME: () [[ATTR2:#.*]] {
+; CHECK-NEXT: [[A:%.*]] = call i32 @indirect_rec2() [[ATTR2]]
+; CHECK-NEXT: unreachable
;
%a = call i32 @indirect_rec2()
ret i32 %a
}
define i32 @indirect_rec2() {
-; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@indirect_rec2
-; NOT_CGSCC_NPM-SAME: () [[ATTR2]] {
-; NOT_CGSCC_NPM-NEXT: unreachable
-;
-; IS__CGSCC_NPM: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@indirect_rec2
-; IS__CGSCC_NPM-SAME: () [[ATTR1]] {
-; IS__CGSCC_NPM-NEXT: unreachable
+; CHECK: Function Attrs: nofree noreturn nosync nounwind readnone
+; CHECK-LABEL: define {{[^@]+}}@indirect_rec2
+; CHECK-SAME: () [[ATTR2]] {
+; CHECK-NEXT: [[A:%.*]] = call i32 @indirect_rec() [[ATTR2]]
+; CHECK-NEXT: unreachable
;
%a = call i32 @indirect_rec()
ret i32 %a
define i32 @extern() {
; CHECK: Function Attrs: nosync readnone
; CHECK-LABEL: define {{[^@]+}}@extern
-; CHECK-SAME: () [[ATTR2:#.*]] {
+; CHECK-SAME: () [[ATTR3:#.*]] {
; CHECK-NEXT: [[A:%.*]] = call i32 @k()
; CHECK-NEXT: ret i32 [[A]]
;
declare i32 @k() readnone
define void @intrinsic(i8* %dest, i8* %src, i32 %len) {
-; NOT_CGSCC_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@intrinsic
-; NOT_CGSCC_NPM-SAME: (i8* nocapture nofree writeonly [[DEST:%.*]], i8* nocapture nofree readonly [[SRC:%.*]], i32 [[LEN:%.*]]) [[ATTR5:#.*]] {
-; NOT_CGSCC_NPM-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[DEST]], i8* noalias nocapture nofree readonly [[SRC]], i32 [[LEN]], i1 noundef false) [[ATTR10:#.*]]
-; NOT_CGSCC_NPM-NEXT: ret void
-;
-; IS__CGSCC_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@intrinsic
-; IS__CGSCC_NPM-SAME: (i8* nocapture nofree writeonly [[DEST:%.*]], i8* nocapture nofree readonly [[SRC:%.*]], i32 [[LEN:%.*]]) [[ATTR4:#.*]] {
-; IS__CGSCC_NPM-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[DEST]], i8* noalias nocapture nofree readonly [[SRC]], i32 [[LEN]], i1 noundef false) [[ATTR7:#.*]]
-; IS__CGSCC_NPM-NEXT: ret void
+; CHECK: Function Attrs: argmemonly nofree nosync nounwind willreturn
+; CHECK-LABEL: define {{[^@]+}}@intrinsic
+; CHECK-SAME: (i8* nocapture nofree writeonly [[DEST:%.*]], i8* nocapture nofree readonly [[SRC:%.*]], i32 [[LEN:%.*]]) [[ATTR5:#.*]] {
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[DEST]], i8* noalias nocapture nofree readonly [[SRC]], i32 [[LEN]], i1 noundef false) [[ATTR10:#.*]]
+; CHECK-NEXT: ret void
;
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false)
ret void
;
; IS__CGSCC____: Function Attrs: norecurse nosync readnone
; IS__CGSCC____-LABEL: define {{[^@]+}}@called_by_norecurse
-; IS__CGSCC____-SAME: () [[ATTR5:#.*]] {
+; IS__CGSCC____-SAME: () [[ATTR6:#.*]] {
; IS__CGSCC____-NEXT: [[A:%.*]] = call i32 @k()
; IS__CGSCC____-NEXT: ret i32 undef
;
;
; IS__CGSCC____: Function Attrs: norecurse nosync readnone
; IS__CGSCC____-LABEL: define {{[^@]+}}@m
-; IS__CGSCC____-SAME: () [[ATTR5]] {
+; IS__CGSCC____-SAME: () [[ATTR6]] {
; IS__CGSCC____-NEXT: [[A:%.*]] = call i32 @called_by_norecurse()
; IS__CGSCC____-NEXT: ret void
;
define internal i32 @called_by_norecurse_indirectly() {
; CHECK: Function Attrs: nosync readnone
; CHECK-LABEL: define {{[^@]+}}@called_by_norecurse_indirectly
-; CHECK-SAME: () [[ATTR2]] {
+; CHECK-SAME: () [[ATTR3]] {
; CHECK-NEXT: [[A:%.*]] = call i32 @k()
; CHECK-NEXT: ret i32 [[A]]
;
;
; IS__CGSCC____: Function Attrs: norecurse nosync readnone
; IS__CGSCC____-LABEL: define {{[^@]+}}@o
-; IS__CGSCC____-SAME: () [[ATTR5]] {
+; IS__CGSCC____-SAME: () [[ATTR6]] {
; IS__CGSCC____-NEXT: [[A:%.*]] = call i32 @called_by_norecurse_indirectly()
; IS__CGSCC____-NEXT: ret i32 [[A]]
;
;
; IS__CGSCC____: Function Attrs: norecurse nosync readnone
; IS__CGSCC____-LABEL: define {{[^@]+}}@p
-; IS__CGSCC____-SAME: () [[ATTR5]] {
+; IS__CGSCC____-SAME: () [[ATTR6]] {
; IS__CGSCC____-NEXT: [[A:%.*]] = call i32 @o()
; IS__CGSCC____-NEXT: ret i32 [[A]]
;
}
define void @f(i32 %x) {
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone
-; IS__TUNIT____-LABEL: define {{[^@]+}}@f
-; IS__TUNIT____-SAME: (i32 [[X:%.*]]) [[ATTR7:#.*]] {
-; IS__TUNIT____-NEXT: entry:
-; IS__TUNIT____-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
-; IS__TUNIT____-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
-; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 4
-; IS__TUNIT____-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
-; IS__TUNIT____-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; IS__TUNIT____: if.then:
-; IS__TUNIT____-NEXT: call void @g() [[ATTR8:#.*]]
-; IS__TUNIT____-NEXT: br label [[IF_END]]
-; IS__TUNIT____: if.end:
-; IS__TUNIT____-NEXT: ret void
-;
-; IS__CGSCC_OPM: Function Attrs: nofree nosync nounwind readnone
-; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@f
-; IS__CGSCC_OPM-SAME: (i32 [[X:%.*]]) [[ATTR7:#.*]] {
-; IS__CGSCC_OPM-NEXT: entry:
-; IS__CGSCC_OPM-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
-; IS__CGSCC_OPM-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
-; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 4
-; IS__CGSCC_OPM-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
-; IS__CGSCC_OPM-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; IS__CGSCC_OPM: if.then:
-; IS__CGSCC_OPM-NEXT: br label [[IF_END]]
-; IS__CGSCC_OPM: if.end:
-; IS__CGSCC_OPM-NEXT: ret void
-;
-; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@f
-; IS__CGSCC_NPM-SAME: (i32 [[X:%.*]]) [[ATTR0:#.*]] {
-; IS__CGSCC_NPM-NEXT: entry:
-; IS__CGSCC_NPM-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
-; IS__CGSCC_NPM-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
-; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 4
-; IS__CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
-; IS__CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; IS__CGSCC_NPM: if.then:
-; IS__CGSCC_NPM-NEXT: br label [[IF_END]]
-; IS__CGSCC_NPM: if.end:
-; IS__CGSCC_NPM-NEXT: ret void
+; CHECK: Function Attrs: nofree nosync nounwind readnone
+; CHECK-LABEL: define {{[^@]+}}@f
+; CHECK-SAME: (i32 [[X:%.*]]) [[ATTR7:#.*]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
+; CHECK-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 4
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: call void @g() [[ATTR8:#.*]]
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: ret void
;
entry:
%x.addr = alloca i32, align 4
}
define void @g() norecurse {
-; IS__TUNIT____: Function Attrs: nofree norecurse nosync nounwind readnone
-; IS__TUNIT____-LABEL: define {{[^@]+}}@g
-; IS__TUNIT____-SAME: () [[ATTR8]] {
-; IS__TUNIT____-NEXT: entry:
-; IS__TUNIT____-NEXT: ret void
-;
-; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone
-; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@g
-; IS__CGSCC_OPM-SAME: () [[ATTR8:#.*]] {
-; IS__CGSCC_OPM-NEXT: entry:
-; IS__CGSCC_OPM-NEXT: call void @f(i32 noundef 0) [[ATTR7]]
-; IS__CGSCC_OPM-NEXT: ret void
-;
-; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@g
-; IS__CGSCC_NPM-SAME: () [[ATTR0]] {
-; IS__CGSCC_NPM-NEXT: entry:
-; IS__CGSCC_NPM-NEXT: ret void
+; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone
+; CHECK-LABEL: define {{[^@]+}}@g
+; CHECK-SAME: () [[ATTR8]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @f(i32 noundef 0) [[ATTR7]]
+; CHECK-NEXT: ret void
;
entry:
call void @f(i32 0)
define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr null_pointer_is_valid{
; CHECK: Function Attrs: null_pointer_is_valid
; CHECK-LABEL: define {{[^@]+}}@eval_func2
-; CHECK-SAME: (i32 (i32)* nocapture nofree [[TMP0:%.*]], i32 [[TMP1:%.*]]) local_unnamed_addr [[ATTR6:#.*]] {
+; CHECK-SAME: (i32 (i32)* nocapture nofree [[TMP0:%.*]], i32 [[TMP1:%.*]]) local_unnamed_addr [[ATTR9:#.*]] {
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 [[TMP0]](i32 [[TMP1]])
; CHECK-NEXT: ret i32 [[TMP3]]
;
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@f1
; IS__CGSCC_OPM-SAME: (i32 [[TMP0:%.*]]) {
-; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = tail call i32 @r1(), [[RNG3:!range !.*]]
+; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = tail call i32 @r1() [[ATTR4:#.*]], [[RNG3:!range !.*]]
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 15
; IS__CGSCC_OPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
; IS__CGSCC_OPM: 4:
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test4-g1
; IS__CGSCC_OPM-SAME: (i32 [[U:%.*]]) [[ATTR2:#.*]] {
; IS__CGSCC_OPM-NEXT: entry:
-; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f1(i32 [[U]]) [[ATTR4:#.*]]
+; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f1(i32 [[U]]) [[ATTR5:#.*]]
; IS__CGSCC_OPM-NEXT: ret i32 [[CALL]]
;
; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test4-g2
; IS__CGSCC_OPM-SAME: (i32 [[U:%.*]]) [[ATTR2]] {
; IS__CGSCC_OPM-NEXT: entry:
-; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]]) [[ATTR4]]
+; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]]) [[ATTR5]]
; IS__CGSCC_OPM-NEXT: ret i32 [[CALL]]
;
; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fcmp_caller
; IS__CGSCC_OPM-SAME: (float [[FA:%.*]], float [[FB:%.*]], double [[DA:%.*]], double [[DB:%.*]], double* nofree readnone [[DPA:%.*]], double* nofree readnone [[DPB:%.*]], i8* nofree readnone [[IPA:%.*]], i8* nofree readnone [[IPB:%.*]]) [[ATTR2]] {
-; IS__CGSCC_OPM-NEXT: [[R1:%.*]] = call i1 @f_fcmp(float [[FA]], float [[FB]]) [[ATTR4]]
-; IS__CGSCC_OPM-NEXT: [[R2:%.*]] = call i1 @d_fcmp(double [[DA]], double [[DB]]) [[ATTR4]]
-; IS__CGSCC_OPM-NEXT: [[R3:%.*]] = call i1 @dp_icmp(double* noalias nofree readnone [[DPA]], double* noalias nofree readnone [[DPB]]) [[ATTR4]]
-; IS__CGSCC_OPM-NEXT: [[R4:%.*]] = call i1 @ip_icmp(i8* noalias nofree readnone [[IPA]], i8* noalias nofree readnone [[IPB]]) [[ATTR4]]
+; IS__CGSCC_OPM-NEXT: [[R1:%.*]] = call i1 @f_fcmp(float [[FA]], float [[FB]]) [[ATTR5]]
+; IS__CGSCC_OPM-NEXT: [[R2:%.*]] = call i1 @d_fcmp(double [[DA]], double [[DB]]) [[ATTR5]]
+; IS__CGSCC_OPM-NEXT: [[R3:%.*]] = call i1 @dp_icmp(double* noalias nofree readnone [[DPA]], double* noalias nofree readnone [[DPB]]) [[ATTR5]]
+; IS__CGSCC_OPM-NEXT: [[R4:%.*]] = call i1 @ip_icmp(i8* noalias nofree readnone [[IPA]], i8* noalias nofree readnone [[IPB]]) [[ATTR5]]
; IS__CGSCC_OPM-NEXT: [[O1:%.*]] = or i1 [[R1]], [[R2]]
; IS__CGSCC_OPM-NEXT: [[O2:%.*]] = or i1 [[R3]], [[R4]]
; IS__CGSCC_OPM-NEXT: [[O3:%.*]] = or i1 [[O1]], [[O2]]
; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@callee_range_2
; IS__CGSCC_OPM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]]) [[ATTR2]] {
-; IS__CGSCC_OPM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) [[ATTR4]], [[RNG5:!range !.*]]
-; IS__CGSCC_OPM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) [[ATTR4]], [[RNG5]]
+; IS__CGSCC_OPM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) [[ATTR5]], [[RNG5:!range !.*]]
+; IS__CGSCC_OPM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) [[ATTR5]], [[RNG5]]
; IS__CGSCC_OPM-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; IS__CGSCC_OPM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; IS__CGSCC_OPM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = select i1 [[D]], i1 true, i1 false
; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; IS__CGSCC_OPM: t:
-; IS__CGSCC_OPM-NEXT: [[RET1:%.*]] = call i32 @func(i1 noundef [[C]]) [[ATTR4]], [[RNG4:!range !.*]]
+; IS__CGSCC_OPM-NEXT: [[RET1:%.*]] = call i32 @func(i1 noundef [[C]]) [[ATTR5]], [[RNG4:!range !.*]]
; IS__CGSCC_OPM-NEXT: ret i32 [[RET1]]
; IS__CGSCC_OPM: f:
-; IS__CGSCC_OPM-NEXT: [[RET2:%.*]] = call i32 @func(i1 noundef false) [[ATTR4]], [[RNG4]]
+; IS__CGSCC_OPM-NEXT: [[RET2:%.*]] = call i32 @func(i1 noundef false) [[ATTR5]], [[RNG4]]
; IS__CGSCC_OPM-NEXT: ret i32 [[RET2]]
;
; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@check_divided_range
; IS__CGSCC_OPM-SAME: (i32 [[ARG:%.*]]) [[ATTR2]] {
-; IS__CGSCC_OPM-NEXT: [[CSRET1:%.*]] = call i32 @less_than_65536(i32 noundef 0) [[ATTR4]]
-; IS__CGSCC_OPM-NEXT: [[CSRET2:%.*]] = call i32 @less_than_65536(i32 [[ARG]]) [[ATTR4]]
-; IS__CGSCC_OPM-NEXT: [[TRUE1:%.*]] = call i1 @is_less_than_65536(i32 [[CSRET1]]) [[ATTR4]]
-; IS__CGSCC_OPM-NEXT: [[TRUE2:%.*]] = call i1 @is_less_than_65536(i32 [[CSRET2]]) [[ATTR4]]
+; IS__CGSCC_OPM-NEXT: [[CSRET1:%.*]] = call i32 @less_than_65536(i32 noundef 0) [[ATTR5]]
+; IS__CGSCC_OPM-NEXT: [[CSRET2:%.*]] = call i32 @less_than_65536(i32 [[ARG]]) [[ATTR5]]
+; IS__CGSCC_OPM-NEXT: [[TRUE1:%.*]] = call i1 @is_less_than_65536(i32 [[CSRET1]]) [[ATTR5]]
+; IS__CGSCC_OPM-NEXT: [[TRUE2:%.*]] = call i1 @is_less_than_65536(i32 [[CSRET2]]) [[ATTR5]]
; IS__CGSCC_OPM-NEXT: [[RET:%.*]] = and i1 [[TRUE1]], [[TRUE2]]
; IS__CGSCC_OPM-NEXT: ret i1 [[RET]]
;
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = icmp slt i8 0, [[L]]
; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; IS__CGSCC_OPM: t:
-; IS__CGSCC_OPM-NEXT: [[R:%.*]] = call i1 @non_zero(i8 [[L]]) [[ATTR4]]
+; IS__CGSCC_OPM-NEXT: [[R:%.*]] = call i1 @non_zero(i8 [[L]]) [[ATTR5]]
; IS__CGSCC_OPM-NEXT: ret i1 [[R]]
; IS__CGSCC_OPM: f:
; IS__CGSCC_OPM-NEXT: ret i1 false
; CHECK: Function Attrs: argmemonly nounwind readonly
; CHECK-LABEL: define {{[^@]+}}@test11_2
; CHECK-SAME: (<4 x i32*> [[PTRS:%.*]]) [[ATTR6:#.*]] {
-; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @test11_1(<4 x i32*> [[PTRS]]) [[ATTR2]]
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @test11_1(<4 x i32*> [[PTRS]]) [[ATTR9:#.*]]
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
%res = call <4 x i32> @test11_1(<4 x i32*> %ptrs)
define void @byval_not_readnone_1(i8* byval(i8) %written) readnone {
; CHECK: Function Attrs: readnone
; CHECK-LABEL: define {{[^@]+}}@byval_not_readnone_1
-; CHECK-SAME: (i8* noalias nonnull byval(i8) dereferenceable(1) [[WRITTEN:%.*]]) [[ATTR9:#.*]] {
+; CHECK-SAME: (i8* noalias nonnull byval(i8) dereferenceable(1) [[WRITTEN:%.*]]) [[ATTR8:#.*]] {
; CHECK-NEXT: call void @escape_i8(i8* nonnull dereferenceable(1) [[WRITTEN]])
; CHECK-NEXT: ret void
;
define void @ptr_uses(i8* %ptr) {
; CHECK: Function Attrs: nounwind readonly
; CHECK-LABEL: define {{[^@]+}}@ptr_uses
-; CHECK-SAME: (i8* nocapture readonly [[PTR:%.*]]) [[ATTR10:#.*]] {
+; CHECK-SAME: (i8* nocapture readonly [[PTR:%.*]]) [[ATTR9:#.*]] {
+; CHECK-NEXT: [[CALL_PTR:%.*]] = call i8* @maybe_returned_ptr(i8* readonly [[PTR]])
+; CHECK-NEXT: [[CALL_VAL:%.*]] = call i8 @maybe_returned_val(i8* readonly [[CALL_PTR]])
; CHECK-NEXT: ret void
;
%call_ptr = call i8* @maybe_returned_ptr(i8* %ptr)
ret i16 %cast
}
-attributes #0 = { nounwind readnone }
+attributes #0 = { nounwind readnone willreturn }
attributes #1 = { nounwind }
if.end:
%gep = getelementptr i8, i8* %d, i32 42
- %call = call i64 @foo(i8* %gep) nounwind readonly
+ %call = call i64 @foo(i8* %gep) nounwind readonly willreturn
%cmp2 = icmp ne i64 %call, 0
call void @llvm.assume(i1 %cmp2)
br label %exit
ret i32 %conv
}
-declare i64 @foo(i8*) nounwind readonly
+declare i64 @foo(i8*) nounwind readonly willreturn
declare void @llvm.assume(i1 noundef) nounwind willreturn
declare noalias i8* @malloc(i32)
declare void @print(i32)
-declare void @free(i8*)
+declare void @free(i8*) willreturn
declare noalias i8* @malloc(i32)
declare void @print(i32)
-declare void @free(i8*)
+declare void @free(i8*) willreturn
}
declare i8* @malloc(i32)
-declare void @free(i8*)
+declare void @free(i8*) willreturn
declare void @print(i32)
declare void @foo()
}
-declare noalias i8* @malloc(i32)
-declare noalias i8* @calloc(i32, i32)
+declare noalias i8* @malloc(i32) willreturn
+declare noalias i8* @calloc(i32, i32) willreturn
define void @test14(i32* %Q) {
; CHECK-LABEL: @test14(
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -basic-aa -dse -enable-dse-memoryssa=false -S | FileCheck %s
-declare i8* @_Znwj(i32) local_unnamed_addr
-declare void @foo() readnone
+declare i8* @_Znwj(i32) willreturn
+declare void @foo() readnone willreturn
define void @test1(i8** %ptr) {
; CHECK-LABEL: @test1(
ret i32 addrspace(1)* %P
}
-declare noalias i8* @malloc(i32)
-declare noalias i8* @calloc(i32, i32)
+declare noalias i8* @malloc(i32) willreturn
+declare noalias i8* @calloc(i32, i32) willreturn
declare noalias i8* @aligned_alloc(i32, i32)
declare void @free(i8*)
define void @caller_may_not_return() ssp {
; CHECK-LABEL: @caller_may_not_return(
; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[WHILE_BODY_I:%.*]]
+; CHECK: while.body.i:
+; CHECK-NEXT: br label [[WHILE_BODY_I]]
+; CHECK: readnone_may_not_return.exit:
; CHECK-NEXT: ret void
;
entry:
; @caller_willreturn is marked as willreturn, so all called functions also must
; return. All calls are dead.
-define void @caller_willreturn() ssp willreturn {
+define void @caller_willreturn() ssp {
; CHECK-LABEL: @caller_willreturn(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;
entry:
- call void @readnone_may_not_return()
+ call void @readnone_may_not_return() willreturn
call void @readnone_willreturn()
ret void
}
; RUN: opt < %s -instcombine -S | FileCheck %s
-declare double @acos(double)
+declare double @acos(double) willreturn
; Check that functions without any function attributes are simplified.
; RUN: opt < %s -instcombine -S | not grep call
; rdar://6880732
-declare double @t1(i32) readonly
+declare double @t1(i32) readonly willreturn
define void @t2() nounwind {
call double @t1(i32 42) ;; dead call even though callee is not nothrow.
; RUN: opt -S -early-cse -earlycse-debug-hash < %s | FileCheck %s
declare float @nearbyintf(float) #0
-declare float @llvm.nearbyint.f32(float) #0
+declare float @llvm.nearbyint.f32(float)
declare double @nearbyint(double) #0
-declare double @llvm.nearbyint.f64(double) #0
+declare double @llvm.nearbyint.f64(double)
declare float @rintf(float) #0
-declare float @llvm.rint.f32(float) #0
+declare float @llvm.rint.f32(float)
declare double @rint(double) #0
-declare double @llvm.rint.f64(double) #0
+declare double @llvm.rint.f64(double)
define float @constant_fold_rint_f32_01() #0 {
; CHECK-LABEL: @constant_fold_rint_f32_01(
ret double %x
}
-attributes #0 = { nounwind readnone }
+attributes #0 = { nounwind readnone willreturn }
define internal void @func_1(i64* nocapture readnone %0) #0 {
; CHECK-LABEL: @func_1(
-; CHECK-NEXT: unreachable
+; CHECK-NEXT: ret void
;
- unreachable
+ ret void
}
define i16 @main(i16 %0, i16** nocapture readnone %1) #1 {
unreachable
}
-attributes #0 = { noinline norecurse nounwind readnone }
+attributes #0 = { noinline norecurse nounwind readnone willreturn }
attributes #1 = { norecurse nounwind readnone }
; CHECK-NEXT: ret i1 false
}
-declare i8* @func1(i8* returned) nounwind readnone
-declare %gept* @func2(%gept* returned) nounwind readnone
+declare i8* @func1(i8* returned) nounwind readnone willreturn
+declare %gept* @func2(%gept* returned) nounwind readnone willreturn
ret void
}
-declare noalias i8* @malloc(i32)
+declare noalias i8* @malloc(i32) willreturn
; rdar://11341081
%struct.big = type { [50 x i32] }
; CHECK: attributes [[ATTR0]] = { nounwind }
; CHECK: attributes #1 = { argmemonly nofree nosync nounwind willreturn }
; CHECK: attributes #2 = { nounwind ssp }
-; CHECK: attributes #3 = { nounwind ssp uwtable }
-; CHECK: attributes #4 = { argmemonly nofree nosync nounwind willreturn writeonly }
+; CHECK: attributes #3 = { willreturn }
+; CHECK: attributes #4 = { nounwind ssp uwtable }
+; CHECK: attributes #5 = { argmemonly nofree nosync nounwind willreturn writeonly }
ret void
}
-attributes #1 = { noinline nounwind readnone }
+attributes #1 = { noinline nounwind readnone willreturn }
;
; We delete all but the first of the parallel regions in this test.
define void @delete_parallel_0() {
-; CHECK-LABEL: define {{[^@]+}}@delete_parallel_0()
+; CHECK-LABEL: define {{[^@]+}}@delete_parallel_0() {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) @0, i32 noundef 0, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*)* @.omp_outlined.willreturn to void (i32*, i32*, ...)*))
+; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0:@.*]], i32 noundef 0, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*)* @.omp_outlined.willreturn to void (i32*, i32*, ...)*))
; CHECK-NEXT: ret void
;
entry:
define internal void @.omp_outlined.willreturn(i32* noalias %.global_tid., i32* noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.willreturn
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #0
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) [[ATTR0:#.*]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @unknown() #0
+; CHECK-NEXT: call void @unknown() [[ATTR0]]
; CHECK-NEXT: ret void
;
entry:
define internal void @.omp_outlined.willreturn.0(i32* noalias %.global_tid., i32* noalias %.bound_tid.) willreturn {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.0
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #1
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) [[ATTR1:#.*]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @readonly() #4
+; CHECK-NEXT: call void @readonly() [[ATTR4:#.*]]
; CHECK-NEXT: ret void
;
entry:
define internal void @.omp_outlined.willreturn.1(i32* noalias %.global_tid., i32* noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.1
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #2
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) [[ATTR2:#.*]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @readnone() #0
+; CHECK-NEXT: call void @readnone() [[ATTR0]]
; CHECK-NEXT: ret void
;
entry:
define internal void @.omp_outlined.willreturn.2(i32* noalias %.global_tid., i32* noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.willreturn.2
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #3
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) [[ATTR3:#.*]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;
;
; We delete only the last parallel regions in this test because the others might not return.
define void @delete_parallel_1() {
-; CHECK-LABEL: define {{[^@]+}}@delete_parallel_1()
+; CHECK-LABEL: define {{[^@]+}}@delete_parallel_1() {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) @0, i32 noundef 0, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*))
-; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) @0, i32 noundef 0, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*)* @.omp_outlined..0 to void (i32*, i32*, ...)*))
-; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) @0, i32 noundef 0, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*)* @.omp_outlined..1 to void (i32*, i32*, ...)*))
+; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 noundef 0, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*))
+; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 noundef 0, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*)* @.omp_outlined..0 to void (i32*, i32*, ...)*))
+; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 noundef 0, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*)* @.omp_outlined..1 to void (i32*, i32*, ...)*))
; CHECK-NEXT: ret void
;
entry:
define internal void @.omp_outlined.(i32* noalias %.global_tid., i32* noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined.
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]])
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret void
define internal void @.omp_outlined..0(i32* noalias %.global_tid., i32* noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..0
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #4
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) [[ATTR4]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @readonly() #4
+; CHECK-NEXT: call void @readonly() [[ATTR4]]
; CHECK-NEXT: ret void
;
entry:
define internal void @.omp_outlined..1(i32* noalias %.global_tid., i32* noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..1
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #5
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) [[ATTR5:#.*]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @readnone()
; CHECK-NEXT: ret void
define internal void @.omp_outlined..2(i32* noalias %.global_tid., i32* noalias %.bound_tid.) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..2
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) #3
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]]) [[ATTR3]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;
; FIXME: We do not realize that `a` is dead and all accesses to it can be removed
; making the parallel regions readonly and deletable.
define void @delete_parallel_2() {
-; CHECK-LABEL: define {{[^@]+}}@delete_parallel_2()
+; CHECK-LABEL: define {{[^@]+}}@delete_parallel_2() {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
-; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* noundef nonnull align 4 dereferenceable(4) [[TMP]]) #0
+; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* noundef nonnull align 4 dereferenceable(4) [[TMP]]) [[ATTR0]]
; CHECK-NEXT: store i32 0, i32* [[A]], align 4
-; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) @0, i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @.omp_outlined..3 to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]])
-; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) @0, i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @.omp_outlined..4 to void (i32*, i32*, ...)*), i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A]])
-; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) @0, i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @.omp_outlined..5 to void (i32*, i32*, ...)*), i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A]])
-; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) @0, i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @.omp_outlined..6 to void (i32*, i32*, ...)*), i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A]])
+; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @.omp_outlined..3 to void (i32*, i32*, ...)*), i32* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]])
+; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @.omp_outlined..4 to void (i32*, i32*, ...)*), i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A]])
+; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @.omp_outlined..5 to void (i32*, i32*, ...)*), i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A]])
+; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* noundef nonnull align 8 dereferenceable(24) [[GLOB0]], i32 noundef 1, void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*)* @.omp_outlined..6 to void (i32*, i32*, ...)*), i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 4, i8* noundef nonnull [[TMP1]])
; CHECK-NEXT: ret void
define internal void @.omp_outlined..3(i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* dereferenceable(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..3
-; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #6
+; CHECK-SAME: (i32* noalias nocapture nofree readnone [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) [[ATTR6:#.*]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CALL:%.*]] = call i32 @omp_get_thread_num() #4
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @omp_get_thread_num() [[ATTR12:#.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
define internal void @.omp_outlined..4(i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* dereferenceable(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..4
-; CHECK-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]])
+; CHECK-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
-; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_master(%struct.ident_t* noundef nonnull @0, i32 [[TMP]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_master(%struct.ident_t* noundef nonnull [[GLOB0]], i32 [[TMP]])
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK-NEXT: br i1 [[TMP2]], label [[OMP_IF_END:%.*]], label [[OMP_IF_THEN:%.*]]
; CHECK: omp_if.then:
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[A]], align 4
; CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP3]], 1
; CHECK-NEXT: store i32 [[INC]], i32* [[A]], align 4
-; CHECK-NEXT: call void @__kmpc_end_master(%struct.ident_t* noundef nonnull @0, i32 [[TMP]])
+; CHECK-NEXT: call void @__kmpc_end_master(%struct.ident_t* noundef nonnull [[GLOB0]], i32 [[TMP]])
; CHECK-NEXT: br label [[OMP_IF_END]]
; CHECK: omp_if.end:
; CHECK-NEXT: ret void
define internal void @.omp_outlined..5(i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* dereferenceable(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..5
-; CHECK-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]])
+; CHECK-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef nonnull @0)
+; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef nonnull [[GLOB0]]) [[ATTR12]]
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
-; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_single(%struct.ident_t* noundef nonnull @0, i32 [[TMP]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_single(%struct.ident_t* noundef nonnull [[GLOB0]], i32 [[TMP]])
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK-NEXT: br i1 [[TMP2]], label [[OMP_IF_END:%.*]], label [[OMP_IF_THEN:%.*]]
; CHECK: omp_if.then:
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[A]], align 4
; CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP3]], 1
; CHECK-NEXT: store i32 [[INC]], i32* [[A]], align 4
-; CHECK-NEXT: call void @__kmpc_end_single(%struct.ident_t* noundef nonnull @0, i32 [[TMP]])
+; CHECK-NEXT: call void @__kmpc_end_single(%struct.ident_t* noundef nonnull [[GLOB0]], i32 [[TMP]])
; CHECK-NEXT: br label [[OMP_IF_END]]
; CHECK: omp_if.end:
-; CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* noundef nonnull @1, i32 [[OMP_GLOBAL_THREAD_NUM]])
+; CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* noundef nonnull [[GLOB1:@.*]], i32 [[OMP_GLOBAL_THREAD_NUM]])
; CHECK-NEXT: ret void
;
entry:
define internal void @.omp_outlined..6(i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* dereferenceable(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..6
-; CHECK-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]])
+; CHECK-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A1:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x i8*], align 8
; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A1]] to i8*
-; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* noundef nonnull align 4 [[TMP]]) #0
+; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* noundef nonnull align 4 [[TMP]]) [[ATTR0]]
; CHECK-NEXT: store i32 1, i32* [[A1]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = bitcast [1 x i8*]* [[DOTOMP_REDUCTION_RED_LIST]] to i32**
; CHECK-NEXT: store i32* [[A1]], i32** [[TMP1]], align 8
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
; CHECK-NEXT: [[TMP3:%.*]] = bitcast [1 x i8*]* [[DOTOMP_REDUCTION_RED_LIST]] to i8*
-; CHECK-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_reduce_nowait(%struct.ident_t* noundef nonnull @2, i32 [[TMP2]], i32 noundef 1, i64 noundef 8, i8* noundef nonnull align 8 [[TMP3]], void (i8*, i8*)* noundef nonnull @.omp.reduction.reduction_func, [8 x i32]* noundef nonnull @.gomp_critical_user_.reduction.var)
+; CHECK-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_reduce_nowait(%struct.ident_t* noundef nonnull [[GLOB2:@.*]], i32 [[TMP2]], i32 noundef 1, i64 noundef 8, i8* noundef nonnull align 8 [[TMP3]], void (i8*, i8*)* noundef nonnull @.omp.reduction.reduction_func, [8 x i32]* noundef nonnull @.gomp_critical_user_.reduction.var)
; CHECK-NEXT: switch i32 [[TMP4]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
; CHECK-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
; CHECK-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
; CHECK-NEXT: [[TMP6:%.*]] = load i32, i32* [[A1]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP5]], [[TMP6]]
; CHECK-NEXT: store i32 [[ADD]], i32* [[A]], align 4
-; CHECK-NEXT: call void @__kmpc_end_reduce_nowait(%struct.ident_t* noundef nonnull @2, i32 [[TMP2]], [8 x i32]* noundef nonnull @.gomp_critical_user_.reduction.var)
+; CHECK-NEXT: call void @__kmpc_end_reduce_nowait(%struct.ident_t* noundef nonnull [[GLOB2]], i32 [[TMP2]], [8 x i32]* noundef nonnull @.gomp_critical_user_.reduction.var)
; CHECK-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
; CHECK: .omp.reduction.case2:
; CHECK-NEXT: [[TMP7:%.*]] = load i32, i32* [[A1]], align 4
define internal void @.omp.reduction.reduction_func(i8* %arg, i8* %arg1) {
; CHECK-LABEL: define {{[^@]+}}@.omp.reduction.reduction_func
-; CHECK-SAME: (i8* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[ARG:%.*]], i8* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[ARG1:%.*]]) #{{[0-9]+}}
+; CHECK-SAME: (i8* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[ARG:%.*]], i8* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[ARG1:%.*]]) [[ATTR9:#.*]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP:%.*]] = bitcast i8* [[ARG1]] to i32**
; CHECK-NEXT: [[TMP2:%.*]] = load i32*, i32** [[TMP]], align 8
ret void
}
-define internal void @bar() noinline nounwind readnone {
+define internal void @bar() noinline nounwind readnone willreturn {
entry:
ret void
}