RetVals.push_back(MVT::i32);
break;
}
- std::vector<SDOperand> Ops;
- Ops.push_back(Chain);
- Ops.push_back(Callee);
- Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
- Ops.push_back(DAG.getConstant(0, getPointerTy()));
- SDOperand TheCall = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
- RetVals, Ops);
- Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, TheCall);
- SDOperand ResultVal;
- switch (RetTyVT) {
- case MVT::isVoid: break;
- default:
- ResultVal = TheCall.getValue(1);
- break;
- case MVT::i1:
- case MVT::i8:
- case MVT::i16:
- ResultVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, TheCall.getValue(1));
- break;
- case MVT::f32:
- // FIXME: we would really like to remember that this FP_ROUND operation is
- // okay to eliminate if we allow excess FP precision.
- ResultVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, TheCall.getValue(1));
- break;
- case MVT::i64:
- ResultVal = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, TheCall.getValue(1),
- TheCall.getValue(2));
- break;
- }
+ if (X86DAGIsel) {
+ std::vector<MVT::ValueType> NodeTys;
+ NodeTys.push_back(MVT::Other); // Returns a chain
+ NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
- return std::make_pair(ResultVal, Chain);
+ std::vector<SDOperand> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+
+ Chain = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
+ NodeTys, Ops);
+ SDOperand InFlag = Chain.getValue(1);
+
+ SDOperand RetVal;
+ if (RetTyVT != MVT::isVoid) {
+ switch (RetTyVT) {
+ default: assert(0 && "Unknown value type to return!");
+ case MVT::i1:
+ case MVT::i8:
+ RetVal = DAG.getCopyFromReg(Chain, X86::AL, MVT::i8, InFlag);
+ Chain = RetVal.getValue(1);
+ break;
+ case MVT::i16:
+ RetVal = DAG.getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag);
+ Chain = RetVal.getValue(1);
+ break;
+ case MVT::i32:
+ RetVal = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag);
+ Chain = RetVal.getValue(1);
+ break;
+ case MVT::i64: {
+ SDOperand Lo = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag);
+ SDOperand Hi = DAG.getCopyFromReg(Lo.getValue(1), X86::EDX, MVT::i32,
+ Lo.getValue(2));
+ RetVal = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, Lo, Hi);
+ Chain = Hi.getValue(1);
+ break;
+ }
+ case MVT::f32:
+ case MVT::f64: {
+ std::vector<MVT::ValueType> Tys;
+ Tys.push_back(MVT::f64);
+ Tys.push_back(MVT::Other);
+ std::vector<SDOperand> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(InFlag);
+ RetVal = DAG.getNode(X86ISD::FP_GET_RESULT, Tys, Ops);
+ Chain = RetVal.getValue(1);
+ if (X86ScalarSSE) {
+ unsigned Size = MVT::getSizeInBits(MVT::f64)/8;
+ MachineFunction &MF = DAG.getMachineFunction();
+ int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size);
+ SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
+ Tys.clear();
+ Tys.push_back(MVT::Other);
+ Ops.clear();
+ Ops.push_back(Chain);
+ Ops.push_back(RetVal);
+ Ops.push_back(StackSlot);
+ Ops.push_back(DAG.getValueType(RetTyVT));
+ Chain = DAG.getNode(X86ISD::FST, Tys, Ops);
+ RetVal = DAG.getLoad(RetTyVT, Chain, StackSlot,
+ DAG.getSrcValue(NULL));
+ Chain = RetVal.getValue(1);
+ } else if (RetTyVT == MVT::f32)
+ RetVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, RetVal);
+ break;
+ }
+ }
+ }
+
+ Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
+ DAG.getConstant(NumBytes, getPointerTy()),
+ DAG.getConstant(0, getPointerTy()));
+ return std::make_pair(RetVal, Chain);
+ } else {
+ std::vector<SDOperand> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+ Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
+ Ops.push_back(DAG.getConstant(0, getPointerTy()));
+
+ SDOperand TheCall = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
+ RetVals, Ops);
+
+ SDOperand ResultVal;
+ switch (RetTyVT) {
+ case MVT::isVoid: break;
+ default:
+ ResultVal = TheCall.getValue(1);
+ break;
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ ResultVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, TheCall.getValue(1));
+ break;
+ case MVT::f32:
+ // FIXME: we would really like to remember that this FP_ROUND operation is
+ // okay to eliminate if we allow excess FP precision.
+ ResultVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, TheCall.getValue(1));
+ break;
+ case MVT::i64:
+ ResultVal = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, TheCall.getValue(1),
+ TheCall.getValue(2));
+ break;
+ }
+
+ Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, TheCall);
+ return std::make_pair(ResultVal, Chain);
+ }
}
SDOperand
case X86ISD::FP_TO_INT32_IN_MEM: return "X86ISD::FP_TO_INT32_IN_MEM";
case X86ISD::FP_TO_INT64_IN_MEM: return "X86ISD::FP_TO_INT64_IN_MEM";
case X86ISD::FLD: return "X86ISD::FLD";
+ case X86ISD::FST: return "X86ISD::FST";
+ case X86ISD::FP_GET_RESULT: return "X86ISD::FP_GET_RESULT";
case X86ISD::FP_SET_RESULT: return "X86ISD::FP_SET_RESULT";
case X86ISD::CALL: return "X86ISD::CALL";
case X86ISD::TAILCALL: return "X86ISD::TAILCALL";
def SDTX86Fld : SDTypeProfile<1, 2, [SDTCisVT<0, f64>,
SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>]>;
+def SDTX86Fst : SDTypeProfile<0, 3, [SDTCisFP<0>,
+ SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>]>;
+
+def SDTX86FpGet : SDTypeProfile<1, 0, [SDTCisVT<0, f64>]>;
def SDTX86FpSet : SDTypeProfile<0, 1, [SDTCisFP<0>]>;
def X86cmp : SDNode<"X86ISD::CMP" , SDTX86CmpTest, []>;
def X86retflag : SDNode<"X86ISD::RET_FLAG", SDTX86RetFlag, [SDNPHasChain]>;
def X86fld : SDNode<"X86ISD::FLD", SDTX86Fld, [SDNPHasChain]>;
+def X86fst : SDNode<"X86ISD::FST", SDTX86Fst, [SDNPHasChain]>;
+def X86fpget : SDNode<"X86ISD::FP_GET_RESULT",
+ SDTX86FpGet, [SDNPHasChain]>;
def X86fpset : SDNode<"X86ISD::FP_SET_RESULT",
SDTX86FpSet, [SDNPHasChain]>;
+def SDT_X86CallSeqStart : SDTypeProfile<0, 1, [ SDTCisVT<0, i32> ]>;
+def SDT_X86CallSeqEnd : SDTypeProfile<0, 2, [ SDTCisVT<0, i32>,
+ SDTCisVT<1, i32> ]>;
+def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_X86CallSeqStart,
+ [SDNPHasChain]>;
+def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_X86CallSeqEnd,
+ [SDNPHasChain]>;
+
+def SDT_X86Call : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
+def call : SDNode<"X86ISD::CALL", SDT_X86Call, [SDNPHasChain]>;
+
//===----------------------------------------------------------------------===//
// X86 Operand Definitions.
//
def PHI : I<0, Pseudo, (ops variable_ops), "PHINODE", []>; // PHI node.
def NOOP : I<0x90, RawFrm, (ops), "nop", []>; // nop
-def ADJCALLSTACKDOWN : I<0, Pseudo, (ops i32imm:$amt), "#ADJCALLSTACKDOWN", []>;
+def ADJCALLSTACKDOWN : I<0, Pseudo, (ops i32imm:$amt), "#ADJCALLSTACKDOWN",
+ [(callseq_start imm:$amt)]>;
def ADJCALLSTACKUP : I<0, Pseudo, (ops i32imm:$amt1, i32imm:$amt2),
- "#ADJCALLSTACKUP", []>;
+ "#ADJCALLSTACKUP",
+ [(callseq_end imm:$amt1, imm:$amt2)]>;
def IMPLICIT_USE : I<0, Pseudo, (ops variable_ops), "#IMPLICIT_USE", []>;
def IMPLICIT_DEF : I<0, Pseudo, (ops variable_ops), "#IMPLICIT_DEF", []>;
let isTerminator = 1 in
}
}
-def : Pat<(X86retflag 0), (RET)>;
-def : Pat<(X86retflag imm:$amt), (RETI imm:$amt)>;
-
// All branches are RawFrm, Void, Branch, and Terminators
let isBranch = 1, isTerminator = 1, noResults = 1 in
class IBr<bits<8> opcode, dag ops, string asm, list<dag> pattern> :
//===----------------------------------------------------------------------===//
// Call Instructions...
//
-let isCall = 1, noResults = 1 in
+// FIXME: How about hasInFlag = 1? A fastcall would require an incoming flag
+// to stick the CopyToRegs to the call.
+let isCall = 1, noResults = 1, hasOutFlag = 1 in
// All calls clobber the non-callee saved registers...
let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0,
XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7] in {
- def CALLpcrel32 : I<0xE8, RawFrm, (ops calltarget:$dst), "call $dst", []>;
- def CALL32r : I<0xFF, MRM2r, (ops R32:$dst), "call {*}$dst", []>;
- def CALL32m : I<0xFF, MRM2m, (ops i32mem:$dst), "call {*}$dst", []>;
+ def CALLpcrel32 : I<0xE8, RawFrm, (ops calltarget:$dst), "call $dst",
+ []>;
+ def CALL32r : I<0xFF, MRM2r, (ops R32:$dst), "call {*}$dst",
+ []>;
+ def CALL32m : I<0xFF, MRM2m, (ops i32mem:$dst), "call {*}$dst",
+ []>;
}
+def : Pat<(call tglobaladdr:$dst),
+ (CALLpcrel32 tglobaladdr:$dst)>;
+def : Pat<(call externalsym:$dst),
+ (CALLpcrel32 externalsym:$dst)>;
+
// Tail call stuff.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, noResults = 1 in
def TAILJMPd : IBr<0xE9, (ops calltarget:$dst), "jmp $dst # TAIL CALL", []>;
}
// Random Pseudo Instructions.
-def FpGETRESULT : FpI<(ops RFP:$dst), SpecialFP, []>; // FPR = ST(0)
+let hasInFlag = 1 in
+ def FpGETRESULT : FpI<(ops RFP:$dst), SpecialFP, []>; // FPR = ST(0)
+
+// Do not inline into instruction def. since it isn't predicated on FPStack.
+def : Pat<(X86fpget), (FpGETRESULT)>;
+
let noResults = 1, hasOutFlag = 1 in
def FpSETRESULT : FpI<(ops RFP:$src), SpecialFP,
[]>, Imp<[], [ST0]>; // ST(0) = FPR
+// Do not inline into instruction def. since it isn't predicated on FPStack.
def : Pat<(X86fpset RFP:$src), (FpSETRESULT RFP:$src)>;
def FpMOV : FpI<(ops RFP:$dst, RFP:$src), SpecialFP, []>; // f1 = fmov f2
[(set RFP:$dst, (fsub RFP:$src1, (loadf64 addr:$src2)))]>;
// ST(0) = ST(0) - [mem64]
def FpSUBR32m : FpI<(ops RFP:$dst, RFP:$src1, f32mem:$src2), OneArgFPRW,
- [(set RFP:$dst, (fadd (extloadf64f32 addr:$src2),
+ [(set RFP:$dst, (fsub (extloadf64f32 addr:$src2),
RFP:$src1))]>;
// ST(0) = [mem32] - ST(0)
def FpSUBR64m : FpI<(ops RFP:$dst, RFP:$src1, f32mem:$src2), OneArgFPRW,
[(truncstore RFP:$src, addr:$op, f32)]>;
def FpST64m : FpI<(ops f64mem:$op, RFP:$src), OneArgFP,
[(store RFP:$src, addr:$op)]>;
+
+def : Pat<(X86fst RFP:$src, addr:$op, f32), (FpST32m addr:$op, RFP:$src)>;
+def : Pat<(X86fst RFP:$src, addr:$op, f64), (FpST64m addr:$op, RFP:$src)>;
+
def FpSTP32m : FpI<(ops f32mem:$op, RFP:$src), OneArgFP, []>;
def FpSTP64m : FpI<(ops f64mem:$op, RFP:$src), OneArgFP, []>;
def FpIST16m : FpI<(ops i16mem:$op, RFP:$src), OneArgFP, []>;