llvm-project/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll
Sameer Sahasrabuddhe 6a2305484e [AAPointerInfo] track multiple constant offsets for each use
An expression of the form `gep(base, select(pred, const1, const2))` can result
in a set of offsets instead of just one. PointerInfo can now track these sets
instead of conservatively modeling them as Unknown. In general, AAPointerInfo
now uses AAPotentialConstantValues to examine the operands of the GEP.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D138646
2022-12-13 22:27:25 +05:30

343 lines
17 KiB
LLVM

; 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-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -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
%struct.T = type { i32, [10 x [20 x i8]] }
define i8 @select_offsets_simplifiable_1(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_1
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
; CHECK-NEXT: store i8 23, i8* [[GEP23]], align 4
; CHECK-NEXT: [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 29
; CHECK-NEXT: store i8 29, i8* [[GEP29]], align 4
; CHECK-NEXT: [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
; CHECK-NEXT: store i8 7, i8* [[GEP7]], align 4
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 31
; CHECK-NEXT: [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP_SEL]], align 4
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
store i8 23, i8* %gep23, align 4
%gep29 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 29
store i8 29, i8* %gep29, align 4
%gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
store i8 7, i8* %gep7, align 4
;; This store is redundant, hence removed.
%gep31 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 31
store i8 42, i8* %gep31, align 4
%sel0 = select i1 %cnd1, i64 23, i64 29
%sel1 = select i1 %cnd2, i64 %sel0, i64 7
%gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
%i = load i8, i8* %gep.sel, align 4
ret i8 %i
}
define i8 @select_offsets_simplifiable_2(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_2
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
; CHECK-NEXT: store i8 23, i8* [[GEP23]], align 4
; CHECK-NEXT: [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 29
; CHECK-NEXT: store i8 29, i8* [[GEP29]], align 4
; CHECK-NEXT: [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
; CHECK-NEXT: store i8 7, i8* [[GEP7]], align 4
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 31
; CHECK-NEXT: [[SEL0:%.*]] = select i1 [[CND1]], i64 20, i64 26
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 4
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
; CHECK-NEXT: [[GEP_PLUS:%.*]] = getelementptr inbounds i8, i8* [[GEP_SEL]], i64 3
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP_PLUS]], align 4
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
store i8 23, i8* %gep23, align 4
%gep29 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 29
store i8 29, i8* %gep29, align 4
%gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
store i8 7, i8* %gep7, align 4
;; This store is redundant, hence removed.
%gep31 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 31
store i8 42, i8* %gep31, align 4
;; Adjust the offsets so that they match the stores after adding 3
%sel0 = select i1 %cnd1, i64 20, i64 26
%sel1 = select i1 %cnd2, i64 %sel0, i64 4
%gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
%gep.plus = getelementptr inbounds i8, i8* %gep.sel, i64 3
%i = load i8, i8* %gep.plus, align 4
ret i8 %i
}
define i8 @select_offsets_simplifiable_3(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_3
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUNDLE:%.*]] = alloca [[STRUCT_T:%.*]], align 64
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CND1]], i64 1, i64 3
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CND2]], i64 5, i64 11
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [[STRUCT_T]], %struct.T* [[BUNDLE]], i64 0, i32 1, i64 [[SEL1]], i64 [[SEL2]]
; CHECK-NEXT: ret i8 100
;
entry:
%bundle = alloca %struct.T, align 64
%gep.fixed = getelementptr inbounds %struct.T, %struct.T* %bundle, i64 0, i32 1, i64 1, i64 1
store i8 100, i8* %gep.fixed, align 4
%sel1 = select i1 %cnd1, i64 1, i64 3
%sel2 = select i1 %cnd2, i64 5, i64 11
%gep.sel = getelementptr inbounds %struct.T, %struct.T* %bundle, i64 0, i32 1, i64 %sel1, i64 %sel2
store i8 42, i8* %gep.sel, align 4
%i = load i8, i8* %gep.fixed, align 4
ret i8 %i
}
define i8 @select_offsets_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_1
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
; CHECK-NEXT: store i8 100, i8* [[GEP23]], align 4
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP_SEL]], align 4
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%sel0 = select i1 %cnd1, i64 23, i64 29
%sel1 = select i1 %cnd2, i64 %sel0, i64 7
%gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
store i8 100, i8* %gep23, align 4
%gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
%i = load i8, i8* %gep.sel, align 4
ret i8 %i
}
define i8 @select_offsets_not_simplifiable_2(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_2
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
; CHECK-NEXT: [[GEP32:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 32
; CHECK-NEXT: store i8 100, i8* [[GEP32]], align 16
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
; CHECK-NEXT: [[GEP_PLUS:%.*]] = getelementptr inbounds i8, i8* [[GEP_SEL]], i64 3
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP_PLUS]], align 4
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%sel0 = select i1 %cnd1, i64 23, i64 29
%sel1 = select i1 %cnd2, i64 %sel0, i64 7
%gep32 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 32
store i8 100, i8* %gep32, align 4
%gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
%gep.plus = getelementptr inbounds i8, i8* %gep.sel, i64 3
%i = load i8, i8* %gep.plus, align 4
ret i8 %i
}
define i8 @select_offsets_not_simplifiable_3(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_3
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
; CHECK-NEXT: store i8 100, i8* [[GEP_SEL]], align 4
; CHECK-NEXT: [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 29
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP29]], align 4
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%sel0 = select i1 %cnd1, i64 23, i64 29
%sel1 = select i1 %cnd2, i64 %sel0, i64 7
%gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
store i8 100, i8* %gep.sel, align 4
%gep29 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 29
%i = load i8, i8* %gep29, align 4
ret i8 %i
}
define i8 @select_offsets_not_simplifiable_4(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_4
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[SEL0:%.*]] = select i1 [[CND1]], i64 23, i64 29
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CND2]], i64 [[SEL0]], i64 7
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[SEL1]]
; CHECK-NEXT: [[GEP_PLUS:%.*]] = getelementptr inbounds i8, i8* [[GEP_SEL]], i64 3
; CHECK-NEXT: store i8 100, i8* [[GEP_PLUS]], align 4
; CHECK-NEXT: [[GEP32:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 32
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP32]], align 16
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%sel0 = select i1 %cnd1, i64 23, i64 29
%sel1 = select i1 %cnd2, i64 %sel0, i64 7
%gep.sel = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %sel1
%gep.plus = getelementptr inbounds i8, i8* %gep.sel, i64 3
store i8 100, i8* %gep.plus, align 4
%gep32 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 32
%i = load i8, i8* %gep32, align 4
ret i8 %i
}
define i8 @select_offsets_not_simplifiable_5(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_5
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUNDLE:%.*]] = alloca [[STRUCT_T:%.*]], align 64
; CHECK-NEXT: [[GEP_FIXED:%.*]] = getelementptr inbounds [[STRUCT_T]], %struct.T* [[BUNDLE]], i64 0, i32 1, i64 3, i64 5
; CHECK-NEXT: store i8 100, i8* [[GEP_FIXED]], align 4
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CND1]], i64 1, i64 3
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CND2]], i64 5, i64 11
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [[STRUCT_T]], %struct.T* [[BUNDLE]], i64 0, i32 1, i64 [[SEL1]], i64 [[SEL2]]
; CHECK-NEXT: store i8 42, i8* [[GEP_SEL]], align 4
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP_FIXED]], align 4
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%bundle = alloca %struct.T, align 64
%gep.fixed = getelementptr inbounds %struct.T, %struct.T* %bundle, i64 0, i32 1, i64 3, i64 5
store i8 100, i8* %gep.fixed, align 4
%sel1 = select i1 %cnd1, i64 1, i64 3
%sel2 = select i1 %cnd2, i64 5, i64 11
%gep.sel = getelementptr inbounds %struct.T, %struct.T* %bundle, i64 0, i32 1, i64 %sel1, i64 %sel2
;; This store prevents the constant 100 from being propagated to ret
store i8 42, i8* %gep.sel, align 4
%i = load i8, i8* %gep.fixed, align 4
ret i8 %i
}
define i8 @select_gep_simplifiable_1(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(write)
; CHECK-LABEL: define {{[^@]+}}@select_gep_simplifiable_1
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
; CHECK-NEXT: [[SEL_PTR:%.*]] = select i1 [[CND1]], i8* [[GEP7]], i8* [[GEP23]]
; CHECK-NEXT: store i8 42, i8* [[SEL_PTR]], align 4
; CHECK-NEXT: ret i8 21
;
entry:
%Bytes = alloca [1024 x i8], align 16
%gep3 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 3
store i8 21, i8* %gep3, align 4
%gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
%gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
%sel.ptr = select i1 %cnd1, i8* %gep7, i8* %gep23
store i8 42, i8* %sel.ptr, align 4
%i = load i8, i8* %gep3, align 4
ret i8 %i
}
define i8 @select_gep_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn
; CHECK-LABEL: define {{[^@]+}}@select_gep_not_simplifiable_1
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 7
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
; CHECK-NEXT: [[SEL_PTR:%.*]] = select i1 [[CND1]], i8* [[GEP7]], i8* [[GEP23]]
; CHECK-NEXT: store i8 42, i8* [[SEL_PTR]], align 4
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP7]], align 4
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%gep7 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 7
%gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
%sel.ptr = select i1 %cnd1, i8* %gep7, i8* %gep23
store i8 42, i8* %sel.ptr, align 4
%i = load i8, i8* %gep7, align 4
ret i8 %i
}
; FIXME: This should be simplifiable. See comment inside.
define i8 @phi_offsets_fixme(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@phi_offsets_fixme
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: [[GEP_FIXED:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0
; CHECK-NEXT: store i8 100, i8* [[GEP_FIXED]], align 16
; CHECK-NEXT: br i1 [[CND1]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
; CHECK-NEXT: br label [[JOIN:%.*]]
; CHECK: else:
; CHECK-NEXT: br label [[JOIN]]
; CHECK: join:
; CHECK-NEXT: [[PHI:%.*]] = phi i64 [ 3, [[THEN]] ], [ 11, [[ELSE]] ]
; CHECK-NEXT: [[GEP_PHI:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[PHI]]
; CHECK-NEXT: store i8 42, i8* [[GEP_PHI]], align 4
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP_FIXED]], align 16
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
%gep.fixed = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 0
store i8 100, i8* %gep.fixed, align 4
br i1 %cnd1, label %then, label %else
then:
br label %join
else:
br label %join
join:
; FIXME: AAPotentialConstantValues does not detect the constant values for the
; PHI below. It needs to rely on AAPotentialValues.
%phi = phi i64 [ 3, %then ], [ 11, %else ]
%gep.phi = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %phi
store i8 42, i8* %gep.phi, align 4
%i = load i8, i8* %gep.fixed, align 4
ret i8 %i
}
;.
; CHECK: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind willreturn memory(write) }
; CHECK: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind willreturn }
;.