Skip to content

Commit 2942c87

Browse files
nikicyuxuanchen1997
authored andcommitted
[InstSimplify] Fix simplifyAndOrWithICmpEq with undef refinement (#98898)
Summary: The final case in Simplify (where Res == Absorber and the predicate is inverted) is not generally safe when the simplification is a refinement. In particular, we may simplify assuming a specific value for undef, but then chose a different one later. However, it *is* safe to refine poison in this context, unlike in the equivalent select folds. This is the reason why this fold did not use AllowRefinement=false in the first place, and using that option would introduce a lot of test regressions. This patch takes the middle path of disabling undef refinements in particular using the getWithoutUndef() SimplifyQuery option. However, this option doesn't actually work in this case, because the problematic fold is inside constant folding, and we currently don't propagate this option all the way from InstSimplify over ConstantFolding to ConstantFold. Work around this by explicitly checking for undef operands in simplifyWithOpReplaced(). Finally, make sure that places where AllowRefinement=false also use Q.getWithoutUndef(). I don't have a specific test case for this (the original one does not work because we don't simplify selects with constant condition in this mode in the first place) but this seems like the correct thing to do to be conservative. Fixes #98753. Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251555
1 parent c01b1e4 commit 2942c87

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
lines changed

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,13 +1975,16 @@ static Value *simplifyAndOrWithICmpEq(unsigned Opcode, Value *Op0, Value *Op1,
19751975
return nullptr;
19761976
};
19771977

1978-
if (Value *Res =
1979-
simplifyWithOpReplaced(Op1, A, B, Q, /* AllowRefinement */ true,
1980-
/* DropFlags */ nullptr, MaxRecurse))
1978+
// In the final case (Res == Absorber with inverted predicate), it is safe to
1979+
// refine poison during simplification, but not undef. For simplicity always
1980+
// disable undef-based folds here.
1981+
if (Value *Res = simplifyWithOpReplaced(Op1, A, B, Q.getWithoutUndef(),
1982+
/* AllowRefinement */ true,
1983+
/* DropFlags */ nullptr, MaxRecurse))
19811984
return Simplify(Res);
1982-
if (Value *Res =
1983-
simplifyWithOpReplaced(Op1, B, A, Q, /* AllowRefinement */ true,
1984-
/* DropFlags */ nullptr, MaxRecurse))
1985+
if (Value *Res = simplifyWithOpReplaced(Op1, B, A, Q.getWithoutUndef(),
1986+
/* AllowRefinement */ true,
1987+
/* DropFlags */ nullptr, MaxRecurse))
19851988
return Simplify(Res);
19861989

19871990
return nullptr;
@@ -4300,6 +4303,9 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
43004303
bool AllowRefinement,
43014304
SmallVectorImpl<Instruction *> *DropFlags,
43024305
unsigned MaxRecurse) {
4306+
assert((AllowRefinement || !Q.CanUseUndef) &&
4307+
"If AllowRefinement=false then CanUseUndef=false");
4308+
43034309
// Trivial replacement.
43044310
if (V == Op)
43054311
return RepOp;
@@ -4347,6 +4353,11 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
43474353
} else {
43484354
NewOps.push_back(InstOp);
43494355
}
4356+
4357+
// Bail out if any operand is undef and SimplifyQuery disables undef
4358+
// simplification. Constant folding currently doesn't respect this option.
4359+
if (isa<UndefValue>(NewOps.back()) && !Q.CanUseUndef)
4360+
return nullptr;
43504361
}
43514362

43524363
if (!AnyReplaced)
@@ -4467,6 +4478,11 @@ Value *llvm::simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
44674478
const SimplifyQuery &Q,
44684479
bool AllowRefinement,
44694480
SmallVectorImpl<Instruction *> *DropFlags) {
4481+
// If refinement is disabled, also disable undef simplifications (which are
4482+
// always refinements) in SimplifyQuery.
4483+
if (!AllowRefinement)
4484+
return ::simplifyWithOpReplaced(V, Op, RepOp, Q.getWithoutUndef(),
4485+
AllowRefinement, DropFlags, RecursionLimit);
44704486
return ::simplifyWithOpReplaced(V, Op, RepOp, Q, AllowRefinement, DropFlags,
44714487
RecursionLimit);
44724488
}
@@ -4606,7 +4622,7 @@ static Value *simplifySelectWithICmpEq(Value *CmpLHS, Value *CmpRHS,
46064622
Value *TrueVal, Value *FalseVal,
46074623
const SimplifyQuery &Q,
46084624
unsigned MaxRecurse) {
4609-
if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q,
4625+
if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q.getWithoutUndef(),
46104626
/* AllowRefinement */ false,
46114627
/* DropFlags */ nullptr, MaxRecurse) == TrueVal)
46124628
return FalseVal;

llvm/test/Transforms/InstSimplify/and-or-implied-cond.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,13 @@ define i1 @and_is_constant(ptr %arg, ptr %arg2) {
331331
ret i1 %and
332332
}
333333

334-
; FIXME: This is a miscompile.
335334
define i1 @pr98753(i32 noundef %x, i32 %y) {
336335
; CHECK-LABEL: @pr98753(
337336
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X:%.*]], 0
338337
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[Y:%.*]], i32 undef
339338
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[SEL]], 0
340-
; CHECK-NEXT: ret i1 [[CMP2]]
339+
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
340+
; CHECK-NEXT: ret i1 [[AND]]
341341
;
342342
%cmp1 = icmp ne i32 %x, 0
343343
%sel = select i1 %cmp1, i32 %y, i32 undef

0 commit comments

Comments
 (0)