[ConstraintElim] Support signed decomposition of `add nsw`.

Add support decomposition for `add nsw` for signed queries.
`add nsw` won't wrap and can be directly added to the signed
system.
This commit is contained in:
Florian Hahn 2022-10-15 18:34:02 +01:00
parent 0b36d1ef1f
commit f12684d36e
No known key found for this signature in database
GPG Key ID: CF59919C6547A668
3 changed files with 71 additions and 21 deletions

View File

@ -326,12 +326,28 @@ static SmallVector<DecompEntry, 4>
decompose(Value *V, SmallVector<PreconditionTy, 4> &Preconditions,
bool IsSigned, const DataLayout &DL) {
auto MergeResults = [&Preconditions, IsSigned,
DL](Value *A, Value *B,
bool IsSignedB) -> SmallVector<DecompEntry, 4> {
auto ResA = decompose(A, Preconditions, IsSigned, DL);
auto ResB = decompose(B, Preconditions, IsSignedB, DL);
if (ResA.empty() || ResB.empty())
return {};
ResA[0].Coefficient += ResB[0].Coefficient;
append_range(ResA, drop_begin(ResB));
return ResA;
};
// Decompose \p V used with a signed predicate.
if (IsSigned) {
if (auto *CI = dyn_cast<ConstantInt>(V)) {
if (canUseSExt(CI))
return {{CI->getSExtValue(), nullptr}};
}
Value *Op0;
Value *Op1;
if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1))))
return MergeResults(Op0, Op1, IsSigned);
return {{0, nullptr}, {1, V}};
}
@ -352,17 +368,6 @@ decompose(Value *V, SmallVector<PreconditionTy, 4> &Preconditions,
V = Op0;
}
auto MergeResults = [&Preconditions, IsSigned,
DL](Value *A, Value *B,
bool IsSignedB) -> SmallVector<DecompEntry, 4> {
auto ResA = decompose(A, Preconditions, IsSigned, DL);
auto ResB = decompose(B, Preconditions, IsSignedB, DL);
if (ResA.empty() || ResB.empty())
return {};
ResA[0].Coefficient += ResB[0].Coefficient;
append_range(ResA, drop_begin(ResB));
return ResA;
};
Value *Op1;
ConstantInt *CI;
if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) {

View File

@ -1,7 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
define void @test.not.uge.ult(i8 %start, i8 %low, i8 %high) {
declare void @use(i1)
define void @test.not.uge.ult(i8 %start, i8 %high) {
; CHECK-LABEL: @test.not.uge.ult(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = add nsw i8 [[START:%.*]], 3
@ -52,7 +54,7 @@ if.end: ; preds = %entry
ret void
}
define void @test.not.sge.slt(i8 %start, i8 %low, i8 %high) {
define void @test.not.sge.slt(i8 %start, i8 %high) {
; CHECK-LABEL: @test.not.sge.slt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = add nsw i8 [[START:%.*]], 3
@ -62,16 +64,16 @@ define void @test.not.sge.slt(i8 %start, i8 %low, i8 %high) {
; CHECK-NEXT: ret void
; CHECK: if.end:
; CHECK-NEXT: [[T_0:%.*]] = icmp slt i8 [[START]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 [[T_0]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[START_1:%.*]] = add nsw i8 [[START]], 1
; CHECK-NEXT: [[T_1:%.*]] = icmp slt i8 [[START_1]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 [[T_1]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[START_2:%.*]] = add nsw i8 [[START]], 2
; CHECK-NEXT: [[T_2:%.*]] = icmp slt i8 [[START_2]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 [[T_2]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[START_3:%.*]] = add nsw i8 [[START]], 3
; CHECK-NEXT: [[T_3:%.*]] = icmp slt i8 [[START_3]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 [[T_3]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[START_4:%.*]] = add nsw i8 [[START]], 4
; CHECK-NEXT: [[C_4:%.*]] = icmp slt i8 [[START_4]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 [[C_4]])
@ -118,10 +120,10 @@ define void @test.decompose.nonconst(i8 %a, i8 %b, i8 %c, i8 %d) {
; CHECK: if.then.2:
; CHECK-NEXT: [[ADD_0:%.*]] = add nsw i8 [[A]], [[B]]
; CHECK-NEXT: [[T_0:%.*]] = icmp sge i8 [[ADD_0]], [[C]]
; CHECK-NEXT: call void @use(i1 [[T_0]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[ADD_1:%.*]] = add nsw i8 [[A]], [[A]]
; CHECK-NEXT: [[T_1:%.*]] = icmp sge i8 [[ADD_0]], [[C]]
; CHECK-NEXT: call void @use(i1 [[T_1]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[ADD_2:%.*]] = add nsw i8 [[A]], [[D:%.*]]
; CHECK-NEXT: [[C_4:%.*]] = icmp sge i8 [[ADD_2]], [[C]]
; CHECK-NEXT: call void @use(i1 [[C_4]])
@ -200,4 +202,47 @@ if.end: ; preds = %entry
ret void
}
declare void @use(i1)
define void @test.sge.slt.add.neg(i8 %start, i8 %high) {
; CHECK-LABEL: @test.sge.slt.add.neg(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = add nsw i8 [[START:%.*]], -3
; CHECK-NEXT: [[C_1:%.*]] = icmp slt i8 [[ADD_PTR_I]], [[HIGH:%.*]]
; CHECK-NEXT: call void @llvm.assume(i1 [[C_1]])
; CHECK-NEXT: [[C_2:%.*]] = icmp slt i8 [[START]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 [[C_2]])
; CHECK-NEXT: [[START_1:%.*]] = add nsw i8 [[START]], 1
; CHECK-NEXT: [[C_3:%.*]] = icmp slt i8 [[START_1]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 [[C_3]])
; CHECK-NEXT: [[START_2:%.*]] = add nsw i8 [[START]], -2
; CHECK-NEXT: [[C_4:%.*]] = icmp slt i8 [[START_2]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 [[C_4]])
; CHECK-NEXT: [[START_3:%.*]] = add nsw i8 [[START]], -3
; CHECK-NEXT: [[T_1:%.*]] = icmp slt i8 [[START_3]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[START_4:%.*]] = add nsw i8 [[START]], -4
; CHECK-NEXT: [[T_2:%.*]] = icmp slt i8 [[START_4]], [[HIGH]]
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
;
entry:
%add.ptr.i = add nsw i8 %start, -3
%c.1 = icmp slt i8 %add.ptr.i, %high
call void @llvm.assume(i1 %c.1)
%c.2 = icmp slt i8 %start, %high
call void @use(i1 %c.2)
%start.1 = add nsw i8 %start, 1
%c.3 = icmp slt i8 %start.1, %high
call void @use(i1 %c.3)
%start.2 = add nsw i8 %start, -2
%c.4 = icmp slt i8 %start.2, %high
call void @use(i1 %c.4)
%start.3 = add nsw i8 %start, -3
%t.1 = icmp slt i8 %start.3, %high
call void @use(i1 %t.1)
%start.4 = add nsw i8 %start, -4
%t.2 = icmp slt i8 %start.4, %high
call void @use(i1 %t.2)
ret void
}
declare void @llvm.assume(i1)

View File

@ -148,7 +148,7 @@ define i1 @test_add_nsw(i8 %start, i8 %low, i8 %high) {
; CHECK-NEXT: [[F_1:%.*]] = icmp uge i8 [[START_1]], [[HIGH]]
; CHECK-NEXT: [[RES_0:%.*]] = xor i1 [[F_0]], [[F_1]]
; CHECK-NEXT: [[SC_1:%.*]] = icmp sgt i8 [[START]], [[HIGH]]
; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[RES_0]], [[SC_1]]
; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[RES_0]], false
; CHECK-NEXT: [[SC_2:%.*]] = icmp sge i8 [[START_1]], [[HIGH]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[SC_2]]
; CHECK-NEXT: [[START_2:%.*]] = add nuw i8 [[START]], 2