R600: Move division custom lowering out of AMDILISelLowering

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@210997 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matt Arsenault 2014-06-15 20:08:02 +00:00
parent 47d34abdb0
commit 57177e3361
3 changed files with 258 additions and 272 deletions

View File

@ -464,8 +464,6 @@ SDValue AMDGPUTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG)
"instruction is not implemented yet!");
break;
// AMDIL DAG lowering
case ISD::SDIV: return LowerSDIV(Op, DAG);
case ISD::SREM: return LowerSREM(Op, DAG);
case ISD::SIGN_EXTEND_INREG: return LowerSIGN_EXTEND_INREG(Op, DAG);
case ISD::BRCOND: return LowerBRCOND(Op, DAG);
// AMDGPU DAG lowering
@ -473,6 +471,8 @@ SDValue AMDGPUTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG)
case ISD::EXTRACT_SUBVECTOR: return LowerEXTRACT_SUBVECTOR(Op, DAG);
case ISD::FrameIndex: return LowerFrameIndex(Op, DAG);
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
case ISD::SDIV: return LowerSDIV(Op, DAG);
case ISD::SREM: return LowerSREM(Op, DAG);
case ISD::UDIVREM: return LowerUDIVREM(Op, DAG);
case ISD::UINT_TO_FP: return LowerUINT_TO_FP(Op, DAG);
}
@ -1199,6 +1199,250 @@ SDValue AMDGPUTargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {
return SDValue();
}
SDValue AMDGPUTargetLowering::LowerSDIV24(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT OVT = Op.getValueType();
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
MVT INTTY;
MVT FLTTY;
if (!OVT.isVector()) {
INTTY = MVT::i32;
FLTTY = MVT::f32;
} else if (OVT.getVectorNumElements() == 2) {
INTTY = MVT::v2i32;
FLTTY = MVT::v2f32;
} else if (OVT.getVectorNumElements() == 4) {
INTTY = MVT::v4i32;
FLTTY = MVT::v4f32;
}
unsigned bitsize = OVT.getScalarType().getSizeInBits();
// char|short jq = ia ^ ib;
SDValue jq = DAG.getNode(ISD::XOR, DL, OVT, LHS, RHS);
// jq = jq >> (bitsize - 2)
jq = DAG.getNode(ISD::SRA, DL, OVT, jq, DAG.getConstant(bitsize - 2, OVT));
// jq = jq | 0x1
jq = DAG.getNode(ISD::OR, DL, OVT, jq, DAG.getConstant(1, OVT));
// jq = (int)jq
jq = DAG.getSExtOrTrunc(jq, DL, INTTY);
// int ia = (int)LHS;
SDValue ia = DAG.getSExtOrTrunc(LHS, DL, INTTY);
// int ib, (int)RHS;
SDValue ib = DAG.getSExtOrTrunc(RHS, DL, INTTY);
// float fa = (float)ia;
SDValue fa = DAG.getNode(ISD::SINT_TO_FP, DL, FLTTY, ia);
// float fb = (float)ib;
SDValue fb = DAG.getNode(ISD::SINT_TO_FP, DL, FLTTY, ib);
// float fq = native_divide(fa, fb);
SDValue fq = DAG.getNode(AMDGPUISD::DIV_INF, DL, FLTTY, fa, fb);
// fq = trunc(fq);
fq = DAG.getNode(ISD::FTRUNC, DL, FLTTY, fq);
// float fqneg = -fq;
SDValue fqneg = DAG.getNode(ISD::FNEG, DL, FLTTY, fq);
// float fr = mad(fqneg, fb, fa);
SDValue fr = DAG.getNode(ISD::FADD, DL, FLTTY,
DAG.getNode(ISD::MUL, DL, FLTTY, fqneg, fb), fa);
// int iq = (int)fq;
SDValue iq = DAG.getNode(ISD::FP_TO_SINT, DL, INTTY, fq);
// fr = fabs(fr);
fr = DAG.getNode(ISD::FABS, DL, FLTTY, fr);
// fb = fabs(fb);
fb = DAG.getNode(ISD::FABS, DL, FLTTY, fb);
// int cv = fr >= fb;
SDValue cv;
if (INTTY == MVT::i32) {
cv = DAG.getSetCC(DL, INTTY, fr, fb, ISD::SETOGE);
} else {
cv = DAG.getSetCC(DL, INTTY, fr, fb, ISD::SETOGE);
}
// jq = (cv ? jq : 0);
jq = DAG.getNode(ISD::SELECT, DL, OVT, cv, jq,
DAG.getConstant(0, OVT));
// dst = iq + jq;
iq = DAG.getSExtOrTrunc(iq, DL, OVT);
iq = DAG.getNode(ISD::ADD, DL, OVT, iq, jq);
return iq;
}
SDValue AMDGPUTargetLowering::LowerSDIV32(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT OVT = Op.getValueType();
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
// The LowerSDIV32 function generates equivalent to the following IL.
// mov r0, LHS
// mov r1, RHS
// ilt r10, r0, 0
// ilt r11, r1, 0
// iadd r0, r0, r10
// iadd r1, r1, r11
// ixor r0, r0, r10
// ixor r1, r1, r11
// udiv r0, r0, r1
// ixor r10, r10, r11
// iadd r0, r0, r10
// ixor DST, r0, r10
// mov r0, LHS
SDValue r0 = LHS;
// mov r1, RHS
SDValue r1 = RHS;
// ilt r10, r0, 0
SDValue r10 = DAG.getSelectCC(DL,
r0, DAG.getConstant(0, OVT),
DAG.getConstant(-1, MVT::i32),
DAG.getConstant(0, MVT::i32),
ISD::SETLT);
// ilt r11, r1, 0
SDValue r11 = DAG.getSelectCC(DL,
r1, DAG.getConstant(0, OVT),
DAG.getConstant(-1, MVT::i32),
DAG.getConstant(0, MVT::i32),
ISD::SETLT);
// iadd r0, r0, r10
r0 = DAG.getNode(ISD::ADD, DL, OVT, r0, r10);
// iadd r1, r1, r11
r1 = DAG.getNode(ISD::ADD, DL, OVT, r1, r11);
// ixor r0, r0, r10
r0 = DAG.getNode(ISD::XOR, DL, OVT, r0, r10);
// ixor r1, r1, r11
r1 = DAG.getNode(ISD::XOR, DL, OVT, r1, r11);
// udiv r0, r0, r1
r0 = DAG.getNode(ISD::UDIV, DL, OVT, r0, r1);
// ixor r10, r10, r11
r10 = DAG.getNode(ISD::XOR, DL, OVT, r10, r11);
// iadd r0, r0, r10
r0 = DAG.getNode(ISD::ADD, DL, OVT, r0, r10);
// ixor DST, r0, r10
SDValue DST = DAG.getNode(ISD::XOR, DL, OVT, r0, r10);
return DST;
}
SDValue AMDGPUTargetLowering::LowerSDIV64(SDValue Op, SelectionDAG &DAG) const {
return SDValue(Op.getNode(), 0);
}
SDValue AMDGPUTargetLowering::LowerSDIV(SDValue Op, SelectionDAG &DAG) const {
EVT OVT = Op.getValueType().getScalarType();
if (OVT == MVT::i64)
return LowerSDIV64(Op, DAG);
if (OVT.getScalarType() == MVT::i32)
return LowerSDIV32(Op, DAG);
if (OVT == MVT::i16 || OVT == MVT::i8) {
// FIXME: We should be checking for the masked bits. This isn't reached
// because i8 and i16 are not legal types.
return LowerSDIV24(Op, DAG);
}
return SDValue(Op.getNode(), 0);
}
SDValue AMDGPUTargetLowering::LowerSREM32(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT OVT = Op.getValueType();
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
// The LowerSREM32 function generates equivalent to the following IL.
// mov r0, LHS
// mov r1, RHS
// ilt r10, r0, 0
// ilt r11, r1, 0
// iadd r0, r0, r10
// iadd r1, r1, r11
// ixor r0, r0, r10
// ixor r1, r1, r11
// udiv r20, r0, r1
// umul r20, r20, r1
// sub r0, r0, r20
// iadd r0, r0, r10
// ixor DST, r0, r10
// mov r0, LHS
SDValue r0 = LHS;
// mov r1, RHS
SDValue r1 = RHS;
// ilt r10, r0, 0
SDValue r10 = DAG.getSetCC(DL, OVT, r0, DAG.getConstant(0, OVT), ISD::SETLT);
// ilt r11, r1, 0
SDValue r11 = DAG.getSetCC(DL, OVT, r1, DAG.getConstant(0, OVT), ISD::SETLT);
// iadd r0, r0, r10
r0 = DAG.getNode(ISD::ADD, DL, OVT, r0, r10);
// iadd r1, r1, r11
r1 = DAG.getNode(ISD::ADD, DL, OVT, r1, r11);
// ixor r0, r0, r10
r0 = DAG.getNode(ISD::XOR, DL, OVT, r0, r10);
// ixor r1, r1, r11
r1 = DAG.getNode(ISD::XOR, DL, OVT, r1, r11);
// udiv r20, r0, r1
SDValue r20 = DAG.getNode(ISD::UREM, DL, OVT, r0, r1);
// umul r20, r20, r1
r20 = DAG.getNode(AMDGPUISD::UMUL, DL, OVT, r20, r1);
// sub r0, r0, r20
r0 = DAG.getNode(ISD::SUB, DL, OVT, r0, r20);
// iadd r0, r0, r10
r0 = DAG.getNode(ISD::ADD, DL, OVT, r0, r10);
// ixor DST, r0, r10
SDValue DST = DAG.getNode(ISD::XOR, DL, OVT, r0, r10);
return DST;
}
SDValue AMDGPUTargetLowering::LowerSREM64(SDValue Op, SelectionDAG &DAG) const {
return SDValue(Op.getNode(), 0);
}
SDValue AMDGPUTargetLowering::LowerSREM(SDValue Op, SelectionDAG &DAG) const {
EVT OVT = Op.getValueType();
if (OVT.getScalarType() == MVT::i64)
return LowerSREM64(Op, DAG);
if (OVT.getScalarType() == MVT::i32)
return LowerSREM32(Op, DAG);
return SDValue(Op.getNode(), 0);
}
SDValue AMDGPUTargetLowering::LowerUDIVREM(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);

