
- Allocas and GlobalValues cannot be simplified, so we should not try. - If we never used any assumed state, the AAUnderlyingObjects doesn't require an additional update. - If we have seen an object (or it's underlying object) before, we do not need to inspect it anymore. The original logic for "SeenObjects" was flawed and caused us to add intermediate values to the underlying object list if a PHI or select instruction referenced the same underlying object twice. The test changes are all instances of this situation and we now correctly derive `memory(none)` for the functions that only access stack memory. --------- Co-authored-by: Shilei Tian <i@tianshilei.me>
523 lines
23 KiB
LLVM
523 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-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
|
|
|
|
%struct.T = type { i32, [10 x [20 x i8]] }
|
|
|
|
declare noalias ptr @calloc(i64, i64) allockind("alloc,zeroed") allocsize(0,1) "alloc-family"="malloc"
|
|
|
|
define i8 @select_offsets_simplifiable_1(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_1
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BYTES:%.*]] = call ptr @calloc(i64 noundef 1024, i64 noundef 1)
|
|
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 23
|
|
; CHECK-NEXT: store i8 23, ptr [[GEP23]], align 4
|
|
; CHECK-NEXT: [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 29
|
|
; CHECK-NEXT: store i8 29, ptr [[GEP29]], align 4
|
|
; CHECK-NEXT: [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 7
|
|
; CHECK-NEXT: store i8 7, ptr [[GEP7]], align 4
|
|
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], ptr [[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], ptr [[BYTES]], i64 0, i64 [[SEL1]]
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[GEP_SEL]], align 4
|
|
; CHECK-NEXT: ret i8 [[I]]
|
|
;
|
|
entry:
|
|
%Bytes = call ptr @calloc(i64 1024, i64 1)
|
|
|
|
%gep23 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 23
|
|
store i8 23, ptr %gep23, align 4
|
|
%gep29 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 29
|
|
store i8 29, ptr %gep29, align 4
|
|
%gep7 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 7
|
|
store i8 7, ptr %gep7, align 4
|
|
|
|
;; This store is redundant, hence removed.
|
|
%gep31 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 31
|
|
store i8 42, ptr %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], ptr %Bytes, i64 0, i64 %sel1
|
|
%i = load i8, ptr %gep.sel, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_offsets_simplifiable_2(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_2
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1:[0-9]+]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
|
|
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 23
|
|
; CHECK-NEXT: store i8 23, ptr [[GEP23]], align 4
|
|
; CHECK-NEXT: [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 29
|
|
; CHECK-NEXT: store i8 29, ptr [[GEP29]], align 4
|
|
; CHECK-NEXT: [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 7
|
|
; CHECK-NEXT: store i8 7, ptr [[GEP7]], align 4
|
|
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], ptr [[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], ptr [[BYTES]], i64 0, i64 [[SEL1]]
|
|
; CHECK-NEXT: [[GEP_PLUS:%.*]] = getelementptr inbounds i8, ptr [[GEP_SEL]], i64 3
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[GEP_PLUS]], align 4
|
|
; CHECK-NEXT: ret i8 [[I]]
|
|
;
|
|
entry:
|
|
%Bytes = alloca [1024 x i8], align 16
|
|
|
|
%gep23 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 23
|
|
store i8 23, ptr %gep23, align 4
|
|
%gep29 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 29
|
|
store i8 29, ptr %gep29, align 4
|
|
%gep7 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 7
|
|
store i8 7, ptr %gep7, align 4
|
|
|
|
;; This store is redundant, hence removed.
|
|
%gep31 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 31
|
|
store i8 42, ptr %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], ptr %Bytes, i64 0, i64 %sel1
|
|
%gep.plus = getelementptr inbounds i8, ptr %gep.sel, i64 3
|
|
%i = load i8, ptr %gep.plus, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_offsets_simplifiable_3(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_3
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
|
|
; 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]], ptr [[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, ptr %bundle, i64 0, i32 1, i64 1, i64 1
|
|
store i8 100, ptr %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, ptr %bundle, i64 0, i32 1, i64 %sel1, i64 %sel2
|
|
store i8 42, ptr %gep.sel, align 4
|
|
%i = load i8, ptr %gep.fixed, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
; Similar to select_offsets_not_simplifiable_3 but with uninitialized memory.
|
|
define i8 @select_offsets_simplifiable_4(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_simplifiable_4
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
|
|
; 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], ptr [[BYTES]], i64 0, i64 [[SEL1]]
|
|
; CHECK-NEXT: ret i8 100
|
|
;
|
|
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], ptr %Bytes, i64 0, i64 %sel1
|
|
store i8 100, ptr %gep.sel, align 4
|
|
%gep29 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 29
|
|
%i = load i8, ptr %gep29, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_offsets_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_1
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
|
|
; 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], ptr [[BYTES]], i64 0, i64 23
|
|
; CHECK-NEXT: store i8 100, ptr [[GEP23]], align 4
|
|
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 [[SEL1]]
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[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], ptr %Bytes, i64 0, i64 23
|
|
store i8 100, ptr %gep23, align 4
|
|
%gep.sel = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 %sel1
|
|
%i = load i8, ptr %gep.sel, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_offsets_not_simplifiable_2(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_2
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
|
|
; 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], ptr [[BYTES]], i64 0, i64 32
|
|
; CHECK-NEXT: store i8 100, ptr [[GEP32]], align 16
|
|
; CHECK-NEXT: [[GEP_SEL:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 [[SEL1]]
|
|
; CHECK-NEXT: [[GEP_PLUS:%.*]] = getelementptr inbounds i8, ptr [[GEP_SEL]], i64 3
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[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], ptr %Bytes, i64 0, i64 32
|
|
store i8 100, ptr %gep32, align 4
|
|
%gep.sel = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 %sel1
|
|
%gep.plus = getelementptr inbounds i8, ptr %gep.sel, i64 3
|
|
%i = load i8, ptr %gep.plus, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_offsets_not_simplifiable_3(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_3
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BYTES:%.*]] = call ptr @calloc(i64 noundef 1024, i64 noundef 1)
|
|
; 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], ptr [[BYTES]], i64 0, i64 [[SEL1]]
|
|
; CHECK-NEXT: store i8 100, ptr [[GEP_SEL]], align 4
|
|
; CHECK-NEXT: [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 29
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[GEP29]], align 4
|
|
; CHECK-NEXT: ret i8 [[I]]
|
|
;
|
|
entry:
|
|
%Bytes = call ptr @calloc(i64 1024, i64 1)
|
|
%sel0 = select i1 %cnd1, i64 23, i64 29
|
|
%sel1 = select i1 %cnd2, i64 %sel0, i64 7
|
|
%gep.sel = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 %sel1
|
|
store i8 100, ptr %gep.sel, align 4
|
|
%gep29 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 29
|
|
%i = load i8, ptr %gep29, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_offsets_not_simplifiable_4(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_4
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BYTES:%.*]] = call ptr @calloc(i64 noundef 1024, i64 noundef 1)
|
|
; 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], ptr [[BYTES]], i64 0, i64 [[SEL1]]
|
|
; CHECK-NEXT: [[GEP_PLUS:%.*]] = getelementptr inbounds i8, ptr [[GEP_SEL]], i64 3
|
|
; CHECK-NEXT: store i8 100, ptr [[GEP_PLUS]], align 4
|
|
; CHECK-NEXT: [[GEP32:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 32
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[GEP32]], align 4
|
|
; CHECK-NEXT: ret i8 [[I]]
|
|
;
|
|
entry:
|
|
%Bytes = call ptr @calloc(i64 1024, i64 1)
|
|
%sel0 = select i1 %cnd1, i64 23, i64 29
|
|
%sel1 = select i1 %cnd2, i64 %sel0, i64 7
|
|
%gep.sel = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 %sel1
|
|
%gep.plus = getelementptr inbounds i8, ptr %gep.sel, i64 3
|
|
store i8 100, ptr %gep.plus, align 4
|
|
%gep32 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 32
|
|
%i = load i8, ptr %gep32, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_offsets_not_simplifiable_5(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@select_offsets_not_simplifiable_5
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BUNDLE:%.*]] = alloca [[STRUCT_T:%.*]], align 64
|
|
; CHECK-NEXT: [[GEP_FIXED:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[BUNDLE]], i64 0, i32 1, i64 3, i64 5
|
|
; CHECK-NEXT: store i8 100, ptr [[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]], ptr [[BUNDLE]], i64 0, i32 1, i64 [[SEL1]], i64 [[SEL2]]
|
|
; CHECK-NEXT: store i8 42, ptr [[GEP_SEL]], align 4
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[GEP_FIXED]], align 4
|
|
; CHECK-NEXT: ret i8 [[I]]
|
|
;
|
|
entry:
|
|
%bundle = alloca %struct.T, align 64
|
|
%gep.fixed = getelementptr inbounds %struct.T, ptr %bundle, i64 0, i32 1, i64 3, i64 5
|
|
store i8 100, ptr %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, ptr %bundle, i64 0, i32 1, i64 %sel1, i64 %sel2
|
|
|
|
;; This store prevents the constant 100 from being propagated to ret
|
|
store i8 42, ptr %gep.sel, align 4
|
|
|
|
%i = load i8, ptr %gep.fixed, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_gep_simplifiable_1(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@select_gep_simplifiable_1
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
|
|
; CHECK-NEXT: [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 7
|
|
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 23
|
|
; CHECK-NEXT: [[SEL_PTR:%.*]] = select i1 [[CND1]], ptr [[GEP7]], ptr [[GEP23]]
|
|
; CHECK-NEXT: ret i8 21
|
|
;
|
|
entry:
|
|
%Bytes = alloca [1024 x i8], align 16
|
|
%gep3 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 3
|
|
store i8 21, ptr %gep3, align 4
|
|
%gep7 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 7
|
|
%gep23 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 23
|
|
%sel.ptr = select i1 %cnd1, ptr %gep7, ptr %gep23
|
|
store i8 42, ptr %sel.ptr, align 4
|
|
%i = load i8, ptr %gep3, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @select_gep_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@select_gep_not_simplifiable_1
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
|
|
; CHECK-NEXT: [[GEP7:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 7
|
|
; CHECK-NEXT: store i8 1, ptr [[GEP7]], align 4
|
|
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 23
|
|
; CHECK-NEXT: [[SEL_PTR:%.*]] = select i1 [[CND1]], ptr [[GEP7]], ptr [[GEP23]]
|
|
; CHECK-NEXT: store i8 42, ptr [[SEL_PTR]], align 4
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[GEP7]], align 4
|
|
; CHECK-NEXT: ret i8 [[I]]
|
|
;
|
|
entry:
|
|
%Bytes = alloca [1024 x i8], align 16
|
|
%gep7 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 7
|
|
store i8 1, ptr %gep7, align 4
|
|
%gep23 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 23
|
|
%sel.ptr = select i1 %cnd1, ptr %gep7, ptr %gep23
|
|
store i8 42, ptr %sel.ptr, align 4
|
|
%i = load i8, ptr %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: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@phi_gep_simplifiable_1
|
|
; CHECK-SAME: (i1 noundef [[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], ptr [[BYTES]], i64 0, i64 23
|
|
; CHECK-NEXT: store i8 21, ptr [[GEP23]], align 4
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 31
|
|
; CHECK-NEXT: store i8 21, ptr [[GEP31]], align 4
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI_PTR:%.*]] = phi ptr [ [[GEP23]], [[THEN]] ], [ [[GEP31]], [[ELSE]] ]
|
|
; CHECK-NEXT: [[GEP29:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 29
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[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], ptr %Bytes, i64 0, i64 23
|
|
store i8 21, ptr %gep23, align 4
|
|
br label %join
|
|
|
|
else:
|
|
%gep31 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 31
|
|
store i8 21, ptr %gep31, align 4
|
|
br label %join
|
|
|
|
join:
|
|
%phi.ptr = phi ptr [%gep23, %then], [%gep31, %else]
|
|
;; This store is eliminated
|
|
%gep29 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 29
|
|
store i8 42, ptr %gep29, align 4
|
|
%i = load i8, ptr %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: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@phi_gep_simplifiable_2
|
|
; CHECK-SAME: (i1 noundef [[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], ptr [[BYTES]], i64 0, i64 23
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: [[GEP31:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BYTES]], i64 0, i64 31
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI_PTR:%.*]] = phi ptr [ [[GEP23]], [[THEN]] ], [ [[GEP31]], [[ELSE]] ]
|
|
; CHECK-NEXT: ret i8 42
|
|
;
|
|
entry:
|
|
%Bytes = alloca [1024 x i8], align 16
|
|
%gep29 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 29
|
|
;; This store is propagated to the load.
|
|
store i8 42, ptr %gep29, align 4
|
|
br i1 %cnd1, label %then, label %else
|
|
|
|
then:
|
|
%gep23 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 23
|
|
br label %join
|
|
|
|
else:
|
|
%gep31 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 31
|
|
br label %join
|
|
|
|
join:
|
|
%phi.ptr = phi ptr [%gep23, %then], [%gep31, %else]
|
|
store i8 21, ptr %phi.ptr, align 4
|
|
;; Replaced with the constant, and both store/load are eliminated.
|
|
%i = load i8, ptr %gep29, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @phi_gep_not_simplifiable_1(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@phi_gep_not_simplifiable_1
|
|
; CHECK-SAME: (i1 noundef [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16
|
|
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], ptr [[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], ptr [[BYTES]], i64 0, i64 31
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI_PTR:%.*]] = phi ptr [ [[GEP23]], [[THEN]] ], [ [[GEP31]], [[ELSE]] ]
|
|
; CHECK-NEXT: store i8 42, ptr [[GEP23]], align 4
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[PHI_PTR]], align 4
|
|
; CHECK-NEXT: ret i8 [[I]]
|
|
;
|
|
entry:
|
|
%Bytes = alloca [1024 x i8], align 16
|
|
%gep23 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 23
|
|
br i1 %cnd1, label %then, label %else
|
|
|
|
then:
|
|
br label %join
|
|
|
|
else:
|
|
%gep31 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 31
|
|
br label %join
|
|
|
|
join:
|
|
%phi.ptr = phi ptr [%gep23, %then], [%gep31, %else]
|
|
;; This store cannot be eliminated
|
|
store i8 42, ptr %gep23, align 4
|
|
%i = load i8, ptr %phi.ptr, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @phi_gep_not_simplifiable_2(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK-LABEL: define {{[^@]+}}@phi_gep_not_simplifiable_2
|
|
; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[BYTES:%.*]] = call ptr @calloc(i64 noundef 1024, i64 noundef 1)
|
|
; CHECK-NEXT: [[GEP23:%.*]] = getelementptr inbounds [1024 x i8], ptr [[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], ptr [[BYTES]], i64 0, i64 31
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI_PTR:%.*]] = phi ptr [ [[GEP23]], [[THEN]] ], [ [[GEP31]], [[ELSE]] ]
|
|
; CHECK-NEXT: store i8 21, ptr [[PHI_PTR]], align 4
|
|
; CHECK-NEXT: [[I:%.*]] = load i8, ptr [[GEP23]], align 4
|
|
; CHECK-NEXT: ret i8 [[I]]
|
|
;
|
|
entry:
|
|
%Bytes = call ptr @calloc(i64 1024, i64 1)
|
|
%gep23 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 23
|
|
br i1 %cnd1, label %then, label %else
|
|
|
|
then:
|
|
br label %join
|
|
|
|
else:
|
|
%gep31 = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 31
|
|
br label %join
|
|
|
|
join:
|
|
%phi.ptr = phi ptr [%gep23, %then], [%gep31, %else]
|
|
store i8 21, ptr %phi.ptr, align 4
|
|
%i = load i8, ptr %gep23, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
define i8 @phi_offsets(i1 %cnd1, i1 %cnd2) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@phi_offsets
|
|
; CHECK-SAME: (i1 noundef [[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: 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], ptr [[BYTES]], i64 0, i64 [[PHI]]
|
|
; CHECK-NEXT: ret i8 100
|
|
;
|
|
entry:
|
|
%Bytes = alloca [1024 x i8], align 16
|
|
store i8 100, ptr %Bytes, align 4
|
|
br i1 %cnd1, label %then, label %else
|
|
|
|
then:
|
|
br label %join
|
|
|
|
else:
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i64 [ 3, %then ], [ 11, %else ]
|
|
%gep.phi = getelementptr inbounds [1024 x i8], ptr %Bytes, i64 0, i64 %phi
|
|
store i8 42, ptr %gep.phi, align 4
|
|
%i = load i8, ptr %Bytes, align 4
|
|
ret i8 %i
|
|
}
|
|
|
|
;.
|
|
; CHECK: attributes #[[ATTR0:[0-9]+]] = { allockind("alloc,zeroed") allocsize(0,1) "alloc-family"="malloc" }
|
|
; CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
|
|
;.
|
|
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
|
|
; CGSCC: {{.*}}
|
|
; TUNIT: {{.*}}
|