[llvm] [LVI][CVP] Fold trunc bittest to true/false. (PR #124480)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 26 12:23:55 PST 2025


https://github.com/andjo403 updated https://github.com/llvm/llvm-project/pull/124480

>From 137baab50595c0f635b6edd3c47b89385c9af97f Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 26 Jan 2025 21:23:35 +0100
Subject: [PATCH] [LVI][CVP] Fold trunc bittest to true/false.

---
 llvm/lib/Analysis/LazyValueInfo.cpp           | 19 ++++++++++++++++
 .../Scalar/CorrelatedValuePropagation.cpp     | 18 +++++++++++++++
 .../CorrelatedValuePropagation/icmp.ll        | 22 +++++++------------
 3 files changed, 45 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 20f69a0955f51c..05c66457fdaa3e 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -398,6 +398,8 @@ class LazyValueInfoImpl {
   std::optional<ValueLatticeElement>
   getValueFromICmpCondition(Value *Val, ICmpInst *ICI, bool isTrueDest,
                             bool UseBlockValue);
+  std::optional<ValueLatticeElement>
+  getValueFromTrunc(Value *Val, TruncInst *Trunc, bool IsTrueDest);
 
   std::optional<ValueLatticeElement>
   getValueFromCondition(Value *Val, Value *Cond, bool IsTrueDest,
@@ -1283,6 +1285,20 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
   return ValueLatticeElement::getOverdefined();
 }
 
+std::optional<ValueLatticeElement>
+LazyValueInfoImpl::getValueFromTrunc(Value *Val, TruncInst *Trunc,
+                                     bool IsTrueDest) {
+  assert(Trunc->getType()->isIntegerTy(1));
+
+  Type *Ty = Val->getType();
+  if (!Ty->isIntegerTy() || Trunc->getOperand(0) != Val)
+    return ValueLatticeElement::getOverdefined();
+
+  if (IsTrueDest)
+    return ValueLatticeElement::getNot(Constant::getNullValue(Ty));
+  return ValueLatticeElement::getNot(Constant::getAllOnesValue(Ty));
+}
+
 // Handle conditions of the form
 // extractvalue(op.with.overflow(%x, C), 1).
 static ValueLatticeElement getValueFromOverflowCondition(
@@ -1312,6 +1328,9 @@ LazyValueInfoImpl::getValueFromCondition(Value *Val, Value *Cond,
   if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond))
     return getValueFromICmpCondition(Val, ICI, IsTrueDest, UseBlockValue);
 
+  if (auto *Trunc = dyn_cast<TruncInst>(Cond))
+    return getValueFromTrunc(Val, Trunc, IsTrueDest);
+
   if (auto *EVI = dyn_cast<ExtractValueInst>(Cond))
     if (auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand()))
       if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1)
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 8e74b8645fad9a..107900cdfdc5d3 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -348,6 +348,21 @@ static bool processCmp(CmpInst *Cmp, LazyValueInfo *LVI) {
   return false;
 }
 
+static bool processTrunc(TruncInst *Trunc, LazyValueInfo *LVI) {
+  Type *Ty = Trunc->getType();
+  if (!Ty->isIntegerTy(1))
+    return false;
+
+  Value *Arg = Trunc->getOperand(0);
+  ConstantRange Res = LVI->getConstantRange(Arg, Trunc, false);
+  if (Res.contains(APInt::getZero(Arg->getType()->getScalarSizeInBits())))
+    return false;
+
+  Trunc->replaceAllUsesWith(ConstantInt::getTrue(Ty));
+  Trunc->eraseFromParent();
+  return true;
+}
+
 /// Simplify a switch instruction by removing cases which can never fire. If the
 /// uselessness of a case could be determined locally then constant propagation
 /// would already have figured it out. Instead, walk the predecessors and
@@ -1239,6 +1254,9 @@ static bool runImpl(Function &F, LazyValueInfo *LVI, DominatorTree *DT,
       case Instruction::FCmp:
         BBChanged |= processCmp(cast<CmpInst>(&II), LVI);
         break;
+      case Instruction::Trunc:
+        BBChanged |= processTrunc(cast<TruncInst>(&II), LVI);
+        break;
       case Instruction::Call:
       case Instruction::Invoke:
         BBChanged |= processCallSite(cast<CallBase>(II), LVI);
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
index e4de34c339d2de..a470109ff7afbd 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
@@ -1515,10 +1515,8 @@ define void @test_trunc_bittest(i8 %a) {
 ; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[A:%.*]] to i1
 ; CHECK-NEXT:    br i1 [[TRUNC]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; CHECK:       if.true:
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[A]], 0
-; CHECK-NEXT:    call void @check1(i1 [[CMP1]])
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 [[A]], 0
-; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 false)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
 ; CHECK-NEXT:    ret void
@@ -1543,10 +1541,8 @@ define void @test_trunc_not_bittest(i8 %a) {
 ; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
 ; CHECK-NEXT:    br i1 [[NOT]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]]
 ; CHECK:       if.true:
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[A]], -1
-; CHECK-NEXT:    call void @check1(i1 [[CMP1]])
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 [[A]], -1
-; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 false)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
 ; CHECK-NEXT:    ret void
@@ -1571,8 +1567,7 @@ define void @test_icmp_trunc(i8 %a) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[A:%.*]], 0
 ; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; CHECK:       if.true:
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[A]] to i1
-; CHECK-NEXT:    call void @check1(i1 [[TRUNC]])
+; CHECK-NEXT:    call void @check1(i1 true)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
 ; CHECK-NEXT:    ret void
@@ -1594,9 +1589,8 @@ define void @test_icmp_trunc_not(i8 %a) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[A:%.*]], -1
 ; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; CHECK:       if.true:
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[A]] to i1
-; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
-; CHECK-NEXT:    call void @check1(i1 [[TRUNC]])
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 true, true
+; CHECK-NEXT:    call void @check1(i1 [[NOT]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
 ; CHECK-NEXT:    ret void
@@ -1607,7 +1601,7 @@ define void @test_icmp_trunc_not(i8 %a) {
 if.true:
   %trunc = trunc i8 %a to i1
   %not = xor i1 %trunc, true
-  call void @check1(i1 %trunc)
+  call void @check1(i1 %not)
   ret void
 
 if.false:



More information about the llvm-commits mailing list