; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes ; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -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=5 -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/25479/steps/test-check-all/logs/FAIL%3A%20LLVM%3A%3Anoalias.ll ; opt -attributor-cgscc -enable-new-pm=0 -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 ; TEST 1 - negative. ; void *G; ; void *foo(){ ; void *V = malloc(4); ; G = V; ; return V; ; } @G = external global i8* define i8* @foo() { ; CHECK-LABEL: define {{[^@]+}}@foo() { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: store i8* [[TMP1]], i8** @G, align 8 ; CHECK-NEXT: ret i8* [[TMP1]] ; %1 = tail call noalias i8* @malloc(i64 4) store i8* %1, i8** @G, align 8 ret i8* %1 } declare noalias i8* @malloc(i64) ; TEST 2 ; call noalias function in return instruction. define i8* @return_noalias(){ ; CHECK-LABEL: define {{[^@]+}}@return_noalias() { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: ret i8* [[TMP1]] ; %1 = tail call noalias i8* @malloc(i64 4) ret i8* %1 } define void @nocapture(i8* %a){ ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@nocapture ; NOT_CGSCC_NPM-SAME: (i8* nocapture nofree readnone [[A:%.*]]) [[ATTR0:#.*]] { ; NOT_CGSCC_NPM-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@nocapture ; IS__CGSCC____-SAME: (i8* nocapture nofree readnone [[A:%.*]]) [[ATTR0:#.*]] { ; IS__CGSCC____-NEXT: ret void ; ret void } define i8* @return_noalias_looks_like_capture(){ ; CHECK-LABEL: define {{[^@]+}}@return_noalias_looks_like_capture() { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: ret i8* [[TMP1]] ; %1 = tail call noalias i8* @malloc(i64 4) call void @nocapture(i8* %1) ret i8* %1 } define i16* @return_noalias_casted(){ ; CHECK-LABEL: define {{[^@]+}}@return_noalias_casted() { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: [[C:%.*]] = bitcast i8* [[TMP1]] to i16* ; CHECK-NEXT: ret i16* [[C]] ; %1 = tail call noalias i8* @malloc(i64 4) %c = bitcast i8* %1 to i16* ret i16* %c } declare i8* @alias() ; TEST 3 define i8* @call_alias(){ ; CHECK-LABEL: define {{[^@]+}}@call_alias() { ; CHECK-NEXT: [[TMP1:%.*]] = tail call i8* @alias() ; CHECK-NEXT: ret i8* [[TMP1]] ; %1 = tail call i8* @alias() ret i8* %1 } ; TEST 4 ; void *baz(); ; void *foo(int a); ; ; void *bar() { ; foo(0); ; return baz(); ; } ; ; void *foo(int a) { ; if (a) ; bar(); ; return malloc(4); ; } define i8* @bar() nounwind uwtable { ; CHECK: Function Attrs: nounwind uwtable ; CHECK-LABEL: define {{[^@]+}}@bar ; CHECK-SAME: () [[ATTR1:#.*]] { ; CHECK-NEXT: [[TMP1:%.*]] = tail call i8* (...) @baz() [[ATTR2:#.*]] ; CHECK-NEXT: ret i8* [[TMP1]] ; %1 = tail call i8* (...) @baz() ret i8* %1 } define i8* @foo1(i32 %0) nounwind uwtable { ; CHECK: Function Attrs: nounwind uwtable ; CHECK-LABEL: define {{[^@]+}}@foo1 ; CHECK-SAME: (i32 [[TMP0:%.*]]) [[ATTR1]] { ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0]], 0 ; CHECK-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]] ; CHECK: 3: ; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* (...) @baz() [[ATTR2]] ; CHECK-NEXT: br label [[TMP5]] ; CHECK: 5: ; CHECK-NEXT: [[TMP6:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: ret i8* [[TMP6]] ; %2 = icmp eq i32 %0, 0 br i1 %2, label %5, label %3 3: ; preds = %1 %4 = tail call i8* (...) @baz() br label %5 5: ; preds = %1, %3 %6 = tail call noalias i8* @malloc(i64 4) ret i8* %6 } declare i8* @baz(...) nounwind uwtable ; TEST 5 ; Returning global pointer. Should not be noalias. define i8** @getter() { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@getter ; NOT_CGSCC_NPM-SAME: () [[ATTR0]] { ; NOT_CGSCC_NPM-NEXT: ret i8** @G ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@getter ; IS__CGSCC____-SAME: () [[ATTR0]] { ; IS__CGSCC____-NEXT: ret i8** @G ; ret i8** @G } ; Returning global pointer. Should not be noalias. define i8** @calle1(){ ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@calle1 ; NOT_CGSCC_NPM-SAME: () [[ATTR0]] { ; NOT_CGSCC_NPM-NEXT: ret i8** @G ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@calle1 ; IS__CGSCC____-SAME: () [[ATTR0]] { ; IS__CGSCC____-NEXT: ret i8** @G ; %1 = call i8** @getter() ret i8** %1 } ; TEST 6 declare noalias i8* @strdup(i8* nocapture) nounwind define i8* @test6() nounwind uwtable ssp { ; CHECK: Function Attrs: nounwind ssp uwtable ; CHECK-LABEL: define {{[^@]+}}@test6 ; CHECK-SAME: () [[ATTR3:#.*]] { ; CHECK-NEXT: [[X:%.*]] = alloca [2 x i8], align 1 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i8], [2 x i8]* [[X]], i64 0, i64 0 ; CHECK-NEXT: store i8 97, i8* [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [2 x i8], [2 x i8]* [[X]], i64 0, i64 1 ; CHECK-NEXT: store i8 0, i8* [[ARRAYIDX1]], align 1 ; CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @strdup(i8* nocapture noundef nonnull dereferenceable(2) [[ARRAYIDX]]) [[ATTR2]] ; CHECK-NEXT: ret i8* [[CALL]] ; %x = alloca [2 x i8], align 1 %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %x, i64 0, i64 0 store i8 97, i8* %arrayidx, align 1 %arrayidx1 = getelementptr inbounds [2 x i8], [2 x i8]* %x, i64 0, i64 1 store i8 0, i8* %arrayidx1, align 1 %call = call noalias i8* @strdup(i8* %arrayidx) nounwind ret i8* %call } ; TEST 7 define i8* @test7() nounwind { ; CHECK: Function Attrs: nounwind ; CHECK-LABEL: define {{[^@]+}}@test7 ; CHECK-SAME: () [[ATTR2]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = call noalias i8* @malloc(i64 noundef 4) [[ATTR2]] ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[A]], null ; CHECK-NEXT: br i1 [[TOBOOL]], label [[RETURN:%.*]], label [[IF_END:%.*]] ; CHECK: if.end: ; CHECK-NEXT: store i8 7, i8* [[A]], align 1 ; CHECK-NEXT: br label [[RETURN]] ; CHECK: return: ; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i8* [ [[A]], [[IF_END]] ], [ null, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i8* [[RETVAL_0]] ; entry: %A = call noalias i8* @malloc(i64 4) nounwind %tobool = icmp eq i8* %A, null br i1 %tobool, label %return, label %if.end if.end: store i8 7, i8* %A br label %return return: %retval.0 = phi i8* [ %A, %if.end ], [ null, %entry ] ret i8* %retval.0 } ; TEST 8 define i8* @test8(i32* %0) nounwind uwtable { ; CHECK: Function Attrs: nounwind uwtable ; CHECK-LABEL: define {{[^@]+}}@test8 ; CHECK-SAME: (i32* [[TMP0:%.*]]) [[ATTR1]] { ; CHECK-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32* [[TMP0]], null ; CHECK-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]] ; CHECK: 4: ; CHECK-NEXT: store i8 10, i8* [[TMP2]], align 1 ; CHECK-NEXT: br label [[TMP5]] ; CHECK: 5: ; CHECK-NEXT: ret i8* [[TMP2]] ; %2 = tail call noalias i8* @malloc(i64 4) %3 = icmp ne i32* %0, null br i1 %3, label %4, label %5 4: ; preds = %1 store i8 10, i8* %2 br label %5 5: ; preds = %1, %4 ret i8* %2 } ; TEST 9 ; Simple Argument Test declare void @use_i8(i8* nocapture) define internal void @test9a(i8* %a, i8* %b) { ; CHECK-LABEL: define {{[^@]+}}@test9a() { ; CHECK-NEXT: call void @use_i8(i8* noalias nocapture noundef align 536870912 null) ; CHECK-NEXT: ret void ; call void @use_i8(i8* null) ret void } define internal void @test9b(i8* %a, i8* %b) { ; FIXME: %b should be noalias ; CHECK-LABEL: define {{[^@]+}}@test9b ; CHECK-SAME: (i8* noalias nocapture [[A:%.*]], i8* nocapture [[B:%.*]]) { ; CHECK-NEXT: call void @use_i8(i8* noalias nocapture [[A]]) ; CHECK-NEXT: call void @use_i8(i8* nocapture [[B]]) ; CHECK-NEXT: ret void ; call void @use_i8(i8* %a) call void @use_i8(i8* %b) ret void } define internal void @test9c(i8* %a, i8* %b, i8* %c) { ; CHECK-LABEL: define {{[^@]+}}@test9c ; CHECK-SAME: (i8* noalias nocapture [[A:%.*]], i8* nocapture [[B:%.*]], i8* nocapture [[C:%.*]]) { ; CHECK-NEXT: call void @use_i8(i8* noalias nocapture [[A]]) ; CHECK-NEXT: call void @use_i8(i8* nocapture [[B]]) ; CHECK-NEXT: call void @use_i8(i8* nocapture [[C]]) ; CHECK-NEXT: ret void ; call void @use_i8(i8* %a) call void @use_i8(i8* %b) call void @use_i8(i8* %c) ret void } define void @test9_helper(i8* %a, i8* %b) { ; CHECK-LABEL: define {{[^@]+}}@test9_helper ; CHECK-SAME: (i8* nocapture [[A:%.*]], i8* nocapture [[B:%.*]]) { ; CHECK-NEXT: tail call void @test9a() ; CHECK-NEXT: tail call void @test9a() ; CHECK-NEXT: tail call void @test9b(i8* noalias nocapture [[A]], i8* nocapture [[B]]) ; CHECK-NEXT: tail call void @test9b(i8* noalias nocapture [[B]], i8* noalias nocapture [[A]]) ; CHECK-NEXT: tail call void @test9c(i8* noalias nocapture [[A]], i8* nocapture [[B]], i8* nocapture [[B]]) ; CHECK-NEXT: tail call void @test9c(i8* noalias nocapture [[B]], i8* noalias nocapture [[A]], i8* noalias nocapture [[A]]) ; CHECK-NEXT: ret void ; tail call void @test9a(i8* noalias %a, i8* %b) tail call void @test9a(i8* noalias %b, i8* noalias %a) tail call void @test9b(i8* noalias %a, i8* %b) tail call void @test9b(i8* noalias %b, i8* noalias %a) tail call void @test9c(i8* noalias %a, i8* %b, i8* %b) tail call void @test9c(i8* noalias %b, i8* noalias %a, i8* noalias %a) ret void } ; TEST 10 ; Simple CallSite Test declare void @test10_helper_1(i8* %a) define void @test10_helper_2(i8* noalias %a) { ; CHECK-LABEL: define {{[^@]+}}@test10_helper_2 ; CHECK-SAME: (i8* noalias [[A:%.*]]) { ; CHECK-NEXT: tail call void @test10_helper_1(i8* [[A]]) ; CHECK-NEXT: ret void ; tail call void @test10_helper_1(i8* %a) ret void } define void @test10(i8* noalias %a) { ; CHECK-LABEL: define {{[^@]+}}@test10 ; CHECK-SAME: (i8* noalias [[A:%.*]]) { ; CHECK-NEXT: tail call void @test10_helper_1(i8* [[A]]) ; CHECK-NEXT: tail call void @test10_helper_2(i8* noalias [[A]]) ; CHECK-NEXT: ret void ; ; FIXME: missing noalias tail call void @test10_helper_1(i8* %a) tail call void @test10_helper_2(i8* %a) ret void } ; TEST 11 ; CallSite Test declare void @test11_helper(i8* %a, i8 *%b) define void @test11(i8* noalias %a) { ; CHECK-LABEL: define {{[^@]+}}@test11 ; CHECK-SAME: (i8* noalias [[A:%.*]]) { ; CHECK-NEXT: tail call void @test11_helper(i8* [[A]], i8* [[A]]) ; CHECK-NEXT: ret void ; tail call void @test11_helper(i8* %a, i8* %a) ret void } ; TEST 12 ; CallSite Argument declare void @use_nocapture(i8* nocapture) declare void @use(i8*) define void @test12_1() { ; CHECK-LABEL: define {{[^@]+}}@test12_1() { ; CHECK-NEXT: [[A:%.*]] = alloca i8, align 4 ; CHECK-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture noundef nonnull align 4 dereferenceable(1) [[A]]) ; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture noundef nonnull align 4 dereferenceable(1) [[A]]) ; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]]) ; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]]) ; CHECK-NEXT: ret void ; %A = alloca i8, align 4 %B = tail call noalias i8* @malloc(i64 4) tail call void @use_nocapture(i8* %A) tail call void @use_nocapture(i8* %A) tail call void @use_nocapture(i8* %B) tail call void @use_nocapture(i8* %B) ret void } define void @test12_2(){ ; CHECK-LABEL: define {{[^@]+}}@test12_2() { ; CHECK-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]]) ; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]]) ; CHECK-NEXT: tail call void @use(i8* [[A]]) ; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) ; CHECK-NEXT: ret void ; ; FIXME: This should be @use_nocapture(i8* noalias [[A]]) ; FIXME: This should be @use_nocapture(i8* noalias nocapture [[A]]) %A = tail call noalias i8* @malloc(i64 4) tail call void @use_nocapture(i8* %A) tail call void @use_nocapture(i8* %A) tail call void @use(i8* %A) tail call void @use_nocapture(i8* %A) ret void } declare void @two_args(i8* nocapture , i8* nocapture) define void @test12_3(){ ; CHECK-LABEL: define {{[^@]+}}@test12_3() { ; CHECK-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A]]) ; CHECK-NEXT: ret void ; %A = tail call noalias i8* @malloc(i64 4) tail call void @two_args(i8* %A, i8* %A) ret void } define void @test12_4(){ ; IS________OPM-LABEL: define {{[^@]+}}@test12_4() { ; IS________OPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: [[A_0:%.*]] = getelementptr i8, i8* [[A]], i64 0 ; IS________OPM-NEXT: [[A_1:%.*]] = getelementptr i8, i8* [[A]], i64 1 ; IS________OPM-NEXT: [[B_0:%.*]] = getelementptr i8, i8* [[B]], i64 0 ; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[B]]) ; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_0]]) ; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_1]]) ; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A_0]], i8* nocapture [[B_0]]) ; IS________OPM-NEXT: ret void ; ; NOT_TUNIT_OPM-LABEL: define {{[^@]+}}@test12_4() { ; NOT_TUNIT_OPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; NOT_TUNIT_OPM-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; NOT_TUNIT_OPM-NEXT: [[A_0:%.*]] = getelementptr i8, i8* [[A]], i64 0 ; NOT_TUNIT_OPM-NEXT: [[A_1:%.*]] = getelementptr i8, i8* [[A]], i64 1 ; NOT_TUNIT_OPM-NEXT: [[B_0:%.*]] = getelementptr i8, i8* [[B]], i64 0 ; NOT_TUNIT_OPM-NEXT: tail call void @two_args(i8* noalias nocapture [[A]], i8* noalias nocapture [[B]]) ; NOT_TUNIT_OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_0]]) ; NOT_TUNIT_OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_1]]) ; NOT_TUNIT_OPM-NEXT: tail call void @two_args(i8* nocapture [[A_0]], i8* nocapture [[B_0]]) ; NOT_TUNIT_OPM-NEXT: ret void ; %A = tail call noalias i8* @malloc(i64 4) %B = tail call noalias i8* @malloc(i64 4) %A_0 = getelementptr i8, i8* %A, i64 0 %A_1 = getelementptr i8, i8* %A, i64 1 %B_0 = getelementptr i8, i8* %B, i64 0 tail call void @two_args(i8* %A, i8* %B) tail call void @two_args(i8* %A, i8* %A_0) tail call void @two_args(i8* %A, i8* %A_1) ; FIXME: This should be @two_args(i8* noalias nocapture %A_0, i8* noalias nocapture %B_0) tail call void @two_args(i8* %A_0, i8* %B_0) ret void } ; TEST 13 define void @use_i8_internal(i8* %a) { ; CHECK-LABEL: define {{[^@]+}}@use_i8_internal ; CHECK-SAME: (i8* nocapture [[A:%.*]]) { ; CHECK-NEXT: call void @use_i8(i8* nocapture [[A]]) ; CHECK-NEXT: ret void ; call void @use_i8(i8* %a) ret void } define void @test13_use_noalias(){ ; CHECK-LABEL: define {{[^@]+}}@test13_use_noalias() { ; CHECK-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16* ; CHECK-NEXT: [[C2:%.*]] = bitcast i16* [[C1]] to i8* ; CHECK-NEXT: call void @use_i8_internal(i8* noalias nocapture [[C2]]) ; CHECK-NEXT: ret void ; ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test13_use_noalias() ; IS__CGSCC_OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 4) ; IS__CGSCC_OPM-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16* ; IS__CGSCC_OPM-NEXT: [[C2:%.*]] = bitcast i16* [[C1]] to i8* ; IS__CGSCC_OPM-NEXT: call void @use_i8_internal(i8* noalias [[C2]]) ; IS__CGSCC_OPM-NEXT: ret void %m1 = tail call noalias i8* @malloc(i64 4) %c1 = bitcast i8* %m1 to i16* %c2 = bitcast i16* %c1 to i8* call void @use_i8_internal(i8* %c2) ret void } define void @test13_use_alias(){ ; CHECK-LABEL: define {{[^@]+}}@test13_use_alias() { ; CHECK-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16* ; CHECK-NEXT: [[C2A:%.*]] = bitcast i16* [[C1]] to i8* ; CHECK-NEXT: [[C2B:%.*]] = bitcast i16* [[C1]] to i8* ; CHECK-NEXT: call void @use_i8_internal(i8* nocapture [[C2A]]) ; CHECK-NEXT: call void @use_i8_internal(i8* nocapture [[C2B]]) ; CHECK-NEXT: ret void ; %m1 = tail call noalias i8* @malloc(i64 4) %c1 = bitcast i8* %m1 to i16* %c2a = bitcast i16* %c1 to i8* %c2b = bitcast i16* %c1 to i8* call void @use_i8_internal(i8* %c2a) call void @use_i8_internal(i8* %c2b) ret void } ; TEST 14 i2p casts define internal i32 @p2i(i32* %arg) { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@p2i ; NOT_CGSCC_NPM-SAME: (i32* noalias nofree readnone [[ARG:%.*]]) [[ATTR0]] { ; NOT_CGSCC_NPM-NEXT: [[P2I:%.*]] = ptrtoint i32* [[ARG]] to i32 ; NOT_CGSCC_NPM-NEXT: ret i32 [[P2I]] ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@p2i ; IS__CGSCC____-SAME: (i32* noalias nofree readnone [[ARG:%.*]]) [[ATTR0]] { ; IS__CGSCC____-NEXT: [[P2I:%.*]] = ptrtoint i32* [[ARG]] to i32 ; IS__CGSCC____-NEXT: ret i32 [[P2I]] ; %p2i = ptrtoint i32* %arg to i32 ret i32 %p2i } define i32 @i2p(i32* %arg) { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind readonly willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@i2p ; NOT_CGSCC_NPM-SAME: (i32* nofree readonly [[ARG:%.*]]) [[ATTR4:#.*]] { ; NOT_CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @p2i(i32* noalias nofree readnone [[ARG]]) [[ATTR0]] ; NOT_CGSCC_NPM-NEXT: [[I2P:%.*]] = inttoptr i32 [[C]] to i8* ; NOT_CGSCC_NPM-NEXT: [[BC:%.*]] = bitcast i8* [[I2P]] to i32* ; NOT_CGSCC_NPM-NEXT: [[CALL:%.*]] = call i32 @ret(i32* nocapture nofree readonly align 4 [[BC]]) [[ATTR4]] ; NOT_CGSCC_NPM-NEXT: ret i32 [[CALL]] ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@i2p ; IS__CGSCC____-SAME: (i32* nofree readonly [[ARG:%.*]]) [[ATTR4:#.*]] { ; IS__CGSCC____-NEXT: [[C:%.*]] = call i32 @p2i(i32* noalias nofree readnone [[ARG]]) [[ATTR10:#.*]] ; IS__CGSCC____-NEXT: [[I2P:%.*]] = inttoptr i32 [[C]] to i8* ; IS__CGSCC____-NEXT: [[BC:%.*]] = bitcast i8* [[I2P]] to i32* ; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @ret(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[BC]]) [[ATTR11:#.*]] ; IS__CGSCC____-NEXT: ret i32 [[CALL]] ; %c = call i32 @p2i(i32* %arg) %i2p = inttoptr i32 %c to i8* %bc = bitcast i8* %i2p to i32* %call = call i32 @ret(i32* %bc) ret i32 %call } define internal i32 @ret(i32* %arg) { ; NOT_CGSCC_NPM: Function Attrs: argmemonly nofree nosync nounwind readonly willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@ret ; NOT_CGSCC_NPM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[ARG:%.*]]) [[ATTR5:#.*]] { ; NOT_CGSCC_NPM-NEXT: [[L:%.*]] = load i32, i32* [[ARG]], align 4 ; NOT_CGSCC_NPM-NEXT: ret i32 [[L]] ; ; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@ret ; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[ARG:%.*]]) [[ATTR5:#.*]] { ; IS__CGSCC____-NEXT: [[L:%.*]] = load i32, i32* [[ARG]], align 4 ; IS__CGSCC____-NEXT: ret i32 [[L]] ; %l = load i32, i32* %arg ret i32 %l } ; Test to propagate noalias where value is assumed to be no-capture in all the ; uses possibly executed before this callsite. ; IR referred from musl/src/strtod.c file %struct._IO_FILE = type { i32, i8*, i8*, i32 (%struct._IO_FILE*)*, i8*, i8*, i8*, i8*, i32 (%struct._IO_FILE*, i8*, i32)*, i32 (%struct._IO_FILE*, i8*, i32)*, i64 (%struct._IO_FILE*, i64, i32)*, i8*, i32, %struct._IO_FILE*, %struct._IO_FILE*, i32, i32, i32, i16, i8, i8, i32, i32, i8*, i64, i8*, i8*, i8*, [4 x i8], i64, i64, %struct._IO_FILE*, %struct._IO_FILE*, %struct.__locale_struct*, [4 x i8] } %struct.__locale_struct = type { [6 x %struct.__locale_map*] } %struct.__locale_map = type opaque ; Function Attrs: nounwind optsize define internal fastcc double @strtox(i8* %s, i8** %p, i32 %prec) unnamed_addr { ; CHECK-LABEL: define {{[^@]+}}@strtox ; CHECK-SAME: (i8* [[S:%.*]]) unnamed_addr { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[F:%.*]] = alloca [[STRUCT__IO_FILE:%.*]], align 8 ; CHECK-NEXT: [[TMP0:%.*]] = bitcast %struct._IO_FILE* [[F]] to i8* ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 144, i8* nocapture nofree noundef nonnull align 8 dereferenceable(240) [[TMP0]]) [[ATTR10:#.*]] ; CHECK-NEXT: [[CALL:%.*]] = call i32 bitcast (i32 (...)* @sh_fromstring to i32 (%struct._IO_FILE*, i8*)*)(%struct._IO_FILE* nonnull align 8 dereferenceable(240) [[F]], i8* [[S]]) ; CHECK-NEXT: call void @__shlim(%struct._IO_FILE* noundef nonnull align 8 dereferenceable(240) [[F]], i64 noundef 0) ; CHECK-NEXT: [[CALL1:%.*]] = call double @__floatscan(%struct._IO_FILE* noundef nonnull align 8 dereferenceable(240) [[F]], i32 noundef 1, i32 noundef 1) ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 144, i8* nocapture nofree noundef nonnull align 8 dereferenceable(240) [[TMP0]]) ; CHECK-NEXT: ret double [[CALL1]] ; entry: %f = alloca %struct._IO_FILE, align 8 %0 = bitcast %struct._IO_FILE* %f to i8* call void @llvm.lifetime.start.p0i8(i64 144, i8* nonnull %0) %call = call i32 bitcast (i32 (...)* @sh_fromstring to i32 (%struct._IO_FILE*, i8*)*)(%struct._IO_FILE* nonnull %f, i8* %s) call void @__shlim(%struct._IO_FILE* nonnull %f, i64 0) %call1 = call double @__floatscan(%struct._IO_FILE* nonnull %f, i32 %prec, i32 1) call void @llvm.lifetime.end.p0i8(i64 144, i8* nonnull %0) ret double %call1 } ; Function Attrs: nounwind optsize define dso_local double @strtod(i8* noalias %s, i8** noalias %p) { ; CHECK-LABEL: define {{[^@]+}}@strtod ; CHECK-SAME: (i8* noalias [[S:%.*]], i8** noalias nocapture nofree readnone [[P:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CALL:%.*]] = tail call fastcc double @strtox(i8* [[S]]) ; CHECK-NEXT: ret double [[CALL]] ; entry: %call = tail call fastcc double @strtox(i8* %s, i8** %p, i32 1) ret double %call } ; Function Attrs: argmemonly nounwind willreturn declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) ; Function Attrs: optsize declare dso_local i32 @sh_fromstring(...) local_unnamed_addr ; Function Attrs: optsize declare dso_local void @__shlim(%struct._IO_FILE*, i64) local_unnamed_addr ; Function Attrs: optsize declare dso_local double @__floatscan(%struct._IO_FILE*, i32, i32) local_unnamed_addr ; Function Attrs: argmemonly nounwind willreturn declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) ; Test 15 ; propagate noalias to some callsite arguments that there is no possibly reachable capture before it @alias_of_p = external global i32* define void @make_alias(i32* %p) { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind willreturn writeonly ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@make_alias ; NOT_CGSCC_NPM-SAME: (i32* nofree writeonly [[P:%.*]]) [[ATTR7:#.*]] { ; NOT_CGSCC_NPM-NEXT: store i32* [[P]], i32** @alias_of_p, align 8 ; NOT_CGSCC_NPM-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@make_alias ; IS__CGSCC____-SAME: (i32* nofree writeonly [[P:%.*]]) [[ATTR7:#.*]] { ; IS__CGSCC____-NEXT: store i32* [[P]], i32** @alias_of_p, align 8 ; IS__CGSCC____-NEXT: ret void ; store i32* %p, i32** @alias_of_p ret void } define void @only_store(i32* %p) { ; NOT_CGSCC_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@only_store ; NOT_CGSCC_NPM-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P:%.*]]) [[ATTR8:#.*]] { ; NOT_CGSCC_NPM-NEXT: store i32 0, i32* [[P]], align 4 ; NOT_CGSCC_NPM-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@only_store ; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P:%.*]]) [[ATTR8:#.*]] { ; IS__CGSCC____-NEXT: store i32 0, i32* [[P]], align 4 ; IS__CGSCC____-NEXT: ret void ; store i32 0, i32* %p ret void } define void @test15_caller(i32* noalias %p, i32 %c) { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind willreturn writeonly ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test15_caller ; NOT_CGSCC_NPM-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C:%.*]]) [[ATTR7]] { ; NOT_CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0 ; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] ; NOT_CGSCC_NPM: if.then: ; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: br label [[IF_END]] ; NOT_CGSCC_NPM: if.end: ; NOT_CGSCC_NPM-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@test15_caller ; IS__CGSCC____-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C:%.*]]) [[ATTR7]] { ; IS__CGSCC____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0 ; IS__CGSCC____-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] ; IS__CGSCC____: if.then: ; IS__CGSCC____-NEXT: tail call void @only_store(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P]]) [[ATTR12:#.*]] ; IS__CGSCC____-NEXT: br label [[IF_END]] ; IS__CGSCC____: if.end: ; IS__CGSCC____-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]]) [[ATTR12]] ; IS__CGSCC____-NEXT: ret void ; %tobool = icmp eq i32 %c, 0 br i1 %tobool, label %if.end, label %if.then if.then: tail call void @only_store(i32* %p) br label %if.end if.end: tail call void @make_alias(i32* %p) ret void } ; Test 16 ; ; __attribute__((noinline)) static void test16_sub(int * restrict p, int c1, int c2) { ; if (c1) { ; only_store(p); ; make_alias(p); ; } ; if (!c2) { ; only_store(p); ; } ; } ; void test16_caller(int * restrict p, int c) { ; test16_sub(p, c, c); ; } ; ; FIXME: this should be tail @only_store(i32* noalias %p) ; when test16_caller is called, c1 always equals to c2. (Note that linkage is internal) ; Therefore, only one of the two conditions of if statementes will be fulfilled. define internal void @test16_sub(i32* noalias %p, i32 %c1, i32 %c2) { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind willreturn writeonly ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test16_sub ; NOT_CGSCC_NPM-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C1:%.*]], i32 [[C2:%.*]]) [[ATTR7]] { ; NOT_CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C1]], 0 ; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] ; NOT_CGSCC_NPM: if.then: ; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: tail call void @make_alias(i32* nofree writeonly align 4 [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: br label [[IF_END]] ; NOT_CGSCC_NPM: if.end: ; NOT_CGSCC_NPM-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C2]], 0 ; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] ; NOT_CGSCC_NPM: if.then2: ; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* nocapture nofree writeonly align 4 [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: br label [[IF_END3]] ; NOT_CGSCC_NPM: if.end3: ; NOT_CGSCC_NPM-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@test16_sub ; IS__CGSCC____-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C1:%.*]], i32 [[C2:%.*]]) [[ATTR7]] { ; IS__CGSCC____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C1]], 0 ; IS__CGSCC____-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] ; IS__CGSCC____: if.then: ; IS__CGSCC____-NEXT: tail call void @only_store(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P]]) [[ATTR12]] ; IS__CGSCC____-NEXT: tail call void @make_alias(i32* nofree nonnull writeonly align 4 dereferenceable(4) [[P]]) [[ATTR12]] ; IS__CGSCC____-NEXT: br label [[IF_END]] ; IS__CGSCC____: if.end: ; IS__CGSCC____-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C2]], 0 ; IS__CGSCC____-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] ; IS__CGSCC____: if.then2: ; IS__CGSCC____-NEXT: tail call void @only_store(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P]]) [[ATTR12]] ; IS__CGSCC____-NEXT: br label [[IF_END3]] ; IS__CGSCC____: if.end3: ; IS__CGSCC____-NEXT: ret void ; %tobool = icmp eq i32 %c1, 0 br i1 %tobool, label %if.end, label %if.then if.then: tail call void @only_store(i32* %p) tail call void @make_alias(i32* %p) br label %if.end if.end: %tobool1 = icmp eq i32 %c2, 0 br i1 %tobool1, label %if.then2, label %if.end3 if.then2: tail call void @only_store(i32* %p) br label %if.end3 if.end3: ret void } define void @test16_caller(i32* %p, i32 %c) { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind willreturn writeonly ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test16_caller ; NOT_CGSCC_NPM-SAME: (i32* nofree writeonly [[P:%.*]], i32 [[C:%.*]]) [[ATTR7]] { ; NOT_CGSCC_NPM-NEXT: tail call void @test16_sub(i32* noalias nofree writeonly [[P]], i32 [[C]], i32 [[C]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@test16_caller ; IS__CGSCC____-SAME: (i32* nofree writeonly [[P:%.*]], i32 [[C:%.*]]) [[ATTR7]] { ; IS__CGSCC____-NEXT: tail call void @test16_sub(i32* noalias nofree writeonly [[P]], i32 [[C]], i32 [[C]]) [[ATTR12]] ; IS__CGSCC____-NEXT: ret void ; tail call void @test16_sub(i32* %p, i32 %c, i32 %c) ret void } ; test 17 ; ; only_store is not called after make_alias is called. ; ; void test17_caller(int* p, int c) { ; if(c) { ; make_alias(p); ; if(0 == 0) { ; goto l3; ; } else { ; goto l2; ; } ; } ; l2: ; only_store(p); ; l3: ; return; ; } define void @test17_caller(i32* noalias %p, i32 %c) { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind willreturn writeonly ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test17_caller ; NOT_CGSCC_NPM-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C:%.*]]) [[ATTR7]] { ; NOT_CGSCC_NPM-NEXT: entry: ; NOT_CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0 ; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[L1:%.*]], label [[L2:%.*]] ; NOT_CGSCC_NPM: l1: ; NOT_CGSCC_NPM-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: br label [[L3:%.*]] ; NOT_CGSCC_NPM: l2: ; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* nocapture nofree writeonly align 4 [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: br label [[L3]] ; NOT_CGSCC_NPM: l3: ; NOT_CGSCC_NPM-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@test17_caller ; IS__CGSCC____-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C:%.*]]) [[ATTR7]] { ; IS__CGSCC____-NEXT: entry: ; IS__CGSCC____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0 ; IS__CGSCC____-NEXT: br i1 [[TOBOOL]], label [[L1:%.*]], label [[L2:%.*]] ; IS__CGSCC____: l1: ; IS__CGSCC____-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]]) [[ATTR12]] ; IS__CGSCC____-NEXT: br label [[L3:%.*]] ; IS__CGSCC____: l2: ; IS__CGSCC____-NEXT: tail call void @only_store(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P]]) [[ATTR12]] ; IS__CGSCC____-NEXT: br label [[L3]] ; IS__CGSCC____: l3: ; IS__CGSCC____-NEXT: ret void ; entry: %tobool = icmp eq i32 %c, 0 br i1 %tobool, label %l1, label %l2 l1: tail call void @make_alias(i32* %p) %tobool2 = icmp eq i32 0, 0 br i1 %tobool2, label %l3, label %l2 l2: tail call void @only_store(i32* %p) br label %l3 l3: ret void } ; test 18 ; void test18_caller(int* p, int c) { ; if(c) { ; make_alias(p); ; noreturn(); ; } ; only_store(p); ; return; ; } define void @noreturn() { ; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@noreturn ; NOT_CGSCC_NPM-SAME: () [[ATTR9:#.*]] { ; NOT_CGSCC_NPM-NEXT: unreachable ; ; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@noreturn ; IS__CGSCC____-SAME: () [[ATTR9:#.*]] { ; IS__CGSCC____-NEXT: unreachable ; call void @noreturn() ret void } define void @test18_caller(i32* noalias %p, i32 %c) { ; NOT_CGSCC_NPM: Function Attrs: nofree nosync nounwind willreturn writeonly ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test18_caller ; NOT_CGSCC_NPM-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C:%.*]]) [[ATTR7]] { ; NOT_CGSCC_NPM-NEXT: entry: ; NOT_CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0 ; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[L1:%.*]], label [[L2:%.*]] ; NOT_CGSCC_NPM: l1: ; NOT_CGSCC_NPM-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: unreachable ; NOT_CGSCC_NPM: l2: ; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* nocapture nofree writeonly align 4 [[P]]) [[ATTR7]] ; NOT_CGSCC_NPM-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@test18_caller ; IS__CGSCC____-SAME: (i32* noalias nofree nonnull writeonly align 4 dereferenceable(4) [[P:%.*]], i32 [[C:%.*]]) [[ATTR7]] { ; IS__CGSCC____-NEXT: entry: ; IS__CGSCC____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0 ; IS__CGSCC____-NEXT: br i1 [[TOBOOL]], label [[L1:%.*]], label [[L2:%.*]] ; IS__CGSCC____: l1: ; IS__CGSCC____-NEXT: tail call void @make_alias(i32* nofree nonnull writeonly align 4 dereferenceable(4) [[P]]) [[ATTR12]] ; IS__CGSCC____-NEXT: unreachable ; IS__CGSCC____: l2: ; IS__CGSCC____-NEXT: tail call void @only_store(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P]]) [[ATTR12]] ; IS__CGSCC____-NEXT: ret void ; entry: %tobool = icmp eq i32 %c, 0 br i1 %tobool, label %l1, label %l2 l1: tail call void @make_alias(i32* %p) tail call void @noreturn() br label %l2 l2: tail call void @only_store(i32* %p) ret void }