; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC ; Determine dereference-ability before unused loads get deleted: ; https://bugs.llvm.org/show_bug.cgi?id=21780 define <4 x double> @PR21780(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: define {{[^@]+}}@PR21780 ; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds double, ptr [[PTR]], i64 1 ; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds double, ptr [[PTR]], i64 2 ; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds double, ptr [[PTR]], i64 3 ; CHECK-NEXT: [[T0:%.*]] = load double, ptr [[PTR]], align 8 ; CHECK-NEXT: [[T1:%.*]] = load double, ptr [[ARRAYIDX1]], align 8 ; CHECK-NEXT: [[T2:%.*]] = load double, ptr [[ARRAYIDX2]], align 8 ; CHECK-NEXT: [[T3:%.*]] = load double, ptr [[ARRAYIDX3]], align 8 ; CHECK-NEXT: [[VECINIT0:%.*]] = insertelement <4 x double> undef, double [[T0]], i32 0 ; CHECK-NEXT: [[VECINIT1:%.*]] = insertelement <4 x double> [[VECINIT0]], double [[T1]], i32 1 ; CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x double> [[VECINIT1]], double [[T2]], i32 2 ; CHECK-NEXT: [[VECINIT3:%.*]] = insertelement <4 x double> [[VECINIT2]], double [[T3]], i32 3 ; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x double> [[VECINIT3]], <4 x double> [[VECINIT3]], <4 x i32> ; CHECK-NEXT: ret <4 x double> [[SHUFFLE]] ; ; GEP of index 0 is simplified away. %arrayidx1 = getelementptr inbounds double, ptr %ptr, i64 1 %arrayidx2 = getelementptr inbounds double, ptr %ptr, i64 2 %arrayidx3 = getelementptr inbounds double, ptr %ptr, i64 3 %t0 = load double, ptr %ptr, align 8 %t1 = load double, ptr %arrayidx1, align 8 %t2 = load double, ptr %arrayidx2, align 8 %t3 = load double, ptr %arrayidx3, align 8 %vecinit0 = insertelement <4 x double> undef, double %t0, i32 0 %vecinit1 = insertelement <4 x double> %vecinit0, double %t1, i32 1 %vecinit2 = insertelement <4 x double> %vecinit1, double %t2, i32 2 %vecinit3 = insertelement <4 x double> %vecinit2, double %t3, i32 3 %shuffle = shufflevector <4 x double> %vecinit3, <4 x double> %vecinit3, <4 x i32> ret <4 x double> %shuffle } define double @PR21780_only_access3_with_inbounds(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: define {{[^@]+}}@PR21780_only_access3_with_inbounds ; CHECK-SAME: (ptr nocapture nofree nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds double, ptr [[PTR]], i64 3 ; CHECK-NEXT: [[T3:%.*]] = load double, ptr [[ARRAYIDX3]], align 8 ; CHECK-NEXT: ret double [[T3]] ; %arrayidx3 = getelementptr inbounds double, ptr %ptr, i64 3 %t3 = load double, ptr %arrayidx3, align 8 ret double %t3 } define double @PR21780_only_access3_without_inbounds(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: define {{[^@]+}}@PR21780_only_access3_without_inbounds ; CHECK-SAME: (ptr nocapture nofree readonly align 8 [[PTR:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr double, ptr [[PTR]], i64 3 ; CHECK-NEXT: [[T3:%.*]] = load double, ptr [[ARRAYIDX3]], align 8 ; CHECK-NEXT: ret double [[T3]] ; %arrayidx3 = getelementptr double, ptr %ptr, i64 3 %t3 = load double, ptr %arrayidx3, align 8 ret double %t3 } define double @PR21780_without_inbounds(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: define {{[^@]+}}@PR21780_without_inbounds ; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr double, ptr [[PTR]], i64 3 ; CHECK-NEXT: [[T3:%.*]] = load double, ptr [[ARRAYIDX3]], align 8 ; CHECK-NEXT: ret double [[T3]] ; %arrayidx1 = getelementptr double, ptr %ptr, i64 1 %arrayidx2 = getelementptr double, ptr %ptr, i64 2 %arrayidx3 = getelementptr double, ptr %ptr, i64 3 %t0 = load double, ptr %ptr, align 8 %t1 = load double, ptr %arrayidx1, align 8 %t2 = load double, ptr %arrayidx2, align 8 %t3 = load double, ptr %arrayidx3, align 8 ret double %t3 } ; Unsimplified, but still valid. Also, throw in some bogus arguments. define void @gep0(ptr %unused, ptr %other, ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@gep0 ; CHECK-SAME: (ptr nocapture nofree readnone [[UNUSED:%.*]], ptr nocapture nofree noundef nonnull writeonly dereferenceable(1) [[OTHER:%.*]], ptr nocapture nofree nonnull readonly dereferenceable(3) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr i8, ptr [[PTR]], i64 2 ; CHECK-NEXT: [[T2:%.*]] = load i8, ptr [[ARRAYIDX2]], align 1 ; CHECK-NEXT: store i8 [[T2]], ptr [[OTHER]], align 1 ; CHECK-NEXT: ret void ; %arrayidx0 = getelementptr i8, ptr %ptr, i64 0 %arrayidx1 = getelementptr i8, ptr %ptr, i64 1 %arrayidx2 = getelementptr i8, ptr %ptr, i64 2 %t0 = load i8, ptr %arrayidx0 %t1 = load i8, ptr %arrayidx1 %t2 = load i8, ptr %arrayidx2 store i8 %t2, ptr %other ret void } ; Order of accesses does not change computation. ; Multiple arguments may be dereferenceable. define void @ordering(ptr %ptr1, ptr %ptr2) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@ordering ; CHECK-SAME: (ptr nocapture nofree noundef nonnull readnone dereferenceable(3) [[PTR1:%.*]], ptr nocapture nofree nonnull readnone align 4 dereferenceable(8) [[PTR2:%.*]]) #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: ret void ; %a20 = getelementptr i32, ptr %ptr2, i64 0 %a12 = getelementptr i8, ptr %ptr1, i64 2 %t12 = load i8, ptr %a12 %a11 = getelementptr i8, ptr %ptr1, i64 1 %t20 = load i32, ptr %a20 %t10 = load i8, ptr %ptr1 %t11 = load i8, ptr %a11 %a21 = getelementptr i32, ptr %ptr2, i64 1 %t21 = load i32, ptr %a21 ret void } ; Not in entry block. define void @not_entry_but_guaranteed_to_execute(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@not_entry_but_guaranteed_to_execute ; CHECK-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(3) [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br label %exit exit: %arrayidx1 = getelementptr i8, ptr %ptr, i64 1 %arrayidx2 = getelementptr i8, ptr %ptr, i64 2 %t0 = load i8, ptr %ptr %t1 = load i8, ptr %arrayidx1 %t2 = load i8, ptr %arrayidx2 ret void } ; Not in entry block and not guaranteed to execute. define void @not_entry_not_guaranteed_to_execute(ptr %ptr, i1 %cond) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@not_entry_not_guaranteed_to_execute ; CHECK-SAME: (ptr nocapture nofree readnone [[PTR:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[COND]], label [[LOADS:%.*]], label [[EXIT:%.*]] ; CHECK: loads: ; CHECK-NEXT: ret void ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br i1 %cond, label %loads, label %exit loads: %arrayidx1 = getelementptr i8, ptr %ptr, i64 1 %arrayidx2 = getelementptr i8, ptr %ptr, i64 2 %t0 = load i8, ptr %ptr %t1 = load i8, ptr %arrayidx1 %t2 = load i8, ptr %arrayidx2 ret void exit: ret void } ; The last load may not execute, so derefenceable bytes only covers the 1st two loads. define void @partial_in_entry(ptr %ptr, i1 %cond) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@partial_in_entry ; CHECK-SAME: (ptr nocapture nofree noundef nonnull readnone align 2 dereferenceable(4) [[PTR:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[COND]], label [[LOADS:%.*]], label [[EXIT:%.*]] ; CHECK: loads: ; CHECK-NEXT: ret void ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: %arrayidx1 = getelementptr i16, ptr %ptr, i64 1 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2 %t0 = load i16, ptr %ptr %t1 = load i16, ptr %arrayidx1 br i1 %cond, label %loads, label %exit loads: %t2 = load i16, ptr %arrayidx2 ret void exit: ret void } ; The volatile load can't be used to prove a non-volatile access is allowed. ; The 2nd and 3rd loads may never execute. define void @volatile_is_not_dereferenceable(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@volatile_is_not_dereferenceable ; CHECK-SAME: (ptr nofree align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { ; CHECK-NEXT: [[T0:%.*]] = load volatile i16, ptr [[PTR]], align 2 ; CHECK-NEXT: ret void ; %arrayidx0 = getelementptr i16, ptr %ptr, i64 0 %arrayidx1 = getelementptr i16, ptr %ptr, i64 1 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2 %t0 = load volatile i16, ptr %arrayidx0 %t1 = load i16, ptr %arrayidx1 %t2 = load i16, ptr %arrayidx2 ret void } ; TODO: We should allow inference for atomic (but not volatile) ops. define void @atomic_is_alright(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@atomic_is_alright ; CHECK-SAME: (ptr nocapture nofree nonnull readnone align 2 dereferenceable(6) [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx0 = getelementptr i16, ptr %ptr, i64 0 %arrayidx1 = getelementptr i16, ptr %ptr, i64 1 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2 %t0 = load atomic i16, ptr %arrayidx0 unordered, align 2 %t1 = load i16, ptr %arrayidx1 %t2 = load i16, ptr %arrayidx2 ret void } declare void @may_not_return() define void @not_guaranteed_to_transfer_execution(ptr %ptr) { ; CHECK-LABEL: define {{[^@]+}}@not_guaranteed_to_transfer_execution ; CHECK-SAME: (ptr nocapture nofree nonnull readnone align 2 dereferenceable(2) [[PTR:%.*]]) { ; CHECK-NEXT: call void @may_not_return() ; CHECK-NEXT: ret void ; %arrayidx0 = getelementptr i16, ptr %ptr, i64 0 %arrayidx1 = getelementptr i16, ptr %ptr, i64 1 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2 %t0 = load i16, ptr %arrayidx0 call void @may_not_return() %t1 = load i16, ptr %arrayidx1 %t2 = load i16, ptr %arrayidx2 ret void } ; We must have consecutive accesses. define void @variable_gep_index(ptr %unused, ptr %ptr, i64 %variable_index) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@variable_gep_index ; CHECK-SAME: (ptr nocapture nofree readnone [[UNUSED:%.*]], ptr nocapture nofree noundef nonnull readnone dereferenceable(1) [[PTR:%.*]], i64 [[VARIABLE_INDEX:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx1 = getelementptr i8, ptr %ptr, i64 %variable_index %arrayidx2 = getelementptr i8, ptr %ptr, i64 2 %t0 = load i8, ptr %ptr %t1 = load i8, ptr %arrayidx1 %t2 = load i8, ptr %arrayidx2 ret void } ; Deal with >1 GEP index. define void @multi_index_gep(ptr %ptr) { ; FIXME: %ptr should be dereferenceable(4) ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@multi_index_gep ; CHECK-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(1) [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx00 = getelementptr <4 x i8>, <4 x i8>* %ptr, i64 0, i64 0 %t0 = load i8, ptr %arrayidx00 ret void } ; Could round weird bitwidths down? define void @not_byte_multiple(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@not_byte_multiple ; CHECK-SAME: (ptr nocapture nofree nonnull readnone align 2 dereferenceable(2) [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx0 = getelementptr i9, ptr %ptr, i64 0 %t0 = load i9, ptr %arrayidx0 ret void } ; Missing direct access from the pointer. define void @no_pointer_deref(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@no_pointer_deref ; CHECK-SAME: (ptr nocapture nofree readnone align 2 [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx1 = getelementptr i16, ptr %ptr, i64 1 %arrayidx2 = getelementptr i16, ptr %ptr, i64 2 %t1 = load i16, ptr %arrayidx1 %t2 = load i16, ptr %arrayidx2 ret void } ; Out-of-order is ok, but missing access concludes dereferenceable range. define void @non_consecutive(ptr %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@non_consecutive ; CHECK-SAME: (ptr nocapture nofree noundef nonnull readnone align 4 dereferenceable(8) [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx1 = getelementptr i32, ptr %ptr, i64 1 %arrayidx3 = getelementptr i32, ptr %ptr, i64 3 %t1 = load i32, ptr %arrayidx1 %t0 = load i32, ptr %ptr %t3 = load i32, ptr %arrayidx3 ret void } ; Improve on existing dereferenceable attribute. define void @more_bytes(ptr dereferenceable(8) %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@more_bytes ; CHECK-SAME: (ptr nocapture nofree noundef nonnull readnone align 4 dereferenceable(16) [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx3 = getelementptr i32, ptr %ptr, i64 3 %arrayidx1 = getelementptr i32, ptr %ptr, i64 1 %arrayidx2 = getelementptr i32, ptr %ptr, i64 2 %t3 = load i32, ptr %arrayidx3 %t1 = load i32, ptr %arrayidx1 %t2 = load i32, ptr %arrayidx2 %t0 = load i32, ptr %ptr ret void } ; Improve on existing dereferenceable_or_null attribute. define void @more_bytes_and_not_null(ptr dereferenceable_or_null(8) %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@more_bytes_and_not_null ; CHECK-SAME: (ptr nocapture nofree noundef nonnull readnone align 4 dereferenceable(16) [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx3 = getelementptr i32, ptr %ptr, i64 3 %arrayidx1 = getelementptr i32, ptr %ptr, i64 1 %arrayidx2 = getelementptr i32, ptr %ptr, i64 2 %t3 = load i32, ptr %arrayidx3 %t1 = load i32, ptr %arrayidx1 %t2 = load i32, ptr %arrayidx2 %t0 = load i32, ptr %ptr ret void } ; But don't pessimize existing dereferenceable attribute. define void @better_bytes(ptr dereferenceable(100) %ptr) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@better_bytes ; CHECK-SAME: (ptr nocapture nofree noundef nonnull readnone align 4 dereferenceable(100) [[PTR:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %arrayidx3 = getelementptr i32, ptr %ptr, i64 3 %arrayidx1 = getelementptr i32, ptr %ptr, i64 1 %arrayidx2 = getelementptr i32, ptr %ptr, i64 2 %t3 = load i32, ptr %arrayidx3 %t1 = load i32, ptr %arrayidx1 %t2 = load i32, ptr %arrayidx2 %t0 = load i32, ptr %ptr ret void } define void @bitcast(ptr %arg) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@bitcast ; CHECK-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(8) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %ptr = bitcast ptr %arg to ptr %arrayidx1 = getelementptr float, ptr %ptr, i64 1 %t0 = load float, ptr %ptr %t1 = load float, ptr %arrayidx1 ret void } define void @bitcast_different_sizes(ptr %arg1, ptr %arg2) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@bitcast_different_sizes ; CHECK-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(12) [[ARG1:%.*]], ptr nocapture nofree noundef nonnull readnone align 4 dereferenceable(16) [[ARG2:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %ptr1 = bitcast ptr %arg1 to ptr %a11 = getelementptr float, ptr %ptr1, i64 1 %a12 = getelementptr float, ptr %ptr1, i64 2 %ld10 = load float, ptr %ptr1 %ld11 = load float, ptr %a11 %ld12 = load float, ptr %a12 %a21 = getelementptr i64, ptr %arg2, i64 1 %ld20 = load i64, ptr %arg2 %ld21 = load i64, ptr %a21 ret void } define void @negative_offset(ptr %arg) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@negative_offset ; CHECK-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(4) [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret void ; %ptr = bitcast ptr %arg to ptr %arrayidx1 = getelementptr float, ptr %ptr, i64 -1 %t0 = load float, ptr %ptr %t1 = load float, ptr %arrayidx1 ret void } define void @stores(ptr %arg) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@stores ; CHECK-SAME: (ptr nocapture nofree nonnull writeonly align 4 dereferenceable(8) [[ARG:%.*]]) #[[ATTR4:[0-9]+]] { ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr float, ptr [[ARG]], i64 1 ; CHECK-NEXT: store float 1.000000e+00, ptr [[ARG]], align 4 ; CHECK-NEXT: store float 2.000000e+00, ptr [[ARRAYIDX1]], align 4 ; CHECK-NEXT: ret void ; %ptr = bitcast ptr %arg to ptr %arrayidx1 = getelementptr float, ptr %ptr, i64 1 store float 1.0, ptr %ptr store float 2.0, ptr %arrayidx1 ret void } define void @load_store(ptr %arg) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@load_store ; CHECK-SAME: (ptr nocapture nofree nonnull writeonly align 4 dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] { ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr float, ptr [[ARG]], i64 1 ; CHECK-NEXT: store float 2.000000e+00, ptr [[ARRAYIDX1]], align 4 ; CHECK-NEXT: ret void ; %ptr = bitcast ptr %arg to ptr %arrayidx1 = getelementptr float, ptr %ptr, i64 1 %t1 = load float, ptr %ptr store float 2.0, ptr %arrayidx1 ret void } define void @different_size1(ptr %arg) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@different_size1 ; CHECK-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] { ; CHECK-NEXT: store double 0.000000e+00, ptr [[ARG]], align 8 ; CHECK-NEXT: store i32 0, ptr [[ARG]], align 8 ; CHECK-NEXT: ret void ; %arg-cast = bitcast ptr %arg to ptr store double 0.000000e+00, ptr %arg-cast store i32 0, ptr %arg ret void } define void @different_size2(ptr %arg) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@different_size2 ; CHECK-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR4]] { ; CHECK-NEXT: store i32 0, ptr [[ARG]], align 8 ; CHECK-NEXT: store double 0.000000e+00, ptr [[ARG]], align 8 ; CHECK-NEXT: ret void ; store i32 0, ptr %arg store double 0.000000e+00, ptr %arg ret void } ; Make use of MustBeExecuted Explorer ; ; [CFG] ; entry ; / \ ; l1 l2 ; | X | ; l3 l4 ; \ / ; l5 ; / \ ; l6 l7 ; \ / ; end ; According to the above CFG, we can see that instructions in l5 Block must be executed. ; Therefore, %p must be dereferenced. ; ; ATTRIBUTOR_CGSCC_NPM-LABEL: define i32 @require_cfg_analysis(i32 %c, ptr {{.*}} dereferenceable(4) %p) define i32 @require_cfg_analysis(i32 %c, ptr %p) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@require_cfg_analysis ; CHECK-SAME: (i32 [[C:%.*]], ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR4]] { ; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C]], 0 ; CHECK-NEXT: br i1 [[TOBOOL1]], label [[L1:%.*]], label [[L2:%.*]] ; CHECK: l1: ; CHECK-NEXT: br label [[L4:%.*]] ; CHECK: l2: ; CHECK-NEXT: [[TOBOOL3:%.*]] = icmp eq i32 [[C]], 2 ; CHECK-NEXT: br i1 [[TOBOOL3]], label [[L3:%.*]], label [[L4]] ; CHECK: l3: ; CHECK-NEXT: br label [[L5:%.*]] ; CHECK: l4: ; CHECK-NEXT: br label [[L5]] ; CHECK: l5: ; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 4 ; CHECK-NEXT: br i1 [[TOBOOL4]], label [[L6:%.*]], label [[L7:%.*]] ; CHECK: l6: ; CHECK-NEXT: store i32 0, ptr [[P]], align 4 ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: l7: ; CHECK-NEXT: store i32 1, ptr [[P]], align 4 ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: ret i32 1 ; %tobool1 = icmp eq i32 %c, 0 br i1 %tobool1, label %l1, label %l2 l1: %tobool2 = icmp eq i32 %c, 1 br i1 %tobool2, label %l3, label %l4 l2: %tobool3 = icmp eq i32 %c, 2 br i1 %tobool3, label %l3, label %l4 l3: br label %l5 l4: br label %l5 l5: %tobool4 = icmp eq i32 %c, 4 br i1 %tobool4, label %l6, label %l7 l6: store i32 0, ptr %p br label %end l7: store i32 1, ptr %p br label %end end: ret i32 1 } ;. ; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) } ; CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) } ; CHECK: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } ; CHECK: attributes #[[ATTR3]] = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) } ; CHECK: attributes #[[ATTR4]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) } ;. ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: ; CGSCC: {{.*}} ; TUNIT: {{.*}}