Files
clang-p2996/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-pointer-cmps.ll
Florian Hahn 06f3ef6626 [ConstraintElimination] Allow adding pre-conditions for constraints.
With this patch pre-conditions can be added to a list of constraints.
Constraints with pre-conditions can only be used if all pre-conditions
are satisfied when the constraint is used.

The pre-conditions at the moment are specified as a list of
(Predicate, Value *,Value *) tuples. This allow easily checking them
like any other condition, using the existing infrastructure.

This then is used to limit GEP decomposition to cases where we can
prove that offsets are signed positive.

This fixes a couple of incorrect transforms where GEP offsets where
assumed to be signed positive, but they were not.

Note that this effectively disables GEP decomposition, as there's no
support for reasoning about signed predicates. D118806 adds initial
signed support.

Fixes PR49624.

Reviewed By: reames

Differential Revision: https://reviews.llvm.org/D118799
2022-02-04 11:45:07 +00:00

224 lines
9.3 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
declare void @use(i1)
define void @checks_in_loops_removable(i8* %ptr, i8* %lower, i8* %upper, i8 %n) {
; CHECK-LABEL: @checks_in_loops_removable(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP_PTR_LOWER:%.*]] = icmp ult i8* [[PTR:%.*]], [[LOWER:%.*]]
; CHECK-NEXT: br i1 [[CMP_PTR_LOWER]], label [[TRAP:%.*]], label [[PRE_1:%.*]]
; CHECK: pre.1:
; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i8 [[N:%.*]] to i16
; CHECK-NEXT: [[PTR_N:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IDX_EXT]]
; CHECK-NEXT: [[CMP_PTR_N_UPPER:%.*]] = icmp ult i8* [[PTR_N]], [[UPPER:%.*]]
; CHECK-NEXT: br i1 [[CMP_PTR_N_UPPER]], label [[PRE_2:%.*]], label [[TRAP]]
; CHECK: pre.2:
; CHECK-NEXT: [[CMP_N_NOT_ZERO:%.*]] = icmp eq i8 [[N]], 0
; CHECK-NEXT: br i1 [[CMP_N_NOT_ZERO]], label [[EXIT:%.*]], label [[LOOP_HEADER:%.*]]
; CHECK: trap:
; CHECK-NEXT: ret void
; CHECK: loop.header:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ 0, [[PRE_2]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
; CHECK-NEXT: [[PTR_IV:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IV]]
; CHECK-NEXT: [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[PTR_IV]]
; CHECK-NEXT: [[CMP_PTR_IV_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[PTR_IV]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP_PTR_IV_LOWER]], [[CMP_PTR_IV_UPPER]]
; CHECK-NEXT: br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
; CHECK: loop.latch:
; CHECK-NEXT: store i8 0, i8* [[PTR_IV]], align 4
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i16 [[IV]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i16 [[IV_NEXT]], [[IDX_EXT]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP_HEADER]], label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp.ptr.lower = icmp ult i8* %ptr, %lower
br i1 %cmp.ptr.lower, label %trap, label %pre.1
pre.1:
%idx.ext = zext i8 %n to i16
%ptr.n = getelementptr inbounds i8, i8* %ptr, i16 %idx.ext
%cmp.ptr.n.upper = icmp ult i8* %ptr.n, %upper
br i1 %cmp.ptr.n.upper, label %pre.2, label %trap
pre.2:
%cmp.n.not.zero = icmp eq i8 %n, 0
br i1 %cmp.n.not.zero, label %exit, label %loop.header
trap:
ret void
loop.header:
%iv = phi i16 [ 0, %pre.2 ], [ %iv.next, %loop.latch ]
%ptr.iv = getelementptr inbounds i8, i8* %ptr, i16 %iv
%cmp.ptr.iv.lower = icmp ugt i8* %lower, %ptr.iv
%cmp.ptr.iv.upper = icmp ule i8* %upper, %ptr.iv
%or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
br i1 %or, label %trap, label %loop.latch
loop.latch:
store i8 0, i8* %ptr.iv, align 4
%iv.next = add nuw nsw i16 %iv, 1
%exitcond = icmp ne i16 %iv.next, %idx.ext
br i1 %exitcond, label %loop.header, label %exit
exit:
ret void
}
define void @some_checks_in_loops_removable(i8* %ptr, i8* %lower, i8* %upper, i8 %n) {
; CHECK-LABEL: @some_checks_in_loops_removable(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP_PTR_LOWER:%.*]] = icmp ult i8* [[PTR:%.*]], [[LOWER:%.*]]
; CHECK-NEXT: br i1 [[CMP_PTR_LOWER]], label [[TRAP:%.*]], label [[PRE_1:%.*]]
; CHECK: pre.1:
; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i8 [[N:%.*]] to i16
; CHECK-NEXT: [[PTR_N:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IDX_EXT]]
; CHECK-NEXT: [[CMP_PTR_N_UPPER:%.*]] = icmp ult i8* [[PTR_N]], [[UPPER:%.*]]
; CHECK-NEXT: br i1 [[CMP_PTR_N_UPPER]], label [[PRE_2:%.*]], label [[TRAP]]
; CHECK: pre.2:
; CHECK-NEXT: [[CMP_N_NOT_ZERO:%.*]] = icmp eq i8 [[N]], 0
; CHECK-NEXT: br i1 [[CMP_N_NOT_ZERO]], label [[EXIT:%.*]], label [[LOOP_HEADER:%.*]]
; CHECK: trap:
; CHECK-NEXT: ret void
; CHECK: loop.header:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ 0, [[PRE_2]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
; CHECK-NEXT: [[PTR_IV:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IV]]
; CHECK-NEXT: [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[PTR_IV]]
; CHECK-NEXT: [[CMP_PTR_IV_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[PTR_IV]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP_PTR_IV_LOWER]], [[CMP_PTR_IV_UPPER]]
; CHECK-NEXT: br i1 [[OR]], label [[TRAP]], label [[LOOP_BODY:%.*]]
; CHECK: loop.body:
; CHECK-NEXT: [[IV_1:%.*]] = add nuw nsw i16 [[IV]], 1
; CHECK-NEXT: [[PTR_IV_1:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IV_1]]
; CHECK-NEXT: [[CMP_PTR_IV_1_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[PTR_IV_1]]
; CHECK-NEXT: [[CMP_PTR_IV_1_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[PTR_IV_1]]
; CHECK-NEXT: [[OR_1:%.*]] = or i1 [[CMP_PTR_IV_1_LOWER]], [[CMP_PTR_IV_1_UPPER]]
; CHECK-NEXT: br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
; CHECK: loop.latch:
; CHECK-NEXT: store i8 0, i8* [[PTR_IV]], align 4
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i16 [[IV]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i16 [[IV_NEXT]], [[IDX_EXT]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP_HEADER]], label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp.ptr.lower = icmp ult i8* %ptr, %lower
br i1 %cmp.ptr.lower, label %trap, label %pre.1
pre.1:
%idx.ext = zext i8 %n to i16
%ptr.n = getelementptr inbounds i8, i8* %ptr, i16 %idx.ext
%cmp.ptr.n.upper = icmp ult i8* %ptr.n, %upper
br i1 %cmp.ptr.n.upper, label %pre.2, label %trap
pre.2:
%cmp.n.not.zero = icmp eq i8 %n, 0
br i1 %cmp.n.not.zero, label %exit, label %loop.header
trap:
ret void
loop.header:
%iv = phi i16 [ 0, %pre.2 ], [ %iv.next, %loop.latch ]
%ptr.iv = getelementptr inbounds i8, i8* %ptr, i16 %iv
%cmp.ptr.iv.lower = icmp ugt i8* %lower, %ptr.iv
%cmp.ptr.iv.upper = icmp ule i8* %upper, %ptr.iv
%or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
br i1 %or, label %trap, label %loop.body
loop.body:
%iv.1 = add nuw nsw i16 %iv, 1
%ptr.iv.1 = getelementptr inbounds i8, i8* %ptr, i16 %iv.1
%cmp.ptr.iv.1.lower = icmp ugt i8* %lower, %ptr.iv.1
%cmp.ptr.iv.1.upper = icmp ule i8* %upper, %ptr.iv.1
%or.1 = or i1 %cmp.ptr.iv.1.lower, %cmp.ptr.iv.1.upper
br i1 %or, label %trap, label %loop.latch
loop.latch:
store i8 0, i8* %ptr.iv, align 4
%iv.next = add nuw nsw i16 %iv, 1
%exitcond = icmp ne i16 %iv.next, %idx.ext
br i1 %exitcond, label %loop.header, label %exit
exit:
ret void
}
; N might be zero, cannot remove upper checks.
define void @no_checks_in_loops_removable(i8* %ptr, i8* %lower, i8* %upper, i8 %n) {
; CHECK-LABEL: @no_checks_in_loops_removable(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP_PTR_LOWER:%.*]] = icmp ult i8* [[PTR:%.*]], [[LOWER:%.*]]
; CHECK-NEXT: br i1 [[CMP_PTR_LOWER]], label [[TRAP:%.*]], label [[PRE_1:%.*]]
; CHECK: pre.1:
; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i8 [[N:%.*]] to i16
; CHECK-NEXT: [[PTR_N:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IDX_EXT]]
; CHECK-NEXT: [[CMP_PTR_N_UPPER:%.*]] = icmp ult i8* [[PTR_N]], [[UPPER:%.*]]
; CHECK-NEXT: br i1 [[CMP_PTR_N_UPPER]], label [[LOOP_HEADER:%.*]], label [[TRAP]]
; CHECK: trap:
; CHECK-NEXT: ret void
; CHECK: loop.header:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ 0, [[PRE_1]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
; CHECK-NEXT: [[PTR_IV:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IV]]
; CHECK-NEXT: [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[PTR_IV]]
; CHECK-NEXT: [[CMP_PTR_IV_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[PTR_IV]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP_PTR_IV_LOWER]], [[CMP_PTR_IV_UPPER]]
; CHECK-NEXT: br i1 [[OR]], label [[TRAP]], label [[LOOP_BODY:%.*]]
; CHECK: loop.body:
; CHECK-NEXT: [[IV_1:%.*]] = add nuw nsw i16 [[IV]], 1
; CHECK-NEXT: [[PTR_IV_1:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IV_1]]
; CHECK-NEXT: [[CMP_PTR_IV_1_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[PTR_IV_1]]
; CHECK-NEXT: [[CMP_PTR_IV_1_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[PTR_IV_1]]
; CHECK-NEXT: [[OR_1:%.*]] = or i1 [[CMP_PTR_IV_1_LOWER]], [[CMP_PTR_IV_1_UPPER]]
; CHECK-NEXT: br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
; CHECK: loop.latch:
; CHECK-NEXT: store i8 0, i8* [[PTR_IV]], align 4
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i16 [[IV]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i16 [[IV_NEXT]], [[IDX_EXT]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp.ptr.lower = icmp ult i8* %ptr, %lower
br i1 %cmp.ptr.lower, label %trap, label %pre.1
pre.1:
%idx.ext = zext i8 %n to i16
%ptr.n = getelementptr inbounds i8, i8* %ptr, i16 %idx.ext
%cmp.ptr.n.upper = icmp ult i8* %ptr.n, %upper
br i1 %cmp.ptr.n.upper, label %loop.header, label %trap
trap:
ret void
loop.header:
%iv = phi i16 [ 0, %pre.1 ], [ %iv.next, %loop.latch ]
%ptr.iv = getelementptr inbounds i8, i8* %ptr, i16 %iv
%cmp.ptr.iv.lower = icmp ugt i8* %lower, %ptr.iv
%cmp.ptr.iv.upper = icmp ule i8* %upper, %ptr.iv
%or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
br i1 %or, label %trap, label %loop.body
loop.body:
%iv.1 = add nuw nsw i16 %iv, 1
%ptr.iv.1 = getelementptr inbounds i8, i8* %ptr, i16 %iv.1
%cmp.ptr.iv.1.lower = icmp ugt i8* %lower, %ptr.iv.1
%cmp.ptr.iv.1.upper = icmp ule i8* %upper, %ptr.iv.1
%or.1 = or i1 %cmp.ptr.iv.1.lower, %cmp.ptr.iv.1.upper
br i1 %or, label %trap, label %loop.latch
loop.latch:
store i8 0, i8* %ptr.iv, align 4
%iv.next = add nuw nsw i16 %iv, 1
%exitcond = icmp ne i16 %iv.next, %idx.ext
br i1 %exitcond, label %loop.header, label %exit
exit:
ret void
}