View File

@ -42,6 +42,14 @@ private:
SDValue MergeVectorStore(const SDValue &Op, SelectionDAG &DAG) const;
/// \brief Split a vector store into multiple scalar stores.
/// \returns The resulting chain.
SDValue LowerSDIV(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSDIV24(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSDIV32(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSDIV64(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSREM(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSREM32(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSREM64(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerUDIVREM(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG) const;
@ -146,13 +154,6 @@ public:
private:
void InitAMDILLowering();
SDValue LowerSREM(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSREM32(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSREM64(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSDIV(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSDIV24(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSDIV32(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSDIV64(SDValue Op, SelectionDAG &DAG) const;
SDValue ExpandSIGN_EXTEND_INREG(SDValue Op,
unsigned BitsDiff,

View File

@ -138,274 +138,15 @@ AMDGPUTargetLowering::ShouldShrinkFPConstant(EVT VT) const {
}
}
// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to
// be zero. Op is expected to be a target specific node. Used by DAG
// combiner.
//===----------------------------------------------------------------------===//
// Other Lowering Hooks
//===----------------------------------------------------------------------===//
SDValue
AMDGPUTargetLowering::LowerSDIV(SDValue Op, SelectionDAG &DAG) const {
EVT OVT = Op.getValueType();
SDValue DST;
if (OVT.getScalarType() == MVT::i64) {
DST = LowerSDIV64(Op, DAG);
} else if (OVT.getScalarType() == MVT::i32) {
DST = LowerSDIV32(Op, DAG);
} else if (OVT.getScalarType() == MVT::i16
|| OVT.getScalarType() == MVT::i8) {
DST = LowerSDIV24(Op, DAG);
} else {
DST = SDValue(Op.getNode(), 0);
}
return DST;
}
SDValue
AMDGPUTargetLowering::LowerSREM(SDValue Op, SelectionDAG &DAG) const {
EVT OVT = Op.getValueType();
if (OVT.getScalarType() == MVT::i64)
return LowerSREM64(Op, DAG);
if (OVT.getScalarType() == MVT::i32)
return LowerSREM32(Op, DAG);
return SDValue(Op.getNode(), 0);
}
SDValue
AMDGPUTargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
SDValue AMDGPUTargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
SDValue Cond = Op.getOperand(1);
SDValue Jump = Op.getOperand(2);
SDValue Result;
Result = DAG.getNode(
AMDGPUISD::BRANCH_COND,
SDLoc(Op),
Op.getValueType(),
Chain, Jump, Cond);
return Result;
}
SDValue
AMDGPUTargetLowering::LowerSDIV24(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT OVT = Op.getValueType();
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
MVT INTTY;
MVT FLTTY;
if (!OVT.isVector()) {
INTTY = MVT::i32;
FLTTY = MVT::f32;
} else if (OVT.getVectorNumElements() == 2) {
INTTY = MVT::v2i32;
FLTTY = MVT::v2f32;
} else if (OVT.getVectorNumElements() == 4) {
INTTY = MVT::v4i32;
FLTTY = MVT::v4f32;
}
unsigned bitsize = OVT.getScalarType().getSizeInBits();
// char|short jq = ia ^ ib;
SDValue jq = DAG.getNode(ISD::XOR, DL, OVT, LHS, RHS);
// jq = jq >> (bitsize - 2)
jq = DAG.getNode(ISD::SRA, DL, OVT, jq, DAG.getConstant(bitsize - 2, OVT));
// jq = jq | 0x1
jq = DAG.getNode(ISD::OR, DL, OVT, jq, DAG.getConstant(1, OVT));
// jq = (int)jq
jq = DAG.getSExtOrTrunc(jq, DL, INTTY);
// int ia = (int)LHS;
SDValue ia = DAG.getSExtOrTrunc(LHS, DL, INTTY);
// int ib, (int)RHS;
SDValue ib = DAG.getSExtOrTrunc(RHS, DL, INTTY);
// float fa = (float)ia;
SDValue fa = DAG.getNode(ISD::SINT_TO_FP, DL, FLTTY, ia);
// float fb = (float)ib;
SDValue fb = DAG.getNode(ISD::SINT_TO_FP, DL, FLTTY, ib);
// float fq = native_divide(fa, fb);
SDValue fq = DAG.getNode(AMDGPUISD::DIV_INF, DL, FLTTY, fa, fb);
// fq = trunc(fq);
fq = DAG.getNode(ISD::FTRUNC, DL, FLTTY, fq);
// float fqneg = -fq;
SDValue fqneg = DAG.getNode(ISD::FNEG, DL, FLTTY, fq);
// float fr = mad(fqneg, fb, fa);
SDValue fr = DAG.getNode(ISD::FADD, DL, FLTTY,
DAG.getNode(ISD::MUL, DL, FLTTY, fqneg, fb), fa);
// int iq = (int)fq;
SDValue iq = DAG.getNode(ISD::FP_TO_SINT, DL, INTTY, fq);
// fr = fabs(fr);
fr = DAG.getNode(ISD::FABS, DL, FLTTY, fr);
// fb = fabs(fb);
fb = DAG.getNode(ISD::FABS, DL, FLTTY, fb);
// int cv = fr >= fb;
SDValue cv;
if (INTTY == MVT::i32) {
cv = DAG.getSetCC(DL, INTTY, fr, fb, ISD::SETOGE);
} else {
cv = DAG.getSetCC(DL, INTTY, fr, fb, ISD::SETOGE);
}
// jq = (cv ? jq : 0);
jq = DAG.getNode(ISD::SELECT, DL, OVT, cv, jq,
DAG.getConstant(0, OVT));
// dst = iq + jq;
iq = DAG.getSExtOrTrunc(iq, DL, OVT);
iq = DAG.getNode(ISD::ADD, DL, OVT, iq, jq);
return iq;
}
SDValue
AMDGPUTargetLowering::LowerSDIV32(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT OVT = Op.getValueType();
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
// The LowerSDIV32 function generates equivalent to the following IL.
// mov r0, LHS
// mov r1, RHS
// ilt r10, r0, 0
// ilt r11, r1, 0
// iadd r0, r0, r10
// iadd r1, r1, r11
// ixor r0, r0, r10
// ixor r1, r1, r11
// udiv r0, r0, r1
// ixor r10, r10, r11
// iadd r0, r0, r10
// ixor DST, r0, r10
// mov r0, LHS
SDValue r0 = LHS;
// mov r1, RHS
SDValue r1 = RHS;
// ilt r10, r0, 0
SDValue r10 = DAG.getSelectCC(DL,
r0, DAG.getConstant(0, OVT),
DAG.getConstant(-1, MVT::i32),
DAG.getConstant(0, MVT::i32),
ISD::SETLT);
// ilt r11, r1, 0
SDValue r11 = DAG.getSelectCC(DL,
r1, DAG.getConstant(0, OVT),
DAG.getConstant(-1, MVT::i32),
DAG.getConstant(0, MVT::i32),
ISD::SETLT);
// iadd r0, r0, r10
r0 = DAG.getNode(ISD::ADD, DL, OVT, r0, r10);
// iadd r1, r1, r11
r1 = DAG.getNode(ISD::ADD, DL, OVT, r1, r11);
// ixor r0, r0, r10
r0 = DAG.getNode(ISD::XOR, DL, OVT, r0, r10);
// ixor r1, r1, r11
r1 = DAG.getNode(ISD::XOR, DL, OVT, r1, r11);
// udiv r0, r0, r1
r0 = DAG.getNode(ISD::UDIV, DL, OVT, r0, r1);
// ixor r10, r10, r11
r10 = DAG.getNode(ISD::XOR, DL, OVT, r10, r11);
// iadd r0, r0, r10
r0 = DAG.getNode(ISD::ADD, DL, OVT, r0, r10);
// ixor DST, r0, r10
SDValue DST = DAG.getNode(ISD::XOR, DL, OVT, r0, r10);
return DST;
}
SDValue
AMDGPUTargetLowering::LowerSDIV64(SDValue Op, SelectionDAG &DAG) const {
return SDValue(Op.getNode(), 0);
}
SDValue
AMDGPUTargetLowering::LowerSREM32(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT OVT = Op.getValueType();
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
// The LowerSREM32 function generates equivalent to the following IL.
// mov r0, LHS
// mov r1, RHS
// ilt r10, r0, 0
// ilt r11, r1, 0
// iadd r0, r0, r10
// iadd r1, r1, r11
// ixor r0, r0, r10
// ixor r1, r1, r11
// udiv r20, r0, r1
// umul r20, r20, r1
// sub r0, r0, r20
// iadd r0, r0, r10
// ixor DST, r0, r10
// mov r0, LHS
SDValue r0 = LHS;
// mov r1, RHS
SDValue r1 = RHS;
// ilt r10, r0, 0
SDValue r10 = DAG.getSetCC(DL, OVT, r0, DAG.getConstant(0, OVT), ISD::SETLT);
// ilt r11, r1, 0
SDValue r11 = DAG.getSetCC(DL, OVT, r1, DAG.getConstant(0, OVT), ISD::SETLT);
// iadd r0, r0, r10
r0 = DAG.getNode(ISD::ADD, DL, OVT, r0, r10);
// iadd r1, r1, r11
r1 = DAG.getNode(ISD::ADD, DL, OVT, r1, r11);
// ixor r0, r0, r10
r0 = DAG.getNode(ISD::XOR, DL, OVT, r0, r10);
// ixor r1, r1, r11
r1 = DAG.getNode(ISD::XOR, DL, OVT, r1, r11);
// udiv r20, r0, r1
SDValue r20 = DAG.getNode(ISD::UREM, DL, OVT, r0, r1);
// umul r20, r20, r1
r20 = DAG.getNode(AMDGPUISD::UMUL, DL, OVT, r20, r1);
// sub r0, r0, r20
r0 = DAG.getNode(ISD::SUB, DL, OVT, r0, r20);
// iadd r0, r0, r10
r0 = DAG.getNode(ISD::ADD, DL, OVT, r0, r10);
// ixor DST, r0, r10
SDValue DST = DAG.getNode(ISD::XOR, DL, OVT, r0, r10);
return DST;
}
SDValue
AMDGPUTargetLowering::LowerSREM64(SDValue Op, SelectionDAG &DAG) const {
return SDValue(Op.getNode(), 0);
return DAG.getNode(AMDGPUISD::BRANCH_COND, SDLoc(Op), Op.getValueType(),
Chain, Jump, Cond);
}