From 4cc8e51b5c7ae9db99b710f2cde3e5a63b0cc5e6 Mon Sep 17 00:00:00 2001 From: Poseydon42 Date: Sun, 7 Jul 2024 23:00:38 +0100 Subject: [PATCH 1/3] [ConstraintElimination] Add support for UCMP/SCMP intrinsics --- .../Scalar/ConstraintElimination.cpp | 26 +++++ .../Transforms/ConstraintElimination/uscmp.ll | 110 ++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 llvm/test/Transforms/ConstraintElimination/uscmp.ll diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 52d9969426105..ea382e8e7ef37 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1087,6 +1087,8 @@ void State::addInfoFor(BasicBlock &BB) { } // Enqueue ssub_with_overflow for simplification. case Intrinsic::ssub_with_overflow: + case Intrinsic::ucmp: + case Intrinsic::scmp: WorkList.push_back( FactOrCheck::getCheck(DT.getNode(&BB), cast(&I))); break; @@ -1448,6 +1450,28 @@ static bool checkAndReplaceMinMax(MinMaxIntrinsic *MinMax, ConstraintInfo &Info, return false; } +static bool checkAndReplaceCmp(CmpIntrinsic *I, ConstraintInfo &Info, + SmallVectorImpl &ToRemove) { + Value *LHS = I->getOperand(0); + Value *RHS = I->getOperand(1); + if (checkCondition(I->getGTPredicate(), LHS, RHS, I, Info).value_or(false)) { + I->replaceAllUsesWith(ConstantInt::get(I->getType(), 1)); + ToRemove.push_back(I); + return true; + } + if (checkCondition(I->getLTPredicate(), LHS, RHS, I, Info).value_or(false)) { + I->replaceAllUsesWith(ConstantInt::getSigned(I->getType(), -1)); + ToRemove.push_back(I); + return true; + } + if (checkCondition(ICmpInst::ICMP_EQ, LHS, RHS, I, Info)) { + I->replaceAllUsesWith(ConstantInt::get(I->getType(), 0)); + ToRemove.push_back(I); + return true; + } + return false; +} + static void removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info, Module *ReproducerModule, @@ -1750,6 +1774,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI, Changed |= Simplified; } else if (auto *MinMax = dyn_cast(Inst)) { Changed |= checkAndReplaceMinMax(MinMax, Info, ToRemove); + } else if (auto *CmpIntrinsic = dyn_cast(Inst)) { + Changed |= checkAndReplaceCmp(CmpIntrinsic, Info, ToRemove); } continue; } diff --git a/llvm/test/Transforms/ConstraintElimination/uscmp.ll b/llvm/test/Transforms/ConstraintElimination/uscmp.ll new file mode 100644 index 0000000000000..16ca93f0427e7 --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/uscmp.ll @@ -0,0 +1,110 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s + +define i8 @scmp_1(i32 %x, i32 %y) { +; CHECK-LABEL: @scmp_1( +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: ret i8 1 +; CHECK: false: +; CHECK-NEXT: ret i8 20 +; + %cond = icmp sgt i32 %x, %y + br i1 %cond, label %true, label %false +true: + %r = call i8 @llvm.scmp(i32 %x, i32 %y) + ret i8 %r +false: + ret i8 20 +} + +define i8 @ucmp_1(i32 %x, i32 %y) { +; CHECK-LABEL: @ucmp_1( +; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: ret i8 -1 +; CHECK: false: +; CHECK-NEXT: ret i8 20 +; + %cond = icmp ult i32 %x, %y + br i1 %cond, label %true, label %false +true: + %r = call i8 @llvm.ucmp(i32 %x, i32 %y) + ret i8 %r +false: + ret i8 20 +} + +define i8 @scmp_2(i32 %x, i32 %y) { +; CHECK-LABEL: @scmp_2( +; CHECK-NEXT: [[COND:%.*]] = icmp sge i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: ret i8 20 +; CHECK: false: +; CHECK-NEXT: ret i8 -1 +; + %cond = icmp sge i32 %x, %y + br i1 %cond, label %true, label %false +true: + ret i8 20 +false: + %r = call i8 @llvm.scmp(i32 %x, i32 %y) + ret i8 %r +} + +define i8 @ucmp_2(i32 %x, i32 %y) { +; CHECK-LABEL: @ucmp_2( +; CHECK-NEXT: [[COND:%.*]] = icmp ule i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: ret i8 20 +; CHECK: false: +; CHECK-NEXT: ret i8 1 +; + %cond = icmp ule i32 %x, %y + br i1 %cond, label %true, label %false +true: + ret i8 20 +false: + %r = call i8 @llvm.ucmp(i32 %x, i32 %y) + ret i8 %r +} + +define i8 @scmp_3(i32 %x, i32 %y) { +; CHECK-LABEL: @scmp_3( +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: ret i8 0 +; CHECK: false: +; CHECK-NEXT: ret i8 20 +; + %cond = icmp eq i32 %x, %y + br i1 %cond, label %true, label %false +true: + %r = call i8 @llvm.scmp(i32 %x, i32 %y) + ret i8 %r +false: + ret i8 20 +} + +define i8 @ucmp_3(i32 %x, i32 %y) { +; CHECK-LABEL: @ucmp_3( +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: ret i8 0 +; CHECK: false: +; CHECK-NEXT: ret i8 20 +; + %cond = icmp eq i32 %x, %y + br i1 %cond, label %true, label %false +true: + %r = call i8 @llvm.ucmp(i32 %x, i32 %y) + ret i8 %r +false: + ret i8 20 +} From 114c4f8dd9b2f14d43de2455df4c7df9143adf90 Mon Sep 17 00:00:00 2001 From: Poseydon42 Date: Tue, 9 Jul 2024 12:40:33 +0100 Subject: [PATCH 2/3] Added negative tests for mismatched signedness --- .../Transforms/ConstraintElimination/uscmp.ll | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/llvm/test/Transforms/ConstraintElimination/uscmp.ll b/llvm/test/Transforms/ConstraintElimination/uscmp.ll index 16ca93f0427e7..63ac050f2c3c5 100644 --- a/llvm/test/Transforms/ConstraintElimination/uscmp.ll +++ b/llvm/test/Transforms/ConstraintElimination/uscmp.ll @@ -108,3 +108,42 @@ true: false: ret i8 20 } + +; Negative test: signedness mismatch +define i8 @scmp_4(i32 %x, i32 %y) { +; CHECK-LABEL: @scmp_4( +; CHECK-NEXT: [[COND:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: ret i8 20 +; CHECK: false: +; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: ret i8 [[R]] +; + %cond = icmp ugt i32 %x, %y + br i1 %cond, label %true, label %false +true: + ret i8 20 +false: + %r = call i8 @llvm.scmp(i32 %x, i32 %y) + ret i8 %r +} + +define i8 @ucmp_4(i32 %x, i32 %y) { +; CHECK-LABEL: @ucmp_4( +; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: ret i8 20 +; CHECK: false: +; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: ret i8 [[R]] +; + %cond = icmp slt i32 %x, %y + br i1 %cond, label %true, label %false +true: + ret i8 20 +false: + %r = call i8 @llvm.ucmp(i32 %x, i32 %y) + ret i8 %r +} From 48a31bf1904a7c5993540a38351433ac6a477648 Mon Sep 17 00:00:00 2001 From: Poseydon42 Date: Wed, 10 Jul 2024 20:01:27 +0100 Subject: [PATCH 3/3] Variable renaming --- llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index ea382e8e7ef37..c31173879af1e 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1774,8 +1774,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI, Changed |= Simplified; } else if (auto *MinMax = dyn_cast(Inst)) { Changed |= checkAndReplaceMinMax(MinMax, Info, ToRemove); - } else if (auto *CmpIntrinsic = dyn_cast(Inst)) { - Changed |= checkAndReplaceCmp(CmpIntrinsic, Info, ToRemove); + } else if (auto *CmpIntr = dyn_cast(Inst)) { + Changed |= checkAndReplaceCmp(CmpIntr, Info, ToRemove); } continue; }