Skip to content

Commit 9d1c8c0

Browse files
committed
[InstCombine] Fix select operand simplification with undef (PR47696)
When replacing X == Y ? f(X) : Z with X == Y ? f(Y) : Z, make sure that Y cannot be undef. If it may be undef, we might end up picking a different value for undef in the comparison and the select operand.
1 parent 8d26760 commit 9d1c8c0

File tree

4 files changed

+56
-19
lines changed

4 files changed

+56
-19
lines changed

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
711711
Value *A, Value *B, Instruction &Outer,
712712
SelectPatternFlavor SPF2, Value *C);
713713
Instruction *foldSelectInstWithICmp(SelectInst &SI, ICmpInst *ICI);
714+
Instruction *foldSelectValueEquivalence(SelectInst &SI, ICmpInst &ICI);
714715

715716
Instruction *OptAndOp(BinaryOperator *Op, ConstantInt *OpRHS,
716717
ConstantInt *AndRHS, BinaryOperator &TheAnd);

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,9 +1165,8 @@ static Instruction *canonicalizeAbsNabs(SelectInst &Sel, ICmpInst &Cmp,
11651165
///
11661166
/// We can't replace %sel with %add unless we strip away the flags.
11671167
/// TODO: Wrapping flags could be preserved in some cases with better analysis.
1168-
static Instruction *foldSelectValueEquivalence(SelectInst &Sel, ICmpInst &Cmp,
1169-
const SimplifyQuery &Q,
1170-
InstCombiner &IC) {
1168+
Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
1169+
ICmpInst &Cmp) {
11711170
if (!Cmp.isEquality())
11721171
return nullptr;
11731172

@@ -1179,18 +1178,20 @@ static Instruction *foldSelectValueEquivalence(SelectInst &Sel, ICmpInst &Cmp,
11791178
Swapped = true;
11801179
}
11811180

1182-
// In X == Y ? f(X) : Z, try to evaluate f(X) and replace the operand.
1183-
// Take care to avoid replacing X == Y ? X : Z with X == Y ? Y : Z, as that
1184-
// would lead to an infinite replacement cycle.
1181+
// In X == Y ? f(X) : Z, try to evaluate f(Y) and replace the operand.
1182+
// Make sure Y cannot be undef though, as we might pick different values for
1183+
// undef in the icmp and in f(Y). Additionally, take care to avoid replacing
1184+
// X == Y ? X : Z with X == Y ? Y : Z, as that would lead to an infinite
1185+
// replacement cycle.
11851186
Value *CmpLHS = Cmp.getOperand(0), *CmpRHS = Cmp.getOperand(1);
1186-
if (TrueVal != CmpLHS)
1187-
if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q,
1187+
if (TrueVal != CmpLHS && isGuaranteedNotToBeUndefOrPoison(CmpRHS, &Sel, &DT))
1188+
if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ,
11881189
/* AllowRefinement */ true))
1189-
return IC.replaceOperand(Sel, Swapped ? 2 : 1, V);
1190-
if (TrueVal != CmpRHS)
1191-
if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, Q,
1190+
return replaceOperand(Sel, Swapped ? 2 : 1, V);
1191+
if (TrueVal != CmpRHS && isGuaranteedNotToBeUndefOrPoison(CmpLHS, &Sel, &DT))
1192+
if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ,
11921193
/* AllowRefinement */ true))
1193-
return IC.replaceOperand(Sel, Swapped ? 2 : 1, V);
1194+
return replaceOperand(Sel, Swapped ? 2 : 1, V);
11941195

11951196
auto *FalseInst = dyn_cast<Instruction>(FalseVal);
11961197
if (!FalseInst)
@@ -1215,11 +1216,11 @@ static Instruction *foldSelectValueEquivalence(SelectInst &Sel, ICmpInst &Cmp,
12151216
// We have an 'EQ' comparison, so the select's false value will propagate.
12161217
// Example:
12171218
// (X == 42) ? 43 : (X + 1) --> (X == 42) ? (X + 1) : (X + 1) --> X + 1
1218-
if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q,
1219+
if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, SQ,
12191220
/* AllowRefinement */ false) == TrueVal ||
1220-
SimplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q,
1221+
SimplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, SQ,
12211222
/* AllowRefinement */ false) == TrueVal) {
1222-
return IC.replaceInstUsesWith(Sel, FalseVal);
1223+
return replaceInstUsesWith(Sel, FalseVal);
12231224
}
12241225

