[llvm] [SelectionDAG] Preserver poison for abs INT_MIN lowering (PR #183851)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 3 15:47:15 PST 2026
https://github.com/aryanmagoon updated https://github.com/llvm/llvm-project/pull/183851
>From f64ac46c74333540f10d3eeb0884618c15aa8f10 Mon Sep 17 00:00:00 2001
From: aryanmagoon <amagoon at nvidia.com>
Date: Fri, 27 Feb 2026 19:13:40 +0000
Subject: [PATCH] SelectionDAG: Preserve poison for abs INT_MIN lowering.
Update affected CodeGen lit tests and added a new lit test for this behavior.
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 4 +
llvm/include/llvm/CodeGen/SDPatternMatch.h | 5 +-
.../include/llvm/Target/TargetSelectionDAG.td | 5 +-
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 55 +++++++-
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 1 +
.../SelectionDAG/LegalizeIntegerTypes.cpp | 15 ++-
.../SelectionDAG/LegalizeVectorOps.cpp | 2 +
.../SelectionDAG/LegalizeVectorTypes.cpp | 3 +
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 20 ++-
.../SelectionDAG/SelectionDAGBuilder.cpp | 5 +-
.../SelectionDAG/SelectionDAGDumper.cpp | 1 +
.../CodeGen/SelectionDAG/TargetLowering.cpp | 10 ++
llvm/lib/CodeGen/TargetLoweringBase.cpp | 3 +
.../Target/AArch64/AArch64ISelLowering.cpp | 6 +-
llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp | 17 ++-
llvm/lib/Target/NVPTX/NVPTXInstrInfo.td | 5 +-
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 16 ++-
llvm/test/CodeGen/NVPTX/idioms.ll | 21 +--
llvm/test/CodeGen/X86/abs.ll | 7 +-
llvm/test/CodeGen/X86/freeze-unary.ll | 16 ++-
llvm/test/CodeGen/X86/icmp-abs-C.ll | 120 ++++++++++--------
.../test/CodeGen/X86/icmp-pow2-logic-npow2.ll | 33 +++--
22 files changed, 261 insertions(+), 109 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index b8c6788e0bc03..d02351cc3c095 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -746,6 +746,10 @@ enum NodeType {
/// is performed.
ABS,
+ /// ABS with an undefined result for INT_MIN. This corresponds to
+ /// llvm.abs(x, true) where the "int min is poison" flag is set.
+ ABS_MIN_POISON,
+
/// Shift and rotation operations. After legalization, the type of the
/// shift amount is known to be TLI.getShiftAmountTy(). Before legalization
/// the shift amount can be any type, but care must be taken to ensure it is
diff --git a/llvm/include/llvm/CodeGen/SDPatternMatch.h b/llvm/include/llvm/CodeGen/SDPatternMatch.h
index b41443f85c3a9..a3cc419404759 100644
--- a/llvm/include/llvm/CodeGen/SDPatternMatch.h
+++ b/llvm/include/llvm/CodeGen/SDPatternMatch.h
@@ -1073,8 +1073,9 @@ template <typename Opnd> inline UnaryOpc_match<Opnd> m_Trunc(const Opnd &Op) {
return UnaryOpc_match<Opnd>(ISD::TRUNCATE, Op);
}
-template <typename Opnd> inline UnaryOpc_match<Opnd> m_Abs(const Opnd &Op) {
- return UnaryOpc_match<Opnd>(ISD::ABS, Op);
+template <typename Opnd> inline auto m_Abs(const Opnd &Op) {
+ return m_AnyOf(UnaryOpc_match<Opnd>(ISD::ABS, Op),
+ UnaryOpc_match<Opnd>(ISD::ABS_MIN_POISON, Op));
}
template <typename Opnd> inline UnaryOpc_match<Opnd> m_FAbs(const Opnd &Op) {
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index d689b3c1beda9..1e4940d4c1f8d 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -519,8 +519,9 @@ def sext_inreg : SDNode<"ISD::SIGN_EXTEND_INREG", SDTExtInreg>;
def sext_invec : SDNode<"ISD::SIGN_EXTEND_VECTOR_INREG", SDTExtInvec>;
def zext_invec : SDNode<"ISD::ZERO_EXTEND_VECTOR_INREG", SDTExtInvec>;
-def abs : SDNode<"ISD::ABS" , SDTIntUnaryOp>;
-def bitreverse : SDNode<"ISD::BITREVERSE" , SDTIntUnaryOp>;
+def abs : SDNode<"ISD::ABS" , SDTIntUnaryOp>;
+def abs_min_poison : SDNode<"ISD::ABS_MIN_POISON", SDTIntUnaryOp>;
+def bitreverse : SDNode<"ISD::BITREVERSE" , SDTIntUnaryOp>;
def bswap : SDNode<"ISD::BSWAP" , SDTIntUnaryOp>;
def ctlz : SDNode<"ISD::CTLZ" , SDTIntBitCountUnaryOp>;
def cttz : SDNode<"ISD::CTTZ" , SDTIntBitCountUnaryOp>;
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 41e77e044d8a9..6b8bc99ec7e3a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -477,6 +477,7 @@ namespace {
SDValue visitSHLSAT(SDNode *N);
SDValue visitRotate(SDNode *N);
SDValue visitABS(SDNode *N);
+ SDValue visitABS_MIN_POISON(SDNode *N);
SDValue visitCLMUL(SDNode *N);
SDValue visitBSWAP(SDNode *N);
SDValue visitBITREVERSE(SDNode *N);
@@ -1983,6 +1984,7 @@ SDValue DAGCombiner::visit(SDNode *N) {
case ISD::SSHLSAT:
case ISD::USHLSAT: return visitSHLSAT(N);
case ISD::ABS: return visitABS(N);
+ case ISD::ABS_MIN_POISON: return visitABS_MIN_POISON(N);
case ISD::CLMUL:
case ISD::CLMULR:
case ISD::CLMULH: return visitCLMUL(N);
@@ -4263,8 +4265,9 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
}
// Convert 0 - abs(x).
- if (N1.getOpcode() == ISD::ABS && N1.hasOneUse() &&
- !TLI.isOperationLegalOrCustom(ISD::ABS, VT))
+ if ((N1.getOpcode() == ISD::ABS || N1.getOpcode() == ISD::ABS_MIN_POISON) &&
+ N1.hasOneUse() &&
+ !TLI.isOperationLegalOrCustom(N1.getOpcode(), VT))
if (SDValue Result = TLI.expandABS(N1.getNode(), DAG, true))
return Result;
@@ -11916,7 +11919,8 @@ SDValue DAGCombiner::visitABS(SDNode *N) {
if (SDValue C = DAG.FoldConstantArithmetic(ISD::ABS, DL, VT, {N0}))
return C;
// fold (abs (abs x)) -> (abs x)
- if (N0.getOpcode() == ISD::ABS)
+ // fold (abs (abs_min_poison x)) -> (abs x)
+ if (N0.getOpcode() == ISD::ABS || N0.getOpcode() == ISD::ABS_MIN_POISON)
return N0;
// fold (abs x) -> x iff not-negative
if (DAG.SignBitIsZero(N0))
@@ -11942,6 +11946,45 @@ SDValue DAGCombiner::visitABS(SDNode *N) {
return SDValue();
}
+SDValue DAGCombiner::visitABS_MIN_POISON(SDNode *N) {
+ SDValue N0 = N->getOperand(0);
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ // fold (abs_min_poison c1) -> c2 (or poison if c1 == INT_MIN)
+ if (SDValue C =
+ DAG.FoldConstantArithmetic(ISD::ABS_MIN_POISON, DL, VT, {N0}))
+ return C;
+ // fold (abs_min_poison (abs_min_poison x)) -> (abs_min_poison x)
+ // fold (abs_min_poison (abs x)) -> (abs x)
+ if (N0.getOpcode() == ISD::ABS_MIN_POISON || N0.getOpcode() == ISD::ABS)
+ return N0;
+ // fold (abs_min_poison x) -> x iff not-negative
+ if (DAG.SignBitIsZero(N0))
+ return N0;
+
+ if (SDValue ABD = foldABSToABD(N, DL))
+ return ABD;
+
+ // fold (abs_min_poison (sign_extend_inreg x)) ->
+ // (zero_extend (abs_min_poison (truncate x)))
+ // iff zero_extend/truncate are free.
+ if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG) {
+ EVT ExtVT = cast<VTSDNode>(N0.getOperand(1))->getVT();
+ if (TLI.isTruncateFree(VT, ExtVT) && TLI.isZExtFree(ExtVT, VT) &&
+ TLI.isTypeDesirableForOp(ISD::ABS, ExtVT) &&
+ hasOperation(ISD::ABS_MIN_POISON, ExtVT)) {
+ return DAG.getNode(
+ ISD::ZERO_EXTEND, DL, VT,
+ DAG.getNode(ISD::ABS_MIN_POISON, DL, ExtVT,
+ DAG.getNode(ISD::TRUNCATE, DL, ExtVT,
+ N0.getOperand(0))));
+ }
+ }
+
+ return SDValue();
+}
+
SDValue DAGCombiner::visitCLMUL(SDNode *N) {
unsigned Opcode = N->getOpcode();
SDValue N0 = N->getOperand(0);
@@ -15322,7 +15365,9 @@ static SDValue widenAbs(SDNode *Extend, SelectionDAG &DAG) {
return SDValue();
SDValue Abs = Extend->getOperand(0);
- if (Abs.getOpcode() != ISD::ABS || !Abs.hasOneUse())
+ unsigned AbsOpc = Abs.getOpcode();
+ if ((AbsOpc != ISD::ABS && AbsOpc != ISD::ABS_MIN_POISON) ||
+ !Abs.hasOneUse())
return SDValue();
EVT AbsVT = Abs.getValueType();
@@ -15335,7 +15380,7 @@ static SDValue widenAbs(SDNode *Extend, SelectionDAG &DAG) {
SDValue SExt =
DAG.getNode(ISD::SIGN_EXTEND, SDLoc(Abs), LegalVT, Abs.getOperand(0));
- SDValue NewAbs = DAG.getNode(ISD::ABS, SDLoc(Abs), LegalVT, SExt);
+ SDValue NewAbs = DAG.getNode(AbsOpc, SDLoc(Abs), LegalVT, SExt);
return DAG.getZExtOrTrunc(NewAbs, SDLoc(Extend), VT);
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index eb20e7982a102..a28739d210933 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -3223,6 +3223,7 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
bool NeedInvert;
switch (Node->getOpcode()) {
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
if ((Tmp1 = TLI.expandABS(Node, DAG)))
Results.push_back(Tmp1);
break;
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
index 0d5cba405d6e3..a2dd494086c68 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
@@ -278,7 +278,8 @@ void DAGTypeLegalizer::PromoteIntegerResult(SDNode *N, unsigned ResNo) {
case ISD::UDIVFIX:
case ISD::UDIVFIXSAT: Res = PromoteIntRes_DIVFIX(N); break;
- case ISD::ABS: Res = PromoteIntRes_ABS(N); break;
+ case ISD::ABS:
+ case ISD::ABS_MIN_POISON: Res = PromoteIntRes_ABS(N); break;
case ISD::ATOMIC_LOAD:
Res = PromoteIntRes_Atomic0(cast<AtomicSDNode>(N)); break;
@@ -1871,6 +1872,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_SADDSUBO_CARRY(SDNode *N,
}
SDValue DAGTypeLegalizer::PromoteIntRes_ABS(SDNode *N) {
+ unsigned Opc = N->getOpcode();
EVT OVT = N->getValueType(0);
EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), OVT);
@@ -1879,13 +1881,14 @@ SDValue DAGTypeLegalizer::PromoteIntRes_ABS(SDNode *N) {
// in sra+xor+sub expansion.
if (!OVT.isVector() &&
!TLI.isOperationLegalOrCustomOrPromote(ISD::ABS, NVT) &&
+ !TLI.isOperationLegalOrCustomOrPromote(ISD::ABS_MIN_POISON, NVT) &&
!TLI.isOperationLegal(ISD::SMAX, NVT)) {
if (SDValue Res = TLI.expandABS(N, DAG))
return DAG.getNode(ISD::ANY_EXTEND, SDLoc(N), NVT, Res);
}
SDValue Op0 = SExtPromotedInteger(N->getOperand(0));
- return DAG.getNode(ISD::ABS, SDLoc(N), Op0.getValueType(), Op0);
+ return DAG.getNode(Opc, SDLoc(N), Op0.getValueType(), Op0);
}
SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
@@ -3061,7 +3064,8 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) {
case ISD::BSWAP: ExpandIntRes_BSWAP(N, Lo, Hi); break;
case ISD::PARITY: ExpandIntRes_PARITY(N, Lo, Hi); break;
case ISD::Constant: ExpandIntRes_Constant(N, Lo, Hi); break;
- case ISD::ABS: ExpandIntRes_ABS(N, Lo, Hi); break;
+ case ISD::ABS:
+ case ISD::ABS_MIN_POISON: ExpandIntRes_ABS(N, Lo, Hi); break;
case ISD::ABDS:
case ISD::ABDU: ExpandIntRes_ABD(N, Lo, Hi); break;
case ISD::CTLZ_ZERO_UNDEF:
@@ -4091,7 +4095,10 @@ void DAGTypeLegalizer::ExpandIntRes_ABS(SDNode *N, SDValue &Lo, SDValue &Hi) {
EVT NVT = Lo.getValueType();
// If the upper half is all sign bits, then we can perform the ABS on the
- // lower half and zero-extend.
+ // lower half and zero-extend. We must use ISD::ABS here (not ABS_MIN_POISON)
+ // because the original poison contract is for INT_MIN of the wider type,
+ // but the lower half may be INT_MIN of the narrower type for a valid
+ // (non-INT_MIN) input of the original type.
if (DAG.ComputeNumSignBits(N0) > NVT.getScalarSizeInBits()) {
Lo = DAG.getNode(ISD::ABS, dl, NVT, Lo);
Hi = DAG.getConstant(0, dl, NVT);
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
index 0b1d5bfd078d8..f082a76bc2a4e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
@@ -376,6 +376,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {
case ISD::ROTL:
case ISD::ROTR:
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
case ISD::ABDS:
case ISD::ABDU:
case ISD::AVGCEILS:
@@ -1075,6 +1076,7 @@ void VectorLegalizer::Expand(SDNode *Node, SmallVectorImpl<SDValue> &Results) {
ExpandSETCC(Node, Results);
return;
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
if (SDValue Expanded = TLI.expandABS(Node, DAG)) {
Results.push_back(Expanded);
return;
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index aeb9d4d7bdc1d..e11a6c508dc12 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -89,6 +89,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
R = ScalarizeVecRes_VecInregOp(N);
break;
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
case ISD::ANY_EXTEND:
case ISD::BITREVERSE:
case ISD::BSWAP:
@@ -1311,6 +1312,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
break;
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
case ISD::VP_ABS:
case ISD::BITREVERSE:
case ISD::VP_BITREVERSE:
@@ -5190,6 +5192,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
[[fallthrough]];
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
case ISD::VP_ABS:
case ISD::BITREVERSE:
case ISD::VP_BITREVERSE:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 4a2bd811b5214..2b8fda77ebec7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -2979,6 +2979,7 @@ bool SelectionDAG::isSplatValue(SDValue V, const APInt &DemandedElts,
return false;
}
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
case ISD::TRUNCATE:
case ISD::SIGN_EXTEND:
case ISD::ZERO_EXTEND:
@@ -4320,7 +4321,8 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
Known = Known2.byteSwap();
break;
}
- case ISD::ABS: {
+ case ISD::ABS:
+ case ISD::ABS_MIN_POISON: {
Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
Known = Known2.abs();
Known.Zero.setHighBits(
@@ -5799,6 +5801,9 @@ bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts,
// ISD::ABS defines abs(INT_MIN) -> INT_MIN and never generates poison.
// Different to Intrinsic::abs.
return false;
+ case ISD::ABS_MIN_POISON:
+ // ABS_MIN_POISON may produce poison if the input is INT_MIN.
+ return true;
case ISD::ADDC:
case ISD::SUBC:
@@ -6268,6 +6273,7 @@ bool SelectionDAG::isKnownNeverZero(SDValue Op, const APInt &DemandedElts,
case ISD::BSWAP:
case ISD::CTPOP:
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
return isKnownNeverZero(Op.getOperand(0), Depth + 1);
case ISD::SRA:
@@ -6662,6 +6668,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
case ISD::BF16_TO_FP:
case ISD::BITCAST:
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
case ISD::BITREVERSE:
case ISD::BSWAP:
case ISD::CTLZ:
@@ -6891,6 +6898,12 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
if (N1.isUndef())
return getConstant(0, DL, VT);
break;
+ case ISD::ABS_MIN_POISON:
+ assert(VT.isInteger() && VT == N1.getValueType() &&
+ "Invalid ABS_MIN_POISON!");
+ if (N1.isUndef())
+ return getConstant(0, DL, VT);
+ break;
case ISD::BSWAP:
assert(VT.isInteger() && VT == N1.getValueType() && "Invalid BSWAP!");
assert((VT.getScalarSizeInBits() % 16 == 0) &&
@@ -7192,6 +7205,11 @@ SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL,
case ISD::ABS:
return getConstant(Val.abs(), DL, VT, C->isTargetOpcode(),
C->isOpaque());
+ case ISD::ABS_MIN_POISON:
+ if (Val.isMinSignedValue())
+ return getPOISON(VT);
+ return getConstant(Val.abs(), DL, VT, C->isTargetOpcode(),
+ C->isOpaque());
case ISD::BITREVERSE:
return getConstant(Val.reverseBits(), DL, VT, C->isTargetOpcode(),
C->isOpaque());
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 392e53b99c64e..18fb2319833fa 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -7427,9 +7427,10 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
return;
}
case Intrinsic::abs: {
- // TODO: Preserve "int min is poison" arg in SDAG?
SDValue Op1 = getValue(I.getArgOperand(0));
- setValue(&I, DAG.getNode(ISD::ABS, sdl, Op1.getValueType(), Op1));
+ bool IntMinIsPoison = cast<ConstantInt>(I.getArgOperand(1))->isOne();
+ unsigned Opc = IntMinIsPoison ? ISD::ABS_MIN_POISON : ISD::ABS;
+ setValue(&I, DAG.getNode(Opc, sdl, Op1.getValueType(), Op1));
return;
}
case Intrinsic::scmp: {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 9453036455727..ea6d7ae14a1a6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -516,6 +516,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
// Bit manipulation
case ISD::ABS: return "abs";
+ case ISD::ABS_MIN_POISON: return "abs_min_poison";
case ISD::BITREVERSE: return "bitreverse";
case ISD::BSWAP: return "bswap";
case ISD::CTPOP: return "ctpop";
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index cc719b1e67f53..01f37e3c39343 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -9911,6 +9911,16 @@ SDValue TargetLowering::expandABS(SDNode *N, SelectionDAG &DAG,
EVT VT = N->getValueType(0);
SDValue Op = N->getOperand(0);
+ // If expanding ABS_MIN_POISON, fall back to ABS if the target supports it.
+ if (N->getOpcode() == ISD::ABS_MIN_POISON &&
+ isOperationLegalOrCustom(ISD::ABS, VT)) {
+ SDValue AbsVal = DAG.getNode(ISD::ABS, dl, VT, Op);
+ if (IsNegative)
+ return DAG.getNode(ISD::SUB, dl, VT, DAG.getConstant(0, dl, VT),
+ AbsVal);
+ return AbsVal;
+ }
+
// abs(x) -> smax(x,sub(0,x))
if (!IsNegative && isOperationLegal(ISD::SUB, VT) &&
isOperationLegal(ISD::SMAX, VT)) {
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index cc5a4219536ac..8d59420c46125 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -1165,6 +1165,9 @@ void TargetLoweringBase::initActions() {
// These default to Expand so they will be expanded to CTLZ/CTTZ by default.
setOperationAction({ISD::CTLZ_ZERO_UNDEF, ISD::CTTZ_ZERO_UNDEF}, VT,
Expand);
+
+ // This defaults to Expand so it will be expanded to ABS by default.
+ setOperationAction(ISD::ABS_MIN_POISON, VT, Expand);
setOperationAction(ISD::CTLS, VT, Expand);
setOperationAction({ISD::BITREVERSE, ISD::PARITY}, VT, Expand);
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index eb6e9146e3839..e6e5b42c887a1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -19574,7 +19574,8 @@ static SDValue performVecReduceAddCombineWithUADDLP(SDNode *N,
// Look through an optional post-ABS ZEXT from v16i16 -> v16i32.
if (VecReduceOp0.getOpcode() == ISD::ZERO_EXTEND &&
VecReduceOp0->getValueType(0) == MVT::v16i32 &&
- VecReduceOp0->getOperand(0)->getOpcode() == ISD::ABS &&
+ (VecReduceOp0->getOperand(0)->getOpcode() == ISD::ABS ||
+ VecReduceOp0->getOperand(0)->getOpcode() == ISD::ABS_MIN_POISON) &&
VecReduceOp0->getOperand(0)->getValueType(0) == MVT::v16i16) {
SawTrailingZext = true;
VecReduceOp0 = VecReduceOp0.getOperand(0);
@@ -19584,7 +19585,8 @@ static SDValue performVecReduceAddCombineWithUADDLP(SDNode *N,
MVT AbsInputVT = SawTrailingZext ? MVT::v16i16 : MVT::v16i32;
// Assumed v16i16 or v16i32 abs input
unsigned Opcode = VecReduceOp0.getOpcode();
- if (Opcode != ISD::ABS || VecReduceOp0->getValueType(0) != AbsInputVT)
+ if ((Opcode != ISD::ABS && Opcode != ISD::ABS_MIN_POISON) ||
+ VecReduceOp0->getValueType(0) != AbsInputVT)
return SDValue();
SDValue ABS = VecReduceOp0;
diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
index f5554be155eac..2f256ac1f3e51 100644
--- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
@@ -657,7 +657,8 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
// Only logical ops can be done on v4i8/v2i32 directly, others must be done
// elementwise.
setOperationAction(
- {ISD::ABS, ISD::ADD, ISD::ADDC, ISD::ADDE,
+ {ISD::ABS,
+ ISD::ADD, ISD::ADDC, ISD::ADDE,
ISD::BITREVERSE, ISD::CTLZ, ISD::CTPOP, ISD::CTTZ,
ISD::FP_TO_SINT, ISD::FP_TO_UINT, ISD::FSHL, ISD::FSHR,
ISD::MUL, ISD::MULHS, ISD::MULHU, ISD::PARITY,
@@ -807,15 +808,21 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
- setOperationAction({ISD::ABS, ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX},
+ setOperationAction({ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX},
{MVT::i16, MVT::i32, MVT::i64}, Legal);
+ // PTX abs.s is undefined for INT_MIN, so ISD::ABS (which requires
+ // abs(INT_MIN) == INT_MIN) must be expanded. ABS_MIN_POISON matches
+ // PTX abs semantics since INT_MIN input is poison/undefined.
+ setOperationAction(ISD::ABS, {MVT::i16, MVT::i32, MVT::i64}, Expand);
+ setOperationAction(ISD::ABS_MIN_POISON, {MVT::i16, MVT::i32, MVT::i64},
+ Legal);
setOperationAction({ISD::CTPOP, ISD::CTLZ, ISD::CTLZ_ZERO_UNDEF}, MVT::i16,
Promote);
setOperationAction({ISD::CTPOP, ISD::CTLZ}, MVT::i32, Legal);
setOperationAction({ISD::CTPOP, ISD::CTLZ}, MVT::i64, Custom);
- setI16x2OperationAction(ISD::ABS, MVT::v2i16, Legal, Custom);
+ setI16x2OperationAction(ISD::ABS_MIN_POISON, MVT::v2i16, Legal, Custom);
setI16x2OperationAction(ISD::SMIN, MVT::v2i16, Legal, Custom);
setI16x2OperationAction(ISD::SMAX, MVT::v2i16, Legal, Custom);
setI16x2OperationAction(ISD::UMIN, MVT::v2i16, Legal, Custom);
@@ -837,7 +844,8 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
{MVT::v2i16, MVT::v2i32}, Expand);
// v2i32 is not supported for any arithmetic operations
- setOperationAction({ISD::ABS, ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX,
+ setOperationAction({ISD::ABS,
+ ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX,
ISD::CTPOP, ISD::CTLZ, ISD::ADD, ISD::SUB, ISD::MUL,
ISD::SHL, ISD::SRA, ISD::SRL, ISD::OR, ISD::AND, ISD::XOR,
ISD::SREM, ISD::UREM},
@@ -3491,6 +3499,7 @@ NVPTXTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::ROTR:
return lowerROT(Op, DAG);
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
case ISD::SMIN:
case ISD::SMAX:
case ISD::UMIN:
diff --git a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
index 096c5e470ed02..dde3ef7493e3f 100644
--- a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
+++ b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
@@ -935,10 +935,13 @@ defm SREM : I3<"rem.s", srem, commutative = false>;
defm UREM : I3<"rem.u", urem, commutative = false>;
foreach t = [I16RT, I32RT, I64RT] in {
+ // PTX abs.s is undefined for INT_MIN, so it matches ABS_MIN_POISON
+ // semantics (where INT_MIN input is poison). ISD::ABS requires
+ // abs(INT_MIN) == INT_MIN and is expanded separately.
def ABS_S # t.Size :
BasicNVPTXInst<(outs t.RC:$dst), (ins t.RC:$a),
"abs.s" # t.Size,
- [(set t.Ty:$dst, (abs t.Ty:$a))]>;
+ [(set t.Ty:$dst, (abs_min_poison t.Ty:$a))]>;
def NEG_S # t.Size :
BasicNVPTXInst<(outs t.RC:$dst), (ins t.RC:$src),
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index a8542be937a87..8cb3435c2436a 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -465,12 +465,12 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
(Subtarget.hasVendorXCValu() && !Subtarget.is64Bit())) {
setOperationAction(ISD::ABS, XLenVT, Legal);
if (Subtarget.is64Bit())
- setOperationAction(ISD::ABS, MVT::i32, Custom);
+ setOperationAction({ISD::ABS, ISD::ABS_MIN_POISON}, MVT::i32, Custom);
} else if (Subtarget.hasShortForwardBranchIALU()) {
// We can use PseudoCCSUB to implement ABS.
setOperationAction(ISD::ABS, XLenVT, Legal);
} else if (Subtarget.is64Bit()) {
- setOperationAction(ISD::ABS, MVT::i32, Custom);
+ setOperationAction({ISD::ABS, ISD::ABS_MIN_POISON}, MVT::i32, Custom);
}
if (!Subtarget.useMIPSCCMovInsn() && !Subtarget.hasVendorXTHeadCondMov())
@@ -1892,7 +1892,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
ISD::VP_STORE, ISD::VP_TRUNCATE, ISD::EXPERIMENTAL_VP_REVERSE,
ISD::MUL, ISD::SDIV, ISD::UDIV,
ISD::SREM, ISD::UREM, ISD::INSERT_VECTOR_ELT,
- ISD::ABS, ISD::CTPOP, ISD::VECTOR_SHUFFLE,
+ ISD::ABS, ISD::ABS_MIN_POISON, ISD::CTPOP, ISD::VECTOR_SHUFFLE,
ISD::FMA, ISD::VSELECT, ISD::VECREDUCE_ADD});
if (Subtarget.hasVendorXTHeadMemPair())
@@ -8910,6 +8910,7 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
return DAG.getNode(ISD::SUB, dl, VT, Max, Min);
}
case ISD::ABS:
+ case ISD::ABS_MIN_POISON:
case ISD::VP_ABS:
return lowerABS(Op, DAG);
case ISD::CTLZ:
@@ -15590,7 +15591,8 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
Results.push_back(expandAddSubSat(N, DAG));
return;
}
- case ISD::ABS: {
+ case ISD::ABS:
+ case ISD::ABS_MIN_POISON: {
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
"Unexpected custom legalisation");
@@ -21546,7 +21548,8 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
return DAG.getNode(ISD::AND, DL, VT, NewFMV,
DAG.getConstant(~SignBit, DL, VT));
}
- case ISD::ABS: {
+ case ISD::ABS:
+ case ISD::ABS_MIN_POISON: {
EVT VT = N->getValueType(0);
SDValue N0 = N->getOperand(0);
// abs (sext) -> zext (abs)
@@ -21554,8 +21557,9 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
if (VT.isVector() && N0.hasOneUse() && N0.getOpcode() == ISD::SIGN_EXTEND) {
SDValue Src = N0.getOperand(0);
SDLoc DL(N);
+ unsigned Opc = N->getOpcode();
return DAG.getNode(ISD::ZERO_EXTEND, DL, VT,
- DAG.getNode(ISD::ABS, DL, Src.getValueType(), Src));
+ DAG.getNode(Opc, DL, Src.getValueType(), Src));
}
break;
}
diff --git a/llvm/test/CodeGen/NVPTX/idioms.ll b/llvm/test/CodeGen/NVPTX/idioms.ll
index 87c5ab27ecf9d..55e5aabe96a57 100644
--- a/llvm/test/CodeGen/NVPTX/idioms.ll
+++ b/llvm/test/CodeGen/NVPTX/idioms.ll
@@ -12,13 +12,14 @@
define i16 @abs_i16(i16 %a) {
; CHECK-LABEL: abs_i16(
; CHECK: {
-; CHECK-NEXT: .reg .b16 %rs<3>;
+; CHECK-NEXT: .reg .b16 %rs<4>;
; CHECK-NEXT: .reg .b32 %r<2>;
; CHECK-EMPTY:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: ld.param.b16 %rs1, [abs_i16_param_0];
-; CHECK-NEXT: abs.s16 %rs2, %rs1;
-; CHECK-NEXT: cvt.u32.u16 %r1, %rs2;
+; CHECK-NEXT: neg.s16 %rs2, %rs1;
+; CHECK-NEXT: max.s16 %rs3, %rs1, %rs2;
+; CHECK-NEXT: cvt.u32.u16 %r1, %rs3;
; CHECK-NEXT: st.param.b32 [func_retval0], %r1;
; CHECK-NEXT: ret;
%neg = sub i16 0, %a
@@ -30,12 +31,13 @@ define i16 @abs_i16(i16 %a) {
define i32 @abs_i32(i32 %a) {
; CHECK-LABEL: abs_i32(
; CHECK: {
-; CHECK-NEXT: .reg .b32 %r<3>;
+; CHECK-NEXT: .reg .b32 %r<4>;
; CHECK-EMPTY:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: ld.param.b32 %r1, [abs_i32_param_0];
-; CHECK-NEXT: abs.s32 %r2, %r1;
-; CHECK-NEXT: st.param.b32 [func_retval0], %r2;
+; CHECK-NEXT: neg.s32 %r2, %r1;
+; CHECK-NEXT: max.s32 %r3, %r1, %r2;
+; CHECK-NEXT: st.param.b32 [func_retval0], %r3;
; CHECK-NEXT: ret;
%neg = sub i32 0, %a
%abs.cond = icmp sge i32 %a, 0
@@ -46,12 +48,13 @@ define i32 @abs_i32(i32 %a) {
define i64 @abs_i64(i64 %a) {
; CHECK-LABEL: abs_i64(
; CHECK: {
-; CHECK-NEXT: .reg .b64 %rd<3>;
+; CHECK-NEXT: .reg .b64 %rd<4>;
; CHECK-EMPTY:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: ld.param.b64 %rd1, [abs_i64_param_0];
-; CHECK-NEXT: abs.s64 %rd2, %rd1;
-; CHECK-NEXT: st.param.b64 [func_retval0], %rd2;
+; CHECK-NEXT: neg.s64 %rd2, %rd1;
+; CHECK-NEXT: max.s64 %rd3, %rd1, %rd2;
+; CHECK-NEXT: st.param.b64 [func_retval0], %rd3;
; CHECK-NEXT: ret;
%neg = sub i64 0, %a
%abs.cond = icmp sge i64 %a, 0
diff --git a/llvm/test/CodeGen/X86/abs.ll b/llvm/test/CodeGen/X86/abs.ll
index e252d5953e60e..0dc7d5136f425 100644
--- a/llvm/test/CodeGen/X86/abs.ll
+++ b/llvm/test/CodeGen/X86/abs.ll
@@ -661,9 +661,10 @@ define i32 @test_sextinreg_i32(i32 %a) nounwind {
define i64 @test_sextinreg_i64(i64 %a) nounwind {
; X64-LABEL: test_sextinreg_i64:
; X64: # %bb.0:
-; X64-NEXT: movl %edi, %eax
-; X64-NEXT: negl %eax
-; X64-NEXT: cmovsl %edi, %eax
+; X64-NEXT: movslq %edi, %rcx
+; X64-NEXT: movq %rcx, %rax
+; X64-NEXT: negq %rax
+; X64-NEXT: cmovsq %rcx, %rax
; X64-NEXT: retq
;
; X86-LABEL: test_sextinreg_i64:
diff --git a/llvm/test/CodeGen/X86/freeze-unary.ll b/llvm/test/CodeGen/X86/freeze-unary.ll
index bc9e29957c74a..c7f61cbae78af 100644
--- a/llvm/test/CodeGen/X86/freeze-unary.ll
+++ b/llvm/test/CodeGen/X86/freeze-unary.ll
@@ -113,7 +113,10 @@ define <4 x i32> @freeze_abs_vec(<4 x i32> %a0) nounwind {
define i32 @freeze_abs_undef(i32 %a0) nounwind {
; X86-LABEL: freeze_abs_undef:
; X86: # %bb.0:
-; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT: movl %eax, %ecx
+; X86-NEXT: negl %ecx
+; X86-NEXT: cmovsl %eax, %ecx
; X86-NEXT: movl %ecx, %eax
; X86-NEXT: negl %eax
; X86-NEXT: cmovsl %ecx, %eax
@@ -121,9 +124,12 @@ define i32 @freeze_abs_undef(i32 %a0) nounwind {
;
; X64-LABEL: freeze_abs_undef:
; X64: # %bb.0:
-; X64-NEXT: movl %edi, %eax
+; X64-NEXT: movl %edi, %ecx
+; X64-NEXT: negl %ecx
+; X64-NEXT: cmovsl %edi, %ecx
+; X64-NEXT: movl %ecx, %eax
; X64-NEXT: negl %eax
-; X64-NEXT: cmovsl %edi, %eax
+; X64-NEXT: cmovsl %ecx, %eax
; X64-NEXT: retq
%x = call i32 @llvm.abs.i32(i32 %a0, i1 -1)
%f = freeze i32 %x
@@ -138,6 +144,10 @@ define <4 x i32> @freeze_abs_undef_vec(<4 x i32> %a0) nounwind {
; X86-NEXT: psrad $31, %xmm1
; X86-NEXT: pxor %xmm1, %xmm0
; X86-NEXT: psubd %xmm1, %xmm0
+; X86-NEXT: movdqa %xmm0, %xmm1
+; X86-NEXT: psrad $31, %xmm1
+; X86-NEXT: pxor %xmm1, %xmm0
+; X86-NEXT: psubd %xmm1, %xmm0
; X86-NEXT: retl
;
; X64-LABEL: freeze_abs_undef_vec:
diff --git a/llvm/test/CodeGen/X86/icmp-abs-C.ll b/llvm/test/CodeGen/X86/icmp-abs-C.ll
index 71893a9e4be67..fe19174b53b42 100644
--- a/llvm/test/CodeGen/X86/icmp-abs-C.ll
+++ b/llvm/test/CodeGen/X86/icmp-abs-C.ll
@@ -13,29 +13,32 @@ define i64 @eq_or_with_dom_abs(i64 %x) nounwind {
; X86-NEXT: pushl %ebx
; X86-NEXT: pushl %edi
; X86-NEXT: pushl %esi
-; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT: movl %edx, %eax
-; X86-NEXT: sarl $31, %eax
-; X86-NEXT: xorl %eax, %edx
+; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: movl {{[0-9]+}}(%esp), %esi
-; X86-NEXT: xorl %eax, %esi
-; X86-NEXT: subl %eax, %esi
-; X86-NEXT: sbbl %eax, %edx
-; X86-NEXT: movl %esi, %eax
+; X86-NEXT: movl %esi, %edi
+; X86-NEXT: sarl $31, %edi
+; X86-NEXT: movl %esi, %edx
+; X86-NEXT: xorl %edi, %edx
+; X86-NEXT: movl %ecx, %eax
+; X86-NEXT: xorl %edi, %eax
+; X86-NEXT: subl %edi, %eax
+; X86-NEXT: sbbl %edi, %edx
; X86-NEXT: xorl $12312, %eax # imm = 0x3018
-; X86-NEXT: xorl $64, %esi
-; X86-NEXT: xorl %ecx, %ecx
-; X86-NEXT: orl %edx, %esi
-; X86-NEXT: sete %bl
+; X86-NEXT: addl $64, %ecx
+; X86-NEXT: adcl $0, %esi
+; X86-NEXT: andl $-129, %ecx
+; X86-NEXT: xorl %ebx, %ebx
+; X86-NEXT: orl %esi, %ecx
+; X86-NEXT: sete %cl
; X86-NEXT: xorl %esi, %esi
; X86-NEXT: movl $2344, %edi # imm = 0x928
; X86-NEXT: cmpl %eax, %edi
; X86-NEXT: sbbl %edx, %esi
; X86-NEXT: jb .LBB0_2
; X86-NEXT: # %bb.1:
-; X86-NEXT: movb %bl, %cl
+; X86-NEXT: movb %cl, %bl
; X86-NEXT: xorl %edx, %edx
-; X86-NEXT: movl %ecx, %eax
+; X86-NEXT: movl %ebx, %eax
; X86-NEXT: .LBB0_2:
; X86-NEXT: popl %esi
; X86-NEXT: popl %edi
@@ -47,13 +50,13 @@ define i64 @eq_or_with_dom_abs(i64 %x) nounwind {
; X64-NEXT: movq %rdi, %rcx
; X64-NEXT: negq %rcx
; X64-NEXT: cmovsq %rdi, %rcx
-; X64-NEXT: movq %rcx, %rdx
-; X64-NEXT: xorq $12312, %rdx # imm = 0x3018
+; X64-NEXT: xorq $12312, %rcx # imm = 0x3018
+; X64-NEXT: addq $64, %rdi
; X64-NEXT: xorl %eax, %eax
-; X64-NEXT: cmpq $64, %rcx
+; X64-NEXT: testq $-129, %rdi
; X64-NEXT: sete %al
-; X64-NEXT: cmpq $2345, %rdx # imm = 0x929
-; X64-NEXT: cmovaeq %rdx, %rax
+; X64-NEXT: cmpq $2345, %rcx # imm = 0x929
+; X64-NEXT: cmovaeq %rcx, %rax
; X64-NEXT: retq
%absx = call i64 @llvm.abs.i64(i64 %x, i1 true)
%foo = xor i64 %absx, 12312
@@ -70,20 +73,21 @@ define i32 @eq_or_with_dom_abs_non_po2(i32 %x) nounwind {
; X86-LABEL: eq_or_with_dom_abs_non_po2:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %edx, %ecx
+; X86-NEXT: sarl $31, %ecx
; X86-NEXT: movl %edx, %eax
-; X86-NEXT: sarl $31, %eax
-; X86-NEXT: xorl %eax, %edx
-; X86-NEXT: subl %eax, %edx
-; X86-NEXT: movl %edx, %eax
+; X86-NEXT: xorl %ecx, %eax
+; X86-NEXT: subl %ecx, %eax
; X86-NEXT: xorl $12312, %eax # imm = 0x3018
-; X86-NEXT: xorl %ecx, %ecx
; X86-NEXT: cmpl $123, %edx
+; X86-NEXT: sete %cl
+; X86-NEXT: cmpl $-123, %edx
; X86-NEXT: sete %dl
; X86-NEXT: cmpl $2345, %eax # imm = 0x929
; X86-NEXT: jae .LBB1_2
; X86-NEXT: # %bb.1:
-; X86-NEXT: movb %dl, %cl
-; X86-NEXT: movl %ecx, %eax
+; X86-NEXT: orb %dl, %cl
+; X86-NEXT: movzbl %cl, %eax
; X86-NEXT: .LBB1_2:
; X86-NEXT: retl
;
@@ -92,13 +96,15 @@ define i32 @eq_or_with_dom_abs_non_po2(i32 %x) nounwind {
; X64-NEXT: movl %edi, %ecx
; X64-NEXT: negl %ecx
; X64-NEXT: cmovsl %edi, %ecx
-; X64-NEXT: movl %ecx, %edx
-; X64-NEXT: xorl $12312, %edx # imm = 0x3018
-; X64-NEXT: xorl %eax, %eax
-; X64-NEXT: cmpl $123, %ecx
+; X64-NEXT: xorl $12312, %ecx # imm = 0x3018
+; X64-NEXT: cmpl $123, %edi
; X64-NEXT: sete %al
-; X64-NEXT: cmpl $2345, %edx # imm = 0x929
-; X64-NEXT: cmovael %edx, %eax
+; X64-NEXT: cmpl $-123, %edi
+; X64-NEXT: sete %dl
+; X64-NEXT: orb %al, %dl
+; X64-NEXT: cmpl $2345, %ecx # imm = 0x929
+; X64-NEXT: movzbl %dl, %eax
+; X64-NEXT: cmovael %ecx, %eax
; X64-NEXT: retq
%absx = call i32 @llvm.abs.i32(i32 %x, i1 true)
%foo = xor i32 %absx, 12312
@@ -114,18 +120,21 @@ define i32 @eq_or_with_dom_abs_non_po2(i32 %x) nounwind {
define i8 @ne_and_with_dom_abs_non_pow2(i8 %x) nounwind {
; X86-LABEL: ne_and_with_dom_abs_non_pow2:
; X86: # %bb.0:
-; X86-NEXT: movzbl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT: movl %ecx, %eax
-; X86-NEXT: sarb $7, %al
-; X86-NEXT: xorb %al, %cl
-; X86-NEXT: subb %al, %cl
-; X86-NEXT: movl %ecx, %eax
+; X86-NEXT: movzbl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %edx, %ecx
+; X86-NEXT: sarb $7, %cl
+; X86-NEXT: movl %edx, %eax
+; X86-NEXT: xorb %cl, %al
+; X86-NEXT: subb %cl, %al
; X86-NEXT: xorb $12, %al
-; X86-NEXT: cmpb $121, %cl
+; X86-NEXT: cmpb $121, %dl
; X86-NEXT: setne %cl
+; X86-NEXT: cmpb $-121, %dl
+; X86-NEXT: setne %dl
; X86-NEXT: cmpb $24, %al
; X86-NEXT: jae .LBB2_2
; X86-NEXT: # %bb.1:
+; X86-NEXT: andb %dl, %cl
; X86-NEXT: movl %ecx, %eax
; X86-NEXT: .LBB2_2:
; X86-NEXT: retl
@@ -134,16 +143,19 @@ define i8 @ne_and_with_dom_abs_non_pow2(i8 %x) nounwind {
; X64: # %bb.0:
; X64-NEXT: movl %edi, %eax
; X64-NEXT: sarb $7, %al
-; X64-NEXT: xorb %al, %dil
-; X64-NEXT: subb %al, %dil
; X64-NEXT: movl %edi, %ecx
+; X64-NEXT: xorb %al, %cl
+; X64-NEXT: subb %al, %cl
; X64-NEXT: xorb $12, %cl
-; X64-NEXT: xorl %eax, %eax
; X64-NEXT: cmpb $121, %dil
; X64-NEXT: setne %al
+; X64-NEXT: cmpb $-121, %dil
+; X64-NEXT: setne %dl
+; X64-NEXT: andb %al, %dl
; X64-NEXT: cmpb $24, %cl
-; X64-NEXT: movzbl %cl, %ecx
-; X64-NEXT: cmovael %ecx, %eax
+; X64-NEXT: movzbl %dl, %edx
+; X64-NEXT: movzbl %cl, %eax
+; X64-NEXT: cmovbl %edx, %eax
; X64-NEXT: # kill: def $al killed $al killed $eax
; X64-NEXT: retq
%absx = call i8 @llvm.abs.i8(i8 %x, i1 true)
@@ -161,16 +173,16 @@ define i16 @ne_and_with_dom_abs(i16 %x) nounwind {
; X86-LABEL: ne_and_with_dom_abs:
; X86: # %bb.0:
; X86-NEXT: pushl %esi
-; X86-NEXT: movswl {{[0-9]+}}(%esp), %eax
-; X86-NEXT: movl %eax, %ecx
+; X86-NEXT: movzwl {{[0-9]+}}(%esp), %eax
+; X86-NEXT: movswl %ax, %ecx
; X86-NEXT: sarl $15, %ecx
+; X86-NEXT: leal 64(%eax), %edx
; X86-NEXT: xorl %ecx, %eax
; X86-NEXT: subl %ecx, %eax
-; X86-NEXT: movl %eax, %edx
; X86-NEXT: xorl $12312, %eax # imm = 0x3018
; X86-NEXT: movzwl %ax, %esi
; X86-NEXT: xorl %ecx, %ecx
-; X86-NEXT: cmpw $64, %dx
+; X86-NEXT: testl $65407, %edx # imm = 0xFF7F
; X86-NEXT: setne %dl
; X86-NEXT: cmpl $2345, %esi # imm = 0x929
; X86-NEXT: jae .LBB3_2
@@ -187,14 +199,14 @@ define i16 @ne_and_with_dom_abs(i16 %x) nounwind {
; X64-NEXT: movl %edi, %ecx
; X64-NEXT: negw %cx
; X64-NEXT: cmovsw %di, %cx
-; X64-NEXT: movl %ecx, %edx
-; X64-NEXT: xorl $12312, %edx # imm = 0x3018
-; X64-NEXT: movzwl %dx, %esi
+; X64-NEXT: xorl $12312, %ecx # imm = 0x3018
+; X64-NEXT: movzwl %cx, %edx
+; X64-NEXT: addl $64, %edi
; X64-NEXT: xorl %eax, %eax
-; X64-NEXT: cmpw $64, %cx
+; X64-NEXT: testl $65407, %edi # imm = 0xFF7F
; X64-NEXT: setne %al
-; X64-NEXT: cmpl $2345, %esi # imm = 0x929
-; X64-NEXT: cmovael %edx, %eax
+; X64-NEXT: cmpl $2345, %edx # imm = 0x929
+; X64-NEXT: cmovael %ecx, %eax
; X64-NEXT: # kill: def $ax killed $ax killed $eax
; X64-NEXT: retq
%absx = call i16 @llvm.abs.i16(i16 %x, i1 true)
diff --git a/llvm/test/CodeGen/X86/icmp-pow2-logic-npow2.ll b/llvm/test/CodeGen/X86/icmp-pow2-logic-npow2.ll
index b14fedeaae57d..298e78103e709 100644
--- a/llvm/test/CodeGen/X86/icmp-pow2-logic-npow2.ll
+++ b/llvm/test/CodeGen/X86/icmp-pow2-logic-npow2.ll
@@ -154,15 +154,20 @@ define i1 @abs_eq_pow2(i32 %0) nounwind {
; X86-LABEL: abs_eq_pow2:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT: addl $4, %eax
-; X86-NEXT: testl $-9, %eax
+; X86-NEXT: movl %eax, %ecx
+; X86-NEXT: sarl $31, %ecx
+; X86-NEXT: xorl %ecx, %eax
+; X86-NEXT: subl %ecx, %eax
+; X86-NEXT: cmpl $4, %eax
; X86-NEXT: sete %al
; X86-NEXT: retl
;
; X64-LABEL: abs_eq_pow2:
; X64: # %bb.0:
-; X64-NEXT: addl $4, %edi
-; X64-NEXT: testl $-9, %edi
+; X64-NEXT: movl %edi, %eax
+; X64-NEXT: negl %eax
+; X64-NEXT: cmovsl %edi, %eax
+; X64-NEXT: cmpl $4, %eax
; X64-NEXT: sete %al
; X64-NEXT: retq
%2 = tail call i32 @llvm.abs.i32(i32 %0, i1 true)
@@ -174,18 +179,24 @@ define i1 @abs_ne_pow2(i64 %0) nounwind {
; X86-LABEL: abs_ne_pow2:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT: addl $2, %eax
-; X86-NEXT: adcl $0, %ecx
-; X86-NEXT: andl $-5, %eax
-; X86-NEXT: orl %ecx, %eax
+; X86-NEXT: movl %eax, %ecx
+; X86-NEXT: sarl $31, %ecx
+; X86-NEXT: xorl %ecx, %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: xorl %ecx, %edx
+; X86-NEXT: subl %ecx, %edx
+; X86-NEXT: sbbl %ecx, %eax
+; X86-NEXT: xorl $2, %edx
+; X86-NEXT: orl %eax, %edx
; X86-NEXT: setne %al
; X86-NEXT: retl
;
; X64-LABEL: abs_ne_pow2:
; X64: # %bb.0:
-; X64-NEXT: addq $2, %rdi
-; X64-NEXT: testq $-5, %rdi
+; X64-NEXT: movq %rdi, %rax
+; X64-NEXT: negq %rax
+; X64-NEXT: cmovsq %rdi, %rax
+; X64-NEXT: cmpq $2, %rax
; X64-NEXT: setne %al
; X64-NEXT: retq
%2 = tail call i64 @llvm.abs.i64(i64 %0, i1 true)
More information about the llvm-commits
mailing list