Files
clang-p2996/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll
Sameer Sahasrabuddhe 9c1b82599d [AAPointerInfo] handle multiple offsets in PHI
Previously reverted in 8b446ea2ba

Reapplying because this commit is NOT DEPENDENT on the reverted commit
fc21f2d7ba, which broke the ASAN buildbot.
See https://reviews.llvm.org/rGfc21f2d7bae2e0be630470cc7ca9323ed5859892 for
more information.

The arguments to a PHI may represent a recurrence by eventually using the output
of the PHI itself. This is now handled by checking for cycles in the control
flow. If a PHI is not in a recurrence, it is now able to report multiple offsets
instead of conservatively reporting unknown.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D138991
2022-12-18 10:51:20 +05:30

512 lines
23 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: The whole function is just "ret i8 21".
define i8 @phi_gep_simplifiable_1(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn
; CHECK-LABEL: define {{[^@]+}}@phi_gep_simplifiable_1
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR2]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: br i1 [[CND1]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
; CHECK-NEXT: store i8 21, i8* [[GEP23]], align 4
; CHECK-NEXT: br label [[JOIN:%.*]]
; CHECK: else:
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 31
; CHECK-NEXT: store i8 21, i8* [[GEP31]], align 4
; CHECK-NEXT: br label [[JOIN]]
; CHECK: join:
; CHECK-NEXT: [[PHI_PTR:%.*]] = phi i8* [ [[GEP23]], [[THEN]] ], [ [[GEP31]], [[ELSE]] ]
; CHECK-NEXT: [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 29
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[PHI_PTR]], align 4
; CHECK-NEXT: ret i8 [[I]]
;
entry:
%Bytes = alloca [1024 x i8], align 16
br i1 %cnd1, label %then, label %else
then:
%gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
store i8 21, i8* %gep23, align 4
br label %join
else:
%gep31 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 31
store i8 21, i8* %gep31, align 4
br label %join
join:
%phi.ptr = phi i8* [%gep23, %then], [%gep31, %else]
;; This store is eliminated
%gep29 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 29
store i8 42, i8* %gep29, align 4
%i = load i8, i8* %phi.ptr, align 4
ret i8 %i
}
; FIXME: The whole function is just "ret i8 42".
define i8 @phi_gep_simplifiable_2(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(write)
; CHECK-LABEL: define {{[^@]+}}@phi_gep_simplifiable_2
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
; CHECK-NEXT: br i1 [[CND1]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 23
; CHECK-NEXT: br label [[JOIN:%.*]]
; CHECK: else:
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 31
; CHECK-NEXT: br label [[JOIN]]
; CHECK: join:
; CHECK-NEXT: [[PHI_PTR:%.*]] = phi i8* [ [[GEP23]], [[THEN]] ], [ [[GEP31]], [[ELSE]] ]
; CHECK-NEXT: store i8 21, i8* [[PHI_PTR]], align 4
; CHECK-NEXT: ret i8 42
;
entry:
%Bytes = alloca [1024 x i8], align 16
%gep29 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 29
;; This store is propagated to the load.
store i8 42, i8* %gep29, align 4
br i1 %cnd1, label %then, label %else
then:
%gep23 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 23
br label %join
else:
%gep31 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 31
br label %join
join:
%phi.ptr = phi i8* [%gep23, %then], [%gep31, %else]
store i8 21, i8* %phi.ptr, align 4
;; Replaced with the constant, and both store/load are eliminated.
%i = load i8, i8* %gep29, align 4
ret i8 %i
}
define i8 @phi_gep_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn
; CHECK-LABEL: define {{[^@]+}}@phi_gep_not_simplifiable_1
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR2]] {
; 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: br i1 [[CND1]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
; CHECK-NEXT: br label [[JOIN:%.*]]
; CHECK: else:
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 31
; CHECK-NEXT: br label [[JOIN]]
; CHECK: join:
; CHECK-NEXT: [[PHI_PTR:%.*]] = phi i8* [ [[GEP23]], [[THEN]] ], [ [[GEP31]], [[ELSE]] ]
; CHECK-NEXT: store i8 42, i8* [[GEP23]], align 4
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[PHI_PTR]], 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
br i1 %cnd1, label %then, label %else
then:
br label %join
else:
%gep31 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 31
br label %join
join:
%phi.ptr = phi i8* [%gep23, %then], [%gep31, %else]
;; This store cannot be eliminated
store i8 42, i8* %gep23, align 4
%i = load i8, i8* %phi.ptr, align 4
ret i8 %i
}
define i8 @phi_gep_not_simplifiable_2(i1 %cnd1, i1 %cnd2) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn
; CHECK-LABEL: define {{[^@]+}}@phi_gep_not_simplifiable_2
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR2]] {
; 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: br i1 [[CND1]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
; CHECK-NEXT: br label [[JOIN:%.*]]
; CHECK: else:
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 31
; CHECK-NEXT: br label [[JOIN]]
; CHECK: join:
; CHECK-NEXT: [[PHI_PTR:%.*]] = phi i8* [ [[GEP23]], [[THEN]] ], [ [[GEP31]], [[ELSE]] ]
; CHECK-NEXT: store i8 21, i8* [[PHI_PTR]], align 4
; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP23]], 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
br i1 %cnd1, label %then, label %else
then:
br label %join
else:
%gep31 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 31
br label %join
join:
%phi.ptr = phi i8* [%gep23, %then], [%gep31, %else]
store i8 21, i8* %phi.ptr, align 4
%i = load i8, i8* %gep23, 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 }
;.
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CGSCC: {{.*}}
; TUNIT: {{.*}}