Skip to content

Commit a1b1c4a

Browse files
authored
[InstCombine] Fix miscompile in negation of select (#89698)
Swapping the operands of a select is not valid if one hand is more poisonous that the other, because the negation zero contains poison elements. Fix this by adding an extra parameter to isKnownNegation() to forbid poison elements. I've implemented this using manual checks to avoid needing four variants for the NeedsNSW/AllowPoison combinations. Maybe there is a better way to do this... Fixes #89669.
1 parent d97cdd7 commit a1b1c4a

File tree

4 files changed

+24
-12
lines changed

4 files changed

+24
-12
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth = 0);
131131
/// Currently can recoginze Value pair:
132132
/// 1: <X, Y> if X = sub (0, Y) or Y = sub (0, X)
133133
/// 2: <X, Y> if X = sub (A, B) and Y = sub (B, A)
134-
bool isKnownNegation(const Value *X, const Value *Y, bool NeedNSW = false);
134+
bool isKnownNegation(const Value *X, const Value *Y, bool NeedNSW = false,
135+
bool AllowPoison = true);
135136

136137
/// Returns true if the give value is known to be non-negative.
137138
bool isKnownNonNegative(const Value *V, const SimplifyQuery &SQ,

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8042,17 +8042,27 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
80428042
return {SPF_UNKNOWN, SPNB_NA, false};
80438043
}
80448044

8045-
bool llvm::isKnownNegation(const Value *X, const Value *Y, bool NeedNSW) {
8045+
bool llvm::isKnownNegation(const Value *X, const Value *Y, bool NeedNSW,
8046+
bool AllowPoison) {
80468047
assert(X && Y && "Invalid operand");
80478048

8048-
// X = sub (0, Y) || X = sub nsw (0, Y)
8049-
if ((!NeedNSW && match(X, m_Sub(m_ZeroInt(), m_Specific(Y)))) ||
8050-
(NeedNSW && match(X, m_NSWNeg(m_Specific(Y)))))
8049+
auto IsNegationOf = [&](const Value *X, const Value *Y) {
8050+
if (!match(X, m_Neg(m_Specific(Y))))
8051+
return false;
8052+
8053+
auto *BO = cast<BinaryOperator>(X);
8054+
if (NeedNSW && !BO->hasNoSignedWrap())
8055+
return false;
8056+
8057+
auto *Zero = cast<Constant>(BO->getOperand(0));
8058+
if (!AllowPoison && !Zero->isNullValue())
8059+
return false;
8060+
80518061
return true;
8062+
};
80528063

8053-
// Y = sub (0, X) || Y = sub nsw (0, X)
8054-
if ((!NeedNSW && match(Y, m_Sub(m_ZeroInt(), m_Specific(X)))) ||
8055-
(NeedNSW && match(Y, m_NSWNeg(m_Specific(X)))))
8064+
// X = -Y or Y = -X
8065+
if (IsNegationOf(X, Y) || IsNegationOf(Y, X))
80568066
return true;
80578067

80588068
// X = sub (A, B), Y = sub (B, A) || X = sub nsw (A, B), Y = sub nsw (B, A)

llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,8 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
320320
return NegatedPHI;
321321
}
322322
case Instruction::Select: {
323-
if (isKnownNegation(I->getOperand(1), I->getOperand(2))) {
323+
if (isKnownNegation(I->getOperand(1), I->getOperand(2), /*NeedNSW=*/false,
324+
/*AllowPoison=*/false)) {
324325
// Of one hand of select is known to be negation of another hand,
325326
// just swap the hands around.
326327
auto *NewSelect = cast<SelectInst>(I->clone());

llvm/test/Transforms/InstCombine/sub-of-negatible.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,12 +1385,12 @@ define i8 @dont_negate_ordinary_select(i8 %x, i8 %y, i8 %z, i1 %c) {
13851385
ret i8 %t1
13861386
}
13871387

1388-
; FIXME: This is a miscompile.
13891388
define <2 x i32> @negate_select_of_negation_poison(<2 x i1> %c, <2 x i32> %x) {
13901389
; CHECK-LABEL: @negate_select_of_negation_poison(
13911390
; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i32> <i32 0, i32 poison>, [[X:%.*]]
1392-
; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C:%.*]], <2 x i32> [[X]], <2 x i32> [[NEG]]
1393-
; CHECK-NEXT: ret <2 x i32> [[TMP1]]
1391+
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i32> [[NEG]], <2 x i32> [[X]]
1392+
; CHECK-NEXT: [[NEG2:%.*]] = sub <2 x i32> zeroinitializer, [[SEL]]
1393+
; CHECK-NEXT: ret <2 x i32> [[NEG2]]
13941394
;
13951395
%neg = sub <2 x i32> <i32 0, i32 poison>, %x
13961396
%sel = select <2 x i1> %c, <2 x i32> %neg, <2 x i32> %x

0 commit comments

Comments
 (0)