[llvm] [LLVM] Improve the DemandedBits Analysis (PR #148880)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 15 09:12:49 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Panagiotis K (karouzakisp)
<details>
<summary>Changes</summary>
This is part of a larger PR: #<!-- -->148853
To improve the DemandedBits Analysis.
Here we add support to the shift operators to handle non-constant shift operands.
---
Full diff: https://github.com/llvm/llvm-project/pull/148880.diff
2 Files Affected:
- (modified) llvm/lib/Analysis/DemandedBits.cpp (+46)
- (modified) llvm/test/Analysis/DemandedBits/shl.ll (+47-1)
``````````diff
diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp
index 6694d5cc06c8c..2d30575c19130 100644
--- a/llvm/lib/Analysis/DemandedBits.cpp
+++ b/llvm/lib/Analysis/DemandedBits.cpp
@@ -36,6 +36,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/KnownBits.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdint>
@@ -183,6 +184,17 @@ void DemandedBits::determineLiveOperandBits(
AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt+1);
else if (S->hasNoUnsignedWrap())
AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt);
+ } else {
+ ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr);
+ unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
+ unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
+ // similar to Lshr case
+ AB = (AOut.lshr(Min) | AOut.lshr(Max));
+ const auto *S = cast<ShlOperator>(UserI);
+ if (S->hasNoSignedWrap())
+ AB |= APInt::getHighBitsSet(BitWidth, Max + 1);
+ else if (S->hasNoUnsignedWrap())
+ AB |= APInt::getHighBitsSet(BitWidth, Max);
}
}
break;
@@ -197,6 +209,19 @@ void DemandedBits::determineLiveOperandBits(
// (they must be zero).
if (cast<LShrOperator>(UserI)->isExact())
AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
+ } else {
+ ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr);
+ unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
+ unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
+ // Suppose AOut == 0b0000 0011
+ // [min, max] = [1, 3]
+ // shift by 1 we get 0b0000 0110
+ // shift by 2 we get 0b0000 1100
+ // shift by 3 we get 0b0001 1000
+ // we take the or here because need to cover all the above possibilities
+ AB = (AOut.shl(Min) | AOut.shl(Max));
+ if (cast<LShrOperator>(UserI)->isExact())
+ AB |= APInt::getLowBitsSet(BitWidth, Max);
}
}
break;
@@ -217,6 +242,27 @@ void DemandedBits::determineLiveOperandBits(
// (they must be zero).
if (cast<AShrOperator>(UserI)->isExact())
AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
+ } else {
+ ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr);
+ unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
+ unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
+ AB = (AOut.shl(Min) | AOut.shl(Max));
+
+ if (Max) {
+ // Suppose AOut = 0011 1100
+ // [min, max] = [1, 3]
+ // ShiftAmount = 1 : Mask is 1000 0000
+ // ShiftAmount = 2 : Mask is 1100 0000
+ // ShiftAmount = 3 : Mask is 1110 0000
+ // The Mask with Max covers every case in [min, max],
+ // so we are done
+ if ((AOut & APInt::getHighBitsSet(BitWidth, Max)).getBoolValue())
+ AB.setSignBit();
+ }
+ // If the shift is exact, then the low bits are not dead
+ // (they must be zero).
+ if (cast<AShrOperator>(UserI)->isExact())
+ AB |= APInt::getLowBitsSet(BitWidth, Max);
}
}
break;
diff --git a/llvm/test/Analysis/DemandedBits/shl.ll b/llvm/test/Analysis/DemandedBits/shl.ll
index e41f5f4107735..c3313a93c1e85 100644
--- a/llvm/test/Analysis/DemandedBits/shl.ll
+++ b/llvm/test/Analysis/DemandedBits/shl.ll
@@ -57,10 +57,56 @@ define i8 @test_shl(i32 %a, i32 %b) {
; CHECK-DAG: DemandedBits: 0xff for %shl.t = trunc i32 %shl to i8
; CHECK-DAG: DemandedBits: 0xff for %shl in %shl.t = trunc i32 %shl to i8
; CHECK-DAG: DemandedBits: 0xff for %shl = shl i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %a in %shl = shl i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xff for %a in %shl = shl i32 %a, %b
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %shl = shl i32 %a, %b
;
%shl = shl i32 %a, %b
%shl.t = trunc i32 %shl to i8
ret i8 %shl.t
}
+
+define i8 @test_shl_var_amount(i32 %a, i32 %b){
+; CHECK-LABEL: 'test_shl_var_amount'
+; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8
+; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8
+; CHECK-DAG: DemandedBits: 0xff for %4 = shl i32 %1, %3
+; CHECK-DAG: DemandedBits: 0xff for %1 in %4 = shl i32 %1, %3
+; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = shl i32 %1, %3
+; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8
+; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8
+; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32
+; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32
+; CHECK-DAG: DemandedBits: 0xff for %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xff for %a in %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xff for %b in %1 = add nsw i32 %a, %b
+;
+ %1 = add nsw i32 %a, %b
+ %2 = trunc i32 %1 to i8
+ %3 = zext i8 %2 to i32
+ %4 = shl i32 %1, %3
+ %5 = trunc i32 %4 to i8
+ ret i8 %5
+}
+
+define i8 @test_shl_var_amount_nsw(i32 %a, i32 %b){
+ ; CHECK-LABEL 'test_shl_var_amount_nsw'
+ ; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8
+ ; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8
+ ; CHECK-DAG: DemandedBits: 0xff for %4 = shl nsw i32 %1, %3
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %1 in %4 = shl nsw i32 %1, %3
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = shl nsw i32 %1, %3
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32
+ ; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32
+ ; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8
+ ; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %1 = add nsw i32 %a, %b
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = add nsw i32 %a, %b
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = add nsw i32 %a, %b
+ ;
+ %1 = add nsw i32 %a, %b
+ %2 = trunc i32 %1 to i8
+ %3 = zext i8 %2 to i32
+ %4 = shl nsw i32 %1, %3
+ %5 = trunc i32 %4 to i8
+ ret i8 %5
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/148880
More information about the llvm-commits
mailing list