[llvm] [InstCombine] Fold reconstruction across select (PR #145102)

Macsen Casaus via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 21 07:43:37 PDT 2025


https://github.com/macsencasaus updated https://github.com/llvm/llvm-project/pull/145102

>From 683da5c0aaa74e4666e072cac3e0b6b0ca9fbb06 Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsencasaus at gmail.com>
Date: Tue, 17 Jun 2025 08:29:40 -0500
Subject: [PATCH 1/3] pre-commit test

---
 .../InstCombine/select-reconstruction.ll      | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/select-reconstruction.ll

diff --git a/llvm/test/Transforms/InstCombine/select-reconstruction.ll b/llvm/test/Transforms/InstCombine/select-reconstruction.ll
new file mode 100644
index 0000000000000..968eb9c1fe67a
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/select-reconstruction.ll
@@ -0,0 +1,112 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i40 @select_reconstruction_i40(i40 %arg0) {
+; CHECK-LABEL: define i40 @select_reconstruction_i40(
+; CHECK-SAME: i40 [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i8
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP7:%.*]] = and i40 [[ARG0]], -256
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i8 0, i8 [[TMP1]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP7]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i8 [[TMP4]] to i40
+; CHECK-NEXT:    [[TMP3:%.*]] = or disjoint i40 [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    ret i40 [[TMP3]]
+;
+  %1 = trunc i40 %arg0 to i8
+  %2 = icmp eq i8 %1, 2
+  %3 = and i40 %arg0, -256
+  %4 = select i1 %2, i8 0, i8 %1
+  %5 = select i1 %2, i40 0, i40 %3
+  %6 = zext i8 %4 to i40
+  %7 = or disjoint i40 %5, %6
+  ret i40 %7
+}
+
+define i40 @select_reconstruction_any_cmp_val(i40 %arg0, i8 %arg1) {
+; CHECK-LABEL: define i40 @select_reconstruction_any_cmp_val(
+; CHECK-SAME: i40 [[ARG0:%.*]], i8 [[ARG1:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i8
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[ARG1]], [[TMP1]]
+; CHECK-NEXT:    [[TMP7:%.*]] = and i40 [[ARG0]], -256
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i8 0, i8 [[TMP1]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP7]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i8 [[TMP4]] to i40
+; CHECK-NEXT:    [[TMP3:%.*]] = or disjoint i40 [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    ret i40 [[TMP3]]
+;
+  %1 = trunc i40 %arg0 to i8
+  %2 = icmp eq i8 %1, %arg1
+  %3 = and i40 %arg0, -256
+  %4 = select i1 %2, i8 0, i8 %1
+  %5 = select i1 %2, i40 0, i40 %3
+  %6 = zext i8 %4 to i40
+  %7 = or disjoint i40 %5, %6
+  ret i40 %7
+}
+
+define i40 @select_reconstruction_257_mask(i40 %arg0) {
+; CHECK-LABEL: define i40 @select_reconstruction_257_mask(
+; CHECK-SAME: i40 [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i8
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = and i40 [[ARG0]], -257
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i8 0, i8 [[TMP1]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i8 [[TMP5]] to i40
+; CHECK-NEXT:    [[TMP7:%.*]] = or disjoint i40 [[TMP4]], [[TMP6]]
+; CHECK-NEXT:    ret i40 [[TMP7]]
+;
+  %1 = trunc i40 %arg0 to i8
+  %2 = icmp eq i8 %1, 2
+  %3 = and i40 %arg0, -257
+  %4 = select i1 %2, i8 0, i8 %1
+  %5 = select i1 %2, i40 0, i40 %3
+  %6 = zext i8 %4 to i40
+  %7 = or disjoint i40 %5, %6
+  ret i40 %7
+}
+
+define i40 @select_reconstruction_i16_mask(i40 %arg0) {
+; CHECK-LABEL: define i40 @select_reconstruction_i16_mask(
+; CHECK-SAME: i40 [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i16
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i16 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP7:%.*]] = and i40 [[ARG0]], -65356
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i16 0, i16 [[TMP1]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP7]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i16 [[TMP4]] to i40
+; CHECK-NEXT:    [[TMP3:%.*]] = or disjoint i40 [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    ret i40 [[TMP3]]
+;
+  %1 = trunc i40 %arg0 to i16
+  %2 = icmp eq i16 %1, 2
+  %3 = and i40 %arg0, -65356
+  %4 = select i1 %2, i16 0, i16 %1
+  %5 = select i1 %2, i40 0, i40 %3
+  %6 = zext i16 %4 to i40
+  %7 = or disjoint i40 %5, %6
+  ret i40 %7
+}
+
+define <2 x i32> @select_reconstruction_vec_any_cmp_val(<2 x i32> %arg0, <2 x i8> %arg1) {
+; CHECK-LABEL: define <2 x i32> @select_reconstruction_vec_any_cmp_val(
+; CHECK-SAME: <2 x i32> [[ARG0:%.*]], <2 x i8> [[ARG1:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[ARG0]] to <2 x i8>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq <2 x i8> [[ARG1]], [[TMP1]]
+; CHECK-NEXT:    [[TMP3:%.*]] = and <2 x i32> [[ARG0]], splat (i32 -256)
+; CHECK-NEXT:    [[TMP4:%.*]] = select <2 x i1> [[TMP2]], <2 x i8> zeroinitializer, <2 x i8> [[TMP1]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> zeroinitializer, <2 x i32> [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext <2 x i8> [[TMP4]] to <2 x i32>
+; CHECK-NEXT:    [[TMP7:%.*]] = or disjoint <2 x i32> [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    ret <2 x i32> [[TMP7]]
+;
+  %1 = trunc <2 x i32> %arg0 to <2 x i8>
+  %2 = icmp eq <2 x i8> %1, %arg1
+  %3 = and <2 x i32> %arg0, <i32 -256, i32 -256>
+  %4 = select <2 x i1> %2, <2 x i8> <i8 0, i8 0>, <2 x i8> %1
+  %5 = select <2 x i1> %2, <2 x i32> <i32 0, i32 0>, <2 x i32> %3
+  %6 = zext <2 x i8> %4 to <2 x i32>
+  %7 = or <2 x i32> %5, %6
+  ret <2 x i32> %7
+}

>From 6f0a946cec035c7613e69fc79e2b6dcd98d0470d Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsencasaus at gmail.com>
Date: Fri, 20 Jun 2025 13:39:57 -0500
Subject: [PATCH 2/3] [InstCombine] Fold reconstruction across select

---
 .../InstCombine/InstructionCombining.cpp      | 35 +++++++++++++++++++
 .../InstCombine/select-reconstruction.ll      | 29 +++------------
 2 files changed, 40 insertions(+), 24 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 4fe900e9421f8..d23441a4a8129 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1349,6 +1349,37 @@ Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,
     return nullptr;
   };
 
+  // Special case for reconstructing across a select:
+  // (Cond ? V1 : (X & Mask)) op
+  // zext (Cond ? V2 : trunc X)
+  // -> (Cond ? (V1 op zext V2) : ((X & Mask) op zext trunc X))
+  auto foldReconstruction = [&](Value *V1, Value *Masked,
+                                Value *ZExtSel) -> Value * {
+    Value *X;
+    if (!match(Masked, m_OneUse(m_And(m_Value(X), m_Constant()))))
+      return nullptr;
+
+    Value *V2, *Trunc;
+    if (!match(ZExtSel, m_ZExt(m_OneUse(m_Select(m_Specific(Cond), m_Value(V2),
+                                                 m_Value(Trunc))))))
+      return nullptr;
+
+    if (!match(Trunc, m_Trunc(m_Specific(X))))
+      return nullptr;
+
+    Value *ZExtTrue = Builder.CreateZExt(V2, V1->getType());
+    Value *True;
+    if (!(True = simplifyBinOp(Opcode, V1, ZExtTrue, FMF, Q)))
+      True = Builder.CreateOr(V1, ZExtTrue);
+
+    Value *ZExtFalse = Builder.CreateZExt(Trunc, V1->getType());
+    Value *False;
+    if (!(False = simplifyBinOp(Opcode, Masked, ZExtFalse, FMF, Q)))
+      False = Builder.CreateOr(Masked, ZExtFalse);
+
+    return Builder.CreateSelect(Cond, True, False, I.getName());
+  };
+
   if (LHSIsSelect && RHSIsSelect && A == D) {
     // (A ? B : C) op (A ? E : F) -> A ? (B op E) : (C op F)
     Cond = A;
@@ -1368,6 +1399,8 @@ Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,
     False = simplifyBinOp(Opcode, C, RHS, FMF, Q);
     if (Value *NewSel = foldAddNegate(B, C, RHS))
       return NewSel;
+    if (Value *NewSel = foldReconstruction(B, C, RHS))
+      return NewSel;
   } else if (RHSIsSelect && RHS->hasOneUse()) {
     // X op (D ? E : F) -> D ? (X op E) : (X op F)
     Cond = D;
@@ -1375,6 +1408,8 @@ Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,
     False = simplifyBinOp(Opcode, LHS, F, FMF, Q);
     if (Value *NewSel = foldAddNegate(E, F, LHS))
       return NewSel;
+    if (Value *NewSel = foldReconstruction(E, F, LHS))
+      return NewSel;
   }
 
   if (!True || !False)
diff --git a/llvm/test/Transforms/InstCombine/select-reconstruction.ll b/llvm/test/Transforms/InstCombine/select-reconstruction.ll
index 968eb9c1fe67a..eb918ed4f40d0 100644
--- a/llvm/test/Transforms/InstCombine/select-reconstruction.ll
+++ b/llvm/test/Transforms/InstCombine/select-reconstruction.ll
@@ -6,11 +6,7 @@ define i40 @select_reconstruction_i40(i40 %arg0) {
 ; CHECK-SAME: i40 [[ARG0:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i8
 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 2
-; CHECK-NEXT:    [[TMP7:%.*]] = and i40 [[ARG0]], -256
-; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i8 0, i8 [[TMP1]]
-; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP7]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i8 [[TMP4]] to i40
-; CHECK-NEXT:    [[TMP3:%.*]] = or disjoint i40 [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP2]], i40 0, i40 [[ARG0]]
 ; CHECK-NEXT:    ret i40 [[TMP3]]
 ;
   %1 = trunc i40 %arg0 to i8
@@ -28,11 +24,7 @@ define i40 @select_reconstruction_any_cmp_val(i40 %arg0, i8 %arg1) {
 ; CHECK-SAME: i40 [[ARG0:%.*]], i8 [[ARG1:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i8
 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[ARG1]], [[TMP1]]
-; CHECK-NEXT:    [[TMP7:%.*]] = and i40 [[ARG0]], -256
-; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i8 0, i8 [[TMP1]]
-; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP7]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i8 [[TMP4]] to i40
-; CHECK-NEXT:    [[TMP3:%.*]] = or disjoint i40 [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP2]], i40 0, i40 [[ARG0]]
 ; CHECK-NEXT:    ret i40 [[TMP3]]
 ;
   %1 = trunc i40 %arg0 to i8
@@ -51,11 +43,8 @@ define i40 @select_reconstruction_257_mask(i40 %arg0) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i8
 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 2
 ; CHECK-NEXT:    [[TMP3:%.*]] = and i40 [[ARG0]], -257
-; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i8 0, i8 [[TMP1]]
 ; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i8 [[TMP5]] to i40
-; CHECK-NEXT:    [[TMP7:%.*]] = or disjoint i40 [[TMP4]], [[TMP6]]
-; CHECK-NEXT:    ret i40 [[TMP7]]
+; CHECK-NEXT:    ret i40 [[TMP4]]
 ;
   %1 = trunc i40 %arg0 to i8
   %2 = icmp eq i8 %1, 2
@@ -72,11 +61,7 @@ define i40 @select_reconstruction_i16_mask(i40 %arg0) {
 ; CHECK-SAME: i40 [[ARG0:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i16
 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i16 [[TMP1]], 2
-; CHECK-NEXT:    [[TMP7:%.*]] = and i40 [[ARG0]], -65356
-; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i16 0, i16 [[TMP1]]
-; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP7]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i16 [[TMP4]] to i40
-; CHECK-NEXT:    [[TMP3:%.*]] = or disjoint i40 [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP2]], i40 0, i40 [[ARG0]]
 ; CHECK-NEXT:    ret i40 [[TMP3]]
 ;
   %1 = trunc i40 %arg0 to i16
@@ -94,11 +79,7 @@ define <2 x i32> @select_reconstruction_vec_any_cmp_val(<2 x i32> %arg0, <2 x i8
 ; CHECK-SAME: <2 x i32> [[ARG0:%.*]], <2 x i8> [[ARG1:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[ARG0]] to <2 x i8>
 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq <2 x i8> [[ARG1]], [[TMP1]]
-; CHECK-NEXT:    [[TMP3:%.*]] = and <2 x i32> [[ARG0]], splat (i32 -256)
-; CHECK-NEXT:    [[TMP4:%.*]] = select <2 x i1> [[TMP2]], <2 x i8> zeroinitializer, <2 x i8> [[TMP1]]
-; CHECK-NEXT:    [[TMP5:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> zeroinitializer, <2 x i32> [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext <2 x i8> [[TMP4]] to <2 x i32>
-; CHECK-NEXT:    [[TMP7:%.*]] = or disjoint <2 x i32> [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    [[TMP7:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> zeroinitializer, <2 x i32> [[ARG0]]
 ; CHECK-NEXT:    ret <2 x i32> [[TMP7]]
 ;
   %1 = trunc <2 x i32> %arg0 to <2 x i8>

>From 9542631ae2818807d199cf0c2ddae8ba6ae3823f Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsencasaus at gmail.com>
Date: Sat, 21 Jun 2025 09:24:00 -0500
Subject: [PATCH 3/3] address review comments

- only apply on OR reconstruction
- rename values in test
---
 .../InstCombine/InstructionCombining.cpp      |   3 +
 .../InstCombine/select-reconstruction.ll      | 103 +++++++++++-------
 2 files changed, 66 insertions(+), 40 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index d23441a4a8129..512a8af43ba46 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1355,6 +1355,9 @@ Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,
   // -> (Cond ? (V1 op zext V2) : ((X & Mask) op zext trunc X))
   auto foldReconstruction = [&](Value *V1, Value *Masked,
                                 Value *ZExtSel) -> Value * {
+    if (Opcode != Instruction::Or)
+      return nullptr;
+
     Value *X;
     if (!match(Masked, m_OneUse(m_And(m_Value(X), m_Constant()))))
       return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/select-reconstruction.ll b/llvm/test/Transforms/InstCombine/select-reconstruction.ll
index eb918ed4f40d0..d54b8ee672222 100644
--- a/llvm/test/Transforms/InstCombine/select-reconstruction.ll
+++ b/llvm/test/Transforms/InstCombine/select-reconstruction.ll
@@ -9,14 +9,14 @@ define i40 @select_reconstruction_i40(i40 %arg0) {
 ; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP2]], i40 0, i40 [[ARG0]]
 ; CHECK-NEXT:    ret i40 [[TMP3]]
 ;
-  %1 = trunc i40 %arg0 to i8
-  %2 = icmp eq i8 %1, 2
-  %3 = and i40 %arg0, -256
-  %4 = select i1 %2, i8 0, i8 %1
-  %5 = select i1 %2, i40 0, i40 %3
-  %6 = zext i8 %4 to i40
-  %7 = or disjoint i40 %5, %6
-  ret i40 %7
+  %low = trunc i40 %arg0 to i8
+  %is_low_two = icmp eq i8 %low, 2
+  %high = and i40 %arg0, -256
+  %select_low = select i1 %is_low_two, i8 0, i8 %low
+  %select_high = select i1 %is_low_two, i40 0, i40 %high
+  %zext_low = zext i8 %select_low to i40
+  %recomb = or disjoint i40 %select_high, %zext_low
+  ret i40 %recomb
 }
 
 define i40 @select_reconstruction_any_cmp_val(i40 %arg0, i8 %arg1) {
@@ -27,14 +27,14 @@ define i40 @select_reconstruction_any_cmp_val(i40 %arg0, i8 %arg1) {
 ; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP2]], i40 0, i40 [[ARG0]]
 ; CHECK-NEXT:    ret i40 [[TMP3]]
 ;
-  %1 = trunc i40 %arg0 to i8
-  %2 = icmp eq i8 %1, %arg1
-  %3 = and i40 %arg0, -256
-  %4 = select i1 %2, i8 0, i8 %1
-  %5 = select i1 %2, i40 0, i40 %3
-  %6 = zext i8 %4 to i40
-  %7 = or disjoint i40 %5, %6
-  ret i40 %7
+  %low = trunc i40 %arg0 to i8
+  %is_low_arg1 = icmp eq i8 %low, %arg1
+  %high = and i40 %arg0, -256
+  %select_low = select i1 %is_low_arg1, i8 0, i8 %low
+  %select_high = select i1 %is_low_arg1, i40 0, i40 %high
+  %zext_low = zext i8 %select_low to i40
+  %recomb = or disjoint i40 %select_high, %zext_low
+  ret i40 %recomb
 }
 
 define i40 @select_reconstruction_257_mask(i40 %arg0) {
@@ -46,14 +46,14 @@ define i40 @select_reconstruction_257_mask(i40 %arg0) {
 ; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP3]]
 ; CHECK-NEXT:    ret i40 [[TMP4]]
 ;
-  %1 = trunc i40 %arg0 to i8
-  %2 = icmp eq i8 %1, 2
-  %3 = and i40 %arg0, -257
-  %4 = select i1 %2, i8 0, i8 %1
-  %5 = select i1 %2, i40 0, i40 %3
-  %6 = zext i8 %4 to i40
-  %7 = or disjoint i40 %5, %6
-  ret i40 %7
+  %low = trunc i40 %arg0 to i8
+  %is_low_two = icmp eq i8 %low, 2
+  %high = and i40 %arg0, -257
+  %select_low = select i1 %is_low_two, i8 0, i8 %low
+  %select_high = select i1 %is_low_two, i40 0, i40 %high
+  %zext_low = zext i8 %select_low to i40
+  %recomb = or disjoint i40 %select_high, %zext_low
+  ret i40 %recomb
 }
 
 define i40 @select_reconstruction_i16_mask(i40 %arg0) {
@@ -64,14 +64,14 @@ define i40 @select_reconstruction_i16_mask(i40 %arg0) {
 ; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP2]], i40 0, i40 [[ARG0]]
 ; CHECK-NEXT:    ret i40 [[TMP3]]
 ;
-  %1 = trunc i40 %arg0 to i16
-  %2 = icmp eq i16 %1, 2
-  %3 = and i40 %arg0, -65356
-  %4 = select i1 %2, i16 0, i16 %1
-  %5 = select i1 %2, i40 0, i40 %3
-  %6 = zext i16 %4 to i40
-  %7 = or disjoint i40 %5, %6
-  ret i40 %7
+  %low = trunc i40 %arg0 to i16
+  %is_low_two = icmp eq i16 %low, 2
+  %high = and i40 %arg0, -65536
+  %select_low = select i1 %is_low_two, i16 0, i16 %low
+  %select_high = select i1 %is_low_two, i40 0, i40 %high
+  %zext_low = zext i16 %select_low to i40
+  %recomb = or disjoint i40 %select_high, %zext_low
+  ret i40 %recomb
 }
 
 define <2 x i32> @select_reconstruction_vec_any_cmp_val(<2 x i32> %arg0, <2 x i8> %arg1) {
@@ -82,12 +82,35 @@ define <2 x i32> @select_reconstruction_vec_any_cmp_val(<2 x i32> %arg0, <2 x i8
 ; CHECK-NEXT:    [[TMP7:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> zeroinitializer, <2 x i32> [[ARG0]]
 ; CHECK-NEXT:    ret <2 x i32> [[TMP7]]
 ;
-  %1 = trunc <2 x i32> %arg0 to <2 x i8>
-  %2 = icmp eq <2 x i8> %1, %arg1
-  %3 = and <2 x i32> %arg0, <i32 -256, i32 -256>
-  %4 = select <2 x i1> %2, <2 x i8> <i8 0, i8 0>, <2 x i8> %1
-  %5 = select <2 x i1> %2, <2 x i32> <i32 0, i32 0>, <2 x i32> %3
-  %6 = zext <2 x i8> %4 to <2 x i32>
-  %7 = or <2 x i32> %5, %6
-  ret <2 x i32> %7
+  %low = trunc <2 x i32> %arg0 to <2 x i8>
+  %is_low_arg1 = icmp eq <2 x i8> %low, %arg1
+  %high = and <2 x i32> %arg0, <i32 -256, i32 -256>
+  %select_low = select <2 x i1> %is_low_arg1, <2 x i8> <i8 0, i8 0>, <2 x i8> %low
+  %select_high = select <2 x i1> %is_low_arg1, <2 x i32> <i32 0, i32 0>, <2 x i32> %high
+  %zext_low = zext <2 x i8> %select_low to <2 x i32>
+  %recomb = or <2 x i32> %select_high, %zext_low
+  ret <2 x i32> %recomb
+}
+
+; negative test
+define i40 @select_reconstruction_impure_i16_mask_and(i40 %arg0) {
+; CHECK-LABEL: define i40 @select_reconstruction_impure_i16_mask_and(
+; CHECK-SAME: i40 [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i40 [[ARG0]] to i16
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i16 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = and i40 [[ARG0]], 180
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i16 0, i16 [[TMP1]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i40 0, i40 [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i16 [[TMP4]] to i40
+; CHECK-NEXT:    [[TMP7:%.*]] = and i40 [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    ret i40 [[TMP7]]
+;
+  %low = trunc i40 %arg0 to i16
+  %is_low_two = icmp eq i16 %low, 2
+  %high = and i40 %arg0, -65356
+  %select_low = select i1 %is_low_two, i16 0, i16 %low
+  %select_high = select i1 %is_low_two, i40 0, i40 %high
+  %zext_low = zext i16 %select_low to i40
+  %recomb = and i40 %select_high, %zext_low
+  ret i40 %recomb
 }



More information about the llvm-commits mailing list