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 7; Determine dereference-ability before unused loads get deleted: 8; https://bugs.llvm.org/show_bug.cgi?id=21780 9 10define <4 x double> @PR21780(double* %ptr) { 11; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn 12; CHECK-LABEL: define {{[^@]+}}@PR21780 13; CHECK-SAME: (double* nocapture nofree noundef nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]]) #[[ATTR0:[0-9]+]] { 14; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds double, double* [[PTR]], i64 1 15; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds double, double* [[PTR]], i64 2 16; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds double, double* [[PTR]], i64 3 17; CHECK-NEXT: [[T0:%.*]] = load double, double* [[PTR]], align 8 18; CHECK-NEXT: [[T1:%.*]] = load double, double* [[ARRAYIDX1]], align 8 19; CHECK-NEXT: [[T2:%.*]] = load double, double* [[ARRAYIDX2]], align 8 20; CHECK-NEXT: [[T3:%.*]] = load double, double* [[ARRAYIDX3]], align 8 21; CHECK-NEXT: [[VECINIT0:%.*]] = insertelement <4 x double> undef, double [[T0]], i32 0 22; CHECK-NEXT: [[VECINIT1:%.*]] = insertelement <4 x double> [[VECINIT0]], double [[T1]], i32 1 23; CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x double> [[VECINIT1]], double [[T2]], i32 2 24; CHECK-NEXT: [[VECINIT3:%.*]] = insertelement <4 x double> [[VECINIT2]], double [[T3]], i32 3 25; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x double> [[VECINIT3]], <4 x double> [[VECINIT3]], <4 x i32> <i32 0, i32 0, i32 2, i32 2> 26; CHECK-NEXT: ret <4 x double> [[SHUFFLE]] 27; 28 29 ; GEP of index 0 is simplified away. 30 %arrayidx1 = getelementptr inbounds double, double* %ptr, i64 1 31 %arrayidx2 = getelementptr inbounds double, double* %ptr, i64 2 32 %arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3 33 34 %t0 = load double, double* %ptr, align 8 35 %t1 = load double, double* %arrayidx1, align 8 36 %t2 = load double, double* %arrayidx2, align 8 37 %t3 = load double, double* %arrayidx3, align 8 38 39 %vecinit0 = insertelement <4 x double> undef, double %t0, i32 0 40 %vecinit1 = insertelement <4 x double> %vecinit0, double %t1, i32 1 41 %vecinit2 = insertelement <4 x double> %vecinit1, double %t2, i32 2 42 %vecinit3 = insertelement <4 x double> %vecinit2, double %t3, i32 3 43 %shuffle = shufflevector <4 x double> %vecinit3, <4 x double> %vecinit3, <4 x i32> <i32 0, i32 0, i32 2, i32 2> 44 ret <4 x double> %shuffle 45} 46 47 48define double @PR21780_only_access3_with_inbounds(double* %ptr) { 49; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn 50; CHECK-LABEL: define {{[^@]+}}@PR21780_only_access3_with_inbounds 51; CHECK-SAME: (double* nocapture nofree nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]]) #[[ATTR0]] { 52; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds double, double* [[PTR]], i64 3 53; CHECK-NEXT: [[T3:%.*]] = load double, double* [[ARRAYIDX3]], align 8 54; CHECK-NEXT: ret double [[T3]] 55; 56 57 %arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3 58 %t3 = load double, double* %arrayidx3, align 8 59 ret double %t3 60} 61 62define double @PR21780_only_access3_without_inbounds(double* %ptr) { 63; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn 64; CHECK-LABEL: define {{[^@]+}}@PR21780_only_access3_without_inbounds 65; CHECK-SAME: (double* nocapture nofree readonly align 8 [[PTR:%.*]]) #[[ATTR0]] { 66; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr double, double* [[PTR]], i64 3 67; CHECK-NEXT: [[T3:%.*]] = load double, double* [[ARRAYIDX3]], align 8 68; CHECK-NEXT: ret double [[T3]] 69; 70 %arrayidx3 = getelementptr double, double* %ptr, i64 3 71 %t3 = load double, double* %arrayidx3, align 8 72 ret double %t3 73} 74 75define double @PR21780_without_inbounds(double* %ptr) { 76; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn 77; CHECK-LABEL: define {{[^@]+}}@PR21780_without_inbounds 78; CHECK-SAME: (double* nocapture nofree noundef nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]]) #[[ATTR0]] { 79; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr double, double* [[PTR]], i64 3 80; CHECK-NEXT: [[T3:%.*]] = load double, double* [[ARRAYIDX3]], align 8 81; CHECK-NEXT: ret double [[T3]] 82; 83 84 %arrayidx1 = getelementptr double, double* %ptr, i64 1 85 %arrayidx2 = getelementptr double, double* %ptr, i64 2 86 %arrayidx3 = getelementptr double, double* %ptr, i64 3 87 88 %t0 = load double, double* %ptr, align 8 89 %t1 = load double, double* %arrayidx1, align 8 90 %t2 = load double, double* %arrayidx2, align 8 91 %t3 = load double, double* %arrayidx3, align 8 92 93 ret double %t3 94} 95 96; Unsimplified, but still valid. Also, throw in some bogus arguments. 97 98define void @gep0(i8* %unused, i8* %other, i8* %ptr) { 99; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn 100; CHECK-LABEL: define {{[^@]+}}@gep0 101; CHECK-SAME: (i8* nocapture nofree readnone [[UNUSED:%.*]], i8* nocapture nofree noundef nonnull writeonly dereferenceable(1) [[OTHER:%.*]], i8* nocapture nofree nonnull readonly dereferenceable(3) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] { 102; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr i8, i8* [[PTR]], i64 2 103; CHECK-NEXT: [[T2:%.*]] = load i8, i8* [[ARRAYIDX2]], align 1 104; CHECK-NEXT: store i8 [[T2]], i8* [[OTHER]], align 1 105; CHECK-NEXT: ret void 106; 107 %arrayidx0 = getelementptr i8, i8* %ptr, i64 0 108 %arrayidx1 = getelementptr i8, i8* %ptr, i64 1 109 %arrayidx2 = getelementptr i8, i8* %ptr, i64 2 110 %t0 = load i8, i8* %arrayidx0 111 %t1 = load i8, i8* %arrayidx1 112 %t2 = load i8, i8* %arrayidx2 113 store i8 %t2, i8* %other 114 ret void 115} 116 117; Order of accesses does not change computation. 118; Multiple arguments may be dereferenceable. 119 120define void @ordering(i8* %ptr1, i32* %ptr2) { 121; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 122; CHECK-LABEL: define {{[^@]+}}@ordering 123; CHECK-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(3) [[PTR1:%.*]], i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) [[PTR2:%.*]]) #[[ATTR2:[0-9]+]] { 124; CHECK-NEXT: ret void 125; 126 %a20 = getelementptr i32, i32* %ptr2, i64 0 127 %a12 = getelementptr i8, i8* %ptr1, i64 2 128 %t12 = load i8, i8* %a12 129 %a11 = getelementptr i8, i8* %ptr1, i64 1 130 %t20 = load i32, i32* %a20 131 %a10 = getelementptr i8, i8* %ptr1, i64 0 132 %t10 = load i8, i8* %a10 133 %t11 = load i8, i8* %a11 134 %a21 = getelementptr i32, i32* %ptr2, i64 1 135 %t21 = load i32, i32* %a21 136 ret void 137} 138 139; Not in entry block. 140 141define void @not_entry_but_guaranteed_to_execute(i8* %ptr) { 142; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 143; CHECK-LABEL: define {{[^@]+}}@not_entry_but_guaranteed_to_execute 144; CHECK-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(3) [[PTR:%.*]]) #[[ATTR2]] { 145; CHECK-NEXT: entry: 146; CHECK-NEXT: br label [[EXIT:%.*]] 147; CHECK: exit: 148; CHECK-NEXT: ret void 149; 150entry: 151 br label %exit 152exit: 153 %arrayidx0 = getelementptr i8, i8* %ptr, i64 0 154 %arrayidx1 = getelementptr i8, i8* %ptr, i64 1 155 %arrayidx2 = getelementptr i8, i8* %ptr, i64 2 156 %t0 = load i8, i8* %arrayidx0 157 %t1 = load i8, i8* %arrayidx1 158 %t2 = load i8, i8* %arrayidx2 159 ret void 160} 161 162; Not in entry block and not guaranteed to execute. 163 164define void @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond) { 165; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 166; CHECK-LABEL: define {{[^@]+}}@not_entry_not_guaranteed_to_execute 167; CHECK-SAME: (i8* nocapture nofree readnone [[PTR:%.*]], i1 [[COND:%.*]]) #[[ATTR2]] { 168; CHECK-NEXT: entry: 169; CHECK-NEXT: br i1 [[COND]], label [[LOADS:%.*]], label [[EXIT:%.*]] 170; CHECK: loads: 171; CHECK-NEXT: ret void 172; CHECK: exit: 173; CHECK-NEXT: ret void 174; 175entry: 176 br i1 %cond, label %loads, label %exit 177loads: 178 %arrayidx0 = getelementptr i8, i8* %ptr, i64 0 179 %arrayidx1 = getelementptr i8, i8* %ptr, i64 1 180 %arrayidx2 = getelementptr i8, i8* %ptr, i64 2 181 %t0 = load i8, i8* %arrayidx0 182 %t1 = load i8, i8* %arrayidx1 183 %t2 = load i8, i8* %arrayidx2 184 ret void 185exit: 186 ret void 187} 188 189; The last load may not execute, so derefenceable bytes only covers the 1st two loads. 190 191define void @partial_in_entry(i16* %ptr, i1 %cond) { 192; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 193; CHECK-LABEL: define {{[^@]+}}@partial_in_entry 194; CHECK-SAME: (i16* nocapture nofree nonnull readnone align 2 dereferenceable(4) [[PTR:%.*]], i1 [[COND:%.*]]) #[[ATTR2]] { 195; CHECK-NEXT: entry: 196; CHECK-NEXT: br i1 [[COND]], label [[LOADS:%.*]], label [[EXIT:%.*]] 197; CHECK: loads: 198; CHECK-NEXT: ret void 199; CHECK: exit: 200; CHECK-NEXT: ret void 201; 202entry: 203 %arrayidx0 = getelementptr i16, i16* %ptr, i64 0 204 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 205 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 206 %t0 = load i16, i16* %arrayidx0 207 %t1 = load i16, i16* %arrayidx1 208 br i1 %cond, label %loads, label %exit 209loads: 210 %t2 = load i16, i16* %arrayidx2 211 ret void 212exit: 213 ret void 214} 215 216; The volatile load can't be used to prove a non-volatile access is allowed. 217; The 2nd and 3rd loads may never execute. 218 219define void @volatile_is_not_dereferenceable(i16* %ptr) { 220; CHECK: Function Attrs: argmemonly nofree norecurse nounwind willreturn 221; CHECK-LABEL: define {{[^@]+}}@volatile_is_not_dereferenceable 222; CHECK-SAME: (i16* nofree align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { 223; CHECK-NEXT: [[T0:%.*]] = load volatile i16, i16* [[PTR]], align 2 224; CHECK-NEXT: ret void 225; 226 %arrayidx0 = getelementptr i16, i16* %ptr, i64 0 227 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 228 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 229 %t0 = load volatile i16, i16* %arrayidx0 230 %t1 = load i16, i16* %arrayidx1 231 %t2 = load i16, i16* %arrayidx2 232 ret void 233} 234 235; TODO: We should allow inference for atomic (but not volatile) ops. 236 237define void @atomic_is_alright(i16* %ptr) { 238; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 239; CHECK-LABEL: define {{[^@]+}}@atomic_is_alright 240; CHECK-SAME: (i16* nocapture nofree nonnull readnone align 2 dereferenceable(6) [[PTR:%.*]]) #[[ATTR2]] { 241; CHECK-NEXT: ret void 242; 243 %arrayidx0 = getelementptr i16, i16* %ptr, i64 0 244 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 245 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 246 %t0 = load atomic i16, i16* %arrayidx0 unordered, align 2 247 %t1 = load i16, i16* %arrayidx1 248 %t2 = load i16, i16* %arrayidx2 249 ret void 250} 251 252declare void @may_not_return() 253 254define void @not_guaranteed_to_transfer_execution(i16* %ptr) { 255; CHECK-LABEL: define {{[^@]+}}@not_guaranteed_to_transfer_execution 256; CHECK-SAME: (i16* nocapture nofree nonnull readnone align 2 dereferenceable(2) [[PTR:%.*]]) { 257; CHECK-NEXT: call void @may_not_return() 258; CHECK-NEXT: ret void 259; 260 %arrayidx0 = getelementptr i16, i16* %ptr, i64 0 261 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 262 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 263 %t0 = load i16, i16* %arrayidx0 264 call void @may_not_return() 265 %t1 = load i16, i16* %arrayidx1 266 %t2 = load i16, i16* %arrayidx2 267 ret void 268} 269 270; We must have consecutive accesses. 271 272define void @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) { 273; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 274; CHECK-LABEL: define {{[^@]+}}@variable_gep_index 275; CHECK-SAME: (i8* nocapture nofree readnone [[UNUSED:%.*]], i8* nocapture nofree nonnull readnone dereferenceable(1) [[PTR:%.*]], i64 [[VARIABLE_INDEX:%.*]]) #[[ATTR2]] { 276; CHECK-NEXT: ret void 277; 278 %arrayidx1 = getelementptr i8, i8* %ptr, i64 %variable_index 279 %arrayidx2 = getelementptr i8, i8* %ptr, i64 2 280 %t0 = load i8, i8* %ptr 281 %t1 = load i8, i8* %arrayidx1 282 %t2 = load i8, i8* %arrayidx2 283 ret void 284} 285 286; Deal with >1 GEP index. 287 288define void @multi_index_gep(<4 x i8>* %ptr) { 289; FIXME: %ptr should be dereferenceable(4) 290; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 291; CHECK-LABEL: define {{[^@]+}}@multi_index_gep 292; CHECK-SAME: (<4 x i8>* nocapture nofree nonnull readnone dereferenceable(1) [[PTR:%.*]]) #[[ATTR2]] { 293; CHECK-NEXT: ret void 294; 295 %arrayidx00 = getelementptr <4 x i8>, <4 x i8>* %ptr, i64 0, i64 0 296 %t0 = load i8, i8* %arrayidx00 297 ret void 298} 299 300; Could round weird bitwidths down? 301 302define void @not_byte_multiple(i9* %ptr) { 303; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 304; CHECK-LABEL: define {{[^@]+}}@not_byte_multiple 305; CHECK-SAME: (i9* nocapture nofree nonnull readnone align 2 dereferenceable(2) [[PTR:%.*]]) #[[ATTR2]] { 306; CHECK-NEXT: ret void 307; 308 %arrayidx0 = getelementptr i9, i9* %ptr, i64 0 309 %t0 = load i9, i9* %arrayidx0 310 ret void 311} 312 313; Missing direct access from the pointer. 314 315define void @no_pointer_deref(i16* %ptr) { 316; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 317; CHECK-LABEL: define {{[^@]+}}@no_pointer_deref 318; CHECK-SAME: (i16* nocapture nofree readnone align 2 [[PTR:%.*]]) #[[ATTR2]] { 319; CHECK-NEXT: ret void 320; 321 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 322 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 323 %t1 = load i16, i16* %arrayidx1 324 %t2 = load i16, i16* %arrayidx2 325 ret void 326} 327 328; Out-of-order is ok, but missing access concludes dereferenceable range. 329 330define void @non_consecutive(i32* %ptr) { 331; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 332; CHECK-LABEL: define {{[^@]+}}@non_consecutive 333; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) [[PTR:%.*]]) #[[ATTR2]] { 334; CHECK-NEXT: ret void 335; 336 %arrayidx1 = getelementptr i32, i32* %ptr, i64 1 337 %arrayidx0 = getelementptr i32, i32* %ptr, i64 0 338 %arrayidx3 = getelementptr i32, i32* %ptr, i64 3 339 %t1 = load i32, i32* %arrayidx1 340 %t0 = load i32, i32* %arrayidx0 341 %t3 = load i32, i32* %arrayidx3 342 ret void 343} 344 345; Improve on existing dereferenceable attribute. 346 347define void @more_bytes(i32* dereferenceable(8) %ptr) { 348; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 349; CHECK-LABEL: define {{[^@]+}}@more_bytes 350; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(16) [[PTR:%.*]]) #[[ATTR2]] { 351; CHECK-NEXT: ret void 352; 353 %arrayidx3 = getelementptr i32, i32* %ptr, i64 3 354 %arrayidx1 = getelementptr i32, i32* %ptr, i64 1 355 %arrayidx0 = getelementptr i32, i32* %ptr, i64 0 356 %arrayidx2 = getelementptr i32, i32* %ptr, i64 2 357 %t3 = load i32, i32* %arrayidx3 358 %t1 = load i32, i32* %arrayidx1 359 %t2 = load i32, i32* %arrayidx2 360 %t0 = load i32, i32* %arrayidx0 361 ret void 362} 363 364; Improve on existing dereferenceable_or_null attribute. 365 366define void @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr) { 367; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 368; CHECK-LABEL: define {{[^@]+}}@more_bytes_and_not_null 369; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(16) [[PTR:%.*]]) #[[ATTR2]] { 370; CHECK-NEXT: ret void 371; 372 %arrayidx3 = getelementptr i32, i32* %ptr, i64 3 373 %arrayidx1 = getelementptr i32, i32* %ptr, i64 1 374 %arrayidx0 = getelementptr i32, i32* %ptr, i64 0 375 %arrayidx2 = getelementptr i32, i32* %ptr, i64 2 376 %t3 = load i32, i32* %arrayidx3 377 %t1 = load i32, i32* %arrayidx1 378 %t2 = load i32, i32* %arrayidx2 379 %t0 = load i32, i32* %arrayidx0 380 ret void 381} 382 383; But don't pessimize existing dereferenceable attribute. 384 385define void @better_bytes(i32* dereferenceable(100) %ptr) { 386; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 387; CHECK-LABEL: define {{[^@]+}}@better_bytes 388; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(100) [[PTR:%.*]]) #[[ATTR2]] { 389; CHECK-NEXT: ret void 390; 391 %arrayidx3 = getelementptr i32, i32* %ptr, i64 3 392 %arrayidx1 = getelementptr i32, i32* %ptr, i64 1 393 %arrayidx0 = getelementptr i32, i32* %ptr, i64 0 394 %arrayidx2 = getelementptr i32, i32* %ptr, i64 2 395 %t3 = load i32, i32* %arrayidx3 396 %t1 = load i32, i32* %arrayidx1 397 %t2 = load i32, i32* %arrayidx2 398 %t0 = load i32, i32* %arrayidx0 399 ret void 400} 401 402define void @bitcast(i32* %arg) { 403; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 404; CHECK-LABEL: define {{[^@]+}}@bitcast 405; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) [[ARG:%.*]]) #[[ATTR2]] { 406; CHECK-NEXT: ret void 407; 408 %ptr = bitcast i32* %arg to float* 409 %arrayidx0 = getelementptr float, float* %ptr, i64 0 410 %arrayidx1 = getelementptr float, float* %ptr, i64 1 411 %t0 = load float, float* %arrayidx0 412 %t1 = load float, float* %arrayidx1 413 ret void 414} 415 416define void @bitcast_different_sizes(double* %arg1, i8* %arg2) { 417; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 418; CHECK-LABEL: define {{[^@]+}}@bitcast_different_sizes 419; CHECK-SAME: (double* nocapture nofree nonnull readnone align 4 dereferenceable(12) [[ARG1:%.*]], i8* nocapture nofree nonnull readnone align 4 dereferenceable(16) [[ARG2:%.*]]) #[[ATTR2]] { 420; CHECK-NEXT: ret void 421; 422 %ptr1 = bitcast double* %arg1 to float* 423 %a10 = getelementptr float, float* %ptr1, i64 0 424 %a11 = getelementptr float, float* %ptr1, i64 1 425 %a12 = getelementptr float, float* %ptr1, i64 2 426 %ld10 = load float, float* %a10 427 %ld11 = load float, float* %a11 428 %ld12 = load float, float* %a12 429 430 %ptr2 = bitcast i8* %arg2 to i64* 431 %a20 = getelementptr i64, i64* %ptr2, i64 0 432 %a21 = getelementptr i64, i64* %ptr2, i64 1 433 %ld20 = load i64, i64* %a20 434 %ld21 = load i64, i64* %a21 435 ret void 436} 437 438define void @negative_offset(i32* %arg) { 439; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 440; CHECK-LABEL: define {{[^@]+}}@negative_offset 441; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[ARG:%.*]]) #[[ATTR2]] { 442; CHECK-NEXT: ret void 443; 444 %ptr = bitcast i32* %arg to float* 445 %arrayidx0 = getelementptr float, float* %ptr, i64 0 446 %arrayidx1 = getelementptr float, float* %ptr, i64 -1 447 %t0 = load float, float* %arrayidx0 448 %t1 = load float, float* %arrayidx1 449 ret void 450} 451 452define void @stores(i32* %arg) { 453; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly 454; CHECK-LABEL: define {{[^@]+}}@stores 455; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(8) [[ARG:%.*]]) #[[ATTR4:[0-9]+]] { 456; CHECK-NEXT: [[PTR:%.*]] = bitcast i32* [[ARG]] to float* 457; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr float, float* [[PTR]], i64 0 458; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr float, float* [[PTR]], i64 1 459; CHECK-NEXT: store float 1.000000e+00, float* [[ARRAYIDX0]], align 4 460; CHECK-NEXT: store float 2.000000e+00, float* [[ARRAYIDX1]], align 4 461; CHECK-NEXT: ret void 462; 463 %ptr = bitcast i32* %arg to float* 464 %arrayidx0 = getelementptr float, float* %ptr, i64 0 465 %arrayidx1 = getelementptr float, float* %ptr, i64 1 466 store float 1.0, float* %arrayidx0 467 store float 2.0, float* %arrayidx1 468 ret void 469} 470 471define void @load_store(i32* %arg) { 472; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly 473; CHECK-LABEL: define {{[^@]+}}@load_store 474; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] { 475; CHECK-NEXT: [[PTR:%.*]] = bitcast i32* [[ARG]] to float* 476; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr float, float* [[PTR]], i64 1 477; CHECK-NEXT: store float 2.000000e+00, float* [[ARRAYIDX1]], align 4 478; CHECK-NEXT: ret void 479; 480 %ptr = bitcast i32* %arg to float* 481 %arrayidx0 = getelementptr float, float* %ptr, i64 0 482 %arrayidx1 = getelementptr float, float* %ptr, i64 1 483 %t1 = load float, float* %arrayidx0 484 store float 2.0, float* %arrayidx1 485 ret void 486} 487 488define void @different_size1(i32* %arg) { 489; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly 490; CHECK-LABEL: define {{[^@]+}}@different_size1 491; CHECK-SAME: (i32* nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] { 492; CHECK-NEXT: [[ARG_CAST:%.*]] = bitcast i32* [[ARG]] to double* 493; CHECK-NEXT: store double 0.000000e+00, double* [[ARG_CAST]], align 8 494; CHECK-NEXT: store i32 0, i32* [[ARG]], align 8 495; CHECK-NEXT: ret void 496; 497 %arg-cast = bitcast i32* %arg to double* 498 store double 0.000000e+00, double* %arg-cast 499 store i32 0, i32* %arg 500 ret void 501} 502 503define void @different_size2(i32* %arg) { 504; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly 505; CHECK-LABEL: define {{[^@]+}}@different_size2 506; CHECK-SAME: (i32* nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] { 507; CHECK-NEXT: store i32 0, i32* [[ARG]], align 8 508; CHECK-NEXT: [[ARG_CAST:%.*]] = bitcast i32* [[ARG]] to double* 509; CHECK-NEXT: store double 0.000000e+00, double* [[ARG_CAST]], align 8 510; CHECK-NEXT: ret void 511; 512 store i32 0, i32* %arg 513 %arg-cast = bitcast i32* %arg to double* 514 store double 0.000000e+00, double* %arg-cast 515 ret void 516} 517 518; Make use of MustBeExecuted Explorer 519; 520; [CFG] 521; entry 522; / \ 523; l1 l2 524; | X | 525; l3 l4 526; \ / 527; l5 528; / \ 529; l6 l7 530; \ / 531; end 532; According to the above CFG, we can see that instructions in l5 Block must be executed. 533; Therefore, %p must be dereferenced. 534; 535; ATTRIBUTOR_CGSCC_NPM-LABEL: define i32 @require_cfg_analysis(i32 %c, i32* {{.*}} dereferenceable(4) %p) 536define i32 @require_cfg_analysis(i32 %c, i32* %p) { 537; IS________OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly 538; IS________OPM-LABEL: define {{[^@]+}}@require_cfg_analysis 539; IS________OPM-SAME: (i32 [[C:%.*]], i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR4]] { 540; IS________OPM-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C]], 0 541; IS________OPM-NEXT: br i1 [[TOBOOL1]], label [[L1:%.*]], label [[L2:%.*]] 542; IS________OPM: l1: 543; IS________OPM-NEXT: [[TOBOOL2:%.*]] = icmp eq i32 [[C]], 1 544; IS________OPM-NEXT: br i1 [[TOBOOL2]], label [[L3:%.*]], label [[L4:%.*]] 545; IS________OPM: l2: 546; IS________OPM-NEXT: [[TOBOOL3:%.*]] = icmp eq i32 [[C]], 2 547; IS________OPM-NEXT: br i1 [[TOBOOL3]], label [[L3]], label [[L4]] 548; IS________OPM: l3: 549; IS________OPM-NEXT: br label [[L5:%.*]] 550; IS________OPM: l4: 551; IS________OPM-NEXT: br label [[L5]] 552; IS________OPM: l5: 553; IS________OPM-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 4 554; IS________OPM-NEXT: br i1 [[TOBOOL4]], label [[L6:%.*]], label [[L7:%.*]] 555; IS________OPM: l6: 556; IS________OPM-NEXT: store i32 0, i32* [[P]], align 4 557; IS________OPM-NEXT: br label [[END:%.*]] 558; IS________OPM: l7: 559; IS________OPM-NEXT: store i32 1, i32* [[P]], align 4 560; IS________OPM-NEXT: br label [[END]] 561; IS________OPM: end: 562; IS________OPM-NEXT: ret i32 1 563; 564; IS________NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly 565; IS________NPM-LABEL: define {{[^@]+}}@require_cfg_analysis 566; IS________NPM-SAME: (i32 [[C:%.*]], i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR4]] { 567; IS________NPM-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C]], 0 568; IS________NPM-NEXT: br i1 [[TOBOOL1]], label [[L1:%.*]], label [[L2:%.*]] 569; IS________NPM: l1: 570; IS________NPM-NEXT: [[TOBOOL2:%.*]] = icmp eq i32 [[C]], 1 571; IS________NPM-NEXT: br i1 [[TOBOOL2]], label [[L3:%.*]], label [[L4:%.*]] 572; IS________NPM: l2: 573; IS________NPM-NEXT: [[TOBOOL3:%.*]] = icmp eq i32 [[C]], 2 574; IS________NPM-NEXT: br i1 [[TOBOOL3]], label [[L3]], label [[L4]] 575; IS________NPM: l3: 576; IS________NPM-NEXT: br label [[L5:%.*]] 577; IS________NPM: l4: 578; IS________NPM-NEXT: br label [[L5]] 579; IS________NPM: l5: 580; IS________NPM-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 4 581; IS________NPM-NEXT: br i1 [[TOBOOL4]], label [[L6:%.*]], label [[L7:%.*]] 582; IS________NPM: l6: 583; IS________NPM-NEXT: store i32 0, i32* [[P]], align 4 584; IS________NPM-NEXT: br label [[END:%.*]] 585; IS________NPM: l7: 586; IS________NPM-NEXT: store i32 1, i32* [[P]], align 4 587; IS________NPM-NEXT: br label [[END]] 588; IS________NPM: end: 589; IS________NPM-NEXT: ret i32 1 590; 591 %tobool1 = icmp eq i32 %c, 0 592 br i1 %tobool1, label %l1, label %l2 593l1: 594 %tobool2 = icmp eq i32 %c, 1 595 br i1 %tobool2, label %l3, label %l4 596l2: 597 %tobool3 = icmp eq i32 %c, 2 598 br i1 %tobool3, label %l3, label %l4 599l3: 600 br label %l5 601l4: 602 br label %l5 603l5: 604 %tobool4 = icmp eq i32 %c, 4 605 br i1 %tobool4, label %l6, label %l7 606l6: 607 store i32 0, i32* %p 608 br label %end 609l7: 610 store i32 1, i32* %p 611 br label %end 612end: 613 ret i32 1 614} 615;. 616; CHECK: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind readonly willreturn } 617; CHECK: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind willreturn } 618; CHECK: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind readnone willreturn } 619; CHECK: attributes #[[ATTR3]] = { argmemonly nofree norecurse nounwind willreturn } 620; CHECK: attributes #[[ATTR4]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } 621;. 622