1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals 2; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM 3; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM 4; RUN: 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 5; 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 6 7target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 8 9; Test 0 10; 11; Make sure we propagate information from the caller to the callback callee but 12; only for arguments that are mapped through the callback metadata. Here, the 13; first two arguments of the call and the callback callee do not correspond to 14; each other but argument 3-5 of the transitive call site in the caller match 15; arguments 2-4 of the callback callee. Here we should see information and value 16; transfer in both directions. 17 18define void @t0_caller(i32* %a) { 19; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t0_caller 20; IS__TUNIT_OPM-SAME: (i32* align 256 [[A:%.*]]) { 21; IS__TUNIT_OPM-NEXT: entry: 22; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 23; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 24; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 25; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 26; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32 27; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 28; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 undef, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 29; IS__TUNIT_OPM-NEXT: ret void 30; 31; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t0_caller 32; IS__TUNIT_NPM-SAME: (i32* align 256 [[A:%.*]]) { 33; IS__TUNIT_NPM-NEXT: entry: 34; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 35; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 36; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 37; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 38; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32 39; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 40; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 undef, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 41; IS__TUNIT_NPM-NEXT: ret void 42; 43; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t0_caller 44; IS__CGSCC_OPM-SAME: (i32* align 256 [[A:%.*]]) { 45; IS__CGSCC_OPM-NEXT: entry: 46; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 47; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 48; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 49; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 50; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32 51; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 52; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 noundef 99, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 53; IS__CGSCC_OPM-NEXT: ret void 54; 55; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t0_caller 56; IS__CGSCC_NPM-SAME: (i32* align 256 [[A:%.*]]) { 57; IS__CGSCC_NPM-NEXT: entry: 58; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 59; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 60; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 61; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 62; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32 63; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 64; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 noundef 99, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 65; IS__CGSCC_NPM-NEXT: ret void 66; 67entry: 68 %b = alloca i32, align 32 69 %c = alloca i32*, align 64 70 %ptr = alloca i32, align 128 71 %0 = bitcast i32* %b to i8* 72 store i32 42, i32* %b, align 4 73 store i32* %b, i32** %c, align 8 74 call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* null, i32* %ptr, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* %a, i64 99, i32** %c) 75 ret void 76} 77 78; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! 79; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. 80define internal void @t0_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) { 81; 82; IS________OPM-LABEL: define {{[^@]+}}@t0_callback_callee 83; IS________OPM-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) { 84; IS________OPM-NEXT: entry: 85; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 86; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 87; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 88; IS________OPM-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 noundef 99, i32* [[TMP0]]) 89; IS________OPM-NEXT: ret void 90; 91; IS________NPM-LABEL: define {{[^@]+}}@t0_callback_callee 92; IS________NPM-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) { 93; IS________NPM-NEXT: entry: 94; IS________NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 95; IS________NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 96; IS________NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 97; IS________NPM-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 noundef 99, i32* [[TMP0]]) 98; IS________NPM-NEXT: ret void 99; 100entry: 101 %ptr_val = load i32, i32* %ptr, align 8 102 store i32 %ptr_val, i32* %is_not_null 103 %0 = load i32*, i32** %c, align 8 104 tail call void @t0_check(i32* %a, i64 %b, i32* %0) 105 ret void 106} 107 108declare void @t0_check(i32* align 256, i64, i32*) 109 110declare !callback !0 void @t0_callback_broker(i32*, i32*, void (i32*, i32*, ...)*, ...) 111 112; Test 1 113; 114; Similar to test 0 but with some additional annotations (noalias/nocapute) to make sure 115; we deduce and propagate noalias and others properly. 116 117define void @t1_caller(i32* noalias %a) { 118; 119; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t1_caller 120; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 121; IS__TUNIT_OPM-NEXT: entry: 122; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 123; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 124; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 125; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 126; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32 127; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 128; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 129; IS__TUNIT_OPM-NEXT: ret void 130; 131; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t1_caller 132; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 133; IS__TUNIT_NPM-NEXT: entry: 134; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 135; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 136; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 137; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 138; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32 139; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 140; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 141; IS__TUNIT_NPM-NEXT: ret void 142; 143; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t1_caller 144; IS__CGSCC_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 145; IS__CGSCC_OPM-NEXT: entry: 146; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 147; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 148; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 149; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 150; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32 151; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 152; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 noundef 99, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 153; IS__CGSCC_OPM-NEXT: ret void 154; 155; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t1_caller 156; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 157; IS__CGSCC_NPM-NEXT: entry: 158; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 159; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 160; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 161; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 162; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32 163; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 164; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 noundef 99, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 165; IS__CGSCC_NPM-NEXT: ret void 166; 167entry: 168 %b = alloca i32, align 32 169 %c = alloca i32*, align 64 170 %ptr = alloca i32, align 128 171 %0 = bitcast i32* %b to i8* 172 store i32 42, i32* %b, align 4 173 store i32* %b, i32** %c, align 8 174 call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* null, i32* %ptr, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* %a, i64 99, i32** %c) 175 ret void 176} 177 178; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! 179; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. 180define internal void @t1_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) { 181; 182; IS________OPM: Function Attrs: nosync 183; IS________OPM-LABEL: define {{[^@]+}}@t1_callback_callee 184; IS________OPM-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] { 185; IS________OPM-NEXT: entry: 186; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 187; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 188; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 189; IS________OPM-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 noundef 99, i32* nocapture [[TMP0]]) 190; IS________OPM-NEXT: ret void 191; 192; IS________NPM: Function Attrs: nosync 193; IS________NPM-LABEL: define {{[^@]+}}@t1_callback_callee 194; IS________NPM-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] { 195; IS________NPM-NEXT: entry: 196; IS________NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 197; IS________NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 198; IS________NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 199; IS________NPM-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 noundef 99, i32* nocapture [[TMP0]]) 200; IS________NPM-NEXT: ret void 201; 202entry: 203 %ptr_val = load i32, i32* %ptr, align 8 204 store i32 %ptr_val, i32* %is_not_null 205 %0 = load i32*, i32** %c, align 8 206 tail call void @t1_check(i32* %a, i64 %b, i32* %0) 207 ret void 208} 209 210declare void @t1_check(i32* nocapture align 256, i64, i32* nocapture) nosync 211 212declare !callback !0 void @t1_callback_broker(i32* nocapture , i32* nocapture , void (i32*, i32*, ...)* nocapture, ...) 213 214; Test 2 215; 216; Similar to test 1 but checking that the noalias is only placed if potential synchronization through @t2_check is preserved. 217 218define void @t2_caller(i32* noalias %a) { 219; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t2_caller 220; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 221; IS__TUNIT_OPM-NEXT: entry: 222; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 223; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 224; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 225; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 226; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32 227; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 228; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 229; IS__TUNIT_OPM-NEXT: ret void 230; 231; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t2_caller 232; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 233; IS__TUNIT_NPM-NEXT: entry: 234; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 235; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 236; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 237; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 238; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32 239; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 240; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 241; IS__TUNIT_NPM-NEXT: ret void 242; 243; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t2_caller 244; IS__CGSCC_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 245; IS__CGSCC_OPM-NEXT: entry: 246; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 247; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 248; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 249; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 250; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32 251; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 252; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 noundef 99, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 253; IS__CGSCC_OPM-NEXT: ret void 254; 255; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t2_caller 256; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 257; IS__CGSCC_NPM-NEXT: entry: 258; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 259; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 260; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 261; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 262; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32 263; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 264; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 noundef 99, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 265; IS__CGSCC_NPM-NEXT: ret void 266; 267entry: 268 %b = alloca i32, align 32 269 %c = alloca i32*, align 64 270 %ptr = alloca i32, align 128 271 %0 = bitcast i32* %b to i8* 272 store i32 42, i32* %b, align 4 273 store i32* %b, i32** %c, align 8 274 call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* null, i32* %ptr, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* %a, i64 99, i32** %c) 275 ret void 276} 277 278; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! 279; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. 280; 281; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls. 282define internal void @t2_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) { 283; 284; IS________OPM-LABEL: define {{[^@]+}}@t2_callback_callee 285; IS________OPM-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) { 286; IS________OPM-NEXT: entry: 287; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 288; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 289; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 290; IS________OPM-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 noundef 99, i32* nocapture [[TMP0]]) 291; IS________OPM-NEXT: ret void 292; 293; IS________NPM-LABEL: define {{[^@]+}}@t2_callback_callee 294; IS________NPM-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) { 295; IS________NPM-NEXT: entry: 296; IS________NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 297; IS________NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 298; IS________NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 299; IS________NPM-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 noundef 99, i32* nocapture [[TMP0]]) 300; IS________NPM-NEXT: ret void 301; 302entry: 303 %ptr_val = load i32, i32* %ptr, align 8 304 store i32 %ptr_val, i32* %is_not_null 305 %0 = load i32*, i32** %c, align 8 306 tail call void @t2_check(i32* %a, i64 %b, i32* %0) 307 ret void 308} 309 310declare void @t2_check(i32* nocapture align 256, i64, i32* nocapture) 311 312declare !callback !0 void @t2_callback_broker(i32* nocapture , i32* nocapture , void (i32*, i32*, ...)* nocapture, ...) 313 314; Test 3 315; 316; Basically test 2 with the casted callback callee used twice. 317 318define void @t3_caller(i32* noalias %a) { 319; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t3_caller 320; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 321; IS__TUNIT_OPM-NEXT: entry: 322; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 323; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 324; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 325; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 326; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32 327; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 328; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 329; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 330; IS__TUNIT_OPM-NEXT: ret void 331; 332; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t3_caller 333; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 334; IS__TUNIT_NPM-NEXT: entry: 335; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 336; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 337; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 338; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 339; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32 340; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 341; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 342; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 343; IS__TUNIT_NPM-NEXT: ret void 344; 345; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t3_caller 346; IS__CGSCC_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 347; IS__CGSCC_OPM-NEXT: entry: 348; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 349; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 350; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 351; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 352; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32 353; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 354; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 noundef 99, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 355; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 noundef 99, i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 356; IS__CGSCC_OPM-NEXT: ret void 357; 358; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t3_caller 359; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) { 360; IS__CGSCC_NPM-NEXT: entry: 361; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 362; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 363; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 364; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 365; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32 366; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 367; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 noundef 99, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 368; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias nocapture noundef align 536870912 null, i32* noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nocapture noundef bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 noundef 99, i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C]]) 369; IS__CGSCC_NPM-NEXT: ret void 370; 371entry: 372 %b = alloca i32, align 32 373 %c = alloca i32*, align 64 374 %ptr = alloca i32, align 128 375 %0 = bitcast i32* %b to i8* 376 store i32 42, i32* %b, align 4 377 store i32* %b, i32** %c, align 8 378 call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* null, i32* %ptr, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* %a, i64 99, i32** %c) 379 call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* null, i32* %ptr, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* %a, i64 99, i32** %c) 380 ret void 381} 382 383; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! 384; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. 385; 386; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls. 387define internal void @t3_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) { 388; 389; IS________OPM-LABEL: define {{[^@]+}}@t3_callback_callee 390; IS________OPM-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) { 391; IS________OPM-NEXT: entry: 392; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 393; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 394; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 395; IS________OPM-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 noundef 99, i32* nocapture [[TMP0]]) 396; IS________OPM-NEXT: ret void 397; 398; IS________NPM-LABEL: define {{[^@]+}}@t3_callback_callee 399; IS________NPM-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) { 400; IS________NPM-NEXT: entry: 401; IS________NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 402; IS________NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 403; IS________NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 404; IS________NPM-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 noundef 99, i32* nocapture [[TMP0]]) 405; IS________NPM-NEXT: ret void 406; 407entry: 408 %ptr_val = load i32, i32* %ptr, align 8 409 store i32 %ptr_val, i32* %is_not_null 410 %0 = load i32*, i32** %c, align 8 411 tail call void @t3_check(i32* %a, i64 %b, i32* %0) 412 ret void 413} 414 415declare void @t3_check(i32* nocapture align 256, i64, i32* nocapture) 416 417declare !callback !0 void @t3_callback_broker(i32* nocapture , i32* nocapture , void (i32*, i32*, ...)* nocapture, ...) 418 419!0 = !{!1} 420!1 = !{i64 2, i64 -1, i64 -1, i1 true} 421;. 422; CHECK: attributes #[[ATTR0:[0-9]+]] = { nosync } 423;. 424; CHECK: [[META0:![0-9]+]] = !{!1} 425; CHECK: [[META1:![0-9]+]] = !{i64 2, i64 -1, i64 -1, i1 true} 426;. 427