Files
clang-p2996/llvm/test/Transforms/LICM/gep-reassociate.ll
Nikita Popov 243df834c6 [LICM] Fix assert failure in no-allowspeculation mode
In this case the source GEP might not be hoisted even though it
has invariant operands. For now just bail out, but we might need
additional checks for AllowSpeculation in these special-case
reassociation folds.
2023-04-11 11:55:54 +02:00

443 lines
14 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -S -passes=licm < %s | FileCheck %s --check-prefixes=CHECK,SPEC
; RUN: opt -S -passes='licm<no-allowspeculation>' < %s | FileCheck %s --check-prefixes=CHECK,NOSPEC
declare void @use(ptr)
declare i32 @get.i32()
declare i64 @get.i64()
declare ptr @get.ptr()
define void @only_one_inbounds(ptr %ptr, i1 %c, i32 %arg) {
; CHECK-LABEL: define void @only_one_inbounds
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ARG_EXT:%.*]] = zext i32 [[ARG]] to i64
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG_EXT]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32()
; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
; CHECK-NEXT: call void @use(ptr [[GEP]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%arg.ext = zext i32 %arg to i64
br label %loop
loop:
%val = call i32 @get.i32()
%val.ext = zext i32 %val to i64
%ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
%ptr3 = getelementptr i8, ptr %ptr2, i64 %arg.ext
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @both_inbounds_one_neg(ptr %ptr, i1 %c) {
; CHECK-LABEL: define void @both_inbounds_one_neg
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 -1
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32()
; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
; CHECK-NEXT: call void @use(ptr [[GEP]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val = call i32 @get.i32()
%val.ext = zext i32 %val to i64
%ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
%ptr3 = getelementptr i8, ptr %ptr2, i64 -1
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @both_inbounds_pos(ptr %ptr, i1 %c) {
; CHECK-LABEL: define void @both_inbounds_pos
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 1
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32()
; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
; CHECK-NEXT: call void @use(ptr [[GEP]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val = call i32 @get.i32()
%val.ext = zext i32 %val to i64
%ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
%ptr3 = getelementptr inbounds i8, ptr %ptr2, i64 1
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @different_elem_types(ptr %ptr, i1 %c, i64 %arg) {
; CHECK-LABEL: define void @different_elem_types
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i64, ptr [[PTR]], i64 [[ARG]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[INVARIANT_GEP]], i64 [[VAL]]
; CHECK-NEXT: call void @use(ptr [[GEP]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val = call i64 @get.i64()
%ptr2 = getelementptr i32, ptr %ptr, i64 %val
%ptr3 = getelementptr i64, ptr %ptr2, i64 %arg
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @different_index_types(ptr %ptr, i1 %c, i32 %arg) {
; CHECK-LABEL: define void @different_index_types
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i32 [[ARG]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]]
; CHECK-NEXT: call void @use(ptr [[GEP]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val = call i64 @get.i64()
%ptr2 = getelementptr i8, ptr %ptr, i64 %val
%ptr3 = getelementptr i8, ptr %ptr2, i32 %arg
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @different_index_count(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
; CHECK-LABEL: define void @different_index_count
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]]
; CHECK-NEXT: call void @use(ptr [[GEP]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val = call i64 @get.i64()
%ptr2 = getelementptr i8, ptr %ptr, i64 %val
%ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @src_has_extra_use(ptr %ptr, i1 %c, i64 %arg) {
; CHECK-LABEL: define void @src_has_extra_use
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL]]
; CHECK-NEXT: call void @use(ptr [[PTR2]])
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG]]
; CHECK-NEXT: call void @use(ptr [[PTR3]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val = call i64 @get.i64()
%ptr2 = getelementptr i8, ptr %ptr, i64 %val
call void @use(ptr %ptr2)
%ptr3 = getelementptr i8, ptr %ptr2, i64 %arg
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @src_already_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
; CHECK-LABEL: define void @src_already_invariant
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: call void @use(ptr [[PTR3]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%ptr2 = getelementptr i8, ptr %ptr, i64 %arg1
%ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @gep_idx_not_invariant(ptr %ptr, i1 %c) {
; CHECK-LABEL: define void @gep_idx_not_invariant
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL1]]
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL2]]
; CHECK-NEXT: call void @use(ptr [[PTR3]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val1 = call i64 @get.i64()
%val2 = call i64 @get.i64()
%ptr2 = getelementptr i8, ptr %ptr, i64 %val1
%ptr3 = getelementptr i8, ptr %ptr2, i64 %val2
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @src_ptr_not_invariant(i1 %c, i64 %arg) {
; CHECK-LABEL: define void @src_ptr_not_invariant
; CHECK-SAME: (i1 [[C:%.*]], i64 [[ARG:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[PTR:%.*]] = call ptr @get.ptr()
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG]]
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL]]
; CHECK-NEXT: call void @use(ptr [[PTR3]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val = call i64 @get.i64()
%ptr = call ptr @get.ptr()
%ptr2 = getelementptr i8, ptr %ptr, i64 %arg
%ptr3 = getelementptr i8, ptr %ptr2, i64 %val
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @multiple_indices(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
; CHECK-LABEL: define void @multiple_indices
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[VAL1]], i64 [[VAL2]]
; CHECK-NEXT: call void @use(ptr [[GEP]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val1 = call i64 @get.i64()
%val2 = call i64 @get.i64()
%ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2
%ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @multiple_indices_not_invariant(ptr %ptr, i1 %c, i64 %arg1) {
; CHECK-LABEL: define void @multiple_indices_not_invariant
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[VAL3:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[VAL1]], i64 [[VAL2]]
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr [0 x i8], ptr [[PTR2]], i64 [[ARG1]], i64 [[VAL3]]
; CHECK-NEXT: call void @use(ptr [[PTR3]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val1 = call i64 @get.i64()
%val2 = call i64 @get.i64()
%val3 = call i64 @get.i64()
%ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2
%ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %val3
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @multiple_indices_very_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2, i64 %arg3) {
; CHECK-LABEL: define void @multiple_indices_very_invariant
; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]], i64 [[ARG3:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64()
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[ARG3]], i64 [[VAL1]]
; CHECK-NEXT: call void @use(ptr [[GEP]])
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val1 = call i64 @get.i64()
%ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %arg3, i64 %val1
%ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
call void @use(ptr %ptr3)
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @src_already_invariant_speculation(ptr %ptr, i1 %c, i1 %c2, i64 %arg1, i64 %arg2) {
; SPEC-LABEL: define void @src_already_invariant_speculation
; SPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
; SPEC-NEXT: entry:
; SPEC-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
; SPEC-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
; SPEC-NEXT: br label [[LOOP:%.*]]
; SPEC: loop:
; SPEC-NEXT: br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]]
; SPEC: if:
; SPEC-NEXT: call void @use(ptr [[PTR3]])
; SPEC-NEXT: br label [[LATCH]]
; SPEC: latch:
; SPEC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; SPEC: exit:
; SPEC-NEXT: ret void
;
; NOSPEC-LABEL: define void @src_already_invariant_speculation
; NOSPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
; NOSPEC-NEXT: entry:
; NOSPEC-NEXT: br label [[LOOP:%.*]]
; NOSPEC: loop:
; NOSPEC-NEXT: br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]]
; NOSPEC: if:
; NOSPEC-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
; NOSPEC-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
; NOSPEC-NEXT: call void @use(ptr [[PTR3]])
; NOSPEC-NEXT: br label [[LATCH]]
; NOSPEC: latch:
; NOSPEC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
; NOSPEC: exit:
; NOSPEC-NEXT: ret void
;
entry:
br label %loop
loop:
br i1 %c2, label %if, label %latch
if:
%ptr2 = getelementptr i8, ptr %ptr, i64 %arg1
%ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2
call void @use(ptr %ptr3)
br label %latch
latch:
br i1 %c, label %loop, label %exit
exit:
ret void
}