mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-20 03:23:01 +02:00
Revisit my fix for PR9028: the issue is that DAGCombine was
generating i8 shift amounts for things like i1024 types. Add an assert in getNode to prevent this from occuring in the future, fix the buggy transformation, revert my previous patch, and document this gotcha in ISDOpcodes.h llvm-svn: 125465
This commit is contained in:
parent
dff71eae10
commit
c9c0de6faf
@ -303,13 +303,21 @@ namespace ISD {
|
|||||||
// an unsigned/signed value of type i[2*N], then return the top part.
|
// an unsigned/signed value of type i[2*N], then return the top part.
|
||||||
MULHU, MULHS,
|
MULHU, MULHS,
|
||||||
|
|
||||||
// Bitwise operators - logical and, logical or, logical xor, shift left,
|
/// Bitwise operators - logical and, logical or, logical xor.
|
||||||
// shift right algebraic (shift in sign bits), shift right logical (shift in
|
AND, OR, XOR,
|
||||||
// zeroes), rotate left, rotate right, and byteswap.
|
|
||||||
AND, OR, XOR, SHL, SRA, SRL, ROTL, ROTR, BSWAP,
|
|
||||||
|
|
||||||
// Counting operators
|
/// Shift and rotation operations. After legalization, the type of the
|
||||||
CTTZ, CTLZ, CTPOP,
|
/// 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
|
||||||
|
/// large enough. TLI.getShiftAmountTy() is i8 on some targets, but before
|
||||||
|
/// legalization, types like i1024 can occur and i8 doesn't have enough bits
|
||||||
|
/// to represent the shift amount. By convention, DAGCombine and IRBuilder
|
||||||
|
/// forces these shift amounts to i32 for simplicity.
|
||||||
|
///
|
||||||
|
SHL, SRA, SRL, ROTL, ROTR,
|
||||||
|
|
||||||
|
/// Byte Swap and Counting operators.
|
||||||
|
BSWAP, CTTZ, CTLZ, CTPOP,
|
||||||
|
|
||||||
// Select(COND, TRUEVAL, FALSEVAL). If the type of the boolean COND is not
|
// Select(COND, TRUEVAL, FALSEVAL). If the type of the boolean COND is not
|
||||||
// i1 then the high bits must conform to getBooleanContents.
|
// i1 then the high bits must conform to getBooleanContents.
|
||||||
|
@ -4000,21 +4000,27 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) {
|
|||||||
isa<ConstantSDNode>(N0.getOperand(1)) &&
|
isa<ConstantSDNode>(N0.getOperand(1)) &&
|
||||||
N0.getOperand(0).getOpcode() == ISD::ZERO_EXTEND &&
|
N0.getOperand(0).getOpcode() == ISD::ZERO_EXTEND &&
|
||||||
N0.hasOneUse()) {
|
N0.hasOneUse()) {
|
||||||
|
SDValue ShAmt = N0.getOperand(1);
|
||||||
|
unsigned ShAmtVal = cast<ConstantSDNode>(ShAmt)->getZExtValue();
|
||||||
if (N0.getOpcode() == ISD::SHL) {
|
if (N0.getOpcode() == ISD::SHL) {
|
||||||
|
SDValue InnerZExt = N0.getOperand(0);
|
||||||
// If the original shl may be shifting out bits, do not perform this
|
// If the original shl may be shifting out bits, do not perform this
|
||||||
// transformation.
|
// transformation.
|
||||||
unsigned ShAmt = cast<ConstantSDNode>(N0.getOperand(1))->getZExtValue();
|
unsigned KnownZeroBits = InnerZExt.getValueType().getSizeInBits() -
|
||||||
unsigned KnownZeroBits = N0.getOperand(0).getValueType().getSizeInBits() -
|
InnerZExt.getOperand(0).getValueType().getSizeInBits();
|
||||||
N0.getOperand(0).getOperand(0).getValueType().getSizeInBits();
|
if (ShAmtVal > KnownZeroBits)
|
||||||
if (ShAmt > KnownZeroBits)
|
|
||||||
return SDValue();
|
return SDValue();
|
||||||
}
|
}
|
||||||
DebugLoc dl = N->getDebugLoc();
|
|
||||||
return DAG.getNode(N0.getOpcode(), dl, VT,
|
DebugLoc DL = N->getDebugLoc();
|
||||||
DAG.getNode(ISD::ZERO_EXTEND, dl, VT, N0.getOperand(0)),
|
|
||||||
DAG.getNode(ISD::ZERO_EXTEND, dl,
|
// Ensure that the shift amount is wide enough for the shifted value.
|
||||||
N0.getOperand(1).getValueType(),
|
if (VT.getSizeInBits() >= 256)
|
||||||
N0.getOperand(1)));
|
ShAmt = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i32, ShAmt);
|
||||||
|
|
||||||
|
return DAG.getNode(N0.getOpcode(), DL, VT,
|
||||||
|
DAG.getNode(ISD::ZERO_EXTEND, DL, VT, N0.getOperand(0)),
|
||||||
|
ShAmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SDValue();
|
return SDValue();
|
||||||
|
@ -1157,7 +1157,7 @@ std::pair <SDValue, SDValue> DAGTypeLegalizer::ExpandAtomic(SDNode *Node) {
|
|||||||
/// and the shift amount is a constant 'Amt'. Expand the operation.
|
/// and the shift amount is a constant 'Amt'. Expand the operation.
|
||||||
void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt,
|
void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt,
|
||||||
SDValue &Lo, SDValue &Hi) {
|
SDValue &Lo, SDValue &Hi) {
|
||||||
DebugLoc dl = N->getDebugLoc();
|
DebugLoc DL = N->getDebugLoc();
|
||||||
// Expand the incoming operand to be shifted, so that we have its parts
|
// Expand the incoming operand to be shifted, so that we have its parts
|
||||||
SDValue InL, InH;
|
SDValue InL, InH;
|
||||||
GetExpandedInteger(N->getOperand(0), InL, InH);
|
GetExpandedInteger(N->getOperand(0), InL, InH);
|
||||||
@ -1167,18 +1167,12 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt,
|
|||||||
unsigned NVTBits = NVT.getSizeInBits();
|
unsigned NVTBits = NVT.getSizeInBits();
|
||||||
EVT ShTy = N->getOperand(1).getValueType();
|
EVT ShTy = N->getOperand(1).getValueType();
|
||||||
|
|
||||||
// If this is a large integer being legalized (e.g. an i512) then plop the
|
|
||||||
// shift amount down as a fixed i32. The target shift amount may be something
|
|
||||||
// like i8, but this isn't enough to represent the shift amount.
|
|
||||||
if (NVTBits > 256)
|
|
||||||
ShTy = MVT::i32;
|
|
||||||
|
|
||||||
if (N->getOpcode() == ISD::SHL) {
|
if (N->getOpcode() == ISD::SHL) {
|
||||||
if (Amt > VTBits) {
|
if (Amt > VTBits) {
|
||||||
Lo = Hi = DAG.getConstant(0, NVT);
|
Lo = Hi = DAG.getConstant(0, NVT);
|
||||||
} else if (Amt > NVTBits) {
|
} else if (Amt > NVTBits) {
|
||||||
Lo = DAG.getConstant(0, NVT);
|
Lo = DAG.getConstant(0, NVT);
|
||||||
Hi = DAG.getNode(ISD::SHL, dl,
|
Hi = DAG.getNode(ISD::SHL, DL,
|
||||||
NVT, InL, DAG.getConstant(Amt-NVTBits, ShTy));
|
NVT, InL, DAG.getConstant(Amt-NVTBits, ShTy));
|
||||||
} else if (Amt == NVTBits) {
|
} else if (Amt == NVTBits) {
|
||||||
Lo = DAG.getConstant(0, NVT);
|
Lo = DAG.getConstant(0, NVT);
|
||||||
@ -1189,15 +1183,15 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt,
|
|||||||
// Emit this X << 1 as X+X.
|
// Emit this X << 1 as X+X.
|
||||||
SDVTList VTList = DAG.getVTList(NVT, MVT::Glue);
|
SDVTList VTList = DAG.getVTList(NVT, MVT::Glue);
|
||||||
SDValue LoOps[2] = { InL, InL };
|
SDValue LoOps[2] = { InL, InL };
|
||||||
Lo = DAG.getNode(ISD::ADDC, dl, VTList, LoOps, 2);
|
Lo = DAG.getNode(ISD::ADDC, DL, VTList, LoOps, 2);
|
||||||
SDValue HiOps[3] = { InH, InH, Lo.getValue(1) };
|
SDValue HiOps[3] = { InH, InH, Lo.getValue(1) };
|
||||||
Hi = DAG.getNode(ISD::ADDE, dl, VTList, HiOps, 3);
|
Hi = DAG.getNode(ISD::ADDE, DL, VTList, HiOps, 3);
|
||||||
} else {
|
} else {
|
||||||
Lo = DAG.getNode(ISD::SHL, dl, NVT, InL, DAG.getConstant(Amt, ShTy));
|
Lo = DAG.getNode(ISD::SHL, DL, NVT, InL, DAG.getConstant(Amt, ShTy));
|
||||||
Hi = DAG.getNode(ISD::OR, dl, NVT,
|
Hi = DAG.getNode(ISD::OR, DL, NVT,
|
||||||
DAG.getNode(ISD::SHL, dl, NVT, InH,
|
DAG.getNode(ISD::SHL, DL, NVT, InH,
|
||||||
DAG.getConstant(Amt, ShTy)),
|
DAG.getConstant(Amt, ShTy)),
|
||||||
DAG.getNode(ISD::SRL, dl, NVT, InL,
|
DAG.getNode(ISD::SRL, DL, NVT, InL,
|
||||||
DAG.getConstant(NVTBits-Amt, ShTy)));
|
DAG.getConstant(NVTBits-Amt, ShTy)));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -1208,43 +1202,43 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt,
|
|||||||
Lo = DAG.getConstant(0, NVT);
|
Lo = DAG.getConstant(0, NVT);
|
||||||
Hi = DAG.getConstant(0, NVT);
|
Hi = DAG.getConstant(0, NVT);
|
||||||
} else if (Amt > NVTBits) {
|
} else if (Amt > NVTBits) {
|
||||||
Lo = DAG.getNode(ISD::SRL, dl,
|
Lo = DAG.getNode(ISD::SRL, DL,
|
||||||
NVT, InH, DAG.getConstant(Amt-NVTBits,ShTy));
|
NVT, InH, DAG.getConstant(Amt-NVTBits,ShTy));
|
||||||
Hi = DAG.getConstant(0, NVT);
|
Hi = DAG.getConstant(0, NVT);
|
||||||
} else if (Amt == NVTBits) {
|
} else if (Amt == NVTBits) {
|
||||||
Lo = InH;
|
Lo = InH;
|
||||||
Hi = DAG.getConstant(0, NVT);
|
Hi = DAG.getConstant(0, NVT);
|
||||||
} else {
|
} else {
|
||||||
Lo = DAG.getNode(ISD::OR, dl, NVT,
|
Lo = DAG.getNode(ISD::OR, DL, NVT,
|
||||||
DAG.getNode(ISD::SRL, dl, NVT, InL,
|
DAG.getNode(ISD::SRL, DL, NVT, InL,
|
||||||
DAG.getConstant(Amt, ShTy)),
|
DAG.getConstant(Amt, ShTy)),
|
||||||
DAG.getNode(ISD::SHL, dl, NVT, InH,
|
DAG.getNode(ISD::SHL, DL, NVT, InH,
|
||||||
DAG.getConstant(NVTBits-Amt, ShTy)));
|
DAG.getConstant(NVTBits-Amt, ShTy)));
|
||||||
Hi = DAG.getNode(ISD::SRL, dl, NVT, InH, DAG.getConstant(Amt, ShTy));
|
Hi = DAG.getNode(ISD::SRL, DL, NVT, InH, DAG.getConstant(Amt, ShTy));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(N->getOpcode() == ISD::SRA && "Unknown shift!");
|
assert(N->getOpcode() == ISD::SRA && "Unknown shift!");
|
||||||
if (Amt > VTBits) {
|
if (Amt > VTBits) {
|
||||||
Hi = Lo = DAG.getNode(ISD::SRA, dl, NVT, InH,
|
Hi = Lo = DAG.getNode(ISD::SRA, DL, NVT, InH,
|
||||||
DAG.getConstant(NVTBits-1, ShTy));
|
DAG.getConstant(NVTBits-1, ShTy));
|
||||||
} else if (Amt > NVTBits) {
|
} else if (Amt > NVTBits) {
|
||||||
Lo = DAG.getNode(ISD::SRA, dl, NVT, InH,
|
Lo = DAG.getNode(ISD::SRA, DL, NVT, InH,
|
||||||
DAG.getConstant(Amt-NVTBits, ShTy));
|
DAG.getConstant(Amt-NVTBits, ShTy));
|
||||||
Hi = DAG.getNode(ISD::SRA, dl, NVT, InH,
|
Hi = DAG.getNode(ISD::SRA, DL, NVT, InH,
|
||||||
DAG.getConstant(NVTBits-1, ShTy));
|
DAG.getConstant(NVTBits-1, ShTy));
|
||||||
} else if (Amt == NVTBits) {
|
} else if (Amt == NVTBits) {
|
||||||
Lo = InH;
|
Lo = InH;
|
||||||
Hi = DAG.getNode(ISD::SRA, dl, NVT, InH,
|
Hi = DAG.getNode(ISD::SRA, DL, NVT, InH,
|
||||||
DAG.getConstant(NVTBits-1, ShTy));
|
DAG.getConstant(NVTBits-1, ShTy));
|
||||||
} else {
|
} else {
|
||||||
Lo = DAG.getNode(ISD::OR, dl, NVT,
|
Lo = DAG.getNode(ISD::OR, DL, NVT,
|
||||||
DAG.getNode(ISD::SRL, dl, NVT, InL,
|
DAG.getNode(ISD::SRL, DL, NVT, InL,
|
||||||
DAG.getConstant(Amt, ShTy)),
|
DAG.getConstant(Amt, ShTy)),
|
||||||
DAG.getNode(ISD::SHL, dl, NVT, InH,
|
DAG.getNode(ISD::SHL, DL, NVT, InH,
|
||||||
DAG.getConstant(NVTBits-Amt, ShTy)));
|
DAG.getConstant(NVTBits-Amt, ShTy)));
|
||||||
Hi = DAG.getNode(ISD::SRA, dl, NVT, InH, DAG.getConstant(Amt, ShTy));
|
Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(Amt, ShTy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2720,6 +2720,13 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT,
|
|||||||
"Shift operators return type must be the same as their first arg");
|
"Shift operators return type must be the same as their first arg");
|
||||||
assert(VT.isInteger() && N2.getValueType().isInteger() &&
|
assert(VT.isInteger() && N2.getValueType().isInteger() &&
|
||||||
"Shifts only work on integers");
|
"Shifts only work on integers");
|
||||||
|
// Verify that the shift amount VT is bit enough to hold valid shift
|
||||||
|
// amounts. This catches things like trying to shift an i1024 value by an
|
||||||
|
// i8, which is easy to fall into in generic code that uses
|
||||||
|
// TLI.getShiftAmount().
|
||||||
|
assert(N2.getValueType().getSizeInBits() >=
|
||||||
|
Log2_32_Ceil(N1.getValueType().getSizeInBits()) &&
|
||||||
|
"Invalid use of small shift amount with oversized value!");
|
||||||
|
|
||||||
// Always fold shifts of i1 values so the code generator doesn't need to
|
// Always fold shifts of i1 values so the code generator doesn't need to
|
||||||
// handle them. Since we know the size of the shift has to be less than the
|
// handle them. Since we know the size of the shift has to be less than the
|
||||||
|
@ -2434,7 +2434,6 @@ void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
|
|||||||
DebugLoc DL = getCurDebugLoc();
|
DebugLoc DL = getCurDebugLoc();
|
||||||
|
|
||||||
// If the operand is smaller than the shift count type, promote it.
|
// If the operand is smaller than the shift count type, promote it.
|
||||||
MVT PtrTy = TLI.getPointerTy();
|
|
||||||
if (ShiftSize > Op2Size)
|
if (ShiftSize > Op2Size)
|
||||||
Op2 = DAG.getNode(ISD::ZERO_EXTEND, DL, ShiftTy, Op2);
|
Op2 = DAG.getNode(ISD::ZERO_EXTEND, DL, ShiftTy, Op2);
|
||||||
|
|
||||||
@ -2445,9 +2444,9 @@ void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
|
|||||||
else if (ShiftSize >= Log2_32_Ceil(Op2.getValueType().getSizeInBits()))
|
else if (ShiftSize >= Log2_32_Ceil(Op2.getValueType().getSizeInBits()))
|
||||||
Op2 = DAG.getNode(ISD::TRUNCATE, DL, ShiftTy, Op2);
|
Op2 = DAG.getNode(ISD::TRUNCATE, DL, ShiftTy, Op2);
|
||||||
// Otherwise we'll need to temporarily settle for some other convenient
|
// Otherwise we'll need to temporarily settle for some other convenient
|
||||||
// type. Type legalization will make adjustments as needed.
|
// type. Type legalization will make adjustments once the shiftee is split.
|
||||||
else
|
else
|
||||||
Op2 = DAG.getZExtOrTrunc(Op2, DL, PtrTy);
|
Op2 = DAG.getZExtOrTrunc(Op2, DL, MVT::i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(&I, DAG.getNode(Opcode, getCurDebugLoc(),
|
setValue(&I, DAG.getNode(Opcode, getCurDebugLoc(),
|
||||||
|
Loading…
Reference in New Issue
Block a user