[llvm] 9ef8290 - [InstCombine] Fix buggy transform in `foldNestedSelects`; PR 71330

Noah Goldstein via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 9 14:37:03 PST 2023


Author: Noah Goldstein
Date: 2023-11-09T16:36:49-06:00
New Revision: 9ef829097bbc4cf908698e3891af11a154e1d3e2

URL: https://github.com/llvm/llvm-project/commit/9ef829097bbc4cf908698e3891af11a154e1d3e2
DIFF: https://github.com/llvm/llvm-project/commit/9ef829097bbc4cf908698e3891af11a154e1d3e2.diff

LOG: [InstCombine] Fix buggy transform in `foldNestedSelects`; PR 71330

The bug is that `IsAndVariant` is used to assume which arm in the
select the output `SelInner` should be placed but match the inner
select condition with `m_c_LogicalOp`. With fully simplified ops, this
works fine, but its possible if the select condition is not
simplified, for it match both `LogicalAnd` and `LogicalOr` i.e `select
true, true, false`.

In PR71330 for example, the issue occurs in the following IR:
```
define i32 @bad() {
  %..i.i = select i1 false, i32 0, i32 3
  %brmerge = select i1 true, i1 true, i1 false
  %not.cmp.i.i.not = xor i1 true, true
  %.mux = zext i1 %not.cmp.i.i.not to i32
  %retval.0.i.i = select i1 %brmerge, i32 %.mux, i32 %..i.i
  ret i32 %retval.0.i.i
}
```

When simplifying:
```
%retval.0.i.i = select i1 %brmerge, i32 %.mux, i32 %..i.i
```

We end up matching `%brmerge` as `LogicalAnd` for `IsAndVariant`, but
the inner select (`%..i.i`) condition which is `false` with
`LogicalOr`.

Closes #71489

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/pr71330.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 9bd49f76d4bd5b7..71c2d68881441ac 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2891,8 +2891,15 @@ static Instruction *foldNestedSelects(SelectInst &OuterSelVal,
     std::swap(InnerSel.TrueVal, InnerSel.FalseVal);
 
   Value *AltCond = nullptr;
-  auto matchOuterCond = [OuterSel, &AltCond](auto m_InnerCond) {
-    return match(OuterSel.Cond, m_c_LogicalOp(m_InnerCond, m_Value(AltCond)));
+  auto matchOuterCond = [OuterSel, IsAndVariant, &AltCond](auto m_InnerCond) {
+    // An unsimplified select condition can match both LogicalAnd and LogicalOr
+    // (select true, true, false). Since below we assume that LogicalAnd implies
+    // InnerSel match the FVal and vice versa for LogicalOr, we can't match the
+    // alternative pattern here.
+    return IsAndVariant ? match(OuterSel.Cond,
+                                m_c_LogicalAnd(m_InnerCond, m_Value(AltCond)))
+                        : match(OuterSel.Cond,
+                                m_c_LogicalOr(m_InnerCond, m_Value(AltCond)));
   };
 
   // Finally, match the condition that was driving the outermost `select`,

diff  --git a/llvm/test/Transforms/InstCombine/pr71330.ll b/llvm/test/Transforms/InstCombine/pr71330.ll
index 1620142523f757e..8eb98b2f6436b7e 100644
--- a/llvm/test/Transforms/InstCombine/pr71330.ll
+++ b/llvm/test/Transforms/InstCombine/pr71330.ll
@@ -15,8 +15,7 @@ define void @pr71330(i32 %conv, i1 %tobool19.not4, i16 %lb) {
 ; CHECK:       for.cond7.preheader.split.us.split:
 ; CHECK-NEXT:    ret void
 ; CHECK:       for.cond7:
-; CHECK-NEXT:    [[ADD9:%.*]] = add i32 [[CONV]], 3
-; CHECK-NEXT:    [[CMP12:%.*]] = icmp slt i32 [[ADD9]], 0
+; CHECK-NEXT:    [[CMP12:%.*]] = icmp slt i32 [[CONV]], 0
 ; CHECK-NEXT:    br i1 [[CMP12]], label [[FOR_BODY14:%.*]], label [[FOR_END25]]
 ; CHECK:       for.body14:
 ; CHECK-NEXT:    ret void


        


More information about the llvm-commits mailing list