Use a custom expander for all FP to int conversions, as the X86 only has

FP-to-int-in-memory: this exposes the load from the stored slot to the
selection dag, allowing it to be folded into other operaions.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22556 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2005-07-30 00:05:54 +00:00
parent f1fa74ee0d
commit 01546c5d50

View File

@ -59,6 +59,8 @@ namespace {
/// to the X86::FIST*m instructions and the rounding mode change stuff. It /// to the X86::FIST*m instructions and the rounding mode change stuff. It
/// has two inputs (token chain and address) and two outputs (FP value and /// has two inputs (token chain and address) and two outputs (FP value and
/// token chain). /// token chain).
FP_TO_INT16_IN_MEM,
FP_TO_INT32_IN_MEM,
FP_TO_INT64_IN_MEM, FP_TO_INT64_IN_MEM,
/// CALL/TAILCALL - These operations represent an abstract X86 call /// CALL/TAILCALL - These operations represent an abstract X86 call
@ -128,8 +130,10 @@ namespace {
if (!X86ScalarSSE) { if (!X86ScalarSSE) {
// We can handle SINT_TO_FP and FP_TO_SINT from/TO i64 even though i64 // We can handle SINT_TO_FP and FP_TO_SINT from/TO i64 even though i64
// isn't legal. // isn't legal.
setOperationAction(ISD::SINT_TO_FP , MVT::i64 , Custom); setOperationAction(ISD::SINT_TO_FP , MVT::i64 , Custom);
setOperationAction(ISD::FP_TO_SINT , MVT::i64 , Custom); setOperationAction(ISD::FP_TO_SINT , MVT::i64 , Custom);
setOperationAction(ISD::FP_TO_SINT , MVT::i32 , Custom);
setOperationAction(ISD::FP_TO_SINT , MVT::i16 , Custom);
} }
// Handle FP_TO_UINT by promoting the destination to a larger signed // Handle FP_TO_UINT by promoting the destination to a larger signed
@ -987,24 +991,34 @@ SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
return DAG.getNode(X86ISD::FILD64m, RTs, Ops); return DAG.getNode(X86ISD::FILD64m, RTs, Ops);
} }
case ISD::FP_TO_SINT: { case ISD::FP_TO_SINT: {
assert(Op.getValueType() == MVT::i64 && assert(Op.getValueType() <= MVT::i64 && Op.getValueType() >= MVT::i16 &&
Op.getOperand(0).getValueType() == MVT::f64 && Op.getOperand(0).getValueType() == MVT::f64 &&
"Unknown FP_TO_SINT to lower!"); "Unknown FP_TO_SINT to lower!");
// We lower FP->sint64 into FISTP64, followed by a load, all to a temporary // We lower FP->sint64 into FISTP64, followed by a load, all to a temporary
// stack slot. // stack slot.
MachineFunction &MF = DAG.getMachineFunction(); MachineFunction &MF = DAG.getMachineFunction();
int SSFI = MF.getFrameInfo()->CreateStackObject(8, 8); unsigned MemSize = MVT::getSizeInBits(Op.getValueType())/8;
int SSFI = MF.getFrameInfo()->CreateStackObject(MemSize, MemSize);
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy()); SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
// Build the FISTP64 unsigned Opc;
switch (Op.getValueType()) {
default: assert(0 && "Invalid FP_TO_SINT to lower!");
case MVT::i16: Opc = X86ISD::FP_TO_INT16_IN_MEM; break;
case MVT::i32: Opc = X86ISD::FP_TO_INT32_IN_MEM; break;
case MVT::i64: Opc = X86ISD::FP_TO_INT64_IN_MEM; break;
}
// Build the FP_TO_INT*_IN_MEM
std::vector<SDOperand> Ops; std::vector<SDOperand> Ops;
Ops.push_back(DAG.getEntryNode()); Ops.push_back(DAG.getEntryNode());
Ops.push_back(Op.getOperand(0)); Ops.push_back(Op.getOperand(0));
Ops.push_back(StackSlot); Ops.push_back(StackSlot);
SDOperand FIST = DAG.getNode(X86ISD::FP_TO_INT64_IN_MEM, MVT::Other, Ops); SDOperand FIST = DAG.getNode(Opc, MVT::Other, Ops);
// Load the result. // Load the result.
return DAG.getLoad(MVT::i64, FIST, StackSlot, DAG.getSrcValue(NULL)); return DAG.getLoad(Op.getValueType(), FIST, StackSlot,
DAG.getSrcValue(NULL));
} }
} }
} }
@ -2449,76 +2463,23 @@ unsigned ISel::SelectExpr(SDOperand N) {
} }
return Result; return Result;
} }
case ISD::FP_TO_SINT: { case ISD::FP_TO_SINT:
Tmp1 = SelectExpr(N.getOperand(0)); // Get the operand register Tmp1 = SelectExpr(N.getOperand(0)); // Get the operand register
// If the target supports SSE2 and is performing FP operations in SSE regs // If the target supports SSE2 and is performing FP operations in SSE regs
// instead of the FP stack, then we can use the efficient CVTSS2SI and // instead of the FP stack, then we can use the efficient CVTSS2SI and
// CVTSD2SI instructions. // CVTSD2SI instructions.
if (X86ScalarSSE) { assert(X86ScalarSSE);
if (MVT::f32 == N.getOperand(0).getValueType()) { if (MVT::f32 == N.getOperand(0).getValueType()) {
BuildMI(BB, X86::CVTTSS2SIrr, 1, Result).addReg(Tmp1); BuildMI(BB, X86::CVTTSS2SIrr, 1, Result).addReg(Tmp1);
} else if (MVT::f64 == N.getOperand(0).getValueType()) { } else if (MVT::f64 == N.getOperand(0).getValueType()) {
BuildMI(BB, X86::CVTTSD2SIrr, 1, Result).addReg(Tmp1); BuildMI(BB, X86::CVTTSD2SIrr, 1, Result).addReg(Tmp1);
} else { } else {
assert(0 && "Not an f32 or f64?"); assert(0 && "Not an f32 or f64?");
abort(); abort();
}
return Result;
} }
// Change the floating point control register to use "round towards zero"
// mode when truncating to an integer value.
//
MachineFunction *F = BB->getParent();
int CWFrameIdx = F->getFrameInfo()->CreateStackObject(2, 2);
addFrameReference(BuildMI(BB, X86::FNSTCW16m, 4), CWFrameIdx);
// Load the old value of the high byte of the control word...
unsigned HighPartOfCW = MakeReg(MVT::i8);
addFrameReference(BuildMI(BB, X86::MOV8rm, 4, HighPartOfCW),
CWFrameIdx, 1);
// Set the high part to be round to zero...
addFrameReference(BuildMI(BB, X86::MOV8mi, 5),
CWFrameIdx, 1).addImm(12);
// Reload the modified control word now...
addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx);
// Restore the memory image of control word to original value
addFrameReference(BuildMI(BB, X86::MOV8mr, 5),
CWFrameIdx, 1).addReg(HighPartOfCW);
// Spill the integer to memory and reload it from there.
unsigned Size = MVT::getSizeInBits(Node->getValueType(0))/8;
int FrameIdx = F->getFrameInfo()->CreateStackObject(Size, Size);
switch (Node->getValueType(0)) {
default: assert(0 && "Unsupported store class!");
case MVT::i16:
addFrameReference(BuildMI(BB, X86::FIST16m, 5), FrameIdx).addReg(Tmp1);
break;
case MVT::i32:
addFrameReference(BuildMI(BB, X86::FIST32m, 5), FrameIdx).addReg(Tmp1);
break;
}
switch (Node->getValueType(0)) {
default:
assert(0 && "Unknown integer type!");
case MVT::i32:
addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Result), FrameIdx);
break;
case MVT::i16:
addFrameReference(BuildMI(BB, X86::MOV16rm, 4, Result), FrameIdx);
break;
}
// Reload the original control word now.
addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx);
return Result; return Result;
}
case ISD::ADD: case ISD::ADD:
Op0 = N.getOperand(0); Op0 = N.getOperand(0);
Op1 = N.getOperand(1); Op1 = N.getOperand(1);
@ -4347,6 +4308,8 @@ void ISel::Select(SDOperand N) {
SelectExpr(N.getValue(0)); SelectExpr(N.getValue(0));
return; return;
case X86ISD::FP_TO_INT16_IN_MEM:
case X86ISD::FP_TO_INT32_IN_MEM:
case X86ISD::FP_TO_INT64_IN_MEM: { case X86ISD::FP_TO_INT64_IN_MEM: {
assert(N.getOperand(1).getValueType() == MVT::f64); assert(N.getOperand(1).getValueType() == MVT::f64);
X86AddressMode AM; X86AddressMode AM;
@ -4383,8 +4346,15 @@ void ISel::Select(SDOperand N) {
// Restore the memory image of control word to original value // Restore the memory image of control word to original value
addFrameReference(BuildMI(BB, X86::MOV8mr, 5), addFrameReference(BuildMI(BB, X86::MOV8mr, 5),
CWFrameIdx, 1).addReg(HighPartOfCW); CWFrameIdx, 1).addReg(HighPartOfCW);
// Get the X86 opcode to use.
switch (N.getOpcode()) {
case X86ISD::FP_TO_INT16_IN_MEM: Tmp1 = X86::FIST16m; break;
case X86ISD::FP_TO_INT32_IN_MEM: Tmp1 = X86::FIST32m; break;
case X86ISD::FP_TO_INT64_IN_MEM: Tmp1 = X86::FISTP64m; break;
}
addFullAddress(BuildMI(BB, X86::FISTP64m, 5), AM).addReg(ValReg); addFullAddress(BuildMI(BB, Tmp1, 5), AM).addReg(ValReg);
// Reload the original control word now. // Reload the original control word now.
addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx); addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx);