Noah Goldstein 9ef829097b [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
2023-11-09 16:36:49 -06:00

77 lines
3.1 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
; RUN: opt -passes=instcombine -S < %s | FileCheck %s
define void @pr71330(i32 %conv, i1 %tobool19.not4, i16 %lb) {
; CHECK-LABEL: define void @pr71330(
; CHECK-SAME: i32 [[CONV:%.*]], i1 [[TOBOOL19_NOT4:%.*]], i16 [[LB:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_COND7_PREHEADER:%.*]]
; CHECK: for.cond7.preheader:
; CHECK-NEXT: br i1 [[TOBOOL19_NOT4]], label [[FOR_COND7_PREHEADER_SPLIT_US:%.*]], label [[FOR_COND7:%.*]]
; CHECK: for.cond7.preheader.split.us:
; CHECK-NEXT: br i1 true, label [[FOR_COND7_PREHEADER_SPLIT_US_SPLIT:%.*]], label [[FOR_COND7_US_US:%.*]]
; CHECK: for.cond7.us.us:
; CHECK-NEXT: br i1 poison, label [[FOR_COND7_US_US]], label [[FOR_END25:%.*]]
; CHECK: for.cond7.preheader.split.us.split:
; CHECK-NEXT: ret void
; CHECK: for.cond7:
; 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
; CHECK: for.end25:
; CHECK-NEXT: br i1 false, label [[FOR_COND7_PREHEADER]], label [[FOR_END36:%.*]]
; CHECK: for.end36:
; CHECK-NEXT: ret void
;
entry:
br label %for.cond7.preheader
for.cond7.preheader: ; preds = %for.end25, %entry
%storemerge33 = phi i32 [ -3, %entry ], [ 0, %for.end25 ]
%sm8 = and i32 %storemerge33, 1
%add = add i32 %storemerge33, 8
%cmp.i.i.not = icmp eq i32 %sm8, 0
%cmp3.i.i = icmp eq i32 %add, 0
%and7.i.i = and i32 %storemerge33, 1
%cmp8.i.i = icmp eq i32 %and7.i.i, 0
%tobool.not.i.i = icmp eq i32 %add, 0
%..i.i = select i1 %tobool.not.i.i, i32 1, i32 3
br i1 %tobool19.not4, label %for.cond7.preheader.split.us, label %for.cond7
for.cond7.preheader.split.us: ; preds = %for.cond7.preheader
br i1 %cmp.i.i.not, label %for.cond7.us.us, label %for.cond7.preheader.split.us.split
for.cond7.us.us: ; preds = %for.cond7.us.us, %for.cond7.preheader.split.us
%spec.select = select i1 %cmp8.i.i, i32 1, i32 %..i.i
%retval.0.i.i.us.us = select i1 %cmp3.i.i, i32 0, i32 %spec.select
%add9.us.us = add i32 %retval.0.i.i.us.us, %conv
%conv10.us.us = sext i32 %add9.us.us to i64
%cmp12.us.us = icmp slt i64 %conv10.us.us, 0
br i1 %cmp12.us.us, label %for.cond7.us.us, label %for.end25
for.cond7.preheader.split.us.split: ; preds = %for.cond7.preheader.split.us
ret void
for.cond7: ; preds = %for.cond7.preheader
%cmp.i.i.not.not = xor i1 %cmp.i.i.not, true
%brmerge = select i1 %cmp.i.i.not.not, i1 true, i1 %cmp3.i.i
%spec.select34 = select i1 %cmp8.i.i, i32 1, i32 %..i.i
%retval.0.i.i = select i1 %brmerge, i32 0, i32 %spec.select34
%add9 = add i32 %retval.0.i.i, %conv
%conv10 = sext i32 %add9 to i64
%cmp12 = icmp slt i64 %conv10, 0
br i1 %cmp12, label %for.body14, label %for.end25
for.body14: ; preds = %for.cond7
ret void
for.end25: ; preds = %for.cond7, %for.cond7.us.us
%conv35 = zext i16 %lb to i32
%cmp = icmp slt i32 %conv35, 0
br i1 %cmp, label %for.cond7.preheader, label %for.end36
for.end36: ; preds = %for.end25
ret void
}