//===----------------------------------------------------------------------===//
#include "X86.h"
+#include "X86InstrBuilder.h"
#include "X86ISelLowering.h"
#include "X86TargetMachine.h"
#include "llvm/CallingConv.h"
setSetCCResultType(MVT::i8);
setSetCCResultContents(ZeroOrOneSetCCResult);
setShiftAmountFlavor(Mask); // shl X, 32 == shl X, 0
+ setStackPointerRegisterToSaveRestore(X86::ESP);
// Set up the register classes.
addRegisterClass(MVT::i8, X86::R8RegisterClass);
setOperationAction(ISD::UINT_TO_FP , MVT::i1 , Promote);
setOperationAction(ISD::UINT_TO_FP , MVT::i8 , Promote);
setOperationAction(ISD::UINT_TO_FP , MVT::i16 , Promote);
- setOperationAction(ISD::UINT_TO_FP , MVT::i32 , Promote);
+
+ if (X86ScalarSSE)
+ // No SSE i64 SINT_TO_FP, so expand i32 UINT_TO_FP instead.
+ setOperationAction(ISD::UINT_TO_FP , MVT::i32 , Expand);
+ else
+ setOperationAction(ISD::UINT_TO_FP , MVT::i32 , Promote);
// Promote i1/i8 SINT_TO_FP to larger SINT_TO_FP's, as X86 doesn't have
// this operation.
setOperationAction(ISD::READCYCLECOUNTER , MVT::i64 , Custom);
if (!X86DAGIsel) {
+ setOperationAction(ISD::BSWAP , MVT::i32 , Expand);
setOperationAction(ISD::ROTL , MVT::i8 , Expand);
setOperationAction(ISD::ROTR , MVT::i8 , Expand);
setOperationAction(ISD::ROTL , MVT::i16 , Expand);
setOperationAction(ISD::ROTL , MVT::i32 , Expand);
setOperationAction(ISD::ROTR , MVT::i32 , Expand);
}
+ setOperationAction(ISD::BSWAP , MVT::i16 , Expand);
setOperationAction(ISD::READIO , MVT::i1 , Expand);
setOperationAction(ISD::READIO , MVT::i8 , Expand);
setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
setOperationAction(ISD::DEBUG_LABEL, MVT::Other, Expand);
+ // Expand to the default code.
+ setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
+ setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Expand);
+
if (X86ScalarSSE) {
// Set up the FP register classes.
addRegisterClass(MVT::f32, X86::FR32RegisterClass);
case MVT::f32:
case MVT::f64:
if (!X86ScalarSSE) {
- if (OpVT == MVT::f32)
- Op = DAG.getNode(ISD::FP_EXTEND, MVT::f64, Op);
std::vector<MVT::ValueType> Tys;
Tys.push_back(MVT::Other);
Tys.push_back(MVT::Flag);
case MVT::i8:
RetVal = DAG.getCopyFromReg(Chain, X86::AL, MVT::i8, InFlag);
Chain = RetVal.getValue(1);
+ if (RetTyVT == MVT::i1)
+ RetVal = DAG.getNode(ISD::TRUNCATE, MVT::i1, RetVal);
break;
case MVT::i16:
RetVal = DAG.getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag);
std::vector<MVT::ValueType> Tys;
Tys.push_back(MVT::f64);
Tys.push_back(MVT::Other);
+ Tys.push_back(MVT::Flag);
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);
+ Chain = RetVal.getValue(1);
+ InFlag = RetVal.getValue(2);
if (X86ScalarSSE) {
+ // FIXME:Currently the FST is flagged to the FP_GET_RESULT. This
+ // shouldn't be necessary except for RFP cannot be live across
+ // multiple blocks. When stackifier is fixed, they can be uncoupled.
unsigned Size = MVT::getSizeInBits(MVT::f64)/8;
MachineFunction &MF = DAG.getMachineFunction();
int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size);
Ops.push_back(RetVal);
Ops.push_back(StackSlot);
Ops.push_back(DAG.getValueType(RetTyVT));
+ Ops.push_back(InFlag);
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)
+ }
+
+ if (RetTyVT == MVT::f32 && !X86ScalarSSE)
+ // FIXME: we would really like to remember that this FP_ROUND
+ // operation is okay to eliminate if we allow excess FP precision.
RetVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, RetVal);
break;
}
case MVT::i8:
RetVal = DAG.getCopyFromReg(Chain, X86::AL, MVT::i8, InFlag);
Chain = RetVal.getValue(1);
+ if (RetTyVT == MVT::i1)
+ RetVal = DAG.getNode(ISD::TRUNCATE, MVT::i1, RetVal);
break;
case MVT::i16:
RetVal = DAG.getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag);
std::vector<MVT::ValueType> Tys;
Tys.push_back(MVT::f64);
Tys.push_back(MVT::Other);
+ Tys.push_back(MVT::Flag);
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);
+ Chain = RetVal.getValue(1);
+ InFlag = RetVal.getValue(2);
if (X86ScalarSSE) {
+ // FIXME:Currently the FST is flagged to the FP_GET_RESULT. This
+ // shouldn't be necessary except for RFP cannot be live across
+ // multiple blocks. When stackifier is fixed, they can be uncoupled.
unsigned Size = MVT::getSizeInBits(MVT::f64)/8;
MachineFunction &MF = DAG.getMachineFunction();
int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size);
Ops.push_back(RetVal);
Ops.push_back(StackSlot);
Ops.push_back(DAG.getValueType(RetTyVT));
+ Ops.push_back(InFlag);
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)
+ }
+
+ if (RetTyVT == MVT::f32 && !X86ScalarSSE)
+ // FIXME: we would really like to remember that this FP_ROUND
+ // operation is okay to eliminate if we allow excess FP precision.
RetVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, RetVal);
break;
}
MachineBasicBlock *
X86TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
MachineBasicBlock *BB) {
- assert((MI->getOpcode() == X86::CMOV_FR32 ||
- MI->getOpcode() == X86::CMOV_FR64) &&
- "Unexpected instr type to insert");
-
- // To "insert" a SELECT_CC instruction, we actually have to insert the diamond
- // control-flow pattern. The incoming instruction knows the destination vreg
- // to set, the condition code register to branch on, the true/false values to
- // select between, and a branch opcode to use.
- const BasicBlock *LLVM_BB = BB->getBasicBlock();
- ilist<MachineBasicBlock>::iterator It = BB;
- ++It;
+ switch (MI->getOpcode()) {
+ default: assert(false && "Unexpected instr type to insert");
+ case X86::CMOV_FR32:
+ case X86::CMOV_FR64: {
+ // To "insert" a SELECT_CC instruction, we actually have to insert the diamond
+ // control-flow pattern. The incoming instruction knows the destination vreg
+ // to set, the condition code register to branch on, the true/false values to
+ // select between, and a branch opcode to use.
+ const BasicBlock *LLVM_BB = BB->getBasicBlock();
+ ilist<MachineBasicBlock>::iterator It = BB;
+ ++It;
- // thisMBB:
- // ...
- // TrueVal = ...
- // cmpTY ccX, r1, r2
- // bCC copy1MBB
- // fallthrough --> copy0MBB
- MachineBasicBlock *thisMBB = BB;
- MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
- MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
- unsigned Opc = getCondBrOpcodeForX86CC(MI->getOperand(3).getImmedValue());
- BuildMI(BB, Opc, 1).addMBB(sinkMBB);
- MachineFunction *F = BB->getParent();
- F->getBasicBlockList().insert(It, copy0MBB);
- F->getBasicBlockList().insert(It, sinkMBB);
- // Update machine-CFG edges
- BB->addSuccessor(copy0MBB);
- BB->addSuccessor(sinkMBB);
+ // thisMBB:
+ // ...
+ // TrueVal = ...
+ // cmpTY ccX, r1, r2
+ // bCC copy1MBB
+ // fallthrough --> copy0MBB
+ MachineBasicBlock *thisMBB = BB;
+ MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
+ unsigned Opc = getCondBrOpcodeForX86CC(MI->getOperand(3).getImmedValue());
+ BuildMI(BB, Opc, 1).addMBB(sinkMBB);
+ MachineFunction *F = BB->getParent();
+ F->getBasicBlockList().insert(It, copy0MBB);
+ F->getBasicBlockList().insert(It, sinkMBB);
+ // Update machine-CFG edges
+ BB->addSuccessor(copy0MBB);
+ BB->addSuccessor(sinkMBB);
- // copy0MBB:
- // %FalseValue = ...
- // # fallthrough to sinkMBB
- BB = copy0MBB;
+ // copy0MBB:
+ // %FalseValue = ...
+ // # fallthrough to sinkMBB
+ BB = copy0MBB;
- // Update machine-CFG edges
- BB->addSuccessor(sinkMBB);
+ // Update machine-CFG edges
+ BB->addSuccessor(sinkMBB);
- // sinkMBB:
- // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
- // ...
- BB = sinkMBB;
- BuildMI(BB, X86::PHI, 4, MI->getOperand(0).getReg())
- .addReg(MI->getOperand(1).getReg()).addMBB(copy0MBB)
- .addReg(MI->getOperand(2).getReg()).addMBB(thisMBB);
-
- delete MI; // The pseudo instruction is gone now.
- return BB;
+ // sinkMBB:
+ // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
+ // ...
+ BB = sinkMBB;
+ BuildMI(BB, X86::PHI, 4, MI->getOperand(0).getReg())
+ .addReg(MI->getOperand(1).getReg()).addMBB(copy0MBB)
+ .addReg(MI->getOperand(2).getReg()).addMBB(thisMBB);
+
+ delete MI; // The pseudo instruction is gone now.
+ return BB;
+ }
+
+ case X86::FP_TO_INT16_IN_MEM:
+ case X86::FP_TO_INT32_IN_MEM:
+ case X86::FP_TO_INT64_IN_MEM: {
+ // 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 OldCW =
+ F->getSSARegMap()->createVirtualRegister(X86::R16RegisterClass);
+ addFrameReference(BuildMI(BB, X86::MOV16rm, 4, OldCW), CWFrameIdx);
+
+ // Set the high part to be round to zero...
+ addFrameReference(BuildMI(BB, X86::MOV16mi, 5), CWFrameIdx).addImm(0xC7F);
+
+ // 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::MOV16mr, 5), CWFrameIdx).addReg(OldCW);
+
+ // Get the X86 opcode to use.
+ unsigned Opc;
+ switch (MI->getOpcode()) {
+ case X86::FP_TO_INT16_IN_MEM: Opc = X86::FpIST16m; break;
+ case X86::FP_TO_INT32_IN_MEM: Opc = X86::FpIST32m; break;
+ case X86::FP_TO_INT64_IN_MEM: Opc = X86::FpIST64m; break;
+ }
+
+ X86AddressMode AM;
+ MachineOperand &Op = MI->getOperand(0);
+ if (Op.isRegister()) {
+ AM.BaseType = X86AddressMode::RegBase;
+ AM.Base.Reg = Op.getReg();
+ } else {
+ AM.BaseType = X86AddressMode::FrameIndexBase;
+ AM.Base.FrameIndex = Op.getFrameIndex();
+ }
+ Op = MI->getOperand(1);
+ if (Op.isImmediate())
+ AM.Scale = Op.getImmedValue();
+ Op = MI->getOperand(2);
+ if (Op.isImmediate())
+ AM.IndexReg = Op.getImmedValue();
+ Op = MI->getOperand(3);
+ if (Op.isGlobalAddress()) {
+ AM.GV = Op.getGlobal();
+ } else {
+ AM.Disp = Op.getImmedValue();
+ }
+ addFullAddress(BuildMI(BB, Opc, 5), AM).addReg(MI->getOperand(4).getReg());
+
+ // Reload the original control word now.
+ addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx);
+
+ delete MI; // The pseudo instruction is gone now.
+ return BB;
+ }
+ }
}
SDOperand ShOpHi = Op.getOperand(1);
SDOperand ShAmt = Op.getOperand(2);
SDOperand Tmp1 = isSRA ? DAG.getNode(ISD::SRA, MVT::i32, ShOpHi,
- DAG.getConstant(31, MVT::i32))
+ DAG.getConstant(31, MVT::i8))
: DAG.getConstant(0, MVT::i32);
SDOperand Tmp2, Tmp3;
Tmp3 = DAG.getNode(ISD::SHL, MVT::i32, ShOpLo, ShAmt);
} else {
Tmp2 = DAG.getNode(X86ISD::SHRD, MVT::i32, ShOpLo, ShOpHi, ShAmt);
- Tmp3 = DAG.getNode(isSRA ? ISD::SRA : ISD::SHL, MVT::i32, ShOpHi, ShAmt);
+ Tmp3 = DAG.getNode(isSRA ? ISD::SRA : ISD::SRL, MVT::i32, ShOpHi, ShAmt);
}
SDOperand InFlag = DAG.getNode(X86ISD::TEST, MVT::Flag,
bool isFP = MVT::isFloatingPoint(VT);
bool isFPStack = isFP && (X86Vector < SSE2);
bool isFPSSE = isFP && (X86Vector >= SSE2);
- bool isValid = false;
+ bool addTest = false;
SDOperand Op0 = Op.getOperand(0);
SDOperand Cond, CC;
if (Op0.getOpcode() == X86ISD::SETCC) {
- CC = Op0.getOperand(0);
- Cond = Op0.getOperand(1);
- isValid =
- !(isFPStack && !hasFPCMov(cast<ConstantSDNode>(CC)->getSignExtended()));
+ // If condition flag is set by a X86ISD::CMP, then make a copy of it
+ // (since flag operand cannot be shared). If the X86ISD::SETCC does not
+ // have another use it will be eliminated.
+ // If the X86ISD::SETCC has more than one use, then it's probably better
+ // to use a test instead of duplicating the X86ISD::CMP (for register
+ // pressure reason).
+ if (Op0.hasOneUse() && Op0.getOperand(1).getOpcode() == X86ISD::CMP) {
+ CC = Op0.getOperand(0);
+ Cond = Op0.getOperand(1);
+ addTest =
+ isFPStack && !hasFPCMov(cast<ConstantSDNode>(CC)->getSignExtended());
+ } else
+ addTest = true;
} else if (Op0.getOpcode() == ISD::SETCC) {
CC = Op0.getOperand(2);
bool isFP = MVT::isFloatingPoint(Op0.getOperand(1).getValueType());
CC = DAG.getConstant(X86CC, MVT::i8);
Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
Op0.getOperand(0), Op0.getOperand(1));
- isValid = true;
- }
+ } else
+ addTest = true;
- if (!isValid) {
- CC = DAG.getConstant(X86ISD::COND_E, MVT::i8);
+ if (addTest) {
+ CC = DAG.getConstant(X86ISD::COND_NE, MVT::i8);
Cond = DAG.getNode(X86ISD::TEST, MVT::Flag, Op0, Op0);
}
Tys.push_back(Op.getValueType());
Tys.push_back(MVT::Flag);
std::vector<SDOperand> Ops;
- Ops.push_back(Op.getOperand(1));
+ // 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);
return DAG.getNode(X86ISD::CMOV, Tys, Ops);
}
case ISD::BRCOND: {
+ bool addTest = false;
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);
+ // If condition flag is set by a X86ISD::CMP, then make a copy of it
+ // (since flag operand cannot be shared). If the X86ISD::SETCC does not
+ // have another use it will be eliminated.
+ // If the X86ISD::SETCC has more than one use, then it's probably better
+ // to use a test instead of duplicating the X86ISD::CMP (for register
+ // pressure reason).
+ if (Cond.hasOneUse() && Cond.getOperand(1).getOpcode() == X86ISD::CMP) {
+ CC = Cond.getOperand(0);
+ Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
+ Cond.getOperand(1).getOperand(0),
+ Cond.getOperand(1).getOperand(1));
+ } else
+ addTest = true;
} else if (Cond.getOpcode() == ISD::SETCC) {
CC = Cond.getOperand(2);
bool isFP = MVT::isFloatingPoint(Cond.getOperand(1).getValueType());
CC = DAG.getConstant(X86CC, MVT::i8);
Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
Cond.getOperand(0), Cond.getOperand(1));
- } else {
+ } else
+ addTest = true;
+
+ if (addTest) {
CC = DAG.getConstant(X86ISD::COND_NE, MVT::i8);
Cond = DAG.getNode(X86ISD::TEST, MVT::Flag, Cond, Cond);
}