[llvm] Test changes (PR #214439)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 6 02:40:34 PDT 2026


https://github.com/Ineshmcw created https://github.com/llvm/llvm-project/pull/214439

None

>From 6c45e7c6870e9d69d43a72c2c2a88c3ab0741fa4 Mon Sep 17 00:00:00 2001
From: Sree Inesh Murugan Palanisamy <inesh.murugan at multicorewareinc.com>
Date: Thu, 6 Aug 2026 15:08:50 +0530
Subject: [PATCH] Test changes

---
 .../InstCombine/InstCombineCasts.cpp          |  18 ++
 .../InstCombine/trunc-Ishr-add-shl.ll         | 167 ++++++++++++++++++
 2 files changed, 185 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/trunc-Ishr-add-shl.ll

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 2db6396b9d661..0eaae3c2dc729 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1216,6 +1216,24 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
     // TODO: Mask high bits with 'and'.
   }
 
+  // trunc (lshr (add (shl X, ShAmt), AddC), ShrAmt) -->
+  //   trunc (add (shl X, ShAmt - ShrAmt), AddC >> ShrAmt)
+  {
+    const APInt *ShAmt, *AddC, *ShrAmt;
+    if (match(Src, m_OneUse(m_LShr(m_Add(m_Shl(m_Value(X), m_APInt(ShAmt)),
+                                         m_APInt(AddC)),
+                                   m_APInt(ShrAmt)))) &&
+        ShrAmt->ule(*ShAmt) &&
+        ShrAmt->getZExtValue() <= SrcWidth - DestWidth &&
+        AddC->countr_zero() >= ShrAmt->getZExtValue()) {
+      Value *NewShl = Builder.CreateShl(
+          X, ConstantInt::get(SrcTy, *ShAmt - *ShrAmt));
+      Value *NewAdd =
+          Builder.CreateAdd(NewShl, ConstantInt::get(SrcTy, AddC->lshr(*ShrAmt)));
+      return new TruncInst(NewAdd, DestTy);
+    }
+  }
+
   if (Instruction *I = narrowBinOp(Trunc))
     return I;
 