12251226
// Restore poison-generating flags if the transform did not apply.
@@ -1455,7 +1456,7 @@ tryToReuseConstantFromSelectInComparison(SelectInst &Sel, ICmpInst &Cmp,
14551456
/// Visit a SelectInst that has an ICmpInst as its first operand.
14561457
Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
14571458
ICmpInst *ICI) {
1458-
if (Instruction *NewSel = foldSelectValueEquivalence(SI, *ICI, SQ, *this))
1459+
if (Instruction *NewSel = foldSelectValueEquivalence(SI, *ICI))
14591460
return NewSel;
14601461

14611462
if (Instruction *NewSel = canonicalizeMinMaxWithConstant(SI, *ICI, *this))

llvm/test/Transforms/InstCombine/select-binop-cmp.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,10 +564,12 @@ define <2 x i8> @select_xor_icmp_vec_bad(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z)
564564
ret <2 x i8> %C
565565
}
566566

567+
; Folding this would only be legal if we sanitized undef to 0.
567568
define <2 x i8> @select_xor_icmp_vec_undef(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
568569
; CHECK-LABEL: @select_xor_icmp_vec_undef(
569570
; CHECK-NEXT: [[A:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 0, i8 undef>
570-
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A]], <2 x i8> [[Z:%.*]], <2 x i8> [[Y:%.*]]
571+
; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> [[X]], [[Z:%.*]]
572+
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A]], <2 x i8> [[B]], <2 x i8> [[Y:%.*]]
571573
; CHECK-NEXT: ret <2 x i8> [[C]]
572574
;
573575
%A = icmp eq <2 x i8> %x, <i8 0, i8 undef>

llvm/test/Transforms/InstCombine/select.ll

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2641,10 +2641,24 @@ define i8 @select_replacement_add_nuw(i8 %x, i8 %y) {
26412641
ret i8 %sel
26422642
}
26432643

2644+
define i8 @select_replacement_sub_noundef(i8 %x, i8 noundef %y, i8 %z) {
2645+
; CHECK-LABEL: @select_replacement_sub_noundef(
2646+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
2647+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 0, i8 [[Z:%.*]]
2648+
; CHECK-NEXT: ret i8 [[SEL]]
2649+
;
2650+
%cmp = icmp eq i8 %x, %y
2651+
%sub = sub i8 %x, %y
2652+
%sel = select i1 %cmp, i8 %sub, i8 %z
2653+
ret i8 %sel
2654+
}
2655+
2656+
; TODO: The transform is also safe without noundef.
26442657
define i8 @select_replacement_sub(i8 %x, i8 %y, i8 %z) {
26452658
; CHECK-LABEL: @select_replacement_sub(
26462659
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
2647-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 0, i8 [[Z:%.*]]
2660+
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
2661+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[SUB]], i8 [[Z:%.*]]
26482662
; CHECK-NEXT: ret i8 [[SEL]]
26492663
;
26502664
%cmp = icmp eq i8 %x, %y
@@ -2653,11 +2667,29 @@ define i8 @select_replacement_sub(i8 %x, i8 %y, i8 %z) {
26532667
ret i8 %sel
26542668
}
26552669

2670+
define i8 @select_replacement_shift_noundef(i8 %x, i8 %y, i8 %z) {
2671+
; CHECK-LABEL: @select_replacement_shift_noundef(
2672+
; CHECK-NEXT: [[SHR:%.*]] = lshr exact i8 [[X:%.*]], 1
2673+
; CHECK-NEXT: call void @use_i8(i8 noundef [[SHR]])
2674+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHR]], [[Y:%.*]]
2675+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[X]], i8 [[Z:%.*]]
2676+
; CHECK-NEXT: ret i8 [[SEL]]
2677+
;
2678+
%shr = lshr exact i8 %x, 1
2679+
call void @use_i8(i8 noundef %shr)
2680+
%cmp = icmp eq i8 %shr, %y
2681+
%shl = shl i8 %y, 1
2682+
%sel = select i1 %cmp, i8 %shl, i8 %z
2683+
ret i8 %sel
2684+
}
2685+
2686+
; TODO: The transform is also safe without noundef.
26562687
define i8 @select_replacement_shift(i8 %x, i8 %y, i8 %z) {
26572688
; CHECK-LABEL: @select_replacement_shift(
26582689
; CHECK-NEXT: [[SHR:%.*]] = lshr exact i8 [[X:%.*]], 1
26592690
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHR]], [[Y:%.*]]
2660-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[X]], i8 [[Z:%.*]]
2691+
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[Y]], 1
2692+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[SHL]], i8 [[Z:%.*]]
26612693
; CHECK-NEXT: ret i8 [[SEL]]
26622694
;
26632695
%shr = lshr exact i8 %x, 1
@@ -2694,4 +2726,5 @@ define i32 @select_replacement_loop2(i32 %arg, i32 %arg2) {
26942726
}
26952727

26962728
declare void @use(i1)
2729+
declare void @use_i8(i8)
26972730
declare i32 @llvm.cttz.i32(i32, i1 immarg)

0 commit comments

Comments
 (0)