[llvm] [InstCombine] Fold `lshr -> zext -> shl` patterns (PR #147737)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 11 23:36:20 PDT 2025


================
@@ -978,6 +978,47 @@ Instruction *InstCombinerImpl::foldLShrOverflowBit(BinaryOperator &I) {
   return new ZExtInst(Overflow, Ty);
 }
 
+/// If the operand of a zext-ed left shift \p V is a logically right-shifted
+/// value, try to fold the opposing shifts.
+static Instruction *foldShrThroughZExtedShl(Type *DestTy, Value *V,
+                                            unsigned ShlAmt,
+                                            InstCombinerImpl &IC,
+                                            const DataLayout &DL) {
+  auto *I = dyn_cast<Instruction>(V);
+  if (!I)
+    return nullptr;
+
+  // Dig through operations until the first shift.
+  while (!I->isShift())
+    if (!match(I, m_BinOp(m_OneUse(m_Instruction(I)), m_Constant())))
+      return nullptr;
----------------
dtcxzyw wrote:

An alternative is to fold two adjacent `unpack-pack` patterns into one in `InstCombinerImpl::foldDisjointOr`: https://alive2.llvm.org/ce/z/N25Hx_
```
define i64 @src(i32 %upper) {
  %r.1 = lshr i32 %upper, 8
  %u.1 = and i32 %r.1, 255
  %z.1 = zext nneg i32 %u.1 to i64
  %s.1 = shl nuw nsw i64 %z.1, 40

  %r.2 = lshr i32 %upper, 16
  %u.2 = and i32 %r.2, 255
  %z.2 = zext nneg i32 %u.2 to i64
  %s.2 = shl nuw nsw i64 %z.2, 48

  %o.1 = or disjoint i64 %s.2, %s.1
  ret i64 %o.1
}

define i64 @tgt(i32 %upper) {
  %r.1 = lshr i32 %upper, 8
  %u.1 = and i32 %r.1, 65535
  %z.1 = zext nneg i32 %u.1 to i64
  %s.1 = shl nuw nsw i64 %z.1, 40
  ret i64 %s.1
}
```
Then `InstCombinerImpl::reassociateDisjointOr` will handle other stuff.


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


More information about the llvm-commits mailing list