[llvm] [InstCombine] lshr (mul (X, 2^N + 1)), N -> add (X, lshr(X, N)) (PR #90295)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Thu May 16 09:53:15 PDT 2024


================
@@ -1457,13 +1457,24 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
 
     const APInt *MulC;
     if (match(Op0, m_NUWMul(m_Value(X), m_APInt(MulC)))) {
-      // Look for a "splat" mul pattern - it replicates bits across each half of
-      // a value, so a right shift is just a mask of the low bits:
-      // lshr i[2N] (mul nuw X, (2^N)+1), N --> and iN X, (2^N)-1
-      // TODO: Generalize to allow more than just half-width shifts?
-      if (BitWidth > 2 && ShAmtC * 2 == BitWidth && (*MulC - 1).isPowerOf2() &&
-          MulC->logBase2() == ShAmtC)
-        return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, *MulC - 2));
+      if (BitWidth > 2 && (*MulC - 1).isPowerOf2() &&
+          MulC->logBase2() == ShAmtC) {
+        // Look for a "splat" mul pattern - it replicates bits across each half
+        // of a value, so a right shift is just a mask of the low bits:
+        // lshr i[2N] (mul nuw X, (2^N)+1), N --> and iN X, (2^N)-1
+        if (ShAmtC * 2 == BitWidth)
+          return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, *MulC - 2));
+
+        // lshr (mul nuw (X, 2^N + 1)), N -> add nuw (X, lshr(X, N))
----------------
dtcxzyw wrote:

> I'm not entirely sure, but it's possible that the nuw flag makes this safe (by converting problematic undef cases to poison).

It is confusing to me. Is this behavior documented in LangRef?
See https://alive2.llvm.org/ce/z/i2eXpk
```
; bad
define i8 @src1(i8 %x) {
  %shl = shl i8 %x, 1
  ret i8 %shl
}

define i8 @tgt1(i8 %x) {
  %add = add i8 %x, %x
  ret i8 %add
}

; good
define i8 @src2(i8 %x) {
  %shl = shl nuw i8 %x, 1
  ret i8 %shl
}

define i8 @tgt2(i8 %x) {
  %add = add i8 %x, %x
  ret i8 %add
}
```

https://github.com/llvm/llvm-project/pull/90295


More information about the llvm-commits mailing list