Serguei Katkov 99da317331 [LoopPredication] Fix the LoopPredication by feezing the result of predication.
LoopPredication introduces the use of possibly posion value in branch (guard)
instruction, so to avoid introducing undefined behavior it should be frozen.

Reviewed By: mkazantsev
Differential Revision: https://reviews.llvm.org/D146685
2023-03-29 15:12:00 +07:00

114 lines
4.4 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=loop-predication < %s 2>&1 | FileCheck %s
; RUN: opt -S -passes='require<scalar-evolution>,loop-mssa(loop-predication)' -verify-memoryssa < %s 2>&1 | FileCheck %s
declare void @llvm.experimental.guard(i1, ...)
; Check the case when N on latch exit might be poison.
define i32 @test1(i32 %length, i32 %nlimit) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[M:%.*]] = add nuw nsw i32 [[NLIMIT:%.*]], 2
; CHECK-NEXT: [[N:%.*]] = xor i32 [[M]], 1
; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], [[LENGTH:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
; CHECK-NEXT: [[TMP3:%.*]] = freeze i1 [[TMP2]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[OK:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[J:%.*]] = phi i32 [ [[J_NEXT:%.*]], [[OK]] ], [ 0, [[ENTRY]] ]
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[J]], [[LENGTH]]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
; CHECK-NEXT: [[TMP:%.*]] = icmp ult i32 [[NLIMIT]], 1000
; CHECK-NEXT: br i1 [[TMP]], label [[OK]], label [[EXIT:%.*]]
; CHECK: ok:
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
; CHECK-NEXT: [[J_NEXT]] = add i32 [[J]], 1
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret i32 0
;
entry:
; %n might be a poison.
%m = add nuw nsw i32 %nlimit, 2
%n = xor i32 %m, 1
br label %loop
loop:
%i = phi i32 [ %i.next, %ok ], [ 0, %entry ]
%j = phi i32 [ %j.next, %ok ], [ 0, %entry ]
%within.bounds = icmp ult i32 %j, %length
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
; This check guarantees %n is not a posion.
%tmp = icmp ult i32 %nlimit, 1000
br i1 %tmp, label %ok, label %exit
ok:
%i.next = add i32 %i, 1
%j.next = add i32 %j, 1
%continue = icmp ult i32 %i.next, %n
br i1 %continue, label %loop, label %exit
exit:
ret i32 0
}
; Check the case when start value of IV might be a poison.
define i32 @test2(i32 noundef %length, i32 noundef %nlimit, i32 %istart) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[M:%.*]] = add nuw nsw i32 [[ISTART:%.*]], 2
; CHECK-NEXT: [[ISTART2:%.*]] = xor i32 [[M]], 1
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[ISTART2]], [[LENGTH:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP0]], -1
; CHECK-NEXT: [[TMP2:%.*]] = icmp ule i32 [[NLIMIT:%.*]], [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 1, [[LENGTH]]
; CHECK-NEXT: [[TMP4:%.*]] = and i1 [[TMP3]], [[TMP2]]
; CHECK-NEXT: [[TMP5:%.*]] = freeze i1 [[TMP4]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[OK:%.*]] ], [ [[ISTART2]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[J:%.*]] = phi i32 [ [[J_NEXT:%.*]], [[OK]] ], [ 1, [[ENTRY]] ]
; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[J]], [[LENGTH]]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP5]], i32 9) [ "deopt"() ]
; CHECK-NEXT: call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
; CHECK-NEXT: [[TMP:%.*]] = icmp ult i32 [[ISTART]], 1000
; CHECK-NEXT: br i1 [[TMP]], label [[OK]], label [[EXIT:%.*]]
; CHECK: ok:
; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1
; CHECK-NEXT: [[J_NEXT]] = add i32 [[J]], 1
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[NLIMIT]]
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret i32 0
;
entry:
; %m might be a poison.
%m = add nuw nsw i32 %istart, 2
%istart2 = xor i32 %m, 1
br label %loop
loop:
%i = phi i32 [ %i.next, %ok ], [ %istart2, %entry ]
%j = phi i32 [ %j.next, %ok ], [ 1, %entry ]
%within.bounds = icmp ult i32 %j, %length
call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
; This check guarantees %n is not a posion.
%tmp = icmp ult i32 %istart, 1000
br i1 %tmp, label %ok, label %exit
ok:
%i.next = add i32 %i, 1
%j.next = add i32 %j, 1
%continue = icmp ult i32 %i.next, %nlimit
br i1 %continue, label %loop, label %exit
exit:
ret i32 0
}