Newer
Older
Ops.push_back(StackSlot);
Ops.push_back(DAG.getValueType(SrcVT));
Result = DAG.getNode(X86ScalarSSE ? X86ISD::FILD_FLAG :X86ISD::FILD,
Tys, &Ops[0], Ops.size());
if (X86ScalarSSE) {
Chain = Result.getValue(1);
SDOperand InFlag = Result.getValue(2);
// FIXME: Currently the FST is flagged to the FILD_FLAG. This
// shouldn't be necessary except that RFP cannot be live across
// multiple blocks. When stackifier is fixed, they can be uncoupled.
MachineFunction &MF = DAG.getMachineFunction();
int SSFI = MF.getFrameInfo()->CreateStackObject(8, 8);
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
Tys.push_back(MVT::Other);
std::vector<SDOperand> Ops;
Ops.push_back(Result);
Ops.push_back(StackSlot);
Ops.push_back(DAG.getValueType(Op.getValueType()));
Ops.push_back(InFlag);
Chain = DAG.getNode(X86ISD::FST, Tys, &Ops[0], Ops.size());
Result = DAG.getLoad(Op.getValueType(), Chain, StackSlot,
DAG.getSrcValue(NULL));
}
return Result;
}
SDOperand X86TargetLowering::LowerFP_TO_SINT(SDOperand Op, SelectionDAG &DAG) {
assert(Op.getValueType() <= MVT::i64 && Op.getValueType() >= MVT::i16 &&
"Unknown FP_TO_SINT to lower!");
// We lower FP->sint64 into FISTP64, followed by a load, all to a temporary
// stack slot.
MachineFunction &MF = DAG.getMachineFunction();
unsigned MemSize = MVT::getSizeInBits(Op.getValueType())/8;
int SSFI = MF.getFrameInfo()->CreateStackObject(MemSize, MemSize);
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
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;
}
SDOperand Chain = DAG.getEntryNode();
SDOperand Value = Op.getOperand(0);
if (X86ScalarSSE) {
assert(Op.getValueType() == MVT::i64 && "Invalid FP_TO_SINT to lower!");
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value, StackSlot,
DAG.getSrcValue(0));
Chris Lattner
committed
std::vector<MVT::ValueType> Tys;
Tys.push_back(MVT::f64);
Chris Lattner
committed
Tys.push_back(MVT::Other);
std::vector<SDOperand> Ops;
Ops.push_back(Chain);
Ops.push_back(StackSlot);
Ops.push_back(DAG.getValueType(Op.getOperand(0).getValueType()));
Value = DAG.getNode(X86ISD::FLD, Tys, &Ops[0], Ops.size());
Chain = Value.getValue(1);
SSFI = MF.getFrameInfo()->CreateStackObject(MemSize, MemSize);
StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
// Build the FP_TO_INT*_IN_MEM
std::vector<SDOperand> Ops;
Ops.push_back(Chain);
Ops.push_back(Value);
Ops.push_back(StackSlot);
Evan Cheng
committed
SDOperand FIST = DAG.getNode(Opc, MVT::Other, &Ops[0], Ops.size());
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
// Load the result.
return DAG.getLoad(Op.getValueType(), FIST, StackSlot,
DAG.getSrcValue(NULL));
}
SDOperand X86TargetLowering::LowerFABS(SDOperand Op, SelectionDAG &DAG) {
MVT::ValueType VT = Op.getValueType();
const Type *OpNTy = MVT::getTypeForValueType(VT);
std::vector<Constant*> CV;
if (VT == MVT::f64) {
CV.push_back(ConstantFP::get(OpNTy, BitsToDouble(~(1ULL << 63))));
CV.push_back(ConstantFP::get(OpNTy, 0.0));
} else {
CV.push_back(ConstantFP::get(OpNTy, BitsToFloat(~(1U << 31))));
CV.push_back(ConstantFP::get(OpNTy, 0.0));
CV.push_back(ConstantFP::get(OpNTy, 0.0));
CV.push_back(ConstantFP::get(OpNTy, 0.0));
}
Constant *CS = ConstantStruct::get(CV);
SDOperand CPIdx = DAG.getConstantPool(CS, getPointerTy(), 4);
std::vector<MVT::ValueType> Tys;
Tys.push_back(VT);
Tys.push_back(MVT::Other);
SmallVector<SDOperand, 3> Ops;
Ops.push_back(DAG.getEntryNode());
Ops.push_back(CPIdx);
Ops.push_back(DAG.getSrcValue(NULL));
SDOperand Mask = DAG.getNode(X86ISD::LOAD_PACK, Tys, &Ops[0], Ops.size());
return DAG.getNode(X86ISD::FAND, VT, Op.getOperand(0), Mask);
}
SDOperand X86TargetLowering::LowerFNEG(SDOperand Op, SelectionDAG &DAG) {
MVT::ValueType VT = Op.getValueType();
const Type *OpNTy = MVT::getTypeForValueType(VT);
std::vector<Constant*> CV;
if (VT == MVT::f64) {
CV.push_back(ConstantFP::get(OpNTy, BitsToDouble(1ULL << 63)));
CV.push_back(ConstantFP::get(OpNTy, 0.0));
} else {
CV.push_back(ConstantFP::get(OpNTy, BitsToFloat(1U << 31)));
CV.push_back(ConstantFP::get(OpNTy, 0.0));
CV.push_back(ConstantFP::get(OpNTy, 0.0));
CV.push_back(ConstantFP::get(OpNTy, 0.0));
}
Constant *CS = ConstantStruct::get(CV);
SDOperand CPIdx = DAG.getConstantPool(CS, getPointerTy(), 4);
std::vector<MVT::ValueType> Tys;
Tys.push_back(VT);
Tys.push_back(MVT::Other);
SmallVector<SDOperand, 3> Ops;
Ops.push_back(DAG.getEntryNode());
Ops.push_back(CPIdx);
Ops.push_back(DAG.getSrcValue(NULL));
SDOperand Mask = DAG.getNode(X86ISD::LOAD_PACK, Tys, &Ops[0], Ops.size());
return DAG.getNode(X86ISD::FXOR, VT, Op.getOperand(0), Mask);
}
SDOperand X86TargetLowering::LowerSETCC(SDOperand Op, SelectionDAG &DAG,
SDOperand Chain) {
assert(Op.getValueType() == MVT::i8 && "SetCC type must be 8-bit integer");
SDOperand Cond;
SDOperand Op0 = Op.getOperand(0);
SDOperand Op1 = Op.getOperand(1);
SDOperand CC = Op.getOperand(2);
ISD::CondCode SetCCOpcode = cast<CondCodeSDNode>(CC)->get();
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
bool isFP = MVT::isFloatingPoint(Op.getOperand(1).getValueType());
unsigned X86CC;
VTs = DAG.getNodeValueTypes(MVT::i8, MVT::Flag);
if (translateX86CC(cast<CondCodeSDNode>(CC)->get(), isFP, X86CC,
Op0, Op1, DAG)) {
SDOperand Ops1[] = { Chain, Op0, Op1 };
Cond = DAG.getNode(X86ISD::CMP, VTs, 2, Ops1, 3).getValue(1);
SDOperand Ops2[] = { DAG.getConstant(X86CC, MVT::i8), Cond };
return DAG.getNode(X86ISD::SETCC, VTs, 2, Ops2, 2);
}
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
assert(isFP && "Illegal integer SetCC!");
SDOperand COps[] = { Chain, Op0, Op1 };
Cond = DAG.getNode(X86ISD::CMP, VTs, 2, COps, 3).getValue(1);
switch (SetCCOpcode) {
default: assert(false && "Illegal floating point SetCC!");
case ISD::SETOEQ: { // !PF & ZF
SDOperand Ops1[] = { DAG.getConstant(X86ISD::COND_NP, MVT::i8), Cond };
SDOperand Tmp1 = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops1, 2);
SDOperand Ops2[] = { DAG.getConstant(X86ISD::COND_E, MVT::i8),
Tmp1.getValue(1) };
SDOperand Tmp2 = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops2, 2);
return DAG.getNode(ISD::AND, MVT::i8, Tmp1, Tmp2);
}
case ISD::SETUNE: { // PF | !ZF
SDOperand Ops1[] = { DAG.getConstant(X86ISD::COND_P, MVT::i8), Cond };
SDOperand Tmp1 = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops1, 2);
SDOperand Ops2[] = { DAG.getConstant(X86ISD::COND_NE, MVT::i8),
Tmp1.getValue(1) };
SDOperand Tmp2 = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops2, 2);
return DAG.getNode(ISD::OR, MVT::i8, Tmp1, Tmp2);
}
}
SDOperand X86TargetLowering::LowerSELECT(SDOperand Op, SelectionDAG &DAG) {
bool addTest = true;
SDOperand Chain = DAG.getEntryNode();
SDOperand Cond = Op.getOperand(0);
SDOperand CC;
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
if (Cond.getOpcode() == ISD::SETCC)
Cond = LowerSETCC(Cond, DAG, Chain);
if (Cond.getOpcode() == X86ISD::SETCC) {
CC = Cond.getOperand(0);
// If condition flag is set by a X86ISD::CMP, then make a copy of it
// (since flag operand cannot be shared). Use it as the condition setting
// operand in place of the X86ISD::SETCC.
// If the X86ISD::SETCC has more than one use, then perhaps it's better
// to use a test instead of duplicating the X86ISD::CMP (for register
// pressure reason)?
SDOperand Cmp = Cond.getOperand(1);
unsigned Opc = Cmp.getOpcode();
bool IllegalFPCMov = !X86ScalarSSE &&
MVT::isFloatingPoint(Op.getValueType()) &&
!hasFPCMov(cast<ConstantSDNode>(CC)->getSignExtended());
if ((Opc == X86ISD::CMP || Opc == X86ISD::COMI || Opc == X86ISD::UCOMI) &&
!IllegalFPCMov) {
SDOperand Ops[] = { Chain, Cmp.getOperand(1), Cmp.getOperand(2) };
Cond = DAG.getNode(Opc, VTs, 2, Ops, 3);
addTest = false;
}
}
if (addTest) {
CC = DAG.getConstant(X86ISD::COND_NE, MVT::i8);
SDOperand Ops[] = { Chain, Cond, DAG.getConstant(0, MVT::i8) };
Cond = DAG.getNode(X86ISD::CMP, VTs, 2, Ops, 3);
VTs = DAG.getNodeValueTypes(Op.getValueType(), MVT::Flag);
SmallVector<SDOperand, 4> Ops;
// X86ISD::CMOV means set the result (which is operand 1) to the RHS if
// condition is true.
Ops.push_back(Op.getOperand(2));
Ops.push_back(Op.getOperand(1));
Ops.push_back(CC);
Ops.push_back(Cond.getValue(1));
return DAG.getNode(X86ISD::CMOV, VTs, 2, &Ops[0], Ops.size());
SDOperand X86TargetLowering::LowerBRCOND(SDOperand Op, SelectionDAG &DAG) {
bool addTest = true;
SDOperand Chain = Op.getOperand(0);
SDOperand Cond = Op.getOperand(1);
SDOperand Dest = Op.getOperand(2);
SDOperand CC;
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
if (Cond.getOpcode() == ISD::SETCC)
Cond = LowerSETCC(Cond, DAG, Chain);
if (Cond.getOpcode() == X86ISD::SETCC) {
CC = Cond.getOperand(0);
// If condition flag is set by a X86ISD::CMP, then make a copy of it
// (since flag operand cannot be shared). Use it as the condition setting
// operand in place of the X86ISD::SETCC.
// If the X86ISD::SETCC has more than one use, then perhaps it's better
// to use a test instead of duplicating the X86ISD::CMP (for register
// pressure reason)?
SDOperand Cmp = Cond.getOperand(1);
unsigned Opc = Cmp.getOpcode();
if (Opc == X86ISD::CMP || Opc == X86ISD::COMI || Opc == X86ISD::UCOMI) {
SDOperand Ops[] = { Chain, Cmp.getOperand(1), Cmp.getOperand(2) };
Cond = DAG.getNode(Opc, VTs, 2, Ops, 3);
addTest = false;
}
}
if (addTest) {
CC = DAG.getConstant(X86ISD::COND_NE, MVT::i8);
SDOperand Ops[] = { Chain, Cond, DAG.getConstant(0, MVT::i8) };
Cond = DAG.getNode(X86ISD::CMP, VTs, 2, Ops, 3);
}
return DAG.getNode(X86ISD::BRCOND, Op.getValueType(),
Cond, Op.getOperand(2), CC, Cond.getValue(1));
SDOperand X86TargetLowering::LowerJumpTable(SDOperand Op, SelectionDAG &DAG) {
JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
SDOperand Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(),
DAG.getTargetJumpTable(JT->getIndex(),
getPointerTy()));
if (Subtarget->isTargetDarwin()) {
// With PIC, the address is actually $g + Offset.
if (!Subtarget->is64Bit() &&
getTargetMachine().getRelocationModel() == Reloc::PIC_)
Result = DAG.getNode(ISD::ADD, getPointerTy(),
DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()),
Result);
return Result;
}
SDOperand X86TargetLowering::LowerCALL(SDOperand Op, SelectionDAG &DAG) {
unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue();
if (Subtarget->is64Bit())
return LowerX86_64CCCCallTo(Op, DAG);
else
switch (CallingConv) {
default:
assert(0 && "Unsupported calling convention");
case CallingConv::Fast:
if (EnableFastCC) {
return LowerFastCCCallTo(Op, DAG, false);
}
// Falls through
case CallingConv::C:
case CallingConv::CSRet:
return LowerCCCCallTo(Op, DAG);
return LowerStdCallCCCallTo(Op, DAG);
return LowerFastCCCallTo(Op, DAG, true);
}
}
SDOperand X86TargetLowering::LowerRET(SDOperand Op, SelectionDAG &DAG) {
SDOperand Copy;
switch(Op.getNumOperands()) {
default:
assert(0 && "Do not know how to return this many arguments!");
abort();
case 1: // ret void.
return DAG.getNode(X86ISD::RET_FLAG, MVT::Other, Op.getOperand(0),
DAG.getConstant(getBytesToPopOnReturn(), MVT::i16));
case 3: {
MVT::ValueType ArgVT = Op.getOperand(1).getValueType();
if (MVT::isVector(ArgVT) ||
(Subtarget->is64Bit() && MVT::isFloatingPoint(ArgVT))) {
// Integer or FP vector result -> XMM0.
if (DAG.getMachineFunction().liveout_empty())
DAG.getMachineFunction().addLiveOut(X86::XMM0);
Copy = DAG.getCopyToReg(Op.getOperand(0), X86::XMM0, Op.getOperand(1),
SDOperand());
} else if (MVT::isInteger(ArgVT)) {
// Integer result -> EAX / RAX.
// The C calling convention guarantees the return value has been
// promoted to at least MVT::i32. The X86-64 ABI doesn't require the
// value to be promoted MVT::i64. So we don't have to extend it to
// 64-bit. Return the value in EAX, but mark RAX as liveout.
unsigned Reg = Subtarget->is64Bit() ? X86::RAX : X86::EAX;
if (DAG.getMachineFunction().liveout_empty())
Reg = (ArgVT == MVT::i64) ? X86::RAX : X86::EAX;
Copy = DAG.getCopyToReg(Op.getOperand(0), Reg, Op.getOperand(1),
SDOperand());
} else if (!X86ScalarSSE) {
// FP return with fp-stack value.
if (DAG.getMachineFunction().liveout_empty())
DAG.getMachineFunction().addLiveOut(X86::ST0);
std::vector<MVT::ValueType> Tys;
Tys.push_back(MVT::Other);
Tys.push_back(MVT::Flag);
std::vector<SDOperand> Ops;
Ops.push_back(Op.getOperand(0));
Ops.push_back(Op.getOperand(1));
Evan Cheng
committed
Copy = DAG.getNode(X86ISD::FP_SET_RESULT, Tys, &Ops[0], Ops.size());
} else {
// FP return with ScalarSSE (return on fp-stack).
if (DAG.getMachineFunction().liveout_empty())
DAG.getMachineFunction().addLiveOut(X86::ST0);
SDOperand MemLoc;
SDOperand Chain = Op.getOperand(0);
SDOperand Value = Op.getOperand(1);
if (Value.getOpcode() == ISD::LOAD &&
(Chain == Value.getValue(1) || Chain == Value.getOperand(0))) {
Chain = Value.getOperand(0);
MemLoc = Value.getOperand(1);
} else {
// Spill the value to memory and reload it into top of stack.
unsigned Size = MVT::getSizeInBits(ArgVT)/8;
MachineFunction &MF = DAG.getMachineFunction();
int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size);
MemLoc = DAG.getFrameIndex(SSFI, getPointerTy());
Chain = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
Value, MemLoc, DAG.getSrcValue(0));
}
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(MemLoc);
Ops.push_back(DAG.getValueType(ArgVT));
Evan Cheng
committed
Copy = DAG.getNode(X86ISD::FLD, Tys, &Ops[0], Ops.size());
Tys.clear();
Tys.push_back(MVT::Other);
Tys.push_back(MVT::Flag);
Ops.clear();
Ops.push_back(Copy.getValue(1));
Ops.push_back(Copy);
Evan Cheng
committed
Copy = DAG.getNode(X86ISD::FP_SET_RESULT, Tys, &Ops[0], Ops.size());
}
break;
}
case 5: {
unsigned Reg1 = Subtarget->is64Bit() ? X86::RAX : X86::EAX;
unsigned Reg2 = Subtarget->is64Bit() ? X86::RDX : X86::EDX;
if (DAG.getMachineFunction().liveout_empty()) {
DAG.getMachineFunction().addLiveOut(Reg1);
DAG.getMachineFunction().addLiveOut(Reg2);
}
Copy = DAG.getCopyToReg(Op.getOperand(0), Reg2, Op.getOperand(3),
SDOperand());
Copy = DAG.getCopyToReg(Copy, Reg1, Op.getOperand(1), Copy.getValue(1));
break;
}
return DAG.getNode(X86ISD::RET_FLAG, MVT::Other,
Copy, DAG.getConstant(getBytesToPopOnReturn(), MVT::i16),
Copy.getValue(1));
}
SDOperand
X86TargetLowering::LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG) {
MachineFunction &MF = DAG.getMachineFunction();
const Function* Fn = MF.getFunction();
if (Fn->hasExternalLinkage() &&
Subtarget->isTargetCygwin() &&
MF.getInfo<X86FunctionInfo>()->setForceFramePointer(true);
unsigned CC = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
if (Subtarget->is64Bit())
return LowerX86_64CCCArguments(Op, DAG);
switch(CC) {
default:
assert(0 && "Unsupported calling convention");
case CallingConv::Fast:
if (EnableFastCC) {
return LowerFastCCArguments(Op, DAG);
}
// Falls through
case CallingConv::C:
case CallingConv::CSRet:
return LowerCCCArguments(Op, DAG);
MF.getInfo<X86FunctionInfo>()->setDecorationStyle(StdCall);
return LowerStdCallCCArguments(Op, DAG);
MF.getInfo<X86FunctionInfo>()->setDecorationStyle(FastCall);
return LowerFastCallCCArguments(Op, DAG);
}
SDOperand X86TargetLowering::LowerMEMSET(SDOperand Op, SelectionDAG &DAG) {
SDOperand InFlag(0, 0);
SDOperand Chain = Op.getOperand(0);
unsigned Align =
(unsigned)cast<ConstantSDNode>(Op.getOperand(4))->getValue();
if (Align == 0) Align = 1;
ConstantSDNode *I = dyn_cast<ConstantSDNode>(Op.getOperand(3));
// If not DWORD aligned, call memset if size is less than the threshold.
// It knows how to align to the right boundary first.
if ((Align & 3) != 0 ||
(I && I->getValue() < Subtarget->getMinRepStrSizeThreshold())) {
MVT::ValueType IntPtr = getPointerTy();
const Type *IntPtrTy = getTargetData()->getIntPtrType();
std::vector<std::pair<SDOperand, const Type*> > Args;
Args.push_back(std::make_pair(Op.getOperand(1), IntPtrTy));
// Extend the ubyte argument to be an int value for the call.
SDOperand Val = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, Op.getOperand(2));
Args.push_back(std::make_pair(Val, IntPtrTy));
Args.push_back(std::make_pair(Op.getOperand(3), IntPtrTy));
std::pair<SDOperand,SDOperand> CallResult =
LowerCallTo(Chain, Type::VoidTy, false, CallingConv::C, false,
DAG.getExternalSymbol("memset", IntPtr), Args, DAG);
return CallResult.second;
}
MVT::ValueType AVT;
SDOperand Count;
ConstantSDNode *ValC = dyn_cast<ConstantSDNode>(Op.getOperand(2));
unsigned BytesLeft = 0;
bool TwoRepStos = false;
if (ValC) {
unsigned ValReg;
// If the value is a constant, then we can potentially use larger sets.
switch (Align & 3) {
case 2: // WORD aligned
AVT = MVT::i16;
ValReg = X86::AX;
AVT = MVT::i32;
Val = (Val << 8) | Val;
Val = (Val << 16) | Val;
if (Subtarget->is64Bit() && ((Align & 0xF) == 0)) { // QWORD aligned
AVT = MVT::i64;
ValReg = X86::RAX;
Val = (Val << 32) | Val;
}
break;
default: // Byte aligned
AVT = MVT::i8;
ValReg = X86::AL;
}
if (AVT > MVT::i8) {
if (I) {
unsigned UBytes = MVT::getSizeInBits(AVT) / 8;
Count = DAG.getConstant(I->getValue() / UBytes, getPointerTy());
BytesLeft = I->getValue() % UBytes;
} else {
assert(AVT >= MVT::i32 &&
"Do not use rep;stos if not at least DWORD aligned");
Count = DAG.getNode(ISD::SRL, Op.getOperand(3).getValueType(),
Op.getOperand(3), DAG.getConstant(2, MVT::i8));
TwoRepStos = true;
}
}
Chain = DAG.getCopyToReg(Chain, ValReg, DAG.getConstant(Val, AVT),
InFlag);
InFlag = Chain.getValue(1);
} else {
AVT = MVT::i8;
Count = Op.getOperand(3);
Chain = DAG.getCopyToReg(Chain, X86::AL, Op.getOperand(2), InFlag);
InFlag = Chain.getValue(1);
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RCX : X86::ECX,
Count, InFlag);
InFlag = Chain.getValue(1);
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RDI : X86::EDI,
Op.getOperand(1), InFlag);
InFlag = Chain.getValue(1);
std::vector<MVT::ValueType> Tys;
Tys.push_back(MVT::Other);
Tys.push_back(MVT::Flag);
std::vector<SDOperand> Ops;
Ops.push_back(Chain);
Ops.push_back(DAG.getValueType(AVT));
Ops.push_back(InFlag);
Evan Cheng
committed
Chain = DAG.getNode(X86ISD::REP_STOS, Tys, &Ops[0], Ops.size());
if (TwoRepStos) {
InFlag = Chain.getValue(1);
Count = Op.getOperand(3);
MVT::ValueType CVT = Count.getValueType();
SDOperand Left = DAG.getNode(ISD::AND, CVT, Count,
DAG.getConstant((AVT == MVT::i64) ? 7 : 3, CVT));
Chain = DAG.getCopyToReg(Chain, (CVT == MVT::i64) ? X86::RCX : X86::ECX,
Left, InFlag);
InFlag = Chain.getValue(1);
Tys.clear();
Tys.push_back(MVT::Other);
Tys.push_back(MVT::Flag);
Ops.clear();
Ops.push_back(Chain);
Ops.push_back(DAG.getValueType(MVT::i8));
Ops.push_back(InFlag);
Evan Cheng
committed
Chain = DAG.getNode(X86ISD::REP_STOS, Tys, &Ops[0], Ops.size());
} else if (BytesLeft) {
SDOperand Value;
unsigned Val = ValC->getValue() & 255;
unsigned Offset = I->getValue() - BytesLeft;
SDOperand DstAddr = Op.getOperand(1);
MVT::ValueType AddrVT = DstAddr.getValueType();
if (BytesLeft >= 4) {
Val = (Val << 8) | Val;
Val = (Val << 16) | Val;
Value = DAG.getConstant(Val, MVT::i32);
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
DAG.getNode(ISD::ADD, AddrVT, DstAddr,
DAG.getConstant(Offset, AddrVT)),
DAG.getSrcValue(NULL));
BytesLeft -= 4;
Offset += 4;
}
if (BytesLeft >= 2) {
Value = DAG.getConstant((Val << 8) | Val, MVT::i16);
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
DAG.getNode(ISD::ADD, AddrVT, DstAddr,
DAG.getConstant(Offset, AddrVT)),
DAG.getSrcValue(NULL));
BytesLeft -= 2;
Offset += 2;
}
if (BytesLeft == 1) {
Value = DAG.getConstant(Val, MVT::i8);
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
DAG.getNode(ISD::ADD, AddrVT, DstAddr,
DAG.getConstant(Offset, AddrVT)),
DAG.getSrcValue(NULL));
}
}
return Chain;
}
SDOperand X86TargetLowering::LowerMEMCPY(SDOperand Op, SelectionDAG &DAG) {
SDOperand Chain = Op.getOperand(0);
unsigned Align =
(unsigned)cast<ConstantSDNode>(Op.getOperand(4))->getValue();
if (Align == 0) Align = 1;
ConstantSDNode *I = dyn_cast<ConstantSDNode>(Op.getOperand(3));
// If not DWORD aligned, call memcpy if size is less than the threshold.
// It knows how to align to the right boundary first.
if ((Align & 3) != 0 ||
(I && I->getValue() < Subtarget->getMinRepStrSizeThreshold())) {
MVT::ValueType IntPtr = getPointerTy();
const Type *IntPtrTy = getTargetData()->getIntPtrType();
std::vector<std::pair<SDOperand, const Type*> > Args;
Args.push_back(std::make_pair(Op.getOperand(1), IntPtrTy));
Args.push_back(std::make_pair(Op.getOperand(2), IntPtrTy));
Args.push_back(std::make_pair(Op.getOperand(3), IntPtrTy));
std::pair<SDOperand,SDOperand> CallResult =
LowerCallTo(Chain, Type::VoidTy, false, CallingConv::C, false,
DAG.getExternalSymbol("memcpy", IntPtr), Args, DAG);
return CallResult.second;
}
MVT::ValueType AVT;
SDOperand Count;
unsigned BytesLeft = 0;
bool TwoRepMovs = false;
switch (Align & 3) {
case 2: // WORD aligned
AVT = MVT::i16;
break;
AVT = MVT::i32;
if (Subtarget->is64Bit() && ((Align & 0xF) == 0)) // QWORD aligned
AVT = MVT::i64;
break;
default: // Byte aligned
AVT = MVT::i8;
Count = Op.getOperand(3);
break;
}
if (AVT > MVT::i8) {
if (I) {
unsigned UBytes = MVT::getSizeInBits(AVT) / 8;
Count = DAG.getConstant(I->getValue() / UBytes, getPointerTy());
BytesLeft = I->getValue() % UBytes;
} else {
assert(AVT >= MVT::i32 &&
"Do not use rep;movs if not at least DWORD aligned");
Count = DAG.getNode(ISD::SRL, Op.getOperand(3).getValueType(),
Op.getOperand(3), DAG.getConstant(2, MVT::i8));
TwoRepMovs = true;
}
}
SDOperand InFlag(0, 0);
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RCX : X86::ECX,
Count, InFlag);
InFlag = Chain.getValue(1);
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RDI : X86::EDI,
Op.getOperand(1), InFlag);
InFlag = Chain.getValue(1);
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RSI : X86::ESI,
Op.getOperand(2), InFlag);
InFlag = Chain.getValue(1);
std::vector<MVT::ValueType> Tys;
Tys.push_back(MVT::Other);
Tys.push_back(MVT::Flag);
std::vector<SDOperand> Ops;
Ops.push_back(Chain);
Ops.push_back(DAG.getValueType(AVT));
Ops.push_back(InFlag);
Evan Cheng
committed
Chain = DAG.getNode(X86ISD::REP_MOVS, Tys, &Ops[0], Ops.size());
if (TwoRepMovs) {
InFlag = Chain.getValue(1);
Count = Op.getOperand(3);
MVT::ValueType CVT = Count.getValueType();
SDOperand Left = DAG.getNode(ISD::AND, CVT, Count,
DAG.getConstant((AVT == MVT::i64) ? 7 : 3, CVT));
Chain = DAG.getCopyToReg(Chain, (CVT == MVT::i64) ? X86::RCX : X86::ECX,
Left, InFlag);
InFlag = Chain.getValue(1);
Tys.clear();
Tys.push_back(MVT::Other);
Tys.push_back(MVT::Flag);
Ops.clear();
Ops.push_back(Chain);
Ops.push_back(DAG.getValueType(MVT::i8));
Ops.push_back(InFlag);
Evan Cheng
committed
Chain = DAG.getNode(X86ISD::REP_MOVS, Tys, &Ops[0], Ops.size());
} else if (BytesLeft) {
// Issue loads and stores for the last 1 - 7 bytes.
unsigned Offset = I->getValue() - BytesLeft;
SDOperand DstAddr = Op.getOperand(1);
MVT::ValueType DstVT = DstAddr.getValueType();
SDOperand SrcAddr = Op.getOperand(2);
MVT::ValueType SrcVT = SrcAddr.getValueType();
SDOperand Value;
if (BytesLeft >= 4) {
Value = DAG.getLoad(MVT::i32, Chain,
DAG.getNode(ISD::ADD, SrcVT, SrcAddr,
DAG.getConstant(Offset, SrcVT)),
DAG.getSrcValue(NULL));
Chain = Value.getValue(1);
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
DAG.getNode(ISD::ADD, DstVT, DstAddr,
DAG.getConstant(Offset, DstVT)),
DAG.getSrcValue(NULL));
BytesLeft -= 4;
Offset += 4;
}
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
if (BytesLeft >= 2) {
Value = DAG.getLoad(MVT::i16, Chain,
DAG.getNode(ISD::ADD, SrcVT, SrcAddr,
DAG.getConstant(Offset, SrcVT)),
DAG.getSrcValue(NULL));
Chain = Value.getValue(1);
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
DAG.getNode(ISD::ADD, DstVT, DstAddr,
DAG.getConstant(Offset, DstVT)),
DAG.getSrcValue(NULL));
BytesLeft -= 2;
Offset += 2;
}
if (BytesLeft == 1) {
Value = DAG.getLoad(MVT::i8, Chain,
DAG.getNode(ISD::ADD, SrcVT, SrcAddr,
DAG.getConstant(Offset, SrcVT)),
DAG.getSrcValue(NULL));
Chain = Value.getValue(1);
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
DAG.getNode(ISD::ADD, DstVT, DstAddr,
DAG.getConstant(Offset, DstVT)),
DAG.getSrcValue(NULL));
return Chain;
}
SDOperand
X86TargetLowering::LowerREADCYCLCECOUNTER(SDOperand Op, SelectionDAG &DAG) {
std::vector<MVT::ValueType> Tys;
Tys.push_back(MVT::Other);
Tys.push_back(MVT::Flag);
std::vector<SDOperand> Ops;
Ops.push_back(Op.getOperand(0));
Evan Cheng
committed
SDOperand rd = DAG.getNode(X86ISD::RDTSC_DAG, Tys, &Ops[0], Ops.size());
Ops.clear();
Ops.push_back(DAG.getCopyFromReg(rd, X86::EAX, MVT::i32, rd.getValue(1)));
Ops.push_back(DAG.getCopyFromReg(Ops[0].getValue(1), X86::EDX,
MVT::i32, Ops[0].getValue(2)));
Ops.push_back(Ops[1].getValue(1));
Tys[0] = Tys[1] = MVT::i32;
Tys.push_back(MVT::Other);
Evan Cheng
committed
return DAG.getNode(ISD::MERGE_VALUES, Tys, &Ops[0], Ops.size());
}
SDOperand X86TargetLowering::LowerVASTART(SDOperand Op, SelectionDAG &DAG) {
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
if (!Subtarget->is64Bit()) {
// vastart just stores the address of the VarArgsFrameIndex slot into the
// memory location argument.
SDOperand FR = DAG.getFrameIndex(VarArgsFrameIndex, getPointerTy());
return DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0), FR,
Op.getOperand(1), Op.getOperand(2));
}
// __va_list_tag:
// gp_offset (0 - 6 * 8)
// fp_offset (48 - 48 + 8 * 16)
// overflow_arg_area (point to parameters coming in memory).
// reg_save_area
std::vector<SDOperand> MemOps;
SDOperand FIN = Op.getOperand(1);
// Store gp_offset
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
DAG.getConstant(VarArgsGPOffset, MVT::i32),
FIN, Op.getOperand(2));
MemOps.push_back(Store);
// Store fp_offset
FIN = DAG.getNode(ISD::ADD, getPointerTy(), FIN,
DAG.getConstant(4, getPointerTy()));
Store = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
DAG.getConstant(VarArgsFPOffset, MVT::i32),
FIN, Op.getOperand(2));
MemOps.push_back(Store);
// Store ptr to overflow_arg_area
FIN = DAG.getNode(ISD::ADD, getPointerTy(), FIN,
DAG.getConstant(4, getPointerTy()));
SDOperand OVFIN = DAG.getFrameIndex(VarArgsFrameIndex, getPointerTy());
Store = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
OVFIN, FIN, Op.getOperand(2));
MemOps.push_back(Store);
// Store ptr to reg_save_area.
FIN = DAG.getNode(ISD::ADD, getPointerTy(), FIN,
DAG.getConstant(8, getPointerTy()));
SDOperand RSFIN = DAG.getFrameIndex(RegSaveFrameIndex, getPointerTy());
Store = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
RSFIN, FIN, Op.getOperand(2));
MemOps.push_back(Store);
return DAG.getNode(ISD::TokenFactor, MVT::Other, &MemOps[0], MemOps.size());
}
SDOperand
X86TargetLowering::LowerINTRINSIC_WO_CHAIN(SDOperand Op, SelectionDAG &DAG) {
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getValue();
switch (IntNo) {
default: return SDOperand(); // Don't custom lower most intrinsics.
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
case Intrinsic::x86_sse_comieq_ss:
case Intrinsic::x86_sse_comilt_ss:
case Intrinsic::x86_sse_comile_ss:
case Intrinsic::x86_sse_comigt_ss:
case Intrinsic::x86_sse_comige_ss:
case Intrinsic::x86_sse_comineq_ss:
case Intrinsic::x86_sse_ucomieq_ss:
case Intrinsic::x86_sse_ucomilt_ss:
case Intrinsic::x86_sse_ucomile_ss:
case Intrinsic::x86_sse_ucomigt_ss:
case Intrinsic::x86_sse_ucomige_ss:
case Intrinsic::x86_sse_ucomineq_ss:
case Intrinsic::x86_sse2_comieq_sd:
case Intrinsic::x86_sse2_comilt_sd:
case Intrinsic::x86_sse2_comile_sd:
case Intrinsic::x86_sse2_comigt_sd:
case Intrinsic::x86_sse2_comige_sd:
case Intrinsic::x86_sse2_comineq_sd:
case Intrinsic::x86_sse2_ucomieq_sd:
case Intrinsic::x86_sse2_ucomilt_sd:
case Intrinsic::x86_sse2_ucomile_sd:
case Intrinsic::x86_sse2_ucomigt_sd:
case Intrinsic::x86_sse2_ucomige_sd:
case Intrinsic::x86_sse2_ucomineq_sd: {
unsigned Opc = 0;
ISD::CondCode CC = ISD::SETCC_INVALID;
switch (IntNo) {
default: break;
case Intrinsic::x86_sse_comieq_ss:
case Intrinsic::x86_sse2_comieq_sd:
Opc = X86ISD::COMI;
CC = ISD::SETEQ;
break;
case Intrinsic::x86_sse_comilt_ss:
case Intrinsic::x86_sse2_comilt_sd:
Opc = X86ISD::COMI;
CC = ISD::SETLT;
break;
case Intrinsic::x86_sse_comile_ss:
Opc = X86ISD::COMI;
CC = ISD::SETLE;
break;
case Intrinsic::x86_sse_comigt_ss:
Opc = X86ISD::COMI;
CC = ISD::SETGT;
break;
case Intrinsic::x86_sse_comige_ss:
Opc = X86ISD::COMI;
CC = ISD::SETGE;
break;
case Intrinsic::x86_sse_comineq_ss:
Opc = X86ISD::COMI;
CC = ISD::SETNE;
break;
case Intrinsic::x86_sse_ucomieq_ss:
Opc = X86ISD::UCOMI;
CC = ISD::SETEQ;
break;
case Intrinsic::x86_sse_ucomilt_ss:
Opc = X86ISD::UCOMI;
CC = ISD::SETLT;
break;
case Intrinsic::x86_sse_ucomile_ss:
Opc = X86ISD::UCOMI;
CC = ISD::SETLE;
break;
case Intrinsic::x86_sse_ucomigt_ss:
Opc = X86ISD::UCOMI;
CC = ISD::SETGT;
break;
case Intrinsic::x86_sse_ucomige_ss:
Opc = X86ISD::UCOMI;
CC = ISD::SETGE;
break;
case Intrinsic::x86_sse_ucomineq_ss:
case Intrinsic::x86_sse2_ucomineq_sd:
Opc = X86ISD::UCOMI;
CC = ISD::SETNE;
break;
unsigned X86CC;
SDOperand LHS = Op.getOperand(1);
SDOperand RHS = Op.getOperand(2);
translateX86CC(CC, true, X86CC, LHS, RHS, DAG);
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
SDOperand Ops1[] = { DAG.getEntryNode(), LHS, RHS };
SDOperand Cond = DAG.getNode(Opc, VTs, 2, Ops1, 3);
VTs = DAG.getNodeValueTypes(MVT::i8, MVT::Flag);
SDOperand Ops2[] = { DAG.getConstant(X86CC, MVT::i8), Cond };
SDOperand SetCC = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops2, 2);
return DAG.getNode(ISD::ANY_EXTEND, MVT::i32, SetCC);
}
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
}
/// LowerOperation - Provide custom lowering hooks for some operations.
///
SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
switch (Op.getOpcode()) {
default: assert(0 && "Should not custom lower this!");
case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG);
case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG);
case ISD::EXTRACT_VECTOR_ELT: return LowerEXTRACT_VECTOR_ELT(Op, DAG);
case ISD::INSERT_VECTOR_ELT: return LowerINSERT_VECTOR_ELT(Op, DAG);
case ISD::SCALAR_TO_VECTOR: return LowerSCALAR_TO_VECTOR(Op, DAG);
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
case ISD::ExternalSymbol: return LowerExternalSymbol(Op, DAG);
case ISD::SHL_PARTS:
case ISD::SRA_PARTS:
case ISD::SRL_PARTS: return LowerShift(Op, DAG);
case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG);
case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG);
case ISD::FABS: return LowerFABS(Op, DAG);
case ISD::FNEG: return LowerFNEG(Op, DAG);
case ISD::SETCC: return LowerSETCC(Op, DAG, DAG.getEntryNode());
case ISD::SELECT: return LowerSELECT(Op, DAG);
case ISD::BRCOND: return LowerBRCOND(Op, DAG);
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
case ISD::CALL: return LowerCALL(Op, DAG);
case ISD::RET: return LowerRET(Op, DAG);
case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG);
case ISD::MEMSET: return LowerMEMSET(Op, DAG);
case ISD::MEMCPY: return LowerMEMCPY(Op, DAG);
case ISD::READCYCLECOUNTER: return LowerREADCYCLCECOUNTER(Op, DAG);
case ISD::VASTART: return LowerVASTART(Op, DAG);
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
}
const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
switch (Opcode) {
default: return NULL;
case X86ISD::SHLD: return "X86ISD::SHLD";
case X86ISD::SHRD: return "X86ISD::SHRD";
case X86ISD::FXOR: return "X86ISD::FXOR";
case X86ISD::FILD_FLAG: return "X86ISD::FILD_FLAG";
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::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";
case X86ISD::RDTSC_DAG: return "X86ISD::RDTSC_DAG";
case X86ISD::CMP: return "X86ISD::CMP";
case X86ISD::COMI: return "X86ISD::COMI";
case X86ISD::UCOMI: return "X86ISD::UCOMI";
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";
case X86ISD::REP_STOS: return "X86ISD::REP_STOS";
case X86ISD::REP_MOVS: return "X86ISD::REP_MOVS";
case X86ISD::LOAD_PACK: return "X86ISD::LOAD_PACK";
case X86ISD::LOAD_UA: return "X86ISD::LOAD_UA";
case X86ISD::GlobalBaseReg: return "X86ISD::GlobalBaseReg";
case X86ISD::Wrapper: return "X86ISD::Wrapper";
case X86ISD::S2VEC: return "X86ISD::S2VEC";
case X86ISD::PEXTRW: return "X86ISD::PEXTRW";
case X86ISD::PINSRW: return "X86ISD::PINSRW";
/// isLegalAddressImmediate - Return true if the integer value or
/// GlobalValue can be used as the offset of the target addressing mode.
bool X86TargetLowering::isLegalAddressImmediate(int64_t V) const {
// X86 allows a sign-extended 32-bit immediate field.
return (V > -(1LL << 32) && V < (1LL << 32)-1);