574 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC4 5; Determine dereference-ability before unused loads get deleted:6; https://bugs.llvm.org/show_bug.cgi?id=217807 8define <4 x double> @PR21780(ptr %ptr) {9; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)10; CHECK-LABEL: define {{[^@]+}}@PR2178011; CHECK-SAME: (ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(32) [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {12; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds double, ptr [[PTR]], i64 113; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds double, ptr [[PTR]], i64 214; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds double, ptr [[PTR]], i64 315; CHECK-NEXT: [[T0:%.*]] = load double, ptr [[PTR]], align 816; CHECK-NEXT: [[T1:%.*]] = load double, ptr [[ARRAYIDX1]], align 817; CHECK-NEXT: [[T2:%.*]] = load double, ptr [[ARRAYIDX2]], align 818; CHECK-NEXT: [[T3:%.*]] = load double, ptr [[ARRAYIDX3]], align 819; CHECK-NEXT: [[VECINIT0:%.*]] = insertelement <4 x double> undef, double [[T0]], i32 020; CHECK-NEXT: [[VECINIT1:%.*]] = insertelement <4 x double> [[VECINIT0]], double [[T1]], i32 121; CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x double> [[VECINIT1]], double [[T2]], i32 222; CHECK-NEXT: [[VECINIT3:%.*]] = insertelement <4 x double> [[VECINIT2]], double [[T3]], i32 323; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x double> [[VECINIT3]], <4 x double> [[VECINIT3]], <4 x i32> <i32 0, i32 0, i32 2, i32 2>24; CHECK-NEXT: ret <4 x double> [[SHUFFLE]]25;26 27 ; GEP of index 0 is simplified away.28 %arrayidx1 = getelementptr inbounds double, ptr %ptr, i64 129 %arrayidx2 = getelementptr inbounds double, ptr %ptr, i64 230 %arrayidx3 = getelementptr inbounds double, ptr %ptr, i64 331 32 %t0 = load double, ptr %ptr, align 833 %t1 = load double, ptr %arrayidx1, align 834 %t2 = load double, ptr %arrayidx2, align 835 %t3 = load double, ptr %arrayidx3, align 836 37 %vecinit0 = insertelement <4 x double> undef, double %t0, i32 038 %vecinit1 = insertelement <4 x double> %vecinit0, double %t1, i32 139 %vecinit2 = insertelement <4 x double> %vecinit1, double %t2, i32 240 %vecinit3 = insertelement <4 x double> %vecinit2, double %t3, i32 341 %shuffle = shufflevector <4 x double> %vecinit3, <4 x double> %vecinit3, <4 x i32> <i32 0, i32 0, i32 2, i32 2>42 ret <4 x double> %shuffle43}44 45 46define double @PR21780_only_access3_with_inbounds(ptr %ptr) {47; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)48; CHECK-LABEL: define {{[^@]+}}@PR21780_only_access3_with_inbounds49; CHECK-SAME: (ptr nofree nonnull readonly align 8 captures(none) dereferenceable(32) [[PTR:%.*]]) #[[ATTR0]] {50; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds double, ptr [[PTR]], i64 351; CHECK-NEXT: [[T3:%.*]] = load double, ptr [[ARRAYIDX3]], align 852; CHECK-NEXT: ret double [[T3]]53;54 55 %arrayidx3 = getelementptr inbounds double, ptr %ptr, i64 356 %t3 = load double, ptr %arrayidx3, align 857 ret double %t358}59 60define double @PR21780_only_access3_without_inbounds(ptr %ptr) {61; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)62; CHECK-LABEL: define {{[^@]+}}@PR21780_only_access3_without_inbounds63; CHECK-SAME: (ptr nofree readonly align 8 captures(none) [[PTR:%.*]]) #[[ATTR0]] {64; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr double, ptr [[PTR]], i64 365; CHECK-NEXT: [[T3:%.*]] = load double, ptr [[ARRAYIDX3]], align 866; CHECK-NEXT: ret double [[T3]]67;68 %arrayidx3 = getelementptr double, ptr %ptr, i64 369 %t3 = load double, ptr %arrayidx3, align 870 ret double %t371}72 73define double @PR21780_without_inbounds(ptr %ptr) {74; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)75; CHECK-LABEL: define {{[^@]+}}@PR21780_without_inbounds76; CHECK-SAME: (ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(32) [[PTR:%.*]]) #[[ATTR0]] {77; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr double, ptr [[PTR]], i64 378; CHECK-NEXT: [[T3:%.*]] = load double, ptr [[ARRAYIDX3]], align 879; CHECK-NEXT: ret double [[T3]]80;81 82 %arrayidx1 = getelementptr double, ptr %ptr, i64 183 %arrayidx2 = getelementptr double, ptr %ptr, i64 284 %arrayidx3 = getelementptr double, ptr %ptr, i64 385 86 %t0 = load double, ptr %ptr, align 887 %t1 = load double, ptr %arrayidx1, align 888 %t2 = load double, ptr %arrayidx2, align 889 %t3 = load double, ptr %arrayidx3, align 890 91 ret double %t392}93 94; Unsimplified, but still valid. Also, throw in some bogus arguments.95 96define void @gep0(ptr %unused, ptr %other, ptr %ptr) {97; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)98; CHECK-LABEL: define {{[^@]+}}@gep099; CHECK-SAME: (ptr nofree readnone captures(none) [[UNUSED:%.*]], ptr nofree noundef nonnull writeonly captures(none) dereferenceable(1) [[OTHER:%.*]], ptr nofree nonnull readonly captures(none) dereferenceable(3) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] {100; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr i8, ptr [[PTR]], i64 2101; CHECK-NEXT: [[T2:%.*]] = load i8, ptr [[ARRAYIDX2]], align 1102; CHECK-NEXT: store i8 [[T2]], ptr [[OTHER]], align 1103; CHECK-NEXT: ret void104;105 %arrayidx0 = getelementptr i8, ptr %ptr, i64 0106 %arrayidx1 = getelementptr i8, ptr %ptr, i64 1107 %arrayidx2 = getelementptr i8, ptr %ptr, i64 2108 %t0 = load i8, ptr %arrayidx0109 %t1 = load i8, ptr %arrayidx1110 %t2 = load i8, ptr %arrayidx2111 store i8 %t2, ptr %other112 ret void113}114 115; Order of accesses does not change computation.116; Multiple arguments may be dereferenceable.117 118define void @ordering(ptr %ptr1, ptr %ptr2) {119; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)120; CHECK-LABEL: define {{[^@]+}}@ordering121; CHECK-SAME: (ptr nofree noundef nonnull readnone captures(none) dereferenceable(3) [[PTR1:%.*]], ptr nofree nonnull readnone align 4 captures(none) dereferenceable(8) [[PTR2:%.*]]) #[[ATTR2:[0-9]+]] {122; CHECK-NEXT: ret void123;124 %a20 = getelementptr i32, ptr %ptr2, i64 0125 %a12 = getelementptr i8, ptr %ptr1, i64 2126 %t12 = load i8, ptr %a12127 %a11 = getelementptr i8, ptr %ptr1, i64 1128 %t20 = load i32, ptr %a20129 %t10 = load i8, ptr %ptr1130 %t11 = load i8, ptr %a11131 %a21 = getelementptr i32, ptr %ptr2, i64 1132 %t21 = load i32, ptr %a21133 ret void134}135 136; Not in entry block.137 138define void @not_entry_but_guaranteed_to_execute(ptr %ptr) {139; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)140; CHECK-LABEL: define {{[^@]+}}@not_entry_but_guaranteed_to_execute141; CHECK-SAME: (ptr nofree nonnull readnone captures(none) dereferenceable(3) [[PTR:%.*]]) #[[ATTR2]] {142; CHECK-NEXT: entry:143; CHECK-NEXT: br label [[EXIT:%.*]]144; CHECK: exit:145; CHECK-NEXT: ret void146;147entry:148 br label %exit149exit:150 %arrayidx1 = getelementptr i8, ptr %ptr, i64 1151 %arrayidx2 = getelementptr i8, ptr %ptr, i64 2152 %t0 = load i8, ptr %ptr153 %t1 = load i8, ptr %arrayidx1154 %t2 = load i8, ptr %arrayidx2155 ret void156}157 158; Not in entry block and not guaranteed to execute.159 160define void @not_entry_not_guaranteed_to_execute(ptr %ptr, i1 %cond) {161; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)162; CHECK-LABEL: define {{[^@]+}}@not_entry_not_guaranteed_to_execute163; CHECK-SAME: (ptr nofree readnone captures(none) [[PTR:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR2]] {164; CHECK-NEXT: entry:165; CHECK-NEXT: br i1 [[COND]], label [[LOADS:%.*]], label [[EXIT:%.*]]166; CHECK: loads:167; CHECK-NEXT: ret void168; CHECK: exit:169; CHECK-NEXT: ret void170;171entry:172 br i1 %cond, label %loads, label %exit173loads:174 %arrayidx1 = getelementptr i8, ptr %ptr, i64 1175 %arrayidx2 = getelementptr i8, ptr %ptr, i64 2176 %t0 = load i8, ptr %ptr177 %t1 = load i8, ptr %arrayidx1178 %t2 = load i8, ptr %arrayidx2179 ret void180exit:181 ret void182}183 184; The last load may not execute, so derefenceable bytes only covers the 1st two loads.185 186define void @partial_in_entry(ptr %ptr, i1 %cond) {187; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)188; CHECK-LABEL: define {{[^@]+}}@partial_in_entry189; CHECK-SAME: (ptr nofree noundef nonnull readnone align 2 captures(none) dereferenceable(4) [[PTR:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR2]] {190; CHECK-NEXT: entry:191; CHECK-NEXT: br i1 [[COND]], label [[LOADS:%.*]], label [[EXIT:%.*]]192; CHECK: loads:193; CHECK-NEXT: ret void194; CHECK: exit:195; CHECK-NEXT: ret void196;197entry:198 %arrayidx1 = getelementptr i16, ptr %ptr, i64 1199 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2200 %t0 = load i16, ptr %ptr201 %t1 = load i16, ptr %arrayidx1202 br i1 %cond, label %loads, label %exit203loads:204 %t2 = load i16, ptr %arrayidx2205 ret void206exit:207 ret void208}209 210; The volatile load can't be used to prove a non-volatile access is allowed.211; The 2nd and 3rd loads may never execute.212 213define void @volatile_is_not_dereferenceable(ptr %ptr) {214; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)215; CHECK-LABEL: define {{[^@]+}}@volatile_is_not_dereferenceable216; CHECK-SAME: (ptr nofree align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] {217; CHECK-NEXT: [[T0:%.*]] = load volatile i16, ptr [[PTR]], align 2218; CHECK-NEXT: ret void219;220 %arrayidx0 = getelementptr i16, ptr %ptr, i64 0221 %arrayidx1 = getelementptr i16, ptr %ptr, i64 1222 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2223 %t0 = load volatile i16, ptr %arrayidx0224 %t1 = load i16, ptr %arrayidx1225 %t2 = load i16, ptr %arrayidx2226 ret void227}228 229; TODO: We should allow inference for atomic (but not volatile) ops.230 231define void @atomic_is_alright(ptr %ptr) {232; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)233; CHECK-LABEL: define {{[^@]+}}@atomic_is_alright234; CHECK-SAME: (ptr nofree nonnull readnone align 2 captures(none) dereferenceable(6) [[PTR:%.*]]) #[[ATTR2]] {235; CHECK-NEXT: ret void236;237 %arrayidx0 = getelementptr i16, ptr %ptr, i64 0238 %arrayidx1 = getelementptr i16, ptr %ptr, i64 1239 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2240 %t0 = load atomic i16, ptr %arrayidx0 unordered, align 2241 %t1 = load i16, ptr %arrayidx1242 %t2 = load i16, ptr %arrayidx2243 ret void244}245 246declare void @may_not_return()247 248define void @not_guaranteed_to_transfer_execution(ptr %ptr) {249; CHECK-LABEL: define {{[^@]+}}@not_guaranteed_to_transfer_execution250; CHECK-SAME: (ptr nofree nonnull readnone align 2 captures(none) dereferenceable(2) [[PTR:%.*]]) {251; CHECK-NEXT: call void @may_not_return()252; CHECK-NEXT: ret void253;254 %arrayidx0 = getelementptr i16, ptr %ptr, i64 0255 %arrayidx1 = getelementptr i16, ptr %ptr, i64 1256 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2257 %t0 = load i16, ptr %arrayidx0258 call void @may_not_return()259 %t1 = load i16, ptr %arrayidx1260 %t2 = load i16, ptr %arrayidx2261 ret void262}263 264; We must have consecutive accesses.265 266define void @variable_gep_index(ptr %unused, ptr %ptr, i64 %variable_index) {267; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)268; CHECK-LABEL: define {{[^@]+}}@variable_gep_index269; CHECK-SAME: (ptr nofree readnone captures(none) [[UNUSED:%.*]], ptr nofree noundef nonnull readnone captures(none) dereferenceable(1) [[PTR:%.*]], i64 [[VARIABLE_INDEX:%.*]]) #[[ATTR2]] {270; CHECK-NEXT: ret void271;272 %arrayidx1 = getelementptr i8, ptr %ptr, i64 %variable_index273 %arrayidx2 = getelementptr i8, ptr %ptr, i64 2274 %t0 = load i8, ptr %ptr275 %t1 = load i8, ptr %arrayidx1276 %t2 = load i8, ptr %arrayidx2277 ret void278}279 280; Deal with >1 GEP index.281 282define void @multi_index_gep(ptr %ptr) {283; FIXME: %ptr should be dereferenceable(4)284; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)285; CHECK-LABEL: define {{[^@]+}}@multi_index_gep286; CHECK-SAME: (ptr nofree nonnull readnone captures(none) dereferenceable(1) [[PTR:%.*]]) #[[ATTR2]] {287; CHECK-NEXT: ret void288;289 %arrayidx00 = getelementptr <4 x i8>, ptr %ptr, i64 0, i64 0290 %t0 = load i8, ptr %arrayidx00291 ret void292}293 294; Could round weird bitwidths down?295 296define void @not_byte_multiple(ptr %ptr) {297; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)298; CHECK-LABEL: define {{[^@]+}}@not_byte_multiple299; CHECK-SAME: (ptr nofree nonnull readnone align 2 captures(none) dereferenceable(2) [[PTR:%.*]]) #[[ATTR2]] {300; CHECK-NEXT: ret void301;302 %arrayidx0 = getelementptr i9, ptr %ptr, i64 0303 %t0 = load i9, ptr %arrayidx0304 ret void305}306 307; Missing direct access from the pointer.308 309define void @no_pointer_deref(ptr %ptr) {310; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)311; CHECK-LABEL: define {{[^@]+}}@no_pointer_deref312; CHECK-SAME: (ptr nofree readnone align 2 captures(none) [[PTR:%.*]]) #[[ATTR2]] {313; CHECK-NEXT: ret void314;315 %arrayidx1 = getelementptr i16, ptr %ptr, i64 1316 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2317 %t1 = load i16, ptr %arrayidx1318 %t2 = load i16, ptr %arrayidx2319 ret void320}321 322; Out-of-order is ok, but missing access concludes dereferenceable range.323 324define void @non_consecutive(ptr %ptr) {325; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)326; CHECK-LABEL: define {{[^@]+}}@non_consecutive327; CHECK-SAME: (ptr nofree noundef nonnull readnone align 4 captures(none) dereferenceable(8) [[PTR:%.*]]) #[[ATTR2]] {328; CHECK-NEXT: ret void329;330 %arrayidx1 = getelementptr i32, ptr %ptr, i64 1331 %arrayidx3 = getelementptr i32, ptr %ptr, i64 3332 %t1 = load i32, ptr %arrayidx1333 %t0 = load i32, ptr %ptr334 %t3 = load i32, ptr %arrayidx3335 ret void336}337 338; Improve on existing dereferenceable attribute.339 340define void @more_bytes(ptr dereferenceable(8) %ptr) {341; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)342; CHECK-LABEL: define {{[^@]+}}@more_bytes343; CHECK-SAME: (ptr nofree noundef nonnull readnone align 4 captures(none) dereferenceable(16) [[PTR:%.*]]) #[[ATTR2]] {344; CHECK-NEXT: ret void345;346 %arrayidx3 = getelementptr i32, ptr %ptr, i64 3347 %arrayidx1 = getelementptr i32, ptr %ptr, i64 1348 %arrayidx2 = getelementptr i32, ptr %ptr, i64 2349 %t3 = load i32, ptr %arrayidx3350 %t1 = load i32, ptr %arrayidx1351 %t2 = load i32, ptr %arrayidx2352 %t0 = load i32, ptr %ptr353 ret void354}355 356; Improve on existing dereferenceable_or_null attribute.357 358define void @more_bytes_and_not_null(ptr dereferenceable_or_null(8) %ptr) {359; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)360; CHECK-LABEL: define {{[^@]+}}@more_bytes_and_not_null361; CHECK-SAME: (ptr nofree noundef nonnull readnone align 4 captures(none) dereferenceable(16) [[PTR:%.*]]) #[[ATTR2]] {362; CHECK-NEXT: ret void363;364 %arrayidx3 = getelementptr i32, ptr %ptr, i64 3365 %arrayidx1 = getelementptr i32, ptr %ptr, i64 1366 %arrayidx2 = getelementptr i32, ptr %ptr, i64 2367 %t3 = load i32, ptr %arrayidx3368 %t1 = load i32, ptr %arrayidx1369 %t2 = load i32, ptr %arrayidx2370 %t0 = load i32, ptr %ptr371 ret void372}373 374; But don't pessimize existing dereferenceable attribute.375 376define void @better_bytes(ptr dereferenceable(100) %ptr) {377; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)378; CHECK-LABEL: define {{[^@]+}}@better_bytes379; CHECK-SAME: (ptr nofree noundef nonnull readnone align 4 captures(none) dereferenceable(100) [[PTR:%.*]]) #[[ATTR2]] {380; CHECK-NEXT: ret void381;382 %arrayidx3 = getelementptr i32, ptr %ptr, i64 3383 %arrayidx1 = getelementptr i32, ptr %ptr, i64 1384 %arrayidx2 = getelementptr i32, ptr %ptr, i64 2385 %t3 = load i32, ptr %arrayidx3386 %t1 = load i32, ptr %arrayidx1387 %t2 = load i32, ptr %arrayidx2388 %t0 = load i32, ptr %ptr389 ret void390}391 392define void @bitcast(ptr %arg) {393; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)394; CHECK-LABEL: define {{[^@]+}}@bitcast395; CHECK-SAME: (ptr nofree nonnull readnone align 4 captures(none) dereferenceable(8) [[ARG:%.*]]) #[[ATTR2]] {396; CHECK-NEXT: ret void397;398 %ptr = bitcast ptr %arg to ptr399 %arrayidx1 = getelementptr float, ptr %ptr, i64 1400 %t0 = load float, ptr %ptr401 %t1 = load float, ptr %arrayidx1402 ret void403}404 405define void @bitcast_different_sizes(ptr %arg1, ptr %arg2) {406; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)407; CHECK-LABEL: define {{[^@]+}}@bitcast_different_sizes408; CHECK-SAME: (ptr nofree nonnull readnone align 4 captures(none) dereferenceable(12) [[ARG1:%.*]], ptr nofree noundef nonnull readnone align 4 captures(none) dereferenceable(16) [[ARG2:%.*]]) #[[ATTR2]] {409; CHECK-NEXT: ret void410;411 %ptr1 = bitcast ptr %arg1 to ptr412 %a11 = getelementptr float, ptr %ptr1, i64 1413 %a12 = getelementptr float, ptr %ptr1, i64 2414 %ld10 = load float, ptr %ptr1415 %ld11 = load float, ptr %a11416 %ld12 = load float, ptr %a12417 418 %a21 = getelementptr i64, ptr %arg2, i64 1419 %ld20 = load i64, ptr %arg2420 %ld21 = load i64, ptr %a21421 ret void422}423 424define void @negative_offset(ptr %arg) {425; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)426; CHECK-LABEL: define {{[^@]+}}@negative_offset427; CHECK-SAME: (ptr nofree nonnull readnone align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR2]] {428; CHECK-NEXT: ret void429;430 %ptr = bitcast ptr %arg to ptr431 %arrayidx1 = getelementptr float, ptr %ptr, i64 -1432 %t0 = load float, ptr %ptr433 %t1 = load float, ptr %arrayidx1434 ret void435}436 437define void @stores(ptr %arg) {438; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)439; CHECK-LABEL: define {{[^@]+}}@stores440; CHECK-SAME: (ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(8) [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {441; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr float, ptr [[ARG]], i64 1442; CHECK-NEXT: store float 1.000000e+00, ptr [[ARG]], align 4443; CHECK-NEXT: store float 2.000000e+00, ptr [[ARRAYIDX1]], align 4444; CHECK-NEXT: ret void445;446 %ptr = bitcast ptr %arg to ptr447 %arrayidx1 = getelementptr float, ptr %ptr, i64 1448 store float 1.0, ptr %ptr449 store float 2.0, ptr %arrayidx1450 ret void451}452 453define void @load_store(ptr %arg) {454; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)455; CHECK-LABEL: define {{[^@]+}}@load_store456; CHECK-SAME: (ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] {457; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr float, ptr [[ARG]], i64 1458; CHECK-NEXT: store float 2.000000e+00, ptr [[ARRAYIDX1]], align 4459; CHECK-NEXT: ret void460;461 %ptr = bitcast ptr %arg to ptr462 %arrayidx1 = getelementptr float, ptr %ptr, i64 1463 %t1 = load float, ptr %ptr464 store float 2.0, ptr %arrayidx1465 ret void466}467 468define void @different_size1(ptr %arg) {469; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)470; CHECK-LABEL: define {{[^@]+}}@different_size1471; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 8 captures(none) dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] {472; CHECK-NEXT: store double 0.000000e+00, ptr [[ARG]], align 8473; CHECK-NEXT: store i32 0, ptr [[ARG]], align 8474; CHECK-NEXT: ret void475;476 %arg-cast = bitcast ptr %arg to ptr477 store double 0.000000e+00, ptr %arg-cast478 store i32 0, ptr %arg479 ret void480}481 482define void @different_size2(ptr %arg) {483; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)484; CHECK-LABEL: define {{[^@]+}}@different_size2485; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 8 captures(none) dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] {486; CHECK-NEXT: store i32 0, ptr [[ARG]], align 8487; CHECK-NEXT: store double 0.000000e+00, ptr [[ARG]], align 8488; CHECK-NEXT: ret void489;490 store i32 0, ptr %arg491 store double 0.000000e+00, ptr %arg492 ret void493}494 495; Make use of MustBeExecuted Explorer496;497; [CFG]498; entry499; / \500; l1 l2501; | X |502; l3 l4503; \ /504; l5505; / \506; l6 l7507; \ /508; end509; According to the above CFG, we can see that instructions in l5 Block must be executed.510; Therefore, %p must be dereferenced.511;512; ATTRIBUTOR_CGSCC_NPM-LABEL: define i32 @require_cfg_analysis(i32 %c, ptr {{.*}} dereferenceable(4) %p)513define i32 @require_cfg_analysis(i32 %c, ptr %p) {514; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)515; CHECK-LABEL: define {{[^@]+}}@require_cfg_analysis516; CHECK-SAME: (i32 [[C:%.*]], ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR4]] {517; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C]], 0518; CHECK-NEXT: br i1 [[TOBOOL1]], label [[L1:%.*]], label [[L2:%.*]]519; CHECK: l1:520; CHECK-NEXT: br label [[L4:%.*]]521; CHECK: l2:522; CHECK-NEXT: [[TOBOOL3:%.*]] = icmp eq i32 [[C]], 2523; CHECK-NEXT: br i1 [[TOBOOL3]], label [[L3:%.*]], label [[L4]]524; CHECK: l3:525; CHECK-NEXT: br label [[L5:%.*]]526; CHECK: l4:527; CHECK-NEXT: br label [[L5]]528; CHECK: l5:529; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 4530; CHECK-NEXT: br i1 [[TOBOOL4]], label [[L6:%.*]], label [[L7:%.*]]531; CHECK: l6:532; CHECK-NEXT: store i32 0, ptr [[P]], align 4533; CHECK-NEXT: br label [[END:%.*]]534; CHECK: l7:535; CHECK-NEXT: store i32 1, ptr [[P]], align 4536; CHECK-NEXT: br label [[END]]537; CHECK: end:538; CHECK-NEXT: ret i32 1539;540 %tobool1 = icmp eq i32 %c, 0541 br i1 %tobool1, label %l1, label %l2542l1:543 %tobool2 = icmp eq i32 %c, 1544 br i1 %tobool2, label %l3, label %l4545l2:546 %tobool3 = icmp eq i32 %c, 2547 br i1 %tobool3, label %l3, label %l4548l3:549 br label %l5550l4:551 br label %l5552l5:553 %tobool4 = icmp eq i32 %c, 4554 br i1 %tobool4, label %l6, label %l7555l6:556 store i32 0, ptr %p557 br label %end558l7:559 store i32 1, ptr %p560 br label %end561end:562 ret i32 1563}564;.565; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }566; CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }567; CHECK: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }568; CHECK: attributes #[[ATTR3]] = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) }569; CHECK: attributes #[[ATTR4]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }570;.571;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:572; CGSCC: {{.*}}573; TUNIT: {{.*}}574