| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals | |
| ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT | |
| ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC | |
| target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" | |
| ; Test 0 | |
| ; | |
| ; Make sure we propagate information from the caller to the callback callee but | |
| ; only for arguments that are mapped through the callback metadata. Here, the | |
| ; first two arguments of the call and the callback callee do not correspond to | |
| ; each other but argument 3-5 of the transitive call site in the caller match | |
| ; arguments 2-4 of the callback callee. Here we should see information and value | |
| ; transfer in both directions. | |
| define void @t0_caller(ptr %a) { | |
| ; TUNIT-LABEL: define {{[^@]+}}@t0_caller | |
| ; TUNIT-SAME: (ptr align 256 [[A:%.*]]) { | |
| ; TUNIT-NEXT: entry: | |
| ; TUNIT-NEXT: [[B:%.*]] = alloca i32, align 32 | |
| ; TUNIT-NEXT: [[C:%.*]] = alloca ptr, align 64 | |
| ; TUNIT-NEXT: [[PTR:%.*]] = alloca i32, align 128 | |
| ; TUNIT-NEXT: store i32 42, ptr [[B]], align 32 | |
| ; TUNIT-NEXT: store ptr [[B]], ptr [[C]], align 64 | |
| ; TUNIT-NEXT: call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr align 256 [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; TUNIT-NEXT: ret void | |
| ; | |
| ; CGSCC-LABEL: define {{[^@]+}}@t0_caller | |
| ; CGSCC-SAME: (ptr align 256 [[A:%.*]]) { | |
| ; CGSCC-NEXT: entry: | |
| ; CGSCC-NEXT: [[B:%.*]] = alloca i32, align 32 | |
| ; CGSCC-NEXT: [[C:%.*]] = alloca ptr, align 64 | |
| ; CGSCC-NEXT: [[PTR:%.*]] = alloca i32, align 128 | |
| ; CGSCC-NEXT: store i32 42, ptr [[B]], align 32 | |
| ; CGSCC-NEXT: store ptr [[B]], ptr [[C]], align 64 | |
| ; CGSCC-NEXT: call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr align 256 [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; CGSCC-NEXT: ret void | |
| ; | |
| entry: | |
| %b = alloca i32, align 32 | |
| %c = alloca ptr, align 64 | |
| %ptr = alloca i32, align 128 | |
| store i32 42, ptr %b, align 4 | |
| store ptr %b, ptr %c, align 8 | |
| call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr null, ptr %ptr, ptr @t0_callback_callee, ptr %a, i64 99, ptr %c) | |
| ret void | |
| } | |
| ; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! | |
| ; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. | |
| define internal void @t0_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) { | |
| ; | |
| ; TUNIT-LABEL: define {{[^@]+}}@t0_callback_callee | |
| ; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) { | |
| ; TUNIT-NEXT: entry: | |
| ; TUNIT-NEXT: [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8, !invariant.load [[META0:![0-9]+]] | |
| ; TUNIT-NEXT: store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4 | |
| ; TUNIT-NEXT: [[TMP0:%.*]] = load ptr, ptr [[C]], align 64 | |
| ; TUNIT-NEXT: tail call void @t0_check(ptr align 256 [[A]], i64 noundef 99, ptr align 32 [[TMP0]]) | |
| ; TUNIT-NEXT: ret void | |
| ; | |
| ; CGSCC-LABEL: define {{[^@]+}}@t0_callback_callee | |
| ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) { | |
| ; CGSCC-NEXT: entry: | |
| ; CGSCC-NEXT: [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8, !invariant.load [[META0:![0-9]+]] | |
| ; CGSCC-NEXT: store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4 | |
| ; CGSCC-NEXT: [[TMP0:%.*]] = load ptr, ptr [[C]], align 64, !invariant.load [[META0]] | |
| ; CGSCC-NEXT: tail call void @t0_check(ptr align 256 [[A]], i64 noundef 99, ptr [[TMP0]]) | |
| ; CGSCC-NEXT: ret void | |
| ; | |
| entry: | |
| %ptr_val = load i32, ptr %ptr, align 8 | |
| store i32 %ptr_val, ptr %is_not_null | |
| %0 = load ptr, ptr %c, align 8 | |
| tail call void @t0_check(ptr %a, i64 %b, ptr %0) | |
| ret void | |
| } | |
| declare void @t0_check(ptr align 256, i64, ptr) | |
| declare !callback !0 void @t0_callback_broker(ptr, ptr, ptr, ...) | |
| ; Test 1 | |
| ; | |
| ; Similar to test 0 but with some additional annotations (noalias/nocapute) to make sure | |
| ; we deduce and propagate noalias and others properly. | |
| define void @t1_caller(ptr noalias %a) { | |
| ; | |
| ; TUNIT-LABEL: define {{[^@]+}}@t1_caller | |
| ; TUNIT-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) { | |
| ; TUNIT-NEXT: entry: | |
| ; TUNIT-NEXT: [[B:%.*]] = alloca i32, align 32 | |
| ; TUNIT-NEXT: [[C:%.*]] = alloca ptr, align 64 | |
| ; TUNIT-NEXT: [[PTR:%.*]] = alloca i32, align 128 | |
| ; TUNIT-NEXT: store i32 42, ptr [[B]], align 32 | |
| ; TUNIT-NEXT: store ptr [[B]], ptr [[C]], align 64 | |
| ; TUNIT-NEXT: call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t1_callback_callee, ptr noalias align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; TUNIT-NEXT: ret void | |
| ; | |
| ; CGSCC-LABEL: define {{[^@]+}}@t1_caller | |
| ; CGSCC-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) { | |
| ; CGSCC-NEXT: entry: | |
| ; CGSCC-NEXT: [[B:%.*]] = alloca i32, align 32 | |
| ; CGSCC-NEXT: [[C:%.*]] = alloca ptr, align 64 | |
| ; CGSCC-NEXT: [[PTR:%.*]] = alloca i32, align 128 | |
| ; CGSCC-NEXT: store i32 42, ptr [[B]], align 32 | |
| ; CGSCC-NEXT: store ptr [[B]], ptr [[C]], align 64 | |
| ; CGSCC-NEXT: call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t1_callback_callee, ptr noalias align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; CGSCC-NEXT: ret void | |
| ; | |
| entry: | |
| %b = alloca i32, align 32 | |
| %c = alloca ptr, align 64 | |
| %ptr = alloca i32, align 128 | |
| store i32 42, ptr %b, align 4 | |
| store ptr %b, ptr %c, align 8 | |
| call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr null, ptr %ptr, ptr @t1_callback_callee, ptr %a, i64 99, ptr %c) | |
| ret void | |
| } | |
| ; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! | |
| ; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. | |
| define internal void @t1_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) { | |
| ; | |
| ; TUNIT: Function Attrs: nosync | |
| ; TUNIT-LABEL: define {{[^@]+}}@t1_callback_callee | |
| ; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr noalias align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] { | |
| ; TUNIT-NEXT: entry: | |
| ; TUNIT-NEXT: [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8, !invariant.load [[META0]] | |
| ; TUNIT-NEXT: store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4 | |
| ; TUNIT-NEXT: [[TMP0:%.*]] = load ptr, ptr [[C]], align 64 | |
| ; TUNIT-NEXT: tail call void @t1_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]]) | |
| ; TUNIT-NEXT: ret void | |
| ; | |
| ; CGSCC: Function Attrs: nosync | |
| ; CGSCC-LABEL: define {{[^@]+}}@t1_callback_callee | |
| ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr noalias align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] { | |
| ; CGSCC-NEXT: entry: | |
| ; CGSCC-NEXT: [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8, !invariant.load [[META0]] | |
| ; CGSCC-NEXT: store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4 | |
| ; CGSCC-NEXT: [[TMP0:%.*]] = load ptr, ptr [[C]], align 64, !invariant.load [[META0]] | |
| ; CGSCC-NEXT: tail call void @t1_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[TMP0]]) | |
| ; CGSCC-NEXT: ret void | |
| ; | |
| entry: | |
| %ptr_val = load i32, ptr %ptr, align 8 | |
| store i32 %ptr_val, ptr %is_not_null | |
| %0 = load ptr, ptr %c, align 8 | |
| tail call void @t1_check(ptr %a, i64 %b, ptr %0) | |
| ret void | |
| } | |
| declare void @t1_check(ptr nocapture align 256, i64, ptr nocapture) nosync | |
| declare !callback !0 void @t1_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...) | |
| ; Test 2 | |
| ; | |
| ; Similar to test 1 but checking that the noalias is only placed if potential synchronization through @t2_check is preserved. | |
| define void @t2_caller(ptr noalias %a) { | |
| ; TUNIT-LABEL: define {{[^@]+}}@t2_caller | |
| ; TUNIT-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) { | |
| ; TUNIT-NEXT: entry: | |
| ; TUNIT-NEXT: [[B:%.*]] = alloca i32, align 32 | |
| ; TUNIT-NEXT: [[C:%.*]] = alloca ptr, align 64 | |
| ; TUNIT-NEXT: [[PTR:%.*]] = alloca i32, align 128 | |
| ; TUNIT-NEXT: store i32 42, ptr [[B]], align 32 | |
| ; TUNIT-NEXT: store ptr [[B]], ptr [[C]], align 64 | |
| ; TUNIT-NEXT: call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t2_callback_callee, ptr noalias align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; TUNIT-NEXT: ret void | |
| ; | |
| ; CGSCC-LABEL: define {{[^@]+}}@t2_caller | |
| ; CGSCC-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) { | |
| ; CGSCC-NEXT: entry: | |
| ; CGSCC-NEXT: [[B:%.*]] = alloca i32, align 32 | |
| ; CGSCC-NEXT: [[C:%.*]] = alloca ptr, align 64 | |
| ; CGSCC-NEXT: [[PTR:%.*]] = alloca i32, align 128 | |
| ; CGSCC-NEXT: store i32 42, ptr [[B]], align 32 | |
| ; CGSCC-NEXT: store ptr [[B]], ptr [[C]], align 64 | |
| ; CGSCC-NEXT: call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t2_callback_callee, ptr noalias align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; CGSCC-NEXT: ret void | |
| ; | |
| entry: | |
| %b = alloca i32, align 32 | |
| %c = alloca ptr, align 64 | |
| %ptr = alloca i32, align 128 | |
| store i32 42, ptr %b, align 4 | |
| store ptr %b, ptr %c, align 8 | |
| call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr null, ptr %ptr, ptr @t2_callback_callee, ptr %a, i64 99, ptr %c) | |
| ret void | |
| } | |
| ; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! | |
| ; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. | |
| ; | |
| ; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls. | |
| define internal void @t2_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) { | |
| ; | |
| ; TUNIT-LABEL: define {{[^@]+}}@t2_callback_callee | |
| ; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) { | |
| ; TUNIT-NEXT: entry: | |
| ; TUNIT-NEXT: [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8, !invariant.load [[META0]] | |
| ; TUNIT-NEXT: store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4 | |
| ; TUNIT-NEXT: [[TMP0:%.*]] = load ptr, ptr [[C]], align 64 | |
| ; TUNIT-NEXT: tail call void @t2_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]]) | |
| ; TUNIT-NEXT: ret void | |
| ; | |
| ; CGSCC-LABEL: define {{[^@]+}}@t2_callback_callee | |
| ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) { | |
| ; CGSCC-NEXT: entry: | |
| ; CGSCC-NEXT: [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8, !invariant.load [[META0]] | |
| ; CGSCC-NEXT: store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4 | |
| ; CGSCC-NEXT: [[TMP0:%.*]] = load ptr, ptr [[C]], align 64, !invariant.load [[META0]] | |
| ; CGSCC-NEXT: tail call void @t2_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[TMP0]]) | |
| ; CGSCC-NEXT: ret void | |
| ; | |
| entry: | |
| %ptr_val = load i32, ptr %ptr, align 8 | |
| store i32 %ptr_val, ptr %is_not_null | |
| %0 = load ptr, ptr %c, align 8 | |
| tail call void @t2_check(ptr %a, i64 %b, ptr %0) | |
| ret void | |
| } | |
| declare void @t2_check(ptr nocapture align 256, i64, ptr nocapture) | |
| declare !callback !0 void @t2_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...) | |
| ; Test 3 | |
| ; | |
| ; Basically test 2 with the casted callback callee used twice. | |
| define void @t3_caller(ptr noalias %a) { | |
| ; TUNIT-LABEL: define {{[^@]+}}@t3_caller | |
| ; TUNIT-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) { | |
| ; TUNIT-NEXT: entry: | |
| ; TUNIT-NEXT: [[B:%.*]] = alloca i32, align 32 | |
| ; TUNIT-NEXT: [[C:%.*]] = alloca ptr, align 64 | |
| ; TUNIT-NEXT: [[PTR:%.*]] = alloca i32, align 128 | |
| ; TUNIT-NEXT: store i32 42, ptr [[B]], align 32 | |
| ; TUNIT-NEXT: store ptr [[B]], ptr [[C]], align 64 | |
| ; TUNIT-NEXT: call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr noalias align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; TUNIT-NEXT: call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr noalias align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; TUNIT-NEXT: ret void | |
| ; | |
| ; CGSCC-LABEL: define {{[^@]+}}@t3_caller | |
| ; CGSCC-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) { | |
| ; CGSCC-NEXT: entry: | |
| ; CGSCC-NEXT: [[B:%.*]] = alloca i32, align 32 | |
| ; CGSCC-NEXT: [[C:%.*]] = alloca ptr, align 64 | |
| ; CGSCC-NEXT: [[PTR:%.*]] = alloca i32, align 128 | |
| ; CGSCC-NEXT: store i32 42, ptr [[B]], align 32 | |
| ; CGSCC-NEXT: store ptr [[B]], ptr [[C]], align 64 | |
| ; CGSCC-NEXT: call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr noalias align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; CGSCC-NEXT: call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr noalias align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]]) | |
| ; CGSCC-NEXT: ret void | |
| ; | |
| entry: | |
| %b = alloca i32, align 32 | |
| %c = alloca ptr, align 64 | |
| %ptr = alloca i32, align 128 | |
| store i32 42, ptr %b, align 4 | |
| store ptr %b, ptr %c, align 8 | |
| call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c) | |
| call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c) | |
| ret void | |
| } | |
| ; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! | |
| ; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. | |
| ; | |
| ; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls. | |
| define internal void @t3_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) { | |
| ; | |
| ; TUNIT-LABEL: define {{[^@]+}}@t3_callback_callee | |
| ; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) { | |
| ; TUNIT-NEXT: entry: | |
| ; TUNIT-NEXT: [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8, !invariant.load [[META0]] | |
| ; TUNIT-NEXT: store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4 | |
| ; TUNIT-NEXT: [[TMP0:%.*]] = load ptr, ptr [[C]], align 64 | |
| ; TUNIT-NEXT: tail call void @t3_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]]) | |
| ; TUNIT-NEXT: ret void | |
| ; | |
| ; CGSCC-LABEL: define {{[^@]+}}@t3_callback_callee | |
| ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) { | |
| ; CGSCC-NEXT: entry: | |
| ; CGSCC-NEXT: [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8, !invariant.load [[META0]] | |
| ; CGSCC-NEXT: store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4 | |
| ; CGSCC-NEXT: [[TMP0:%.*]] = load ptr, ptr [[C]], align 64, !invariant.load [[META0]] | |
| ; CGSCC-NEXT: tail call void @t3_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[TMP0]]) | |
| ; CGSCC-NEXT: ret void | |
| ; | |
| entry: | |
| %ptr_val = load i32, ptr %ptr, align 8 | |
| store i32 %ptr_val, ptr %is_not_null | |
| %0 = load ptr, ptr %c, align 8 | |
| tail call void @t3_check(ptr %a, i64 %b, ptr %0) | |
| ret void | |
| } | |
| declare void @t3_check(ptr nocapture align 256, i64, ptr nocapture) | |
| declare !callback !0 void @t3_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...) | |
| !0 = !{!1} | |
| !1 = !{i64 2, i64 -1, i64 -1, i1 true} | |
| ;. | |
| ; TUNIT: attributes #[[ATTR0]] = { nosync } | |
| ;. | |
| ; CGSCC: attributes #[[ATTR0]] = { nosync } | |
| ;. | |
| ; TUNIT: [[META0]] = !{} | |
| ; TUNIT: [[META1:![0-9]+]] = !{[[META2:![0-9]+]]} | |
| ; TUNIT: [[META2]] = !{i64 2, i64 -1, i64 -1, i1 true} | |
| ;. | |
| ; CGSCC: [[META0]] = !{} | |
| ; CGSCC: [[META1:![0-9]+]] = !{[[META2:![0-9]+]]} | |
| ; CGSCC: [[META2]] = !{i64 2, i64 -1, i64 -1, i1 true} | |
| ;. | |
| ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: | |
| ; CHECK: {{.*}} |