-//===-- MipsISelLowering.cpp - Mips DAG Lowering Implementation -----------===//
+//===-- MipsISelLowering.cpp - Mips DAG Lowering Implementation ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
//
// This file defines the interfaces that Mips uses to lower LLVM code into a
// selection DAG.
//
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
#define DEBUG_TYPE "mips-lower"
#include "MipsISelLowering.h"
case MipsISD::MSubu : return "MipsISD::MSubu";
case MipsISD::DivRem : return "MipsISD::DivRem";
case MipsISD::DivRemU : return "MipsISD::DivRemU";
+ case MipsISD::BuildPairF64: return "MipsISD::BuildPairF64";
+ case MipsISD::ExtractElementF64: return "MipsISD::ExtractElementF64";
default : return NULL;
}
}
// Transform this to a MADD only if ADDENode and ADDCNode are the only users
// of the values of MultNode, in which case MultNode will be removed in later
// phases.
- // If there exist users other than ADDENode or ADDCNode, this function returns
- // here, which will result in MultNode being mapped to a single MULT
+ // If there exist users other than ADDENode or ADDCNode, this function
+ // returns here, which will result in MultNode being mapped to a single MULT
// instruction node rather than a pair of MULT and MADD instructions being
// produced.
if (!MultHi.hasOneUse() || !MultLo.hasOneUse())
// Transform this to a MSUB only if SUBENode and SUBCNode are the only users
// of the values of MultNode, in which case MultNode will be removed in later
// phases.
- // If there exist users other than SUBENode or SUBCNode, this function returns
- // here, which will result in MultNode being mapped to a single MULT
+ // If there exist users other than SUBENode or SUBCNode, this function
+ // returns here, which will result in MultNode being mapped to a single MULT
// instruction node rather than a pair of MULT and MSUB instructions being
// produced.
if (!MultHi.hasOneUse() || !MultLo.hasOneUse())
SDValue RHS = Op.getOperand(1);
DebugLoc dl = Op.getDebugLoc();
- // Assume the 3rd operand is a CondCodeSDNode. Add code to check the type of node
- // if necessary.
+ // Assume the 3rd operand is a CondCodeSDNode. Add code to check the type of
+ // node if necessary.
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
return DAG.getNode(MipsISD::FPCmp, dl, MVT::Glue, LHS, RHS,
return SDValue();
}
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// Lower helper functions
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// AddLiveIn - This helper function adds the specified physical register to the
// MachineFunction as a live in value. It also creates a corresponding
return BB;
}
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// Misc Lower Operation implementation
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
SDValue MipsTargetLowering::
LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const
SDValue CondRes = CreateFPCmp(DAG, Op.getOperand(1));
- // Return if flag is not set by a floating point comparision.
+ // Return if flag is not set by a floating point comparison.
if (CondRes.getOpcode() != MipsISD::FPCmp)
return Op;
{
SDValue Cond = CreateFPCmp(DAG, Op.getOperand(0));
- // Return if flag is not set by a floating point comparision.
+ // Return if flag is not set by a floating point comparison.
if (Cond.getOpcode() != MipsISD::FPCmp)
return Op;
false, false, 0);
// On functions and global targets not internal linked only
// a load from got/GP is necessary for PIC to work.
- if (!GV->hasLocalLinkage() || isa<Function>(GV))
+ if (!GV->hasInternalLinkage() &&
+ (!GV->hasLocalLinkage() || isa<Function>(GV)))
return ResNode;
SDValue GALo = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0,
MipsII::MO_ABS_LO);
MachinePointerInfo(),
false, false, 0);
- SDValue JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MipsII::MO_ABS_LO);
+ SDValue JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT,
+ MipsII::MO_ABS_LO);
SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, JTILo);
ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo);
// gp_rel relocation
// FIXME: we should reference the constant pool using small data sections,
- // but the asm printer currently doens't support this feature without
+ // but the asm printer currently doesn't support this feature without
// hacking it. This feature should come soon so we can uncomment the
// stuff below.
//if (IsInSmallSection(C->getType())) {
if (getTargetMachine().getRelocationModel() != Reloc::PIC_) {
SDValue CPHi = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(),
- N->getOffset(), MipsII::MO_ABS_HI);
+ N->getOffset(),
+ MipsII::MO_ABS_HI);
SDValue CPLo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(),
- N->getOffset(), MipsII::MO_ABS_LO);
+ N->getOffset(),
+ MipsII::MO_ABS_LO);
SDValue HiPart = DAG.getNode(MipsISD::Hi, dl, MVT::i32, CPHi);
SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CPLo);
ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo);
CP, MachinePointerInfo::getConstantPool(),
false, false, 0);
SDValue CPLo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(),
- N->getOffset(), MipsII::MO_ABS_LO);
+ N->getOffset(),
+ MipsII::MO_ABS_LO);
SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CPLo);
ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, Load, Lo);
}
false, false, 0);
}
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// Calling Convention Implementation
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
#include "MipsGenCallingConv.inc"
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// TODO: Implement a generic logic using tblgen that can support this.
// Mips O32 ABI rules:
// ---
// yet to hold an argument. Otherwise, use A2, A3 and stack. If A1 is
// not used, it must be shadowed. If only A3 is avaiable, shadow it and
// go to stack.
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
static bool CC_MipsO32(unsigned ValNo, MVT ValVT,
MVT LocVT, CCValAssign::LocInfo LocInfo,
// This must be the first arg of the call if no regs have been allocated.
// Initialize IntRegUsed in that case.
if (IntRegs[State.getFirstUnallocated(IntRegs, IntRegsSize)] == Mips::A0 &&
- F32Regs[State.getFirstUnallocated(F32Regs, FloatRegsSize)] == Mips::F12 &&
+ F32Regs[State.getFirstUnallocated(F32Regs, FloatRegsSize)] ==
+ Mips::F12 &&
F64Regs[State.getFirstUnallocated(F64Regs, FloatRegsSize)] == Mips::D6)
IntRegUsed = false;
return false; // CC must always match
}
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// Call Calling Convention Implementation
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
/// LowerCall - functions arguments are copied from virtual regs to
/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted.
if (VA.getValVT() == MVT::f32 && VA.getLocVT() == MVT::i32)
Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Arg);
if (VA.getValVT() == MVT::f64 && VA.getLocVT() == MVT::i32) {
- Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i64, Arg);
- SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Arg,
- DAG.getConstant(0, getPointerTy()));
- SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Arg,
- DAG.getConstant(1, getPointerTy()));
+ SDValue Lo = DAG.getNode(MipsISD::ExtractElementF64, dl,
+ MVT::i32, Arg,
+ DAG.getConstant(0, MVT::i32));
+ SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32,
+ Arg, DAG.getConstant(1, MVT::i32));
+ if (!Subtarget->isLittle())
+ std::swap(Lo, Hi);
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Lo));
RegsToPass.push_back(std::make_pair(VA.getLocReg()+1, Hi));
continue;
// Build a sequence of copy-to-reg nodes chained together with token
// chain and flag operands which copy the outgoing args into registers.
- // The InFlag in necessary since all emited instructions must be
+ // The InFlag in necessary since all emitted instructions must be
// stuck together.
SDValue InFlag;
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
// direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
// node so that legalize doesn't hack it.
unsigned char OpFlag = IsPIC ? MipsII::MO_GOT_CALL : MipsII::MO_NO_FLAG;
- if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl,
- getPointerTy(), 0, OpFlag);
- else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
+ bool LoadSymAddr = false;
+ SDValue CalleeLo;
+
+ if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ if (IsPIC && G->getGlobal()->hasInternalLinkage()) {
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl,
+ getPointerTy(), 0,MipsII:: MO_GOT);
+ CalleeLo = DAG.getTargetGlobalAddress(G->getGlobal(), dl, getPointerTy(),
+ 0, MipsII::MO_ABS_LO);
+ } else {
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl,
+ getPointerTy(), 0, OpFlag);
+ }
+
+ LoadSymAddr = true;
+ }
+ else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
Callee = DAG.getTargetExternalSymbol(S->getSymbol(),
getPointerTy(), OpFlag);
+ LoadSymAddr = true;
+ }
+
+ // Create nodes that load address of callee and copy it to T9
+ if (IsPIC) {
+ if (LoadSymAddr) {
+ // Load callee address
+ SDValue LoadValue = DAG.getLoad(MVT::i32, dl, Chain, Callee,
+ MachinePointerInfo::getGOT(),
+ false, false, 0);
+
+ // Use GOT+LO if callee has internal linkage.
+ if (CalleeLo.getNode()) {
+ SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CalleeLo);
+ Callee = DAG.getNode(ISD::ADD, dl, MVT::i32, LoadValue, Lo);
+ } else
+ Callee = LoadValue;
+
+ // Use chain output from LoadValue
+ Chain = LoadValue.getValue(1);
+ }
+
+ // copy to T9
+ Chain = DAG.getCopyToReg(Chain, dl, Mips::T9, Callee, SDValue(0, 0));
+ InFlag = Chain.getValue(1);
+ Callee = DAG.getRegister(Mips::T9, MVT::i32);
+ }
// MipsJmpLink = #chain, #target_address, #opt_in_flags...
// = Chain, Callee, Reg#1, Reg#2, ...
// 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
- // emited CALL's to restore GP.
+ // emitted CALL's to restore GP.
if (IsPIC) {
// Function can have an arbitrary number of calls, so
// hold the LastArgStackLoc with the biggest offset.
return Chain;
}
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// Formal Arguments Calling Convention Implementation
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
/// LowerFormalArguments - transform physical registers into virtual registers
/// and generate load operations for arguments places on the stack.
SDValue
MipsTargetLowering::LowerFormalArguments(SDValue Chain,
- CallingConv::ID CallConv, bool isVarArg,
- const SmallVectorImpl<ISD::InputArg>
- &Ins,
- DebugLoc dl, SelectionDAG &DAG,
- SmallVectorImpl<SDValue> &InVals)
- const {
+ CallingConv::ID CallConv,
+ bool isVarArg,
+ const SmallVectorImpl<ISD::InputArg>
+ &Ins,
+ DebugLoc dl, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals)
+ const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
unsigned Reg2 = AddLiveIn(DAG.getMachineFunction(),
VA.getLocReg()+1, RC);
SDValue ArgValue2 = DAG.getCopyFromReg(Chain, dl, Reg2, RegVT);
- SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, ArgValue,
- ArgValue2);
- ArgValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, Pair);
+ if (!Subtarget->isLittle())
+ std::swap(ArgValue, ArgValue2);
+ ArgValue = DAG.getNode(MipsISD::BuildPairF64, dl, MVT::f64,
+ ArgValue, ArgValue2);
}
}
// be used on emitPrologue) to avoid mis-calc of the first stack
// offset on PEI::calculateFrameObjectOffsets.
unsigned ArgSize = VA.getValVT().getSizeInBits()/8;
- LastStackArgEndOffset = FirstStackArgLoc + VA.getLocMemOffset() + ArgSize;
+ LastStackArgEndOffset = FirstStackArgLoc + VA.getLocMemOffset() +
+ ArgSize;
int FI = MFI->CreateFixedObject(ArgSize, 0, true);
MipsFI->recordLoadArgsFI(FI, -(4 +
(FirstStackArgLoc + VA.getLocMemOffset())));
return Chain;
}
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// Return Value Calling Convention Implementation
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
SDValue
MipsTargetLowering::LowerReturn(SDValue Chain,
if (DAG.getMachineFunction().getRegInfo().liveout_empty()) {
for (unsigned i = 0; i != RVLocs.size(); ++i)
if (RVLocs[i].isRegLoc())
- DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg());
+ DAG.getMachineFunction().getRegInfo()
+ .addLiveOut(RVLocs[i].getLocReg());
}
SDValue Flag;
Chain, DAG.getRegister(Mips::RA, MVT::i32));
}
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
// Mips Inline Assembly Support
-//===----------------------------------------------------------------------===//
+//===---------------------------------------------------------------------===//
/// getConstraintType - Given a constraint letter, return the type of
/// constraint it is for this target.