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