diff --git a/llvm/test/Transforms/InstCombine/trunc-Ishr-add-shl.ll b/llvm/test/Transforms/InstCombine/trunc-Ishr-add-shl.ll
new file mode 100644
index 0000000000000..de2a6064b53f4
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/trunc-Ishr-add-shl.ll
@@ -0,0 +1,167 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+; trunc(lshr(add(shl(X, ShAmt), AddC), ShrAmt))
+;   --> trunc(add(shl(X, ShAmt - ShrAmt), AddC >> ShrAmt))
+;
+; %x is the result of an opaque call in most tests below purely so the
+; RUN line's output is stable and easy to read; InstCombine's generic
+; "shrink the whole expression to a smaller type" machinery still applies
+; on top of this fold once the lshr is gone, which is expected -- it just
+; means the fold enables further cleanup, not that it's being bypassed.
+declare i32 @opaque(i32)
+declare void @use32(i32)
+
+define i8 @src_from_issue(i32 %x) {
+; CHECK-LABEL: define i8 @src_from_issue(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[X_TR:%.*]] = trunc i32 [[X]] to i8
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i8 [[X_TR]], 4
+; CHECK-NEXT:    [[V17:%.*]] = add i8 [[TMP1]], -120
+; CHECK-NEXT:    ret i8 [[V17]]
+;
+  %v2 = shl i32 %x, 12
+  %v3 = add i32 %v2, 34816
+  %v16 = lshr i32 %v3, 8
+  %v17 = trunc i32 %v16 to i8
+  ret i8 %v17
+}
+
+define i8 @positive_basic(i32 %y) {
+; CHECK-LABEL: define i8 @positive_basic(
+; CHECK-SAME: i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[X:%.*]] = call i32 @opaque(i32 [[Y]])
+; CHECK-NEXT:    [[X_TR:%.*]] = trunc i32 [[X]] to i8
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i8 [[X_TR]], 4
+; CHECK-NEXT:    [[V17:%.*]] = add i8 [[TMP1]], -120
+; CHECK-NEXT:    ret i8 [[V17]]
+;
+  %x = call i32 @opaque(i32 %y)
+  %v2 = shl i32 %x, 12
+  %v3 = add i32 %v2, 34816
+  %v16 = lshr i32 %v3, 8
+  %v17 = trunc i32 %v16 to i8
+  ret i8 %v17
+}
+
+; ShrAmt == ShAmt: the new shift amount is 0.
+define i8 @positive_boundary_shramt_eq_shamt(i32 %y) {
+; CHECK-LABEL: define i8 @positive_boundary_shramt_eq_shamt(
+; CHECK-SAME: i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[X:%.*]] = call i32 @opaque(i32 [[Y]])
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[X]] to i8
+; CHECK-NEXT:    [[V17:%.*]] = add i8 [[TMP1]], -120
+; CHECK-NEXT:    ret i8 [[V17]]
+;
+  %x = call i32 @opaque(i32 %y)
+  %v2 = shl i32 %x, 8
+  %v3 = add i32 %v2, 34816
+  %v16 = lshr i32 %v3, 8
+  %v17 = trunc i32 %v16 to i8
+  ret i8 %v17
+}
+
+; ShrAmt == SrcWidth - DestWidth (24): still safe, right at the boundary.
+define i8 @positive_boundary_shramt_eq_srcwidth_minus_destwidth(i32 %y) {
+; CHECK-LABEL: define i8 @positive_boundary_shramt_eq_srcwidth_minus_destwidth(
+; CHECK-SAME: i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[X:%.*]] = call i32 @opaque(i32 [[Y]])
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[X]] to i8
+; CHECK-NEXT:    [[V17:%.*]] = add i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i8 [[V17]]
+;
+  %x = call i32 @opaque(i32 %y)
+  %v2 = shl i32 %x, 24
+  %v3 = add i32 %v2, 16777216
+  %v16 = lshr i32 %v3, 24
+  %v17 = trunc i32 %v16 to i8
+  ret i8 %v17
+}
+
+; Negative test: ShrAmt (4) < ShAmt is fine, but here ShrAmt (8) > ShAmt (4),
+; which would require a negative shift amount, so the fold must not fire.
+define i8 @negative_shramt_gt_shamt(i32 %y) {
+; CHECK-LABEL: define i8 @negative_shramt_gt_shamt(
+; CHECK-SAME: i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[X:%.*]] = call i32 @opaque(i32 [[Y]])
+; CHECK-NEXT:    [[V2:%.*]] = shl i32 [[X]], 4
+; CHECK-NEXT:    [[V3:%.*]] = add i32 [[V2]], 34816
+; CHECK-NEXT:    [[V16:%.*]] = lshr i32 [[V3]], 8
+; CHECK-NEXT:    [[V17:%.*]] = trunc i32 [[V16]] to i8
+; CHECK-NEXT:    ret i8 [[V17]]
+;
+  %x = call i32 @opaque(i32 %y)
+  %v2 = shl i32 %x, 4
+  %v3 = add i32 %v2, 34816
+  %v16 = lshr i32 %v3, 8
+  %v17 = trunc i32 %v16 to i8
+  ret i8 %v17
+}
+
+; Negative test: AddC's low ShrAmt bits are not zero (34817 is not a
+; multiple of 256), so the lshr can't be distributed over the add exactly.
+; %v3 is kept alive via @use32 so an unrelated demanded-bits simplification
+; can't quietly clear that low bit before this fold's check ever runs.
+define i8 @negative_addc_not_aligned(i32 %y) {
+; CHECK-LABEL: define i8 @negative_addc_not_aligned(
+; CHECK-SAME: i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[X:%.*]] = call i32 @opaque(i32 [[Y]])
+; CHECK-NEXT:    [[V2:%.*]] = shl i32 [[X]], 12
+; CHECK-NEXT:    [[V3:%.*]] = add i32 [[V2]], 34817
+; CHECK-NEXT:    call void @use32(i32 [[V3]])
+; CHECK-NEXT:    [[V16:%.*]] = lshr i32 [[V3]], 8
+; CHECK-NEXT:    [[V17:%.*]] = trunc i32 [[V16]] to i8
+; CHECK-NEXT:    ret i8 [[V17]]
+;
+  %x = call i32 @opaque(i32 %y)
+  %v2 = shl i32 %x, 12
+  %v3 = add i32 %v2, 34817
+  call void @use32(i32 %v3)
+  %v16 = lshr i32 %v3, 8
+  %v17 = trunc i32 %v16 to i8
+  ret i8 %v17
+}
+
+; Negative test: ShrAmt (25) > SrcWidth - DestWidth (24), even though AddC
+; (2^25) is still a multiple of 2^25. A freshly computed "X << (ShAmt -
+; ShrAmt)" would disagree with "(X << ShAmt) >> ShrAmt" in a bit that the
+; final trunc to i8 would still observe, so the fold must not fire.
+define i8 @negative_shramt_too_large(i32 %y) {
+; CHECK-LABEL: define i8 @negative_shramt_too_large(
+; CHECK-SAME: i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[X:%.*]] = call i32 @opaque(i32 [[Y]])
+; CHECK-NEXT:    [[X_TR:%.*]] = trunc i32 [[X]] to i8
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i8 [[X_TR]], 5
+; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[TMP1]], 96
+; CHECK-NEXT:    [[V17:%.*]] = or disjoint i8 [[TMP2]], 1
+; CHECK-NEXT:    ret i8 [[V17]]
+;
+  %x = call i32 @opaque(i32 %y)
+  %v2 = shl i32 %x, 30
+  %v3 = add i32 %v2, 33554432
+  %v16 = lshr i32 %v3, 25
+  %v17 = trunc i32 %v16 to i8
+  ret i8 %v17
+}
+
+; Negative test: the lshr has another use, so replacing the trunc's operand
+; would leave the original computation behind rather than eliminating it.
+define i8 @negative_lshr_multi_use(i32 %y, ptr %p) {
+; CHECK-LABEL: define i8 @negative_lshr_multi_use(
+; CHECK-SAME: i32 [[Y:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[X:%.*]] = call i32 @opaque(i32 [[Y]])
+; CHECK-NEXT:    [[V2:%.*]] = shl i32 [[X]], 12
+; CHECK-NEXT:    [[V3:%.*]] = add i32 [[V2]], 34816
+; CHECK-NEXT:    [[V16:%.*]] = lshr exact i32 [[V3]], 8
+; CHECK-NEXT:    store i32 [[V16]], ptr [[P]], align 4
+; CHECK-NEXT:    [[V17:%.*]] = trunc i32 [[V16]] to i8
+; CHECK-NEXT:    ret i8 [[V17]]
+;
+  %x = call i32 @opaque(i32 %y)
+  %v2 = shl i32 %x, 12
+  %v3 = add i32 %v2, 34816
+  %v16 = lshr i32 %v3, 8
+  store i32 %v16, ptr %p
+  %v17 = trunc i32 %v16 to i8
+  ret i8 %v17
+}



More information about the llvm-commits mailing list