1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes 2; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -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-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -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 -attributor-manifest-internal -attributor-disable=false -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-disable=false -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 align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 undef, i32** nocapture 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 align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 undef, i32** noalias nocapture 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* [[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 align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull 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 align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 99, i32** noalias nocapture 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 nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture 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 99, i32* [[TMP0]]) 89; IS________OPM-NEXT: ret void 90; 91; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t0_callback_callee 92; IS__TUNIT_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) 93; IS__TUNIT_NPM-NEXT: entry: 94; IS__TUNIT_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 95; IS__TUNIT_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 96; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 97; IS__TUNIT_NPM-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 99, i32* [[TMP0]]) 98; IS__TUNIT_NPM-NEXT: ret void 99; 100; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t0_callback_callee 101; IS__CGSCC_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 8 dereferenceable(8) [[C:%.*]]) 102; IS__CGSCC_NPM-NEXT: entry: 103; IS__CGSCC_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 104; IS__CGSCC_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 105; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 8 106; IS__CGSCC_NPM-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 99, i32* [[TMP0]]) 107; IS__CGSCC_NPM-NEXT: ret void 108; 109entry: 110 %ptr_val = load i32, i32* %ptr, align 8 111 store i32 %ptr_val, i32* %is_not_null 112 %0 = load i32*, i32** %c, align 8 113 tail call void @t0_check(i32* %a, i64 %b, i32* %0) 114 ret void 115} 116 117declare void @t0_check(i32* align 256, i64, i32*) 118 119declare !callback !0 void @t0_callback_broker(i32*, i32*, void (i32*, i32*, ...)*, ...) 120 121; Test 1 122; 123; Similar to test 0 but with some additional annotations (noalias/nocapute) to make sure 124; we deduce and propagate noalias and others properly. 125 126define void @t1_caller(i32* noalias %a) { 127; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t1_caller 128; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 129; IS__TUNIT_OPM-NEXT: entry: 130; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 131; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 132; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 133; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 134; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32 135; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 136; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 137; IS__TUNIT_OPM-NEXT: ret void 138; 139; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t1_caller 140; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 141; IS__TUNIT_NPM-NEXT: entry: 142; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 143; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 144; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 145; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 146; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32 147; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 148; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 149; IS__TUNIT_NPM-NEXT: ret void 150; 151; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t1_caller 152; IS__CGSCC_OPM-SAME: (i32* noalias [[A:%.*]]) 153; IS__CGSCC_OPM-NEXT: entry: 154; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 155; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 156; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 157; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 158; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32 159; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 160; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]]) 161; IS__CGSCC_OPM-NEXT: ret void 162; 163; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t1_caller 164; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 165; IS__CGSCC_NPM-NEXT: entry: 166; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 167; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 168; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 169; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 170; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32 171; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 172; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 173; IS__CGSCC_NPM-NEXT: ret void 174; 175entry: 176 %b = alloca i32, align 32 177 %c = alloca i32*, align 64 178 %ptr = alloca i32, align 128 179 %0 = bitcast i32* %b to i8* 180 store i32 42, i32* %b, align 4 181 store i32* %b, i32** %c, align 8 182 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) 183 ret void 184} 185 186; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! 187; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. 188define internal void @t1_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) { 189; 190; IS________OPM-LABEL: define {{[^@]+}}@t1_callback_callee 191; IS________OPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) 192; IS________OPM-NEXT: entry: 193; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 194; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 195; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 196; IS________OPM-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 197; IS________OPM-NEXT: ret void 198; 199; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t1_callback_callee 200; IS__TUNIT_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* noalias nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) 201; IS__TUNIT_NPM-NEXT: entry: 202; IS__TUNIT_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 203; IS__TUNIT_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 204; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 205; IS__TUNIT_NPM-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 206; IS__TUNIT_NPM-NEXT: ret void 207; 208; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t1_callback_callee 209; IS__CGSCC_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 8 dereferenceable(8) [[C:%.*]]) 210; IS__CGSCC_NPM-NEXT: entry: 211; IS__CGSCC_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 212; IS__CGSCC_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 213; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 8 214; IS__CGSCC_NPM-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 215; IS__CGSCC_NPM-NEXT: ret void 216; 217entry: 218 %ptr_val = load i32, i32* %ptr, align 8 219 store i32 %ptr_val, i32* %is_not_null 220 %0 = load i32*, i32** %c, align 8 221 tail call void @t1_check(i32* %a, i64 %b, i32* %0) 222 ret void 223} 224 225declare void @t1_check(i32* nocapture align 256, i64, i32* nocapture) nosync 226 227declare !callback !0 void @t1_callback_broker(i32* nocapture , i32* nocapture , void (i32*, i32*, ...)* nocapture, ...) 228 229; Test 2 230; 231; Similar to test 1 but checking that the noalias is only placed if potential synchronization through @t2_check is preserved. 232 233define void @t2_caller(i32* noalias %a) { 234; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t2_caller 235; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 236; IS__TUNIT_OPM-NEXT: entry: 237; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 238; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 239; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 240; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 241; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32 242; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 243; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 244; IS__TUNIT_OPM-NEXT: ret void 245; 246; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t2_caller 247; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 248; IS__TUNIT_NPM-NEXT: entry: 249; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 250; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 251; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 252; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 253; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32 254; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 255; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 256; IS__TUNIT_NPM-NEXT: ret void 257; 258; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t2_caller 259; IS__CGSCC_OPM-SAME: (i32* noalias [[A:%.*]]) 260; IS__CGSCC_OPM-NEXT: entry: 261; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 262; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 263; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 264; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 265; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32 266; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 267; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]]) 268; IS__CGSCC_OPM-NEXT: ret void 269; 270; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t2_caller 271; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 272; IS__CGSCC_NPM-NEXT: entry: 273; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 274; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 275; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 276; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 277; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32 278; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 279; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 280; IS__CGSCC_NPM-NEXT: ret void 281; 282entry: 283 %b = alloca i32, align 32 284 %c = alloca i32*, align 64 285 %ptr = alloca i32, align 128 286 %0 = bitcast i32* %b to i8* 287 store i32 42, i32* %b, align 4 288 store i32* %b, i32** %c, align 8 289 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) 290 ret void 291} 292 293; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! 294; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. 295; 296; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls. 297define internal void @t2_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) { 298; 299; IS________OPM-LABEL: define {{[^@]+}}@t2_callback_callee 300; IS________OPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) 301; IS________OPM-NEXT: entry: 302; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 303; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 304; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 305; IS________OPM-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 306; IS________OPM-NEXT: ret void 307; 308; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t2_callback_callee 309; IS__TUNIT_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) 310; IS__TUNIT_NPM-NEXT: entry: 311; IS__TUNIT_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 312; IS__TUNIT_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 313; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 314; IS__TUNIT_NPM-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 315; IS__TUNIT_NPM-NEXT: ret void 316; 317; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t2_callback_callee 318; IS__CGSCC_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 8 dereferenceable(8) [[C:%.*]]) 319; IS__CGSCC_NPM-NEXT: entry: 320; IS__CGSCC_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 321; IS__CGSCC_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 322; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 8 323; IS__CGSCC_NPM-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 324; IS__CGSCC_NPM-NEXT: ret void 325; 326entry: 327 %ptr_val = load i32, i32* %ptr, align 8 328 store i32 %ptr_val, i32* %is_not_null 329 %0 = load i32*, i32** %c, align 8 330 tail call void @t2_check(i32* %a, i64 %b, i32* %0) 331 ret void 332} 333 334declare void @t2_check(i32* nocapture align 256, i64, i32* nocapture) 335 336declare !callback !0 void @t2_callback_broker(i32* nocapture , i32* nocapture , void (i32*, i32*, ...)* nocapture, ...) 337 338; Test 3 339; 340; Basically test 2 with the casted callback callee used twice. 341 342define void @t3_caller(i32* noalias %a) { 343; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t3_caller 344; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 345; IS__TUNIT_OPM-NEXT: entry: 346; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 347; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 348; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 349; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 350; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32 351; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 352; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 353; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 354; IS__TUNIT_OPM-NEXT: ret void 355; 356; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t3_caller 357; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 358; IS__TUNIT_NPM-NEXT: entry: 359; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 360; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 361; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 362; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 363; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32 364; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 365; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 366; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 367; IS__TUNIT_NPM-NEXT: ret void 368; 369; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t3_caller 370; IS__CGSCC_OPM-SAME: (i32* noalias [[A:%.*]]) 371; IS__CGSCC_OPM-NEXT: entry: 372; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32 373; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64 374; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 375; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 376; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32 377; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64 378; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]]) 379; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]]) 380; IS__CGSCC_OPM-NEXT: ret void 381; 382; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t3_caller 383; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]]) 384; IS__CGSCC_NPM-NEXT: entry: 385; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32 386; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64 387; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128 388; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* 389; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32 390; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64 391; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 392; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]]) 393; IS__CGSCC_NPM-NEXT: ret void 394; 395entry: 396 %b = alloca i32, align 32 397 %c = alloca i32*, align 64 398 %ptr = alloca i32, align 128 399 %0 = bitcast i32* %b to i8* 400 store i32 42, i32* %b, align 4 401 store i32* %b, i32** %c, align 8 402 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) 403 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) 404 ret void 405} 406 407; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! 408; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. 409; 410; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls. 411define internal void @t3_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) { 412; 413; IS________OPM-LABEL: define {{[^@]+}}@t3_callback_callee 414; IS________OPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) 415; IS________OPM-NEXT: entry: 416; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 417; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 418; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 419; IS________OPM-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 420; IS________OPM-NEXT: ret void 421; 422; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t3_callback_callee 423; IS__TUNIT_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) 424; IS__TUNIT_NPM-NEXT: entry: 425; IS__TUNIT_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 426; IS__TUNIT_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 427; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64 428; IS__TUNIT_NPM-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 429; IS__TUNIT_NPM-NEXT: ret void 430; 431; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t3_callback_callee 432; IS__CGSCC_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 8 dereferenceable(8) [[C:%.*]]) 433; IS__CGSCC_NPM-NEXT: entry: 434; IS__CGSCC_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8 435; IS__CGSCC_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4 436; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 8 437; IS__CGSCC_NPM-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]]) 438; IS__CGSCC_NPM-NEXT: ret void 439; 440entry: 441 %ptr_val = load i32, i32* %ptr, align 8 442 store i32 %ptr_val, i32* %is_not_null 443 %0 = load i32*, i32** %c, align 8 444 tail call void @t3_check(i32* %a, i64 %b, i32* %0) 445 ret void 446} 447 448declare void @t3_check(i32* nocapture align 256, i64, i32* nocapture) 449 450declare !callback !0 void @t3_callback_broker(i32* nocapture , i32* nocapture , void (i32*, i32*, ...)* nocapture, ...) 451 452!0 = !{!1} 453!1 = !{i64 2, i64 -1, i64 -1, i1 true} 454