X86TargetLowering::X86TargetLowering(TargetMachine &TM)
: TargetLowering(TM) {
-
// Set up the TargetLowering object.
// X86 is weird, it always uses i8 for shift amounts and setcc results.
setShiftAmountFlavor(Mask); // shl X, 32 == shl X, 0
// Set up the register classes.
- // FIXME: Eliminate these two classes when legalize can handle promotions
- // well.
- addRegisterClass(MVT::i1, X86::R8RegisterClass);
addRegisterClass(MVT::i8, X86::R8RegisterClass);
addRegisterClass(MVT::i16, X86::R16RegisterClass);
addRegisterClass(MVT::i32, X86::R32RegisterClass);
setOperationAction(ISD::FP_TO_SINT , MVT::i8 , Promote);
setOperationAction(ISD::FP_TO_SINT , MVT::i16 , Promote);
+ setOperationAction(ISD::BIT_CONVERT, MVT::f32, Expand);
+ setOperationAction(ISD::BIT_CONVERT, MVT::i32, Expand);
+
+ if (X86DAGIsel) {
+ setOperationAction(ISD::BRCOND , MVT::Other, Custom);
+ }
setOperationAction(ISD::BRCONDTWOWAY , MVT::Other, Expand);
setOperationAction(ISD::BRTWOWAY_CC , MVT::Other, Expand);
setOperationAction(ISD::MEMMOVE , MVT::Other, Expand);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16 , Expand);
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
setOperationAction(ISD::FP_ROUND_INREG , MVT::f32 , Expand);
setOperationAction(ISD::SEXTLOAD , MVT::i1 , Expand);
// These should be promoted to a larger select which is supported.
setOperationAction(ISD::SELECT , MVT::i1 , Promote);
setOperationAction(ISD::SELECT , MVT::i8 , Promote);
+ // X86 wants to expand cmov itself.
+ if (X86DAGIsel) {
+ setOperationAction(ISD::SELECT , MVT::i16 , Custom);
+ setOperationAction(ISD::SELECT , MVT::i32 , Custom);
+ setOperationAction(ISD::SETCC , MVT::i8 , Custom);
+ setOperationAction(ISD::SETCC , MVT::i16 , Custom);
+ setOperationAction(ISD::SETCC , MVT::i32 , Custom);
+ setOperationAction(ISD::GlobalAddress , MVT::i32 , Custom);
+ }
+
+ // We don't have line number support yet.
+ setOperationAction(ISD::LOCATION, MVT::Other, Expand);
+ setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
if (X86ScalarSSE) {
// Set up the FP register classes.
return LowerCCCCallTo(Chain, RetTy, isVarArg, isTailCall, Callee, Args, DAG);
}
+SDOperand X86TargetLowering::LowerReturnTo(SDOperand Chain, SDOperand Op,
+ SelectionDAG &DAG) {
+ if (!X86DAGIsel)
+ return DAG.getNode(ISD::RET, MVT::Other, Chain, Op);
+
+ SDOperand Copy;
+ MVT::ValueType OpVT = Op.getValueType();
+ switch (OpVT) {
+ default: assert(0 && "Unknown type to return!");
+ case MVT::i32:
+ Copy = DAG.getCopyToReg(Chain, X86::EAX, Op, SDOperand());
+ break;
+ case MVT::i64: {
+ SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Op,
+ DAG.getConstant(1, MVT::i32));
+ SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Op,
+ DAG.getConstant(0, MVT::i32));
+ Copy = DAG.getCopyToReg(Chain, X86::EAX, Hi, SDOperand());
+ Copy = DAG.getCopyToReg(Copy, X86::EDX, Lo, Copy.getValue(1));
+ break;
+ }
+ case MVT::f32:
+ case MVT::f64:
+ if (!X86ScalarSSE) {
+ std::vector<MVT::ValueType> Tys;
+ Tys.push_back(MVT::Other);
+ Tys.push_back(MVT::Flag);
+ std::vector<SDOperand> Ops;
+ Ops.push_back(Chain);
+ if (OpVT == MVT::f32)
+ Op = DAG.getNode(ISD::FP_EXTEND, MVT::f64, Op);
+ Ops.push_back(Op);
+ Copy = DAG.getNode(X86ISD::FP_SET_RESULT, Tys, Ops);
+ } else {
+ // Spill the value to memory and reload it into top of stack.
+ unsigned Size = MVT::getSizeInBits(OpVT)/8;
+ MachineFunction &MF = DAG.getMachineFunction();
+ int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size);
+ SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
+ Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Op,
+ StackSlot, DAG.getSrcValue(NULL));
+ 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(StackSlot);
+ Ops.push_back(DAG.getValueType(OpVT));
+ Copy = DAG.getNode(X86ISD::FLD, Tys, Ops);
+ Tys.clear();
+ Tys.push_back(MVT::Other);
+ Tys.push_back(MVT::Flag);
+ Ops.clear();
+ Ops.push_back(Copy.getValue(1));
+ Ops.push_back(Copy);
+ Copy = DAG.getNode(X86ISD::FP_SET_RESULT, Tys, Ops);
+ }
+ break;
+ }
+
+ return DAG.getNode(X86ISD::RET_FLAG, MVT::Other,
+ Copy, DAG.getConstant(getBytesToPopOnReturn(), MVT::i16),
+ Copy.getValue(1));
+}
+
//===----------------------------------------------------------------------===//
// C Calling Convention implementation
//===----------------------------------------------------------------------===//
Tys.push_back(MVT::Other);
return DAG.getNode(ISD::MERGE_VALUES, Tys, Ops);
}
+ case ISD::SETCC: {
+ assert(Op.getValueType() == MVT::i8 && "SetCC type must be 8-bit integer");
+ SDOperand CC = Op.getOperand(2);
+ SDOperand Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
+ Op.getOperand(0), Op.getOperand(1));
+ return DAG.getNode(X86ISD::SETCC, MVT::i8, CC, Cond);
}
+ case ISD::SELECT: {
+ SDOperand Cond = Op.getOperand(0);
+ SDOperand CC;
+ if (Cond.getOpcode() == X86ISD::SETCC) {
+ CC = Cond.getOperand(0);
+ Cond = Cond.getOperand(1);
+ } else if (Cond.getOpcode() == ISD::SETCC) {
+ CC = Cond.getOperand(2);
+ Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
+ Cond.getOperand(0), Cond.getOperand(1));
+ } else {
+ CC = DAG.getCondCode(ISD::SETEQ);
+ Cond = DAG.getNode(X86ISD::TEST, MVT::Flag, Cond, Cond);
+ }
+ return DAG.getNode(X86ISD::CMOV, Op.getValueType(),
+ Op.getOperand(1), Op.getOperand(2), CC, Cond);
+ }
+ case ISD::BRCOND: {
+ SDOperand Cond = Op.getOperand(1);
+ SDOperand Dest = Op.getOperand(2);
+ SDOperand CC;
+ // TODO: handle Cond == OR / AND / XOR
+ if (Cond.getOpcode() == X86ISD::SETCC) {
+ CC = Cond.getOperand(0);
+ Cond = Cond.getOperand(1);
+ } else if (Cond.getOpcode() == ISD::SETCC) {
+ CC = Cond.getOperand(2);
+ Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
+ Cond.getOperand(0), Cond.getOperand(1));
+ } else {
+ CC = DAG.getCondCode(ISD::SETNE);
+ Cond = DAG.getNode(X86ISD::TEST, MVT::Flag, Cond, Cond);
+ }
+ return DAG.getNode(X86ISD::BRCOND, Op.getValueType(),
+ Op.getOperand(0), Op.getOperand(2), CC, Cond);
+ }
+ case ISD::GlobalAddress: {
+ GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
+ SDOperand GVOp = DAG.getTargetGlobalAddress(GV, getPointerTy());
+ // For Darwin, external and weak symbols are indirect, so we want to load
+ // the value at address GV, not the value of GV itself. This means that
+ // the GlobalAddress must be in the base or index register of the address,
+ // not the GV offset field.
+ if (getTargetMachine().
+ getSubtarget<X86Subtarget>().getIndirectExternAndWeakGlobals() &&
+ (GV->hasWeakLinkage() || GV->isExternal()))
+ return DAG.getLoad(MVT::i32, DAG.getEntryNode(),
+ GVOp, DAG.getSrcValue(NULL));
+ else
+ return GVOp;
+ break;
+ }
+ }
+}
+
+const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
+ switch (Opcode) {
+ default: return NULL;
+ case X86ISD::FILD64m: return "X86ISD::FILD64m";
+ case X86ISD::FP_TO_INT16_IN_MEM: return "X86ISD::FP_TO_INT16_IN_MEM";
+ 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::FP_SET_RESULT: return "X86ISD::FP_SET_RESULT";
+ case X86ISD::CALL: return "X86ISD::CALL";
+ case X86ISD::TAILCALL: return "X86ISD::TAILCALL";
+ case X86ISD::RDTSC_DAG: return "X86ISD::RDTSC_DAG";
+ case X86ISD::CMP: return "X86ISD::CMP";
+ case X86ISD::TEST: return "X86ISD::TEST";
+ case X86ISD::SETCC: return "X86ISD::SETCC";
+ case X86ISD::CMOV: return "X86ISD::CMOV";
+ case X86ISD::BRCOND: return "X86ISD::BRCOND";
+ case X86ISD::RET_FLAG: return "X86ISD::RET_FLAG";
+ }
+}
+
+bool X86TargetLowering::isMaskedValueZeroForTargetNode(const SDOperand &Op,
+ uint64_t Mask) const {
+
+ unsigned Opc = Op.getOpcode();
+
+ switch (Opc) {
+ default:
+ assert(Opc >= ISD::BUILTIN_OP_END && "Expected a target specific node");
+ break;
+ case X86ISD::SETCC: return (Mask & 1) == 0;
+ }
+
+ return false;
}