setOperationAction(ISD::SELECT, MVT::i32, Custom);
setOperationAction(ISD::BRCOND, MVT::Other, Custom);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom);
- setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::SDIV, MVT::i32, Expand);
setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
- setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
- setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
+ setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom);
+ setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom);
setOperationAction(ISD::FSIN, MVT::f32, Expand);
setOperationAction(ISD::FSIN, MVT::f64, Expand);
setOperationAction(ISD::FCOS, MVT::f32, Expand);
setOperationAction(ISD::FLOG10, MVT::f32, Expand);
setOperationAction(ISD::FEXP, MVT::f32, Expand);
- setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
-
+ setOperationAction(ISD::EXCEPTIONADDR, MVT::i32, Expand);
+ setOperationAction(ISD::EHSELECTION, MVT::i32, Expand);
+
setOperationAction(ISD::VAARG, MVT::Other, Expand);
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
setStackPointerRegisterToSaveRestore(Mips::SP);
computeRegisterProperties();
+
+ setExceptionPointerRegister(Mips::A0);
+ setExceptionSelectorRegister(Mips::A1);
}
MVT::SimpleValueType MipsTargetLowering::getSetCCResultType(EVT VT) const {
case ISD::BRCOND: return LowerBRCOND(Op, DAG);
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
- case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG);
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
case ISD::SELECT: return LowerSELECT(Op, DAG);
case ISD::VASTART: return LowerVASTART(Op, DAG);
+ case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG);
}
return SDValue();
}
//===----------------------------------------------------------------------===//
// Misc Lower Operation implementation
//===----------------------------------------------------------------------===//
-
-SDValue MipsTargetLowering::
-LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const
-{
- if (!Subtarget->isMips1())
- return Op;
-
- MachineFunction &MF = DAG.getMachineFunction();
- unsigned CCReg = AddLiveIn(MF, Mips::FCR31, Mips::CCRRegisterClass);
-
- SDValue Chain = DAG.getEntryNode();
- DebugLoc dl = Op.getDebugLoc();
- SDValue Src = Op.getOperand(0);
-
- // Set the condition register
- SDValue CondReg = DAG.getCopyFromReg(Chain, dl, CCReg, MVT::i32);
- CondReg = DAG.getCopyToReg(Chain, dl, Mips::AT, CondReg);
- CondReg = DAG.getCopyFromReg(CondReg, dl, Mips::AT, MVT::i32);
-
- SDValue Cst = DAG.getConstant(3, MVT::i32);
- SDValue Or = DAG.getNode(ISD::OR, dl, MVT::i32, CondReg, Cst);
- Cst = DAG.getConstant(2, MVT::i32);
- SDValue Xor = DAG.getNode(ISD::XOR, dl, MVT::i32, Or, Cst);
-
- SDValue InFlag(0, 0);
- CondReg = DAG.getCopyToReg(Chain, dl, Mips::FCR31, Xor, InFlag);
-
- // Emit the round instruction and bit convert to integer
- SDValue Trunc = DAG.getNode(MipsISD::FPRound, dl, MVT::f32,
- Src, CondReg.getValue(1));
- SDValue BitCvt = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Trunc);
- return BitCvt;
-}
-
SDValue MipsTargetLowering::
LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const
{
// must be placed in the stack pointer register.
Chain = DAG.getCopyToReg(StackPointer.getValue(1), dl, Mips::SP, Sub,
SDValue());
+ // Retrieve updated $sp. There is a glue input to prevent instructions that
+ // clobber $sp from being inserted between copytoreg and copyfromreg.
SDValue NewSP = DAG.getCopyFromReg(Chain, dl, Mips::SP, MVT::i32,
Chain.getValue(1));
- // Align the allocated space.
+ // The stack space reserved by alloca is located right above the argument
+ // area. It is aligned on a boundary that is a multiple of StackAlignment.
MachineFunction &MF = DAG.getMachineFunction();
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
unsigned SPOffset = (MipsFI->getMaxCallFrameSize() + StackAlignment - 1) /
false, false, 0);
}
+static SDValue LowerFCOPYSIGN32(SDValue Op, SelectionDAG &DAG) {
+ // FIXME: Use ext/ins instructions if target architecture is Mips32r2.
+ DebugLoc dl = Op.getDebugLoc();
+ SDValue Op0 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op.getOperand(0));
+ SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op.getOperand(1));
+ SDValue And0 = DAG.getNode(ISD::AND, dl, MVT::i32, Op0,
+ DAG.getConstant(0x7fffffff, MVT::i32));
+ SDValue And1 = DAG.getNode(ISD::AND, dl, MVT::i32, Op1,
+ DAG.getConstant(0x80000000, MVT::i32));
+ SDValue Result = DAG.getNode(ISD::OR, dl, MVT::i32, And0, And1);
+ return DAG.getNode(ISD::BITCAST, dl, MVT::f32, Result);
+}
+
+static SDValue LowerFCOPYSIGN64(SDValue Op, SelectionDAG &DAG, bool isLittle) {
+ // FIXME:
+ // Use ext/ins instructions if target architecture is Mips32r2.
+ // Eliminate redundant mfc1 and mtc1 instructions.
+ unsigned LoIdx = 0, HiIdx = 1;
+
+ if (!isLittle)
+ std::swap(LoIdx, HiIdx);
+
+ DebugLoc dl = Op.getDebugLoc();
+ SDValue Word0 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32,
+ Op.getOperand(0),
+ DAG.getConstant(LoIdx, MVT::i32));
+ SDValue Hi0 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32,
+ Op.getOperand(0), DAG.getConstant(HiIdx, MVT::i32));
+ SDValue Hi1 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32,
+ Op.getOperand(1), DAG.getConstant(HiIdx, MVT::i32));
+ SDValue And0 = DAG.getNode(ISD::AND, dl, MVT::i32, Hi0,
+ DAG.getConstant(0x7fffffff, MVT::i32));
+ SDValue And1 = DAG.getNode(ISD::AND, dl, MVT::i32, Hi1,
+ DAG.getConstant(0x80000000, MVT::i32));
+ SDValue Word1 = DAG.getNode(ISD::OR, dl, MVT::i32, And0, And1);
+
+ if (!isLittle)
+ std::swap(Word0, Word1);
+
+ return DAG.getNode(MipsISD::BuildPairF64, dl, MVT::f64, Word0, Word1);
+}
+
+SDValue MipsTargetLowering::LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG)
+ const {
+ EVT Ty = Op.getValueType();
+
+ assert(Ty == MVT::f32 || Ty == MVT::f64);
+
+ if (Ty == MVT::f32)
+ return LowerFCOPYSIGN32(Op, DAG);
+ else
+ return LowerFCOPYSIGN64(Op, DAG, Subtarget->isLittle());
+}
+
//===----------------------------------------------------------------------===//
// Calling Convention Implementation
//===----------------------------------------------------------------------===//
SmallVector<std::pair<unsigned, SDValue>, 16>& RegsToPass,
SmallVector<SDValue, 8>& MemOpChains, int& LastFI,
MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg,
- const CCValAssign &VA, const ISD::ArgFlagsTy& Flags, MVT PtrType) {
+ const CCValAssign &VA, const ISD::ArgFlagsTy& Flags,
+ MVT PtrType) {
unsigned FirstWord = VA.getLocMemOffset() / 4;
unsigned NumWords = (Flags.getByValSize() + 3) / 4;
unsigned LastWord = FirstWord + NumWords;
MipsFI->setHasCall();
- // Create GP frame object if this is the first call.
- // SPOffset will be updated after call frame size is known.
+ // If this is the first call, create a stack frame object that points to
+ // a location to which .cprestore saves $gp. The offset of this frame object
+ // is set to 0, since we know nothing about the size of the argument area at
+ // this point.
if (IsPIC && !MipsFI->getGPFI())
MipsFI->setGPFI(MFI->CreateFixedObject(4, 0, true));
}
// Create the frame index object for this incoming parameter
- // This guarantees that when allocating Local Area the firsts
- // 16 bytes which are alwayes reserved won't be overwritten
- // if O32 ABI is used. For EABI the first address is zero.
LastFI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8,
VA.getLocMemOffset(), true);
SDValue PtrOff = DAG.getFrameIndex(LastFI, getPointerTy());
Chain = DAG.getNode(MipsISD::JmpLink, dl, NodeTys, &Ops[0], Ops.size());
InFlag = Chain.getValue(1);
- // Create a stack location to hold GP when PIC is used. This stack
- // location is used on function prologue to save GP and also after all
- // emitted CALL's to restore GP.
- if (IsPIC) {
- // Function can have an arbitrary number of calls, so
- // hold the LastArgStackLoc with the biggest offset.
- int MaxCallFrameSize = MipsFI->getMaxCallFrameSize();
- unsigned NextStackOffset = CCInfo.getNextStackOffset();
+ // Function can have an arbitrary number of calls, so
+ // hold the LastArgStackLoc with the biggest offset.
+ unsigned MaxCallFrameSize = MipsFI->getMaxCallFrameSize();
+ unsigned NextStackOffset = CCInfo.getNextStackOffset();
- // For O32, a minimum of four words (16 bytes) of argument space is
- // allocated.
- if (Subtarget->isABI_O32())
- NextStackOffset = std::max(NextStackOffset, (unsigned)16);
+ // For O32, a minimum of four words (16 bytes) of argument space is
+ // allocated.
+ if (Subtarget->isABI_O32())
+ NextStackOffset = std::max(NextStackOffset, (unsigned)16);
- if (MaxCallFrameSize < (int)NextStackOffset) {
- MipsFI->setMaxCallFrameSize(NextStackOffset);
+ if (MaxCallFrameSize < NextStackOffset) {
+ MipsFI->setMaxCallFrameSize(NextStackOffset);
+ if (IsPIC) {
// $gp restore slot must be aligned.
unsigned StackAlignment = TFL->getStackAlignment();
NextStackOffset = (NextStackOffset + StackAlignment - 1) /
DebugLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals)
const {
-
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
}
// The stack pointer offset is relative to the caller stack frame.
- // Since the real stack size is unknown here, a negative SPOffset
- // is used so there's a way to adjust these offsets when the stack
- // size get known (on EliminateFrameIndex). A dummy SPOffset is
- // used instead of a direct negative address (which is recorded to
- // be used on emitPrologue) to avoid mis-calc of the first stack
- // offset on PEI::calculateFrameObjectOffsets.
LastFI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8,
VA.getLocMemOffset(), true);
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain);
}
- // To meet ABI, when VARARGS are passed on registers, the registers
- // must have their values written to the caller stack frame. If the last
- // argument was placed in the stack, there's no need to save any register.
if (isVarArg && Subtarget->isABI_O32()) {
// Record the frame index of the first variable argument
// which is a value necessary to VASTART.
"NextStackOffset must be aligned to 4-byte boundaries.");
LastFI = MFI->CreateFixedObject(4, NextStackOffset, true);
MipsFI->setVarArgsFrameIndex(LastFI);
-
- // Copy variable arguments passed in registers to stack.
+
+ // If NextStackOffset is smaller than o32's 16-byte reserved argument area,
+ // copy the integer registers that have not been used for argument passing
+ // to the caller's stack frame.
for (; NextStackOffset < 16; NextStackOffset += 4) {
TargetRegisterClass *RC = Mips::CPURegsRegisterClass;
unsigned Idx = NextStackOffset / 4;