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.
443 lines
14 KiB
LLVM
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
|
|
}
|