mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-23 17:32:49 +00:00
Several changes to Mips backend, experimental fp support being the most
important. - Cleanup in the Subtarget info with addition of new features, not all support yet, but they allow the future inclusion of features easier. Among new features, we have : Arch family info (mips1, mips2, ...), ABI info (o32, eabi), 64-bit integer and float registers, allegrex vector FPU (VFPU), single float only support. - TargetMachine now detects allegrex core. - Added allegrex (Mips32r2) sext_inreg instructions. - *Added Float Point Instructions*, handling single float only, and aliased accesses for 32-bit FPUs. - Some cleanup in FP instruction formats and FP register classes. - Calling conventions improved to support mips 32-bit EABI. - Added Asm Printer support for fp cond codes. - Added support for sret copy to a return register. - EABI support added into LowerCALL and FORMAL_ARGS. - MipsFunctionInfo now keeps a virtual register per function to track the sret on function entry until function ret. - MipsInstrInfo FP support into methods (isMoveInstr, isLoadFromStackSlot, ...), FP cond codes mapping and initial FP Branch Analysis. - Two new Mips SDNode to handle fp branch and compare instructions : FPBrcond, FPCmp - MipsTargetLowering : handling different FP classes, Allegrex support, sret return copy, no homing location within EABI, non 32-bit stack objects arguments, and asm constraint for float. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53146 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
126d90770b
commit
225ca9cdd7
@ -16,7 +16,7 @@
|
||||
include "../Target.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Descriptions
|
||||
// Register File, Calling Conv, Instruction Descriptions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "MipsRegisterInfo.td"
|
||||
@ -30,22 +30,43 @@ def MipsInstrInfo : InstrInfo {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CPU Directives //
|
||||
// Mips Subtarget features //
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Not currently supported, but work as SubtargetFeature placeholder.
|
||||
def FeatureMipsIII : SubtargetFeature<"mips3", "IsMipsIII", "true",
|
||||
"MipsIII ISA Support">;
|
||||
def FeatureGP64Bit : SubtargetFeature<"gp64", "IsGP64bit", "true",
|
||||
"General Purpose Registers are 64-bit wide.">;
|
||||
def FeatureFP64Bit : SubtargetFeature<"fp64", "IsFP64bit", "true",
|
||||
"Support 64-bit FP registers.">;
|
||||
def FeatureSingleFloat : SubtargetFeature<"single-float", "IsSingleFloat",
|
||||
"true", "Only supports single precision float">;
|
||||
def FeatureAllegrexVFPU : SubtargetFeature<"allegrex-vfpu", "HasAllegrexVFPU",
|
||||
"true", "Enable Allegrex VFPU instructions.">;
|
||||
def FeatureMips2 : SubtargetFeature<"mips2", "MipsArchVersion", "Mips2",
|
||||
"Mips2 ISA Support">;
|
||||
def FeatureO32 : SubtargetFeature<"o32", "MipsABI", "O32",
|
||||
"Enable o32 ABI">;
|
||||
def FeatureEABI : SubtargetFeature<"eabi", "MipsABI", "EABI",
|
||||
"Enable eabi ABI">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips processors supported.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def : Processor<"mips1", MipsGenericItineraries, []>;
|
||||
def : Processor<"r2000", MipsGenericItineraries, []>;
|
||||
def : Processor<"r3000", MipsGenericItineraries, []>;
|
||||
class Proc<string Name, list<SubtargetFeature> Features>
|
||||
: Processor<Name, MipsGenericItineraries, Features>;
|
||||
|
||||
def : Proc<"mips1", []>;
|
||||
def : Proc<"r2000", []>;
|
||||
def : Proc<"r3000", []>;
|
||||
|
||||
def : Proc<"mips2", [FeatureMips2]>;
|
||||
def : Proc<"r6000", [FeatureMips2]>;
|
||||
|
||||
// Allegrex is a 32bit subset of r4000, both for interger and fp registers,
|
||||
// but much more similar to Mips2 than Mips3.
|
||||
def : Proc<"allegrex", [FeatureMips2, FeatureSingleFloat, FeatureAllegrexVFPU,
|
||||
FeatureEABI]>;
|
||||
|
||||
def Mips : Target {
|
||||
let InstructionSet = MipsInstrInfo;
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,8 @@ namespace {
|
||||
void printOperand(const MachineInstr *MI, int opNum);
|
||||
void printMemOperand(const MachineInstr *MI, int opNum,
|
||||
const char *Modifier = 0);
|
||||
void printFCCOperand(const MachineInstr *MI, int opNum,
|
||||
const char *Modifier = 0);
|
||||
|
||||
unsigned int getSavedRegsBitmask(bool isFloat, MachineFunction &MF);
|
||||
void printHex32(unsigned int Value);
|
||||
@ -428,6 +430,13 @@ printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier)
|
||||
O << ")";
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::
|
||||
printFCCOperand(const MachineInstr *MI, int opNum, const char *Modifier)
|
||||
{
|
||||
const MachineOperand& MO = MI->getOperand(opNum);
|
||||
O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
|
||||
}
|
||||
|
||||
bool MipsAsmPrinter::
|
||||
doInitialization(Module &M)
|
||||
{
|
||||
|
@ -14,18 +14,9 @@ class CCIfSubtarget<string F, CCAction A>:
|
||||
CCIf<!strconcat("State.getTarget().getSubtarget<MipsSubtarget>().", F), A>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips Return Value Calling Convention
|
||||
// Mips O32 Calling Convention
|
||||
//===----------------------------------------------------------------------===//
|
||||
def RetCC_Mips : CallingConv<[
|
||||
// i32 are returned in registers V0, V1
|
||||
CCIfType<[i32], CCAssignToReg<[V0, V1]>>
|
||||
]>;
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips Argument Calling Conventions
|
||||
//===----------------------------------------------------------------------===//
|
||||
def CC_Mips : CallingConv<[
|
||||
def CC_MipsO32 : CallingConv<[
|
||||
// Promote i8/i16 arguments to i32.
|
||||
CCIfType<[i8, i16], CCPromoteToType<i32>>,
|
||||
|
||||
@ -37,3 +28,62 @@ def CC_Mips : CallingConv<[
|
||||
CCIfType<[i32], CCAssignToStack<4, 4>>
|
||||
]>;
|
||||
|
||||
def RetCC_MipsO32 : CallingConv<[
|
||||
// i32 are returned in registers V0, V1
|
||||
CCIfType<[i32], CCAssignToReg<[V0, V1]>>
|
||||
]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips EABI Calling Convention
|
||||
//===----------------------------------------------------------------------===//
|
||||
def CC_MipsEABI : CallingConv<[
|
||||
// Promote i8/i16 arguments to i32.
|
||||
CCIfType<[i8, i16], CCPromoteToType<i32>>,
|
||||
|
||||
// Integer arguments are passed in integer registers.
|
||||
CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3]>>,
|
||||
|
||||
// Single fp arguments are passed in pairs within 32-bit mode
|
||||
CCIfType<[f32], CCIfSubtarget<"isSingleFloat()",
|
||||
CCAssignToReg<[F12, F13, F14, F15, F16, F17, F18, F19]>>>,
|
||||
|
||||
CCIfType<[f32], CCIfSubtarget<"isNotSingleFloat()",
|
||||
CCAssignToReg<[F12, F14, F16, F18]>>>,
|
||||
|
||||
// The first 4 doubl fp arguments are passed in single fp registers.
|
||||
CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()",
|
||||
CCAssignToReg<[D6, D7, D8, D9]>>>,
|
||||
|
||||
// Integer values get stored in stack slots that are 4 bytes in
|
||||
// size and 4-byte aligned.
|
||||
CCIfType<[i32, f32], CCAssignToStack<4, 4>>,
|
||||
|
||||
// Integer values get stored in stack slots that are 8 bytes in
|
||||
// size and 8-byte aligned.
|
||||
CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToStack<8, 8>>>
|
||||
]>;
|
||||
|
||||
def RetCC_MipsEABI : CallingConv<[
|
||||
// i32 are returned in registers V0, V1
|
||||
CCIfType<[i32], CCAssignToReg<[V0, V1]>>,
|
||||
|
||||
// f32 are returned in registers F0, F1
|
||||
CCIfType<[f32], CCAssignToReg<[F0, F1]>>,
|
||||
|
||||
// f64 are returned in register D0
|
||||
CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToReg<[D0]>>>
|
||||
]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips Calling Convention Dispatch
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CC_Mips : CallingConv<[
|
||||
CCIfSubtarget<"isABI_EABI()", CCDelegateTo<CC_MipsEABI>>,
|
||||
CCDelegateTo<CC_MipsO32>
|
||||
]>;
|
||||
|
||||
def RetCC_Mips : CallingConv<[
|
||||
CCIfSubtarget<"isABI_EABI()", CCDelegateTo<RetCC_MipsEABI>>,
|
||||
CCDelegateTo<RetCC_MipsO32>
|
||||
]>;
|
||||
|
@ -58,13 +58,12 @@ class VISIBILITY_HIDDEN MipsDAGToDAGISel : public SelectionDAGISel {
|
||||
|
||||
/// Subtarget - Keep a pointer to the MipsSubtarget around so that we can
|
||||
/// make the right decision when generating code for different targets.
|
||||
//TODO: add initialization on constructor
|
||||
//const MipsSubtarget *Subtarget;
|
||||
const MipsSubtarget &Subtarget;
|
||||
|
||||
public:
|
||||
MipsDAGToDAGISel(MipsTargetMachine &tm) :
|
||||
SelectionDAGISel(MipsLowering),
|
||||
TM(tm), MipsLowering(*TM.getTargetLowering()) {}
|
||||
MipsDAGToDAGISel(MipsTargetMachine &tm) : SelectionDAGISel(MipsLowering),
|
||||
TM(tm), MipsLowering(*TM.getTargetLowering()),
|
||||
Subtarget(tm.getSubtarget<MipsSubtarget>()) {}
|
||||
|
||||
virtual void InstructionSelect(SelectionDAG &SD);
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "MipsISelLowering.h"
|
||||
#include "MipsMachineFunction.h"
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "MipsSubtarget.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
@ -44,6 +45,8 @@ getTargetNodeName(unsigned Opcode) const
|
||||
case MipsISD::Lo : return "MipsISD::Lo";
|
||||
case MipsISD::Ret : return "MipsISD::Ret";
|
||||
case MipsISD::SelectCC : return "MipsISD::SelectCC";
|
||||
case MipsISD::FPBrcond : return "MipsISD::FPBrcond";
|
||||
case MipsISD::FPCmp : return "MipsISD::FPCmp";
|
||||
default : return NULL;
|
||||
}
|
||||
}
|
||||
@ -51,6 +54,8 @@ getTargetNodeName(unsigned Opcode) const
|
||||
MipsTargetLowering::
|
||||
MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM)
|
||||
{
|
||||
Subtarget = &TM.getSubtarget<MipsSubtarget>();
|
||||
|
||||
// Mips does not have i1 type, so use i32 for
|
||||
// setcc operations results (slt, sgt, ...).
|
||||
setSetCCResultContents(ZeroOrOneSetCCResult);
|
||||
@ -61,12 +66,24 @@ MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM)
|
||||
// Set up the register classes
|
||||
addRegisterClass(MVT::i32, Mips::CPURegsRegisterClass);
|
||||
|
||||
// When dealing with single precision only, use libcalls
|
||||
if (!Subtarget->isSingleFloat()) {
|
||||
addRegisterClass(MVT::f32, Mips::AFGR32RegisterClass);
|
||||
if (!Subtarget->isFP64bit())
|
||||
addRegisterClass(MVT::f64, Mips::AFGR64RegisterClass);
|
||||
} else
|
||||
addRegisterClass(MVT::f32, Mips::FGR32RegisterClass);
|
||||
|
||||
// Custom
|
||||
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
|
||||
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
|
||||
setOperationAction(ISD::RET, MVT::Other, Custom);
|
||||
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
|
||||
|
||||
if (Subtarget->isSingleFloat())
|
||||
setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
|
||||
|
||||
// Load extented operations for i1 types must be promoted
|
||||
setLoadXAction(ISD::EXTLOAD, MVT::i1, Promote);
|
||||
@ -80,6 +97,11 @@ MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM)
|
||||
setOperationAction(ISD::SELECT, MVT::i32, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
|
||||
|
||||
if (!Subtarget->isAllegrex()) {
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
|
||||
}
|
||||
|
||||
// Mips not supported intrinsics.
|
||||
setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand);
|
||||
|
||||
@ -323,7 +345,7 @@ LowerCALL(SDOperand Op, SelectionDAG &DAG)
|
||||
/// LowerCCCCallTo - functions arguments are copied from virtual
|
||||
/// regs to (physical regs)/(stack frame), CALLSEQ_START and
|
||||
/// CALLSEQ_END are emitted.
|
||||
/// TODO: isVarArg, isTailCall, sret.
|
||||
/// TODO: isVarArg, isTailCall.
|
||||
SDOperand MipsTargetLowering::
|
||||
LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
|
||||
{
|
||||
@ -351,10 +373,14 @@ LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
|
||||
Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes,
|
||||
getPointerTy()));
|
||||
|
||||
SmallVector<std::pair<unsigned, SDOperand>, 8> RegsToPass;
|
||||
// With EABI is it possible to have 16 args on registers.
|
||||
SmallVector<std::pair<unsigned, SDOperand>, 16> RegsToPass;
|
||||
SmallVector<SDOperand, 8> MemOpChains;
|
||||
|
||||
int LastStackLoc = 0;
|
||||
// First/LastArgStackLoc contains the first/last
|
||||
// "at stack" argument location.
|
||||
int LastArgStackLoc = 0;
|
||||
unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16);
|
||||
|
||||
// Walk the register/memloc assignments, inserting copies/loads.
|
||||
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||
@ -385,14 +411,16 @@ LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Register cant get to this point...
|
||||
assert(VA.isMemLoc());
|
||||
|
||||
// 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.
|
||||
LastStackLoc = (16 + VA.getLocMemOffset());
|
||||
// 16 bytes which are alwayes reserved won't be overwritten
|
||||
// if O32 ABI is used. For EABI the first address is zero.
|
||||
LastArgStackLoc = (FirstStackArgLoc + VA.getLocMemOffset());
|
||||
int FI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8,
|
||||
LastStackLoc);
|
||||
LastArgStackLoc);
|
||||
|
||||
SDOperand PtrOff = DAG.getFrameIndex(FI,getPointerTy());
|
||||
|
||||
@ -401,8 +429,8 @@ LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
|
||||
MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
|
||||
}
|
||||
|
||||
// Transform all store nodes into one single node because
|
||||
// all store nodes are independent of each other.
|
||||
// Transform all store nodes into one single node because all store
|
||||
// nodes are independent of each other.
|
||||
if (!MemOpChains.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
|
||||
&MemOpChains[0], MemOpChains.size());
|
||||
@ -460,18 +488,18 @@ LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
|
||||
// emited CALL's to restore GP.
|
||||
if (getTargetMachine().getRelocationModel() == Reloc::PIC_) {
|
||||
// Function can have an arbitrary number of calls, so
|
||||
// hold the LastStackLoc with the biggest offset.
|
||||
// hold the LastArgStackLoc with the biggest offset.
|
||||
int FI;
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
if (LastStackLoc >= MipsFI->getGPStackOffset()) {
|
||||
LastStackLoc = (!LastStackLoc) ? (16) : (LastStackLoc+4);
|
||||
if (LastArgStackLoc >= MipsFI->getGPStackOffset()) {
|
||||
LastArgStackLoc = (!LastArgStackLoc) ? (16) : (LastArgStackLoc+4);
|
||||
// Create the frame index only once. SPOffset here can be anything
|
||||
// (this will be fixed on processFunctionBeforeFrameFinalized)
|
||||
if (MipsFI->getGPStackOffset() == -1) {
|
||||
FI = MFI->CreateFixedObject(4, 0);
|
||||
MipsFI->setGPFI(FI);
|
||||
}
|
||||
MipsFI->setGPStackOffset(LastStackLoc);
|
||||
MipsFI->setGPStackOffset(LastArgStackLoc);
|
||||
}
|
||||
|
||||
// Reload GP value.
|
||||
@ -543,7 +571,7 @@ LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG)
|
||||
/// LowerCCCArguments - transform physical registers into
|
||||
/// virtual registers and generate load operations for
|
||||
/// arguments places on the stack.
|
||||
/// TODO: isVarArg, sret
|
||||
/// TODO: isVarArg
|
||||
SDOperand MipsTargetLowering::
|
||||
LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
|
||||
{
|
||||
@ -566,9 +594,11 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
|
||||
CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs);
|
||||
|
||||
CCInfo.AnalyzeFormalArguments(Op.Val, CC_Mips);
|
||||
SmallVector<SDOperand, 8> ArgValues;
|
||||
SmallVector<SDOperand, 16> ArgValues;
|
||||
SDOperand StackPtr;
|
||||
|
||||
unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16);
|
||||
|
||||
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||
|
||||
CCValAssign &VA = ArgLocs[i];
|
||||
@ -579,9 +609,17 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
|
||||
TargetRegisterClass *RC;
|
||||
|
||||
if (RegVT == MVT::i32)
|
||||
RC = Mips::CPURegsRegisterClass;
|
||||
else
|
||||
assert(0 && "support only Mips::CPURegsRegisterClass");
|
||||
RC = Mips::CPURegsRegisterClass;
|
||||
else if (RegVT == MVT::f32) {
|
||||
if (Subtarget->isSingleFloat())
|
||||
RC = Mips::FGR32RegisterClass;
|
||||
else
|
||||
RC = Mips::AFGR32RegisterClass;
|
||||
} else if (RegVT == MVT::f64) {
|
||||
if (!Subtarget->isSingleFloat())
|
||||
RC = Mips::AFGR64RegisterClass;
|
||||
} else
|
||||
assert(0 && "RegVT not supported by FORMAL_ARGUMENTS Lowering");
|
||||
|
||||
// Transform the arguments stored on
|
||||
// physical registers into virtual ones
|
||||
@ -605,8 +643,7 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
|
||||
|
||||
// To meet ABI, when VARARGS are passed on registers, the registers
|
||||
// must have their values written to the caller stack frame.
|
||||
if (isVarArg) {
|
||||
|
||||
if ((isVarArg) && (Subtarget->isABI_O32())) {
|
||||
if (StackPtr.Val == 0)
|
||||
StackPtr = DAG.getRegister(StackReg, getPointerTy());
|
||||
|
||||
@ -627,7 +664,8 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
|
||||
ArgValues.push_back(DAG.getStore(Root, ArgValue, PtrOff, NULL, 0));
|
||||
}
|
||||
|
||||
} else {
|
||||
} else { // VA.isRegLoc()
|
||||
|
||||
// sanity check
|
||||
assert(VA.isMemLoc());
|
||||
|
||||
@ -639,14 +677,30 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
|
||||
// be used on emitPrologue) to avoid mis-calc of the first stack
|
||||
// offset on PEI::calculateFrameObjectOffsets.
|
||||
// Arguments are always 32-bit.
|
||||
int FI = MFI->CreateFixedObject(4, 0);
|
||||
MipsFI->recordLoadArgsFI(FI, -(4+(16+VA.getLocMemOffset())));
|
||||
unsigned ArgSize = VA.getLocVT().getSizeInBits()/8;
|
||||
int FI = MFI->CreateFixedObject(ArgSize, 0);
|
||||
MipsFI->recordLoadArgsFI(FI, -(ArgSize+
|
||||
(FirstStackArgLoc + VA.getLocMemOffset())));
|
||||
|
||||
// Create load nodes to retrieve arguments from the stack
|
||||
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
|
||||
ArgValues.push_back(DAG.getLoad(VA.getValVT(), Root, FIN, NULL, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// The mips ABIs for returning structs by value requires that we copy
|
||||
// the sret argument into $v0 for the return. Save the argument into
|
||||
// a virtual register so that we can access it from the return points.
|
||||
if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) {
|
||||
unsigned Reg = MipsFI->getSRetReturnReg();
|
||||
if (!Reg) {
|
||||
Reg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i32));
|
||||
MipsFI->setSRetReturnReg(Reg);
|
||||
}
|
||||
SDOperand Copy = DAG.getCopyToReg(DAG.getEntryNode(), Reg, ArgValues[0]);
|
||||
Root = DAG.getNode(ISD::TokenFactor, MVT::Other, Copy, Root);
|
||||
}
|
||||
|
||||
ArgValues.push_back(Root);
|
||||
|
||||
// Return the new list of results.
|
||||
@ -699,6 +753,23 @@ LowerRET(SDOperand Op, SelectionDAG &DAG)
|
||||
Flag = Chain.getValue(1);
|
||||
}
|
||||
|
||||
// The mips ABIs for returning structs by value requires that we copy
|
||||
// the sret argument into $v0 for the return. We saved the argument into
|
||||
// a virtual register in the entry block, so now we copy the value out
|
||||
// and into $v0.
|
||||
if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) {
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
unsigned Reg = MipsFI->getSRetReturnReg();
|
||||
|
||||
if (!Reg)
|
||||
assert(0 && "sret virtual register not created in the entry block");
|
||||
SDOperand Val = DAG.getCopyFromReg(Chain, Reg, getPointerTy());
|
||||
|
||||
Chain = DAG.getCopyToReg(Chain, Mips::V0, Val, Flag);
|
||||
Flag = Chain.getValue(1);
|
||||
}
|
||||
|
||||
// Return on Mips is always a "jr $ra"
|
||||
if (Flag.Val)
|
||||
return DAG.getNode(MipsISD::Ret, MVT::Other,
|
||||
@ -717,19 +788,20 @@ LowerRET(SDOperand Op, SelectionDAG &DAG)
|
||||
MipsTargetLowering::ConstraintType MipsTargetLowering::
|
||||
getConstraintType(const std::string &Constraint) const
|
||||
{
|
||||
// Mips specific constrainy
|
||||
// GCC config/mips/constraints.md
|
||||
//
|
||||
// 'd' : An address register. Equivalent to r
|
||||
// unless generating MIPS16 code.
|
||||
// 'y' : Equivalent to r; retained for
|
||||
// backwards compatibility.
|
||||
// 'f' : Float Point registers.
|
||||
if (Constraint.size() == 1) {
|
||||
// Mips specific constrainy
|
||||
// GCC config/mips/constraints.md
|
||||
//
|
||||
// 'd' : An address register. Equivalent to r
|
||||
// unless generating MIPS16 code.
|
||||
// 'y' : Equivalent to r; retained for
|
||||
// backwards compatibility.
|
||||
//
|
||||
switch (Constraint[0]) {
|
||||
default : break;
|
||||
case 'd':
|
||||
case 'y':
|
||||
case 'f':
|
||||
return C_RegisterClass;
|
||||
break;
|
||||
}
|
||||
@ -737,6 +809,9 @@ getConstraintType(const std::string &Constraint) const
|
||||
return TargetLowering::getConstraintType(Constraint);
|
||||
}
|
||||
|
||||
/// getRegClassForInlineAsmConstraint - Given a constraint letter (e.g. "r"),
|
||||
/// return a list of registers that can be used to satisfy the constraint.
|
||||
/// This should only be used for C_RegisterClass constraints.
|
||||
std::pair<unsigned, const TargetRegisterClass*> MipsTargetLowering::
|
||||
getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const
|
||||
{
|
||||
@ -744,12 +819,23 @@ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const
|
||||
switch (Constraint[0]) {
|
||||
case 'r':
|
||||
return std::make_pair(0U, Mips::CPURegsRegisterClass);
|
||||
break;
|
||||
case 'f':
|
||||
if (VT == MVT::f32)
|
||||
if (Subtarget->isSingleFloat())
|
||||
return std::make_pair(0U, Mips::FGR32RegisterClass);
|
||||
else
|
||||
return std::make_pair(0U, Mips::AFGR32RegisterClass);
|
||||
if (VT == MVT::f64)
|
||||
if ((!Subtarget->isSingleFloat()) && (!Subtarget->isFP64bit()))
|
||||
return std::make_pair(0U, Mips::AFGR64RegisterClass);
|
||||
}
|
||||
}
|
||||
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
|
||||
}
|
||||
|
||||
/// Given a register class constraint, like 'r', if this corresponds directly
|
||||
/// to an LLVM register class, return a register of 0 and the register class
|
||||
/// pointer.
|
||||
std::vector<unsigned> MipsTargetLowering::
|
||||
getRegClassForInlineAsmConstraint(const std::string &Constraint,
|
||||
MVT VT) const
|
||||
@ -763,15 +849,29 @@ getRegClassForInlineAsmConstraint(const std::string &Constraint,
|
||||
// GCC Mips Constraint Letters
|
||||
case 'd':
|
||||
case 'y':
|
||||
return make_vector<unsigned>(Mips::V0, Mips::V1, Mips::A0,
|
||||
Mips::A1, Mips::A2, Mips::A3,
|
||||
Mips::T0, Mips::T1, Mips::T2,
|
||||
Mips::T3, Mips::T4, Mips::T5,
|
||||
Mips::T6, Mips::T7, Mips::S0,
|
||||
Mips::S1, Mips::S2, Mips::S3,
|
||||
Mips::S4, Mips::S5, Mips::S6,
|
||||
Mips::S7, Mips::T8, Mips::T9, 0);
|
||||
break;
|
||||
return make_vector<unsigned>(Mips::T0, Mips::T1, Mips::T2, Mips::T3,
|
||||
Mips::T4, Mips::T5, Mips::T6, Mips::T7, Mips::S0, Mips::S1,
|
||||
Mips::S2, Mips::S3, Mips::S4, Mips::S5, Mips::S6, Mips::S7,
|
||||
Mips::T8, 0);
|
||||
|
||||
case 'f':
|
||||
if (VT == MVT::f32)
|
||||
if (Subtarget->isSingleFloat())
|
||||
return make_vector<unsigned>(Mips::F2, Mips::F3, Mips::F4, Mips::F5,
|
||||
Mips::F6, Mips::F7, Mips::F8, Mips::F9, Mips::F10, Mips::F11,
|
||||
Mips::F20, Mips::F21, Mips::F22, Mips::F23, Mips::F24,
|
||||
Mips::F25, Mips::F26, Mips::F27, Mips::F28, Mips::F29,
|
||||
Mips::F30, Mips::F31, 0);
|
||||
else
|
||||
return make_vector<unsigned>(Mips::F2, Mips::F4, Mips::F6, Mips::F8,
|
||||
Mips::F10, Mips::F20, Mips::F22, Mips::F24, Mips::F26,
|
||||
Mips::F28, Mips::F30, 0);
|
||||
|
||||
if (VT == MVT::f64)
|
||||
if ((!Subtarget->isSingleFloat()) && (!Subtarget->isFP64bit()))
|
||||
return make_vector<unsigned>(Mips::D1, Mips::D2, Mips::D3, Mips::D4,
|
||||
Mips::D5, Mips::D10, Mips::D11, Mips::D12, Mips::D13,
|
||||
Mips::D14, Mips::D15, 0);
|
||||
}
|
||||
return std::vector<unsigned>();
|
||||
}
|
||||
|
@ -40,6 +40,12 @@ namespace llvm {
|
||||
// Select CC Pseudo Instruction
|
||||
SelectCC,
|
||||
|
||||
// Float Point Branch Conditional
|
||||
FPBrcond,
|
||||
|
||||
// Float Point Compare
|
||||
FPCmp,
|
||||
|
||||
// Return
|
||||
Ret
|
||||
};
|
||||
@ -69,6 +75,9 @@ namespace llvm {
|
||||
MVT getSetCCResultType(const SDOperand &) const;
|
||||
|
||||
private:
|
||||
// Subtarget Info
|
||||
const MipsSubtarget *Subtarget;
|
||||
|
||||
// Lower Operand helpers
|
||||
SDOperand LowerCCCArguments(SDOperand Op, SelectionDAG &DAG);
|
||||
SDOperand LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC);
|
||||
|
296
lib/Target/Mips/MipsInstrFPU.td
Normal file
296
lib/Target/Mips/MipsInstrFPU.td
Normal file
@ -0,0 +1,296 @@
|
||||
//===- MipsInstrFPU.td - Mips FPU Instruction Information -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the Mips implementation of the TargetInstrInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Float Point Instructions
|
||||
// ------------------------
|
||||
// * 64bit fp:
|
||||
// - 32 64-bit registers (default mode)
|
||||
// - 16 even 32-bit registers (32-bit compatible mode) for
|
||||
// single and double access.
|
||||
// * 32bit fp:
|
||||
// - 16 even 32-bit registers - single and double (aliased)
|
||||
// - 32 32-bit registers (within single-only mode)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Float Point Compare and Branch
|
||||
def SDT_MipsFPBrcond : SDTypeProfile<0, 3, [SDTCisSameAs<0, 2>, SDTCisInt<0>,
|
||||
SDTCisVT<1, OtherVT>]>;
|
||||
def SDT_MipsFPCmp : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>, SDTCisFP<0>,
|
||||
SDTCisInt<2>]>;
|
||||
def MipsFPBrcond : SDNode<"MipsISD::FPBrcond", SDT_MipsFPBrcond,
|
||||
[SDNPHasChain]>;
|
||||
def MipsFPCmp : SDNode<"MipsISD::FPCmp", SDT_MipsFPCmp>;
|
||||
|
||||
// Operand for printing out a condition code.
|
||||
let PrintMethod = "printFCCOperand" in
|
||||
def condcode : Operand<i32>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Feature predicates.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def In32BitMode : Predicate<"!Subtarget.isFP64bit()">;
|
||||
def In64BitMode : Predicate<"Subtarget.isFP64bit()">;
|
||||
def IsSingleFloat : Predicate<"Subtarget.isSingleFloat()">;
|
||||
def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction Class Templates
|
||||
//
|
||||
// A set of multiclasses is used to address this in one shot.
|
||||
// SO32 - single precision only, uses all 32 32-bit fp registers
|
||||
// require FGR32 Register Class and IsSingleFloat
|
||||
// AS32 - 16 even fp registers are used for single precision
|
||||
// require AFGR32 Register Class and In32BitMode
|
||||
// S64 - 32 64 bit registers are used to hold 32-bit single precision values.
|
||||
// require FGR64 Register Class and In64BitMode
|
||||
// D32 - 16 even fp registers are used for double precision
|
||||
// require AFGR64 Register Class and In32BitMode
|
||||
// D64 - 32 64 bit registers are used to hold 64-bit double precision values.
|
||||
// require FGR64 Register Class and In64BitMode
|
||||
//
|
||||
// Only SO32, AS32 and D32 are supported right now.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
multiclass FFR1_1<bits<6> funct, string asmstr>
|
||||
{
|
||||
def _SO32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), (ins FGR32:$fs),
|
||||
!strconcat(asmstr, ".s $fd, $fs"), []>, Requires<[IsSingleFloat]>;
|
||||
|
||||
def _AS32 : FFR<0x11, funct, 0x0, (outs AFGR32:$fd), (ins AFGR32:$fs),
|
||||
!strconcat(asmstr, ".s $fd, $fs"), []>, Requires<[In32BitMode]>;
|
||||
|
||||
def _D32 : FFR<0x11, funct, 0x1, (outs AFGR64:$fd), (ins AFGR64:$fs),
|
||||
!strconcat(asmstr, ".d $fd, $fs"), []>, Requires<[In32BitMode]>;
|
||||
}
|
||||
|
||||
multiclass FFR1_2<bits<6> funct, string asmstr, SDNode FOp>
|
||||
{
|
||||
def _SO32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), (ins FGR32:$fs),
|
||||
!strconcat(asmstr, ".s $fd, $fs"),
|
||||
[(set FGR32:$fd, (FOp FGR32:$fs))]>, Requires<[IsSingleFloat]>;
|
||||
|
||||
def _AS32 : FFR<0x11, funct, 0x0, (outs AFGR32:$fd), (ins AFGR32:$fs),
|
||||
!strconcat(asmstr, ".s $fd, $fs"),
|
||||
[(set AFGR32:$fd, (FOp AFGR32:$fs))]>, Requires<[In32BitMode]>;
|
||||
|
||||
def _D32 : FFR<0x11, funct, 0x1, (outs AFGR64:$fd), (ins AFGR64:$fs),
|
||||
!strconcat(asmstr, ".d $fd, $fs"),
|
||||
[(set AFGR64:$fd, (FOp AFGR64:$fs))]>, Requires<[In32BitMode]>;
|
||||
}
|
||||
|
||||
class FFR1_3<bits<6> funct, bits<5> fmt, RegisterClass RcSrc,
|
||||
RegisterClass RcDst, string asmstr>:
|
||||
FFR<0x11, funct, fmt, (outs RcSrc:$fd), (ins RcDst:$fs),
|
||||
!strconcat(asmstr, " $fd, $fs"), []>;
|
||||
|
||||
|
||||
multiclass FFR1_4<bits<6> funct, string asmstr, SDNode FOp> {
|
||||
def _SO32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), (ins FGR32:$fs, FGR32:$ft),
|
||||
!strconcat(asmstr, ".s $fd, $fs, $ft"),
|
||||
[(set FGR32:$fd, (FOp FGR32:$fs, FGR32:$ft))]>,
|
||||
Requires<[IsSingleFloat]>;
|
||||
|
||||
def _AS32 : FFR<0x11, funct, 0x0, (outs AFGR32:$fd),
|
||||
(ins AFGR32:$fs, AFGR32:$ft),
|
||||
!strconcat(asmstr, ".s $fd, $fs, $ft"),
|
||||
[(set AFGR32:$fd, (FOp AFGR32:$fs, AFGR32:$ft))]>,
|
||||
Requires<[In32BitMode]>;
|
||||
|
||||
def _D32 : FFR<0x11, funct, 0x1, (outs AFGR64:$fd),
|
||||
(ins AFGR64:$fs, AFGR64:$ft),
|
||||
!strconcat(asmstr, ".d $fd, $fs, $ft"),
|
||||
[(set AFGR64:$fd, (FOp AFGR64:$fs, AFGR64:$ft))]>,
|
||||
Requires<[In32BitMode]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Float Point Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
let ft = 0 in {
|
||||
defm FLOOR_W : FFR1_1<0b001111, "floor.w">;
|
||||
defm CEIL_W : FFR1_1<0b001110, "ceil.w">;
|
||||
defm ROUND_W : FFR1_1<0b001100, "round.w">;
|
||||
defm TRUNC_W : FFR1_1<0b001101, "trunc.w">;
|
||||
defm CVTW : FFR1_1<0b100100, "cvt.w">;
|
||||
defm FMOV : FFR1_1<0b000110, "mov">;
|
||||
|
||||
defm FABS : FFR1_2<0b000101, "abs", fabs>;
|
||||
defm FNEG : FFR1_2<0b000111, "neg", fneg>;
|
||||
defm FSQRT : FFR1_2<0b000100, "sqrt", fsqrt>;
|
||||
|
||||
let Predicates = [IsNotSingleFloat] in {
|
||||
/// Ceil to long signed integer
|
||||
def CEIL_LS : FFR1_3<0b001010, 0x0, AFGR32, AFGR32, "ceil.l">;
|
||||
def CEIL_LD : FFR1_3<0b001010, 0x1, AFGR64, AFGR64, "ceil.l">;
|
||||
|
||||
/// Round to long signed integer
|
||||
def ROUND_LS : FFR1_3<0b001000, 0x0, AFGR32, AFGR32, "round.l">;
|
||||
def ROUND_LD : FFR1_3<0b001000, 0x1, AFGR64, AFGR64, "round.l">;
|
||||
|
||||
/// Floor to long signed integer
|
||||
def FLOOR_LS : FFR1_3<0b001011, 0x0, AFGR32, AFGR32, "floor.l">;
|
||||
def FLOOR_LD : FFR1_3<0b001011, 0x1, AFGR64, AFGR64, "floor.l">;
|
||||
|
||||
/// Trunc to long signed integer
|
||||
def TRUNC_LS : FFR1_3<0b001001, 0x0, AFGR32, AFGR32, "trunc.l">;
|
||||
def TRUNC_LD : FFR1_3<0b001001, 0x1, AFGR64, AFGR64, "trunc.l">;
|
||||
|
||||
/// Convert to long signed integer
|
||||
def CVTL_S : FFR1_3<0b100101, 0x0, AFGR32, AFGR32, "cvt.l">;
|
||||
def CVTL_D : FFR1_3<0b100101, 0x1, AFGR64, AFGR64, "cvt.l">;
|
||||
|
||||
/// Convert to Double Precison
|
||||
def CVTD_S32 : FFR1_3<0b100001, 0x0, AFGR64, FGR32, "cvt.d.s">;
|
||||
def CVTD_W32 : FFR1_3<0b100001, 0x2, AFGR64, FGR32, "cvt.d.w">;
|
||||
def CVTD_L32 : FFR1_3<0b100001, 0x3, AFGR64, AFGR64, "cvt.d.l">;
|
||||
|
||||
/// Convert to Single Precison
|
||||
def CVTS_D32 : FFR1_3<0b100000, 0x1, FGR32, AFGR64, "cvt.s.d">;
|
||||
def CVTS_L32 : FFR1_3<0b100000, 0x3, FGR32, AFGR64, "cvt.s.l">;
|
||||
}
|
||||
|
||||
/// Convert to Single Precison
|
||||
def CVTS_W32 : FFR1_3<0b100000, 0x2, FGR32, FGR32, "cvt.s.w">,
|
||||
Requires<[IsSingleFloat]>;
|
||||
}
|
||||
|
||||
// The odd-numbered registers are only referenced when doing loads,
|
||||
// stores, and moves between floating-point and integer registers.
|
||||
// When defining instructions, we reference all 32-bit registers,
|
||||
// regardless of register aliasing.
|
||||
let fd = 0 in {
|
||||
/// Move Control Registers From/To CPU Registers
|
||||
///def CFC1 : FFR<0x11, 0x0, 0x2, (outs CPURegs:$rt), (ins FGR32:$fs),
|
||||
/// "cfc1 $rt, $fs", []>;
|
||||
|
||||
///def CTC1 : FFR<0x11, 0x0, 0x6, (outs CPURegs:$rt), (ins FGR32:$fs),
|
||||
/// "ctc1 $rt, $fs", []>;
|
||||
///
|
||||
///def CFC1A : FFR<0x11, 0x0, 0x2, (outs CPURegs:$rt), (ins AFGR32:$fs),
|
||||
/// "cfc1 $rt, $fs", []>;
|
||||
|
||||
///def CTC1A : FFR<0x11, 0x0, 0x6, (outs CPURegs:$rt), (ins AFGR32:$fs),
|
||||
/// "ctc1 $rt, $fs", []>;
|
||||
|
||||
def MFC1 : FFR<0x11, 0x00, 0x00, (outs CPURegs:$rt), (ins FGR32:$fs),
|
||||
"mfc1 $rt, $fs", []>;
|
||||
|
||||
def MTC1 : FFR<0x11, 0x00, 0x04, (outs FGR32:$fs), (ins CPURegs:$rt),
|
||||
"mtc1 $fs, $rt", []>;
|
||||
|
||||
def MFC1A : FFR<0x11, 0x00, 0x00, (outs CPURegs:$rt), (ins AFGR32:$fs),
|
||||
"mfc1 $rt, $fs", []>;
|
||||
|
||||
def MTC1A : FFR<0x11, 0x00, 0x04, (outs AFGR32:$fs), (ins CPURegs:$rt),
|
||||
"mtc1 $fs, $rt", []>;
|
||||
}
|
||||
|
||||
/// Float Point Memory Instructions
|
||||
let Predicates = [IsNotSingleFloat] in {
|
||||
def LDC1 : FFI<0b110101, (outs AFGR64:$ft), (ins mem:$addr),
|
||||
"ldc1 $ft, $addr", [(set AFGR64:$ft, (load addr:$addr))]>;
|
||||
|
||||
def SDC1 : FFI<0b111101, (outs), (ins AFGR64:$ft, mem:$addr),
|
||||
"sdc1 $ft, $addr", [(store AFGR64:$ft, addr:$addr)]>;
|
||||
}
|
||||
|
||||
// LWC1 and SWC1 can always be emited with odd registers.
|
||||
def LWC1 : FFI<0b110001, (outs FGR32:$ft), (ins mem:$addr), "lwc1 $ft, $addr",
|
||||
[(set FGR32:$ft, (load addr:$addr))]>;
|
||||
def SWC1 : FFI<0b111001, (outs), (ins FGR32:$ft, mem:$addr), "swc1 $ft, $addr",
|
||||
[(store FGR32:$ft, addr:$addr)]>;
|
||||
|
||||
def LWC1A : FFI<0b110001, (outs AFGR32:$ft), (ins mem:$addr), "lwc1 $ft, $addr",
|
||||
[(set AFGR32:$ft, (load addr:$addr))]>;
|
||||
def SWC1A : FFI<0b111001, (outs), (ins AFGR32:$ft, mem:$addr), "swc1 $ft, $addr",
|
||||
[(store AFGR32:$ft, addr:$addr)]>;
|
||||
|
||||
/// Floating-point Aritmetic
|
||||
defm FADD : FFR1_4<0x10, "add", fadd>;
|
||||
defm FDIV : FFR1_4<0x03, "div", fdiv>;
|
||||
defm FMUL : FFR1_4<0x02, "mul", fmul>;
|
||||
defm FSUB : FFR1_4<0x01, "sub", fsub>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Float Point Branch Codes
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips branch codes. These correspond to condcode in MipsInstrInfo.h.
|
||||
// They must be kept in synch.
|
||||
def MIPS_BRANCH_F : PatLeaf<(i32 0)>;
|
||||
def MIPS_BRANCH_T : PatLeaf<(i32 1)>;
|
||||
def MIPS_BRANCH_FL : PatLeaf<(i32 2)>;
|
||||
def MIPS_BRANCH_TL : PatLeaf<(i32 3)>;
|
||||
|
||||
/// Float Point Branch of False/True (Likely)
|
||||
let isBranch=1, isTerminator=1, hasDelaySlot=1, base=0x8, Uses=[FCR31] in {
|
||||
class FBRANCH<PatLeaf op, string asmstr> : FFI<0x11, (ops),
|
||||
(ins brtarget:$dst), !strconcat(asmstr, " $dst"),
|
||||
[(MipsFPBrcond op, bb:$dst, FCR31)]>;
|
||||
}
|
||||
def BC1F : FBRANCH<MIPS_BRANCH_F, "bc1f">;
|
||||
def BC1T : FBRANCH<MIPS_BRANCH_T, "bc1t">;
|
||||
def BC1FL : FBRANCH<MIPS_BRANCH_FL, "bc1fl">;
|
||||
def BC1TL : FBRANCH<MIPS_BRANCH_TL, "bc1tl">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Float Point Flag Conditions
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips condition codes. They must correspond to condcode in MipsInstrInfo.h.
|
||||
// They must be kept in synch.
|
||||
def MIPS_FCOND_F : PatLeaf<(i32 0)>;
|
||||
def MIPS_FCOND_UN : PatLeaf<(i32 1)>;
|
||||
def MIPS_FCOND_EQ : PatLeaf<(i32 2)>;
|
||||
def MIPS_FCOND_UEQ : PatLeaf<(i32 3)>;
|
||||
def MIPS_FCOND_OLT : PatLeaf<(i32 4)>;
|
||||
def MIPS_FCOND_ULT : PatLeaf<(i32 5)>;
|
||||
def MIPS_FCOND_OLE : PatLeaf<(i32 6)>;
|
||||
def MIPS_FCOND_ULE : PatLeaf<(i32 7)>;
|
||||
def MIPS_FCOND_SF : PatLeaf<(i32 8)>;
|
||||
def MIPS_FCOND_NGLE : PatLeaf<(i32 9)>;
|
||||
def MIPS_FCOND_SEQ : PatLeaf<(i32 10)>;
|
||||
def MIPS_FCOND_NGL : PatLeaf<(i32 11)>;
|
||||
def MIPS_FCOND_LT : PatLeaf<(i32 12)>;
|
||||
def MIPS_FCOND_NGE : PatLeaf<(i32 13)>;
|
||||
def MIPS_FCOND_LE : PatLeaf<(i32 14)>;
|
||||
def MIPS_FCOND_NGT : PatLeaf<(i32 15)>;
|
||||
|
||||
/// Floating Point Compare
|
||||
let hasDelaySlot = 1, Defs=[FCR31] in {
|
||||
|
||||
//multiclass FCC1_1<RegisterClass RC>
|
||||
|
||||
def FCMP_SO32 : FCC<0x0, (outs), (ins FGR32:$fs, FGR32:$ft, condcode:$cc),
|
||||
"c.$cc.s $fs $ft", [(MipsFPCmp FGR32:$fs, FGR32:$ft, imm:$cc),
|
||||
(implicit FCR31)]>, Requires<[IsSingleFloat]>;
|
||||
|
||||
def FCMP_AS32 : FCC<0x0, (outs), (ins AFGR32:$fs, AFGR32:$ft, condcode:$cc),
|
||||
"c.$cc.s $fs $ft", [(MipsFPCmp AFGR32:$fs, AFGR32:$ft, imm:$cc),
|
||||
(implicit FCR31)]>, Requires<[In32BitMode]>;
|
||||
|
||||
def FCMP_D32 : FCC<0x1, (outs), (ins AFGR64:$fs, AFGR64:$ft, condcode:$cc),
|
||||
"c.$cc.d $fs $ft", [(MipsFPCmp AFGR64:$fs, AFGR64:$ft, imm:$cc),
|
||||
(implicit FCR31)]>, Requires<[In32BitMode]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Float Point Patterns
|
||||
//===----------------------------------------------------------------------===//
|
||||
def : Pat<(f32 (sint_to_fp CPURegs:$src)), (CVTS_W32 (MTC1 CPURegs:$src))>;
|
||||
def : Pat<(f64 (sint_to_fp CPURegs:$src)), (CVTD_W32 (MTC1 CPURegs:$src))>;
|
||||
def : Pat<(i32 (fp_to_sint FGR32:$src)), (MFC1 (CVTW_SO32 FGR32:$src))>;
|
||||
def : Pat<(i32 (fp_to_sint AFGR32:$src)), (MFC1 (CVTW_AS32 AFGR32:$src))>;
|
||||
|
@ -120,8 +120,8 @@ class FJ<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern,
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class FFR<bits<6> op, bits<6> _funct, bits<5> _fmt, dag outs, dag ins,
|
||||
string asmstr, list<dag> pattern, InstrItinClass itin> :
|
||||
MipsInst<outs, ins, asmstr, pattern, itin>
|
||||
string asmstr, list<dag> pattern> :
|
||||
MipsInst<outs, ins, asmstr, pattern, NoItinerary>
|
||||
{
|
||||
bits<5> fd;
|
||||
bits<5> fs;
|
||||
@ -141,21 +141,42 @@ class FFR<bits<6> op, bits<6> _funct, bits<5> _fmt, dag outs, dag ins,
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Format FI instruction class in Mips : <|opcode|fmt|ft|immediate|>
|
||||
// Format FI instruction class in Mips : <|opcode|base|ft|immediate|>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class FFI<bits<6> op, bits<5> _fmt, dag outs, dag ins, string asmstr,
|
||||
list<dag> pattern, InstrItinClass itin>:
|
||||
MipsInst<outs, ins, asmstr, pattern, itin>
|
||||
class FFI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern>:
|
||||
MipsInst<outs, ins, asmstr, pattern, NoItinerary>
|
||||
{
|
||||
bits<5> ft;
|
||||
bits<5> fmt;
|
||||
bits<5> base;
|
||||
bits<16> imm16;
|
||||
|
||||
let opcode = op;
|
||||
|
||||
let Inst{25-21} = base;
|
||||
let Inst{20-16} = ft;
|
||||
let Inst{15-0} = imm16;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Compare instruction class in Mips : <|010001|fmt|ft|fs|0000011|condcode|>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class FCC<bits<5> _fmt, dag outs, dag ins, string asmstr, list<dag> pattern> :
|
||||
MipsInst<outs, ins, asmstr, pattern, NoItinerary>
|
||||
{
|
||||
bits<5> fs;
|
||||
bits<5> ft;
|
||||
bits<4> cc;
|
||||
bits<5> fmt;
|
||||
|
||||
let opcode = 0x11;
|
||||
let fmt = _fmt;
|
||||
|
||||
let Inst{25-21} = fmt;
|
||||
let Inst{20-16} = ft;
|
||||
let Inst{15-0} = imm16;
|
||||
let Inst{15-11} = fs;
|
||||
let Inst{10-6} = 0;
|
||||
let Inst{5-4} = 0b11;
|
||||
let Inst{3-0} = cc;
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// TODO: Add the subtarget support on this constructor
|
||||
MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm)
|
||||
: TargetInstrInfoImpl(MipsInsts, array_lengthof(MipsInsts)),
|
||||
TM(tm), RI(*this) {}
|
||||
@ -35,8 +34,7 @@ isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const
|
||||
{
|
||||
// addu $dst, $src, $zero || addu $dst, $zero, $src
|
||||
// or $dst, $src, $zero || or $dst, $zero, $src
|
||||
if ((MI.getOpcode() == Mips::ADDu) || (MI.getOpcode() == Mips::OR))
|
||||
{
|
||||
if ((MI.getOpcode() == Mips::ADDu) || (MI.getOpcode() == Mips::OR)) {
|
||||
if (MI.getOperand(1).getReg() == Mips::ZERO) {
|
||||
DstReg = MI.getOperand(0).getReg();
|
||||
SrcReg = MI.getOperand(2).getReg();
|
||||
@ -48,9 +46,20 @@ isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const
|
||||
}
|
||||
}
|
||||
|
||||
// mov $fpDst, $fpSrc
|
||||
// mfc $gpDst, $fpSrc
|
||||
// mtc $fpDst, $gpSrc
|
||||
if (MI.getOpcode() == Mips::FMOV_SO32 || MI.getOpcode() == Mips::FMOV_AS32 ||
|
||||
MI.getOpcode() == Mips::FMOV_D32 || MI.getOpcode() == Mips::MFC1A ||
|
||||
MI.getOpcode() == Mips::MFC1 || MI.getOpcode() == Mips::MTC1A ||
|
||||
MI.getOpcode() == Mips::MTC1 ) {
|
||||
DstReg = MI.getOperand(0).getReg();
|
||||
SrcReg = MI.getOperand(1).getReg();
|
||||
return true;
|
||||
}
|
||||
|
||||
// addiu $dst, $src, 0
|
||||
if (MI.getOpcode() == Mips::ADDiu)
|
||||
{
|
||||
if (MI.getOpcode() == Mips::ADDiu) {
|
||||
if ((MI.getOperand(1).isRegister()) && (isZeroImm(MI.getOperand(2)))) {
|
||||
DstReg = MI.getOperand(0).getReg();
|
||||
SrcReg = MI.getOperand(1).getReg();
|
||||
@ -68,12 +77,11 @@ isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const
|
||||
unsigned MipsInstrInfo::
|
||||
isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const
|
||||
{
|
||||
if (MI->getOpcode() == Mips::LW)
|
||||
{
|
||||
if ((MI->getOpcode() == Mips::LW) || (MI->getOpcode() == Mips::LWC1) ||
|
||||
(MI->getOpcode() == Mips::LWC1A) || (MI->getOpcode() == Mips::LDC1)) {
|
||||
if ((MI->getOperand(2).isFrameIndex()) && // is a stack slot
|
||||
(MI->getOperand(1).isImmediate()) && // the imm is zero
|
||||
(isZeroImm(MI->getOperand(1))))
|
||||
{
|
||||
(isZeroImm(MI->getOperand(1)))) {
|
||||
FrameIndex = MI->getOperand(2).getIndex();
|
||||
return MI->getOperand(0).getReg();
|
||||
}
|
||||
@ -90,11 +98,11 @@ isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const
|
||||
unsigned MipsInstrInfo::
|
||||
isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) const
|
||||
{
|
||||
if (MI->getOpcode() == Mips::SW) {
|
||||
if ((MI->getOpcode() == Mips::SW) || (MI->getOpcode() == Mips::SWC1) ||
|
||||
(MI->getOpcode() == Mips::SWC1A) || (MI->getOpcode() == Mips::SDC1)) {
|
||||
if ((MI->getOperand(0).isFrameIndex()) && // is a stack slot
|
||||
(MI->getOperand(1).isImmediate()) && // the imm is zero
|
||||
(isZeroImm(MI->getOperand(1))))
|
||||
{
|
||||
(isZeroImm(MI->getOperand(1)))) {
|
||||
FrameIndex = MI->getOperand(0).getIndex();
|
||||
return MI->getOperand(2).getReg();
|
||||
}
|
||||
@ -110,6 +118,208 @@ insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const
|
||||
BuildMI(MBB, MI, get(Mips::NOP));
|
||||
}
|
||||
|
||||
void MipsInstrInfo::
|
||||
copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
unsigned DestReg, unsigned SrcReg,
|
||||
const TargetRegisterClass *DestRC,
|
||||
const TargetRegisterClass *SrcRC) const {
|
||||
if (DestRC != SrcRC) {
|
||||
if ((DestRC == Mips::CPURegsRegisterClass) &&
|
||||
(SrcRC == Mips::FGR32RegisterClass))
|
||||
BuildMI(MBB, I, get(Mips::MFC1), DestReg).addReg(SrcReg);
|
||||
else if ((DestRC == Mips::CPURegsRegisterClass) &&
|
||||
(SrcRC == Mips::AFGR32RegisterClass))
|
||||
BuildMI(MBB, I, get(Mips::MFC1A), DestReg).addReg(SrcReg);
|
||||
else if ((DestRC == Mips::FGR32RegisterClass) &&
|
||||
(SrcRC == Mips::CPURegsRegisterClass))
|
||||
BuildMI(MBB, I, get(Mips::MTC1), DestReg).addReg(SrcReg);
|
||||
else if ((DestRC == Mips::AFGR32RegisterClass) &&
|
||||
(SrcRC == Mips::CPURegsRegisterClass))
|
||||
BuildMI(MBB, I, get(Mips::MTC1A), DestReg).addReg(SrcReg);
|
||||
else
|
||||
assert (0 && "DestRC != SrcRC, Can't copy this register");
|
||||
}
|
||||
|
||||
if (DestRC == Mips::CPURegsRegisterClass)
|
||||
BuildMI(MBB, I, get(Mips::ADDu), DestReg).addReg(Mips::ZERO)
|
||||
.addReg(SrcReg);
|
||||
else if (DestRC == Mips::FGR32RegisterClass)
|
||||
BuildMI(MBB, I, get(Mips::FMOV_SO32), DestReg).addReg(SrcReg);
|
||||
else if (DestRC == Mips::AFGR32RegisterClass)
|
||||
BuildMI(MBB, I, get(Mips::FMOV_AS32), DestReg).addReg(SrcReg);
|
||||
else if (DestRC == Mips::AFGR64RegisterClass)
|
||||
BuildMI(MBB, I, get(Mips::FMOV_D32), DestReg).addReg(SrcReg);
|
||||
else
|
||||
assert (0 && "Can't copy this register");
|
||||
}
|
||||
|
||||
void MipsInstrInfo::
|
||||
storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
unsigned SrcReg, bool isKill, int FI,
|
||||
const TargetRegisterClass *RC) const
|
||||
{
|
||||
unsigned Opc;
|
||||
if (RC == Mips::CPURegsRegisterClass)
|
||||
Opc = Mips::SW;
|
||||
else if (RC == Mips::FGR32RegisterClass)
|
||||
Opc = Mips::SWC1;
|
||||
else if (RC == Mips::AFGR32RegisterClass)
|
||||
Opc = Mips::SWC1A;
|
||||
else if (RC == Mips::AFGR64RegisterClass)
|
||||
Opc = Mips::SDC1;
|
||||
else
|
||||
assert(0 && "Can't store this register to stack slot");
|
||||
|
||||
BuildMI(MBB, I, get(Opc)).addReg(SrcReg, false, false, isKill)
|
||||
.addImm(0).addFrameIndex(FI);
|
||||
}
|
||||
|
||||
void MipsInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
|
||||
bool isKill, SmallVectorImpl<MachineOperand> &Addr,
|
||||
const TargetRegisterClass *RC, SmallVectorImpl<MachineInstr*> &NewMIs) const
|
||||
{
|
||||
unsigned Opc;
|
||||
if (RC == Mips::CPURegsRegisterClass)
|
||||
Opc = Mips::SW;
|
||||
else if (RC == Mips::FGR32RegisterClass)
|
||||
Opc = Mips::SWC1;
|
||||
else if (RC == Mips::AFGR32RegisterClass)
|
||||
Opc = Mips::SWC1A;
|
||||
else if (RC == Mips::AFGR64RegisterClass)
|
||||
Opc = Mips::SDC1;
|
||||
else
|
||||
assert(0 && "Can't store this register");
|
||||
|
||||
MachineInstrBuilder MIB = BuildMI(get(Opc))
|
||||
.addReg(SrcReg, false, false, isKill);
|
||||
for (unsigned i = 0, e = Addr.size(); i != e; ++i) {
|
||||
MachineOperand &MO = Addr[i];
|
||||
if (MO.isRegister())
|
||||
MIB.addReg(MO.getReg());
|
||||
else if (MO.isImmediate())
|
||||
MIB.addImm(MO.getImm());
|
||||
else
|
||||
MIB.addFrameIndex(MO.getIndex());
|
||||
}
|
||||
NewMIs.push_back(MIB);
|
||||
return;
|
||||
}
|
||||
|
||||
void MipsInstrInfo::
|
||||
loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
unsigned DestReg, int FI,
|
||||
const TargetRegisterClass *RC) const
|
||||
{
|
||||
unsigned Opc;
|
||||
if (RC == Mips::CPURegsRegisterClass)
|
||||
Opc = Mips::LW;
|
||||
else if (RC == Mips::FGR32RegisterClass)
|
||||
Opc = Mips::LWC1;
|
||||
else if (RC == Mips::AFGR32RegisterClass)
|
||||
Opc = Mips::LWC1A;
|
||||
else if (RC == Mips::AFGR64RegisterClass)
|
||||
Opc = Mips::LDC1;
|
||||
else
|
||||
assert(0 && "Can't load this register from stack slot");
|
||||
|
||||
BuildMI(MBB, I, get(Opc), DestReg).addImm(0).addFrameIndex(FI);
|
||||
}
|
||||
|
||||
void MipsInstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
|
||||
SmallVectorImpl<MachineOperand> &Addr,
|
||||
const TargetRegisterClass *RC,
|
||||
SmallVectorImpl<MachineInstr*> &NewMIs) const {
|
||||
unsigned Opc;
|
||||
if (RC == Mips::CPURegsRegisterClass)
|
||||
Opc = Mips::LW;
|
||||
else if (RC == Mips::FGR32RegisterClass)
|
||||
Opc = Mips::LWC1;
|
||||
else if (RC == Mips::AFGR32RegisterClass)
|
||||
Opc = Mips::LWC1A;
|
||||
else if (RC == Mips::AFGR64RegisterClass)
|
||||
Opc = Mips::LDC1;
|
||||
else
|
||||
assert(0 && "Can't load this register");
|
||||
|
||||
MachineInstrBuilder MIB = BuildMI(get(Opc), DestReg);
|
||||
for (unsigned i = 0, e = Addr.size(); i != e; ++i) {
|
||||
MachineOperand &MO = Addr[i];
|
||||
if (MO.isRegister())
|
||||
MIB.addReg(MO.getReg());
|
||||
else if (MO.isImmediate())
|
||||
MIB.addImm(MO.getImm());
|
||||
else
|
||||
MIB.addFrameIndex(MO.getIndex());
|
||||
}
|
||||
NewMIs.push_back(MIB);
|
||||
return;
|
||||
}
|
||||
|
||||
MachineInstr *MipsInstrInfo::
|
||||
foldMemoryOperand(MachineFunction &MF,
|
||||
MachineInstr* MI,
|
||||
SmallVectorImpl<unsigned> &Ops, int FI) const
|
||||
{
|
||||
if (Ops.size() != 1) return NULL;
|
||||
|
||||
MachineInstr *NewMI = NULL;
|
||||
|
||||
switch (MI->getOpcode()) {
|
||||
case Mips::ADDu:
|
||||
if ((MI->getOperand(0).isRegister()) &&
|
||||
(MI->getOperand(1).isRegister()) &&
|
||||
(MI->getOperand(1).getReg() == Mips::ZERO) &&
|
||||
(MI->getOperand(2).isRegister())) {
|
||||
if (Ops[0] == 0) { // COPY -> STORE
|
||||
unsigned SrcReg = MI->getOperand(2).getReg();
|
||||
bool isKill = MI->getOperand(2).isKill();
|
||||
NewMI = BuildMI(get(Mips::SW)).addFrameIndex(FI)
|
||||
.addImm(0).addReg(SrcReg, false, false, isKill);
|
||||
} else { // COPY -> LOAD
|
||||
unsigned DstReg = MI->getOperand(0).getReg();
|
||||
bool isDead = MI->getOperand(0).isDead();
|
||||
NewMI = BuildMI(get(Mips::LW))
|
||||
.addReg(DstReg, true, false, false, isDead)
|
||||
.addImm(0).addFrameIndex(FI);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Mips::FMOV_SO32:
|
||||
case Mips::FMOV_AS32:
|
||||
case Mips::FMOV_D32:
|
||||
if ((MI->getOperand(0).isRegister()) &&
|
||||
(MI->getOperand(1).isRegister())) {
|
||||
const TargetRegisterClass *RC = RI.getRegClass(MI->getOperand(0).getReg());
|
||||
unsigned StoreOpc, LoadOpc;
|
||||
|
||||
if (RC == Mips::FGR32RegisterClass) {
|
||||
LoadOpc = Mips::LWC1; StoreOpc = Mips::SWC1;
|
||||
} else if (RC == Mips::AFGR32RegisterClass) {
|
||||
LoadOpc = Mips::LWC1A; StoreOpc = Mips::SWC1A;
|
||||
} else if (RC == Mips::AFGR64RegisterClass) {
|
||||
LoadOpc = Mips::LDC1; StoreOpc = Mips::SDC1;
|
||||
} else
|
||||
assert(0 && "foldMemoryOperand register unknown");
|
||||
|
||||
if (Ops[0] == 0) { // COPY -> STORE
|
||||
unsigned SrcReg = MI->getOperand(1).getReg();
|
||||
bool isKill = MI->getOperand(1).isKill();
|
||||
NewMI = BuildMI(get(StoreOpc)).addFrameIndex(FI)
|
||||
.addImm(0).addReg(SrcReg, false, false, isKill);
|
||||
} else { // COPY -> LOAD
|
||||
unsigned DstReg = MI->getOperand(0).getReg();
|
||||
bool isDead = MI->getOperand(0).isDead();
|
||||
NewMI = BuildMI(get(LoadOpc))
|
||||
.addReg(DstReg, true, false, false, isDead)
|
||||
.addImm(0).addFrameIndex(FI);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return NewMI;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Branch Analysis
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -120,12 +330,12 @@ static Mips::CondCode GetCondFromBranchOpc(unsigned BrOpc)
|
||||
{
|
||||
switch (BrOpc) {
|
||||
default: return Mips::COND_INVALID;
|
||||
case Mips::BEQ : return Mips::COND_E;
|
||||
case Mips::BNE : return Mips::COND_NE;
|
||||
case Mips::BGTZ : return Mips::COND_GZ;
|
||||
case Mips::BGEZ : return Mips::COND_GEZ;
|
||||
case Mips::BLTZ : return Mips::COND_LZ;
|
||||
case Mips::BLEZ : return Mips::COND_LEZ;
|
||||
case Mips::BEQ : return Mips::COND_E;
|
||||
case Mips::BNE : return Mips::COND_NE;
|
||||
case Mips::BGTZ : return Mips::COND_GZ;
|
||||
case Mips::BGEZ : return Mips::COND_GEZ;
|
||||
case Mips::BLTZ : return Mips::COND_LZ;
|
||||
case Mips::BLEZ : return Mips::COND_LEZ;
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,6 +366,22 @@ Mips::CondCode Mips::GetOppositeBranchCondition(Mips::CondCode CC)
|
||||
case Mips::COND_GEZ : return Mips::COND_LZ;
|
||||
case Mips::COND_LZ : return Mips::COND_GEZ;
|
||||
case Mips::COND_LEZ : return Mips::COND_GZ;
|
||||
case Mips::FCOND_F : return Mips::FCOND_T;
|
||||
case Mips::FCOND_UN : return Mips::FCOND_OR;
|
||||
case Mips::FCOND_EQ : return Mips::FCOND_NEQ;
|
||||
case Mips::FCOND_UEQ: return Mips::FCOND_OGL;
|
||||
case Mips::FCOND_OLT: return Mips::FCOND_UGE;
|
||||
case Mips::FCOND_ULT: return Mips::FCOND_OGE;
|
||||
case Mips::FCOND_OLE: return Mips::FCOND_UGT;
|
||||
case Mips::FCOND_ULE: return Mips::FCOND_OGT;
|
||||
case Mips::FCOND_SF: return Mips::FCOND_ST;
|
||||
case Mips::FCOND_NGLE:return Mips::FCOND_GLE;
|
||||
case Mips::FCOND_SEQ: return Mips::FCOND_SNE;
|
||||
case Mips::FCOND_NGL: return Mips::FCOND_GL;
|
||||
case Mips::FCOND_LT: return Mips::FCOND_NLT;
|
||||
case Mips::FCOND_NGE: return Mips::FCOND_GE;
|
||||
case Mips::FCOND_LE: return Mips::FCOND_NLE;
|
||||
case Mips::FCOND_NGT: return Mips::FCOND_GT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,124 +513,6 @@ InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
|
||||
return 2;
|
||||
}
|
||||
|
||||
void MipsInstrInfo::
|
||||
copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
unsigned DestReg, unsigned SrcReg,
|
||||
const TargetRegisterClass *DestRC,
|
||||
const TargetRegisterClass *SrcRC) const {
|
||||
if (DestRC != SrcRC) {
|
||||
cerr << "Not yet supported!";
|
||||
abort();
|
||||
}
|
||||
|
||||
if (DestRC == Mips::CPURegsRegisterClass)
|
||||
BuildMI(MBB, I, get(Mips::ADDu), DestReg).addReg(Mips::ZERO)
|
||||
.addReg(SrcReg);
|
||||
else
|
||||
assert (0 && "Can't copy this register");
|
||||
}
|
||||
|
||||
void MipsInstrInfo::
|
||||
storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
unsigned SrcReg, bool isKill, int FI,
|
||||
const TargetRegisterClass *RC) const
|
||||
{
|
||||
if (RC == Mips::CPURegsRegisterClass)
|
||||
BuildMI(MBB, I, get(Mips::SW)).addReg(SrcReg, false, false, isKill)
|
||||
.addImm(0).addFrameIndex(FI);
|
||||
else
|
||||
assert(0 && "Can't store this register to stack slot");
|
||||
}
|
||||
|
||||
void MipsInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
|
||||
bool isKill,
|
||||
SmallVectorImpl<MachineOperand> &Addr,
|
||||
const TargetRegisterClass *RC,
|
||||
SmallVectorImpl<MachineInstr*> &NewMIs) const {
|
||||
if (RC != Mips::CPURegsRegisterClass)
|
||||
assert(0 && "Can't store this register");
|
||||
MachineInstrBuilder MIB = BuildMI(get(Mips::SW))
|
||||
.addReg(SrcReg, false, false, isKill);
|
||||
for (unsigned i = 0, e = Addr.size(); i != e; ++i) {
|
||||
MachineOperand &MO = Addr[i];
|
||||
if (MO.isRegister())
|
||||
MIB.addReg(MO.getReg());
|
||||
else if (MO.isImmediate())
|
||||
MIB.addImm(MO.getImm());
|
||||
else
|
||||
MIB.addFrameIndex(MO.getIndex());
|
||||
}
|
||||
NewMIs.push_back(MIB);
|
||||
return;
|
||||
}
|
||||
|
||||
void MipsInstrInfo::
|
||||
loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
unsigned DestReg, int FI,
|
||||
const TargetRegisterClass *RC) const
|
||||
{
|
||||
if (RC == Mips::CPURegsRegisterClass)
|
||||
BuildMI(MBB, I, get(Mips::LW), DestReg).addImm(0).addFrameIndex(FI);
|
||||
else
|
||||
assert(0 && "Can't load this register from stack slot");
|
||||
}
|
||||
|
||||
void MipsInstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
|
||||
SmallVectorImpl<MachineOperand> &Addr,
|
||||
const TargetRegisterClass *RC,
|
||||
SmallVectorImpl<MachineInstr*> &NewMIs) const {
|
||||
if (RC != Mips::CPURegsRegisterClass)
|
||||
assert(0 && "Can't load this register");
|
||||
MachineInstrBuilder MIB = BuildMI(get(Mips::LW), DestReg);
|
||||
for (unsigned i = 0, e = Addr.size(); i != e; ++i) {
|
||||
MachineOperand &MO = Addr[i];
|
||||
if (MO.isRegister())
|
||||
MIB.addReg(MO.getReg());
|
||||
else if (MO.isImmediate())
|
||||
MIB.addImm(MO.getImm());
|
||||
else
|
||||
MIB.addFrameIndex(MO.getIndex());
|
||||
}
|
||||
NewMIs.push_back(MIB);
|
||||
return;
|
||||
}
|
||||
|
||||
MachineInstr *MipsInstrInfo::
|
||||
foldMemoryOperand(MachineFunction &MF,
|
||||
MachineInstr* MI,
|
||||
SmallVectorImpl<unsigned> &Ops, int FI) const
|
||||
{
|
||||
if (Ops.size() != 1) return NULL;
|
||||
|
||||
MachineInstr *NewMI = NULL;
|
||||
|
||||
switch (MI->getOpcode())
|
||||
{
|
||||
case Mips::ADDu:
|
||||
if ((MI->getOperand(0).isRegister()) &&
|
||||
(MI->getOperand(1).isRegister()) &&
|
||||
(MI->getOperand(1).getReg() == Mips::ZERO) &&
|
||||
(MI->getOperand(2).isRegister()))
|
||||
{
|
||||
if (Ops[0] == 0) { // COPY -> STORE
|
||||
unsigned SrcReg = MI->getOperand(2).getReg();
|
||||
bool isKill = MI->getOperand(2).isKill();
|
||||
NewMI = BuildMI(get(Mips::SW)).addFrameIndex(FI)
|
||||
.addImm(0).addReg(SrcReg, false, false, isKill);
|
||||
} else { // COPY -> LOAD
|
||||
unsigned DstReg = MI->getOperand(0).getReg();
|
||||
bool isDead = MI->getOperand(0).isDead();
|
||||
NewMI = BuildMI(get(Mips::LW))
|
||||
.addReg(DstReg, true, false, false, isDead)
|
||||
.addImm(0).addFrameIndex(FI);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return NewMI;
|
||||
}
|
||||
|
||||
unsigned MipsInstrInfo::
|
||||
RemoveBranch(MachineBasicBlock &MBB) const
|
||||
{
|
||||
@ -456,5 +564,3 @@ ReverseBranchCondition(std::vector<MachineOperand> &Cond) const
|
||||
Cond[0].setImm(GetOppositeBranchCondition((Mips::CondCode)Cond[0].getImm()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,6 +24,45 @@ namespace Mips {
|
||||
|
||||
// Mips Condition Codes
|
||||
enum CondCode {
|
||||
// To be used with float branch True
|
||||
FCOND_F,
|
||||
FCOND_UN,
|
||||
FCOND_EQ,
|
||||
FCOND_UEQ,
|
||||
FCOND_OLT,
|
||||
FCOND_ULT,
|
||||
FCOND_OLE,
|
||||
FCOND_ULE,
|
||||
FCOND_SF,
|
||||
FCOND_NGLE,
|
||||
FCOND_SEQ,
|
||||
FCOND_NGL,
|
||||
FCOND_LT,
|
||||
FCOND_NGE,
|
||||
FCOND_LE,
|
||||
FCOND_NGT,
|
||||
|
||||
// To be used with float branch False
|
||||
// This conditions have the same mnemonic as the
|
||||
// above ones, but are used with a branch False;
|
||||
FCOND_T,
|
||||
FCOND_OR,
|
||||
FCOND_NEQ,
|
||||
FCOND_OGL,
|
||||
FCOND_UGE,
|
||||
FCOND_OGE,
|
||||
FCOND_UGT,
|
||||
FCOND_OGT,
|
||||
FCOND_ST,
|
||||
FCOND_GLE,
|
||||
FCOND_SNE,
|
||||
FCOND_GL,
|
||||
FCOND_NLT,
|
||||
FCOND_GE,
|
||||
FCOND_NLE,
|
||||
FCOND_GT,
|
||||
|
||||
// Only integer conditions
|
||||
COND_E,
|
||||
COND_GZ,
|
||||
COND_GEZ,
|
||||
@ -40,6 +79,45 @@ namespace Mips {
|
||||
/// e.g. turning COND_E to COND_NE.
|
||||
CondCode GetOppositeBranchCondition(Mips::CondCode CC);
|
||||
|
||||
/// MipsCCToString - Map each FP condition code to its string
|
||||
inline static const char *MipsFCCToString(Mips::CondCode CC)
|
||||
{
|
||||
switch (CC) {
|
||||
default: assert(0 && "Unknown condition code");
|
||||
case FCOND_F:
|
||||
case FCOND_T: return "f";
|
||||
case FCOND_UN:
|
||||
case FCOND_OR: return "un";
|
||||
case FCOND_EQ:
|
||||
case FCOND_NEQ: return "eq";
|
||||
case FCOND_UEQ:
|
||||
case FCOND_OGL: return "ueq";
|
||||
case FCOND_OLT:
|
||||
case FCOND_UGE: return "olt";
|
||||
case FCOND_ULT:
|
||||
case FCOND_OGE: return "ult";
|
||||
case FCOND_OLE:
|
||||
case FCOND_UGT: return "ole";
|
||||
case FCOND_ULE:
|
||||
case FCOND_OGT: return "ule";
|
||||
case FCOND_SF:
|
||||
case FCOND_ST: return "sf";
|
||||
case FCOND_NGLE:
|
||||
case FCOND_GLE: return "ngle";
|
||||
case FCOND_SEQ:
|
||||
case FCOND_SNE: return "seq";
|
||||
case FCOND_NGL:
|
||||
case FCOND_GL: return "ngl";
|
||||
case FCOND_LT:
|
||||
case FCOND_NLT: return "lt";
|
||||
case FCOND_NGE:
|
||||
case FCOND_GE: return "ge";
|
||||
case FCOND_LE:
|
||||
case FCOND_NLE: return "nle";
|
||||
case FCOND_NGT:
|
||||
case FCOND_GT: return "gt";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MipsInstrInfo : public TargetInstrInfoImpl {
|
||||
|
@ -17,10 +17,16 @@ include "MipsInstrFormats.td"
|
||||
// Mips profiles and nodes
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def SDT_MipsRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
|
||||
def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
|
||||
def SDT_MipsSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>,
|
||||
SDTCisSameAs<1, 2>, SDTCisInt<3>]>;
|
||||
def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>;
|
||||
def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
|
||||
|
||||
// Call
|
||||
def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
|
||||
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain,
|
||||
SDNPOutFlag]>;
|
||||
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain,
|
||||
SDNPOutFlag]>;
|
||||
|
||||
// Hi and Lo nodes are used to handle global addresses. Used on
|
||||
// MipsISelLowering to lower stuff like GlobalAddress, ExternalSymbol
|
||||
@ -29,29 +35,22 @@ def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp, [SDNPOutFlag]>;
|
||||
def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>;
|
||||
|
||||
// Return
|
||||
def SDT_MipsRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
|
||||
def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain,
|
||||
SDNPOptInFlag]>;
|
||||
def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain,
|
||||
SDNPOptInFlag]>;
|
||||
|
||||
// These are target-independent nodes, but have target-specific formats.
|
||||
def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>;
|
||||
def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>,
|
||||
SDTCisVT<1, i32>]>;
|
||||
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart,
|
||||
[SDNPHasChain, SDNPOutFlag]>;
|
||||
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd,
|
||||
[SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
|
||||
|
||||
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart,
|
||||
[SDNPHasChain, SDNPOutFlag]>;
|
||||
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd,
|
||||
[SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
|
||||
|
||||
// Select CC
|
||||
def SDT_MipsSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>,
|
||||
SDTCisSameAs<1, 2>, SDTCisInt<3>]>;
|
||||
def MipsSelectCC : SDNode<"MipsISD::SelectCC", SDT_MipsSelectCC>;
|
||||
// Select Condition Code
|
||||
def MipsSelectCC : SDNode<"MipsISD::SelectCC", SDT_MipsSelectCC>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips Instruction Predicate Definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
def IsStatic : Predicate<"TM.getRelocationModel() == Reloc::Static">;
|
||||
def IsAllegrex : Predicate<"Subtarget.isAllegrex()">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mips Operand, Complex Patterns and Transformations Definitions.
|
||||
@ -63,7 +62,6 @@ def calltarget : Operand<i32>;
|
||||
def uimm16 : Operand<i32>;
|
||||
def simm16 : Operand<i32>;
|
||||
def shamt : Operand<i32>;
|
||||
def addrlabel : Operand<i32>;
|
||||
|
||||
// Address operand
|
||||
def mem : Operand<i32> {
|
||||
@ -345,6 +343,12 @@ class EffectiveAddress<string instr_asm> :
|
||||
instr_asm,
|
||||
[(set CPURegs:$dst, addr:$addr)], IIAlu>;
|
||||
|
||||
class SignExtInReg<bits<6> func, string instr_asm, ValueType vt>:
|
||||
FR< 0x3f, func, (outs CPURegs:$dst), (ins CPURegs:$src),
|
||||
!strconcat(instr_asm, " $dst, $src"),
|
||||
[(set CPURegs:$dst, (sext_inreg CPURegs:$src, vt))], NoItinerary>;
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pseudo instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -352,11 +356,11 @@ class EffectiveAddress<string instr_asm> :
|
||||
// As stack alignment is always done with addiu, we need a 16-bit immediate
|
||||
let Defs = [SP], Uses = [SP] in {
|
||||
def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins uimm16:$amt),
|
||||
"!ADJCALLSTACKDOWN $amt",
|
||||
[(callseq_start imm:$amt)]>;
|
||||
"!ADJCALLSTACKDOWN $amt",
|
||||
[(callseq_start imm:$amt)]>;
|
||||
def ADJCALLSTACKUP : MipsPseudo<(outs), (ins uimm16:$amt1, uimm16:$amt2),
|
||||
"!ADJCALLSTACKUP $amt1",
|
||||
[(callseq_end imm:$amt1, imm:$amt2)]>;
|
||||
"!ADJCALLSTACKUP $amt1",
|
||||
[(callseq_end imm:$amt1, imm:$amt2)]>;
|
||||
}
|
||||
|
||||
// When handling PIC code the assembler needs .cpload and .cprestore
|
||||
@ -364,10 +368,10 @@ def ADJCALLSTACKUP : MipsPseudo<(outs), (ins uimm16:$amt1, uimm16:$amt2),
|
||||
// are used, we have the same behavior, but get also a bunch of warnings
|
||||
// from the assembler.
|
||||
def CPLOAD : MipsPseudo<(outs), (ins CPURegs:$reg),
|
||||
".set noreorder\n\t.cpload $reg\n\t.set reorder\n",
|
||||
[]>;
|
||||
".set noreorder\n\t.cpload $reg\n\t.set reorder\n",
|
||||
[]>;
|
||||
def CPRESTORE : MipsPseudo<(outs), (ins uimm16:$loc),
|
||||
".cprestore $loc\n", []>;
|
||||
".cprestore $loc\n", []>;
|
||||
|
||||
// The supported Mips ISAs dont have any instruction close to the SELECT_CC
|
||||
// operation. The solution is to create a Mips pseudo SELECT_CC instruction
|
||||
@ -474,19 +478,6 @@ def MFLO : MoveFromTo<0x12, "mflo">;
|
||||
def MTHI : MoveFromTo<0x11, "mthi">;
|
||||
def MTLO : MoveFromTo<0x13, "mtlo">;
|
||||
|
||||
// Count Leading
|
||||
// CLO/CLZ are part of the newer MIPS32(tm) instruction
|
||||
// set and not older Mips I keep this for future use
|
||||
// though.
|
||||
//def CLO : CountLeading<0x21, "clo">;
|
||||
//def CLZ : CountLeading<0x20, "clz">;
|
||||
|
||||
// MADD*/MSUB* are not part of MipsI either.
|
||||
//def MADD : MArithR<0x00, "madd">;
|
||||
//def MADDU : MArithR<0x01, "maddu">;
|
||||
//def MSUB : MArithR<0x04, "msub">;
|
||||
//def MSUBU : MArithR<0x05, "msubu">;
|
||||
|
||||
// No operation
|
||||
let addr=0 in
|
||||
def NOP : FJ<0, (outs), (ins), "nop", [], IIAlu>;
|
||||
@ -506,6 +497,27 @@ let isReturn=1, isTerminator=1, hasDelaySlot=1,
|
||||
// can be matched. It's similar to Sparc LEA_ADDRi
|
||||
def LEA_ADDiu : EffectiveAddress<"addiu $dst, ${addr:stackloc}">;
|
||||
|
||||
// Count Leading
|
||||
// CLO/CLZ are part of the newer MIPS32(tm) instruction
|
||||
// set and not older Mips I keep this for future use
|
||||
// though.
|
||||
//def CLO : CountLeading<0x21, "clo">;
|
||||
//def CLZ : CountLeading<0x20, "clz">;
|
||||
|
||||
// MADD*/MSUB* are not part of MipsI either.
|
||||
//def MADD : MArithR<0x00, "madd">;
|
||||
//def MADDU : MArithR<0x01, "maddu">;
|
||||
//def MSUB : MArithR<0x04, "msub">;
|
||||
//def MSUBU : MArithR<0x05, "msubu">;
|
||||
|
||||
let Predicates = [IsAllegrex] in {
|
||||
let shamt = 0x10, rs = 0 in
|
||||
def SEB : SignExtInReg<0x21, "seb", i8>;
|
||||
|
||||
let shamt = 0x18, rs = 0 in
|
||||
def SEH : SignExtInReg<0x20, "seh", i16>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Arbitrary patterns that map to one or more instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -546,7 +558,7 @@ def : Pat<(MipsLo tjumptable:$in), (ADDiu ZERO, tjumptable:$in)>;
|
||||
def : Pat<(add CPURegs:$hi, (MipsLo tjumptable:$lo)),
|
||||
(ADDiu CPURegs:$hi, tjumptable:$lo)>;
|
||||
|
||||
// Mips does not have not, so we increase the operation
|
||||
// Mips does not have "not", so we expand our way
|
||||
def : Pat<(not CPURegs:$in),
|
||||
(NOR CPURegs:$in, ZERO)>;
|
||||
|
||||
@ -558,10 +570,7 @@ def : Pat<(i32 (extloadi16 addr:$src)), (LHu addr:$src)>;
|
||||
// peepholes
|
||||
def : Pat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>;
|
||||
|
||||
///
|
||||
/// brcond patterns
|
||||
///
|
||||
|
||||
// brcond patterns
|
||||
// direct match equal/notequal zero branches
|
||||
def : Pat<(brcond (setne CPURegs:$lhs, 0), bb:$dst),
|
||||
(BNE CPURegs:$lhs, ZERO, bb:$dst)>;
|
||||
@ -601,12 +610,8 @@ def : Pat<(brcond (setult CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
|
||||
def : Pat<(brcond CPURegs:$cond, bb:$dst),
|
||||
(BNE CPURegs:$cond, ZERO, bb:$dst)>;
|
||||
|
||||
///
|
||||
/// setcc patterns, only matched when there
|
||||
/// is no brcond following a setcc operation
|
||||
///
|
||||
|
||||
// setcc 2 register operands
|
||||
def : Pat<(setle CPURegs:$lhs, CPURegs:$rhs),
|
||||
(XORi (SLT CPURegs:$rhs, CPURegs:$lhs), 1)>;
|
||||
def : Pat<(setule CPURegs:$lhs, CPURegs:$rhs),
|
||||
@ -630,8 +635,14 @@ def : Pat<(seteq CPURegs:$lhs, CPURegs:$rhs),
|
||||
(XORi (OR (SLT CPURegs:$lhs, CPURegs:$rhs),
|
||||
(SLT CPURegs:$rhs, CPURegs:$lhs)), 1)>;
|
||||
|
||||
// setcc reg/imm operands
|
||||
def : Pat<(setge CPURegs:$lhs, immSExt16:$rhs),
|
||||
(XORi (SLTi CPURegs:$lhs, immSExt16:$rhs), 1)>;
|
||||
def : Pat<(setuge CPURegs:$lhs, immZExt16:$rhs),
|
||||
(XORi (SLTiu CPURegs:$lhs, immZExt16:$rhs), 1)>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating Point Support
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "MipsInstrFPU.td"
|
||||
|
||||
|
@ -25,12 +25,12 @@ namespace llvm {
|
||||
class MipsFunctionInfo : public MachineFunctionInfo {
|
||||
|
||||
private:
|
||||
/// Holds for each function where on the stack
|
||||
/// the Frame Pointer must be saved
|
||||
/// Holds for each function where on the stack the Frame Pointer must be
|
||||
/// saved.
|
||||
int FPStackOffset;
|
||||
|
||||
/// Holds for each function where on the stack
|
||||
/// the Return Address must be saved
|
||||
/// Holds for each function where on the stack the Return Address must be
|
||||
/// saved.
|
||||
int RAStackOffset;
|
||||
|
||||
/// MipsFIHolder - Holds a FrameIndex and it's Stack Pointer Offset
|
||||
@ -43,31 +43,34 @@ private:
|
||||
: FI(FrameIndex), SPOffset(StackPointerOffset) {}
|
||||
};
|
||||
|
||||
/// When PIC is used the GP must be saved on the stack
|
||||
/// on the function prologue and must be reloaded from this
|
||||
/// stack location after every call. A reference to its stack
|
||||
/// location and frame index must be kept to be used on
|
||||
/// emitPrologue and processFunctionBeforeFrameFinalized.
|
||||
/// When PIC is used the GP must be saved on the stack on the function
|
||||
/// prologue and must be reloaded from this stack location after every
|
||||
/// call. A reference to its stack location and frame index must be kept
|
||||
/// to be used on emitPrologue and processFunctionBeforeFrameFinalized.
|
||||
MipsFIHolder GPHolder;
|
||||
|
||||
// On LowerFORMAL_ARGUMENTS the stack size is unknown,
|
||||
// so the Stack Pointer Offset calculation of "not in
|
||||
// register arguments" must be postponed to emitPrologue.
|
||||
// On LowerFORMAL_ARGUMENTS the stack size is unknown, so the Stack
|
||||
// Pointer Offset calculation of "not in register arguments" must be
|
||||
// postponed to emitPrologue.
|
||||
SmallVector<MipsFIHolder, 16> FnLoadArgs;
|
||||
bool HasLoadArgs;
|
||||
|
||||
// When VarArgs, we must write registers back to caller
|
||||
// stack, preserving on register arguments. Since the
|
||||
// stack size is unknown on LowerFORMAL_ARGUMENTS,
|
||||
// the Stack Pointer Offset calculation must be
|
||||
// When VarArgs, we must write registers back to caller stack, preserving
|
||||
// on register arguments. Since the stack size is unknown on
|
||||
// LowerFORMAL_ARGUMENTS, the Stack Pointer Offset calculation must be
|
||||
// postponed to emitPrologue.
|
||||
SmallVector<MipsFIHolder, 4> FnStoreVarArgs;
|
||||
bool HasStoreVarArgs;
|
||||
|
||||
/// SRetReturnReg - Some subtargets require that sret lowering includes
|
||||
/// returning the value of the returned struct in a register. This field
|
||||
/// holds the virtual register into which the sret argument is passed.
|
||||
unsigned SRetReturnReg;
|
||||
|
||||
public:
|
||||
MipsFunctionInfo(MachineFunction& MF)
|
||||
: FPStackOffset(0), RAStackOffset(0), GPHolder(-1,-1),
|
||||
HasLoadArgs(false), HasStoreVarArgs(false)
|
||||
: FPStackOffset(0), RAStackOffset(0), GPHolder(-1,-1), HasLoadArgs(false),
|
||||
HasStoreVarArgs(false), SRetReturnReg(0)
|
||||
{}
|
||||
|
||||
int getFPStackOffset() const { return FPStackOffset; }
|
||||
@ -109,6 +112,8 @@ public:
|
||||
MFI->setObjectOffset( FnStoreVarArgs[i].FI, FnStoreVarArgs[i].SPOffset );
|
||||
}
|
||||
|
||||
unsigned getSRetReturnReg() const { return SRetReturnReg; }
|
||||
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
|
||||
};
|
||||
|
||||
} // end of namespace llvm
|
||||
|
@ -32,14 +32,12 @@
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
//#include "MipsSubtarget.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// TODO: add subtarget support
|
||||
MipsRegisterInfo::MipsRegisterInfo(const TargetInstrInfo &tii)
|
||||
: MipsGenRegisterInfo(Mips::ADJCALLSTACKDOWN, Mips::ADJCALLSTACKUP),
|
||||
TII(tii) {}
|
||||
TII(tii) {}
|
||||
|
||||
/// getRegisterNumbering - Given the enum value for some register, e.g.
|
||||
/// Mips::RA, return the number that it corresponds to (e.g. 31).
|
||||
@ -47,38 +45,38 @@ unsigned MipsRegisterInfo::
|
||||
getRegisterNumbering(unsigned RegEnum)
|
||||
{
|
||||
switch (RegEnum) {
|
||||
case Mips::ZERO : return 0;
|
||||
case Mips::AT : return 1;
|
||||
case Mips::V0 : return 2;
|
||||
case Mips::V1 : return 3;
|
||||
case Mips::A0 : return 4;
|
||||
case Mips::A1 : return 5;
|
||||
case Mips::A2 : return 6;
|
||||
case Mips::A3 : return 7;
|
||||
case Mips::T0 : return 8;
|
||||
case Mips::T1 : return 9;
|
||||
case Mips::T2 : return 10;
|
||||
case Mips::T3 : return 11;
|
||||
case Mips::T4 : return 12;
|
||||
case Mips::T5 : return 13;
|
||||
case Mips::T6 : return 14;
|
||||
case Mips::T7 : return 15;
|
||||
case Mips::T8 : return 16;
|
||||
case Mips::T9 : return 17;
|
||||
case Mips::S0 : return 18;
|
||||
case Mips::S1 : return 19;
|
||||
case Mips::S2 : return 20;
|
||||
case Mips::S3 : return 21;
|
||||
case Mips::S4 : return 22;
|
||||
case Mips::S5 : return 23;
|
||||
case Mips::S6 : return 24;
|
||||
case Mips::S7 : return 25;
|
||||
case Mips::K0 : return 26;
|
||||
case Mips::K1 : return 27;
|
||||
case Mips::GP : return 28;
|
||||
case Mips::SP : return 29;
|
||||
case Mips::FP : return 30;
|
||||
case Mips::RA : return 31;
|
||||
case Mips::ZERO : case Mips::F0 : return 0;
|
||||
case Mips::AT : case Mips::F1 : return 1;
|
||||
case Mips::V0 : case Mips::F2 : return 2;
|
||||
case Mips::V1 : case Mips::F3 : return 3;
|
||||
case Mips::A0 : case Mips::F4 : return 4;
|
||||
case Mips::A1 : case Mips::F5 : return 5;
|
||||
case Mips::A2 : case Mips::F6 : return 6;
|
||||
case Mips::A3 : case Mips::F7 : return 7;
|
||||
case Mips::T0 : case Mips::F8 : return 8;
|
||||
case Mips::T1 : case Mips::F9 : return 9;
|
||||
case Mips::T2 : case Mips::F10: return 10;
|
||||
case Mips::T3 : case Mips::F11: return 11;
|
||||
case Mips::T4 : case Mips::F12: return 12;
|
||||
case Mips::T5 : case Mips::F13: return 13;
|
||||
case Mips::T6 : case Mips::F14: return 14;
|
||||
case Mips::T7 : case Mips::F15: return 15;
|
||||
case Mips::T8 : case Mips::F16: return 16;
|
||||
case Mips::T9 : case Mips::F17: return 17;
|
||||
case Mips::S0 : case Mips::F18: return 18;
|
||||
case Mips::S1 : case Mips::F19: return 19;
|
||||
case Mips::S2 : case Mips::F20: return 20;
|
||||
case Mips::S3 : case Mips::F21: return 21;
|
||||
case Mips::S4 : case Mips::F22: return 22;
|
||||
case Mips::S5 : case Mips::F23: return 23;
|
||||
case Mips::S6 : case Mips::F24: return 24;
|
||||
case Mips::S7 : case Mips::F25: return 25;
|
||||
case Mips::K0 : case Mips::F26: return 26;
|
||||
case Mips::K1 : case Mips::F27: return 27;
|
||||
case Mips::GP : case Mips::F28: return 28;
|
||||
case Mips::SP : case Mips::F29: return 29;
|
||||
case Mips::FP : case Mips::F30: return 30;
|
||||
case Mips::RA : case Mips::F31: return 31;
|
||||
default: assert(0 && "Unknown register number!");
|
||||
}
|
||||
return 0; // Not reached
|
||||
@ -94,11 +92,12 @@ getRegisterNumbering(unsigned RegEnum)
|
||||
const unsigned* MipsRegisterInfo::
|
||||
getCalleeSavedRegs(const MachineFunction *MF) const
|
||||
{
|
||||
// Mips calle-save register range is $16-$26(s0-s7)
|
||||
// Mips callee-save register range is $16-$23(s0-s7)
|
||||
static const unsigned CalleeSavedRegs[] = {
|
||||
Mips::S0, Mips::S1, Mips::S2, Mips::S3,
|
||||
Mips::S4, Mips::S5, Mips::S6, Mips::S7, 0
|
||||
};
|
||||
|
||||
return CalleeSavedRegs;
|
||||
}
|
||||
|
||||
@ -271,6 +270,8 @@ emitPrologue(MachineFunction &MF) const
|
||||
int FPOffset, RAOffset;
|
||||
|
||||
// Allocate space for saved RA and FP when needed
|
||||
// FIXME: within 64-bit registers, change hardcoded
|
||||
// sizes for RA and FP offsets.
|
||||
if ((hasFP(MF)) && (MFI->hasCalls())) {
|
||||
FPOffset = NumBytes;
|
||||
RAOffset = (NumBytes+4);
|
||||
@ -283,8 +284,7 @@ emitPrologue(MachineFunction &MF) const
|
||||
FPOffset = NumBytes;
|
||||
RAOffset = 0;
|
||||
NumBytes += 4;
|
||||
} else {
|
||||
// No calls and no fp.
|
||||
} else { // No calls and no fp.
|
||||
RAOffset = FPOffset = 0;
|
||||
}
|
||||
|
||||
|
@ -17,50 +17,123 @@ class MipsReg<string n> : Register<n> {
|
||||
let Namespace = "Mips";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// General Purpose Registers
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Mips CPU Registers
|
||||
class MipsGPRReg<bits<5> num, string n> : MipsReg<n> {
|
||||
let Num = num;
|
||||
}
|
||||
|
||||
// CPU GPR Registers
|
||||
def ZERO : MipsGPRReg< 0, "ZERO">, DwarfRegNum<[0]>;
|
||||
def AT : MipsGPRReg< 1, "AT">, DwarfRegNum<[1]>;
|
||||
def V0 : MipsGPRReg< 2, "2">, DwarfRegNum<[2]>;
|
||||
def V1 : MipsGPRReg< 3, "3">, DwarfRegNum<[3]>;
|
||||
def A0 : MipsGPRReg< 4, "4">, DwarfRegNum<[5]>;
|
||||
def A1 : MipsGPRReg< 5, "5">, DwarfRegNum<[5]>;
|
||||
def A2 : MipsGPRReg< 6, "6">, DwarfRegNum<[6]>;
|
||||
def A3 : MipsGPRReg< 7, "7">, DwarfRegNum<[7]>;
|
||||
def T0 : MipsGPRReg< 8, "8">, DwarfRegNum<[8]>;
|
||||
def T1 : MipsGPRReg< 9, "9">, DwarfRegNum<[9]>;
|
||||
def T2 : MipsGPRReg< 10, "10">, DwarfRegNum<[10]>;
|
||||
def T3 : MipsGPRReg< 11, "11">, DwarfRegNum<[11]>;
|
||||
def T4 : MipsGPRReg< 12, "12">, DwarfRegNum<[12]>;
|
||||
def T5 : MipsGPRReg< 13, "13">, DwarfRegNum<[13]>;
|
||||
def T6 : MipsGPRReg< 14, "14">, DwarfRegNum<[14]>;
|
||||
def T7 : MipsGPRReg< 15, "15">, DwarfRegNum<[15]>;
|
||||
def S0 : MipsGPRReg< 16, "16">, DwarfRegNum<[16]>;
|
||||
def S1 : MipsGPRReg< 17, "17">, DwarfRegNum<[17]>;
|
||||
def S2 : MipsGPRReg< 18, "18">, DwarfRegNum<[18]>;
|
||||
def S3 : MipsGPRReg< 19, "19">, DwarfRegNum<[19]>;
|
||||
def S4 : MipsGPRReg< 20, "20">, DwarfRegNum<[20]>;
|
||||
def S5 : MipsGPRReg< 21, "21">, DwarfRegNum<[21]>;
|
||||
def S6 : MipsGPRReg< 22, "22">, DwarfRegNum<[22]>;
|
||||
def S7 : MipsGPRReg< 23, "23">, DwarfRegNum<[23]>;
|
||||
def T8 : MipsGPRReg< 24, "24">, DwarfRegNum<[24]>;
|
||||
def T9 : MipsGPRReg< 25, "25">, DwarfRegNum<[25]>;
|
||||
def K0 : MipsGPRReg< 26, "26">, DwarfRegNum<[26]>;
|
||||
def K1 : MipsGPRReg< 27, "27">, DwarfRegNum<[27]>;
|
||||
def GP : MipsGPRReg< 28, "GP">, DwarfRegNum<[28]>;
|
||||
def SP : MipsGPRReg< 29, "SP">, DwarfRegNum<[29]>;
|
||||
def FP : MipsGPRReg< 30, "FP">, DwarfRegNum<[30]>;
|
||||
def RA : MipsGPRReg< 31, "RA">, DwarfRegNum<[31]>;
|
||||
// Mips 32-bit FPU Registers
|
||||
class FPR<bits<5> num, string n> : MipsReg<n> {
|
||||
let Num = num;
|
||||
}
|
||||
|
||||
// Mips 64-bit (aliased) FPU Registers
|
||||
class AFPR<bits<5> num, string n, list<Register> aliases> : MipsReg<n> {
|
||||
let Num = num;
|
||||
let Aliases = aliases;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Registers
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
let Namespace = "Mips" in {
|
||||
|
||||
// General Purpose Registers
|
||||
def ZERO : MipsGPRReg< 0, "ZERO">, DwarfRegNum<[0]>;
|
||||
def AT : MipsGPRReg< 1, "AT">, DwarfRegNum<[1]>;
|
||||
def V0 : MipsGPRReg< 2, "2">, DwarfRegNum<[2]>;
|
||||
def V1 : MipsGPRReg< 3, "3">, DwarfRegNum<[3]>;
|
||||
def A0 : MipsGPRReg< 4, "4">, DwarfRegNum<[5]>;
|
||||
def A1 : MipsGPRReg< 5, "5">, DwarfRegNum<[5]>;
|
||||
def A2 : MipsGPRReg< 6, "6">, DwarfRegNum<[6]>;
|
||||
def A3 : MipsGPRReg< 7, "7">, DwarfRegNum<[7]>;
|
||||
def T0 : MipsGPRReg< 8, "8">, DwarfRegNum<[8]>;
|
||||
def T1 : MipsGPRReg< 9, "9">, DwarfRegNum<[9]>;
|
||||
def T2 : MipsGPRReg< 10, "10">, DwarfRegNum<[10]>;
|
||||
def T3 : MipsGPRReg< 11, "11">, DwarfRegNum<[11]>;
|
||||
def T4 : MipsGPRReg< 12, "12">, DwarfRegNum<[12]>;
|
||||
def T5 : MipsGPRReg< 13, "13">, DwarfRegNum<[13]>;
|
||||
def T6 : MipsGPRReg< 14, "14">, DwarfRegNum<[14]>;
|
||||
def T7 : MipsGPRReg< 15, "15">, DwarfRegNum<[15]>;
|
||||
def S0 : MipsGPRReg< 16, "16">, DwarfRegNum<[16]>;
|
||||
def S1 : MipsGPRReg< 17, "17">, DwarfRegNum<[17]>;
|
||||
def S2 : MipsGPRReg< 18, "18">, DwarfRegNum<[18]>;
|
||||
def S3 : MipsGPRReg< 19, "19">, DwarfRegNum<[19]>;
|
||||
def S4 : MipsGPRReg< 20, "20">, DwarfRegNum<[20]>;
|
||||
def S5 : MipsGPRReg< 21, "21">, DwarfRegNum<[21]>;
|
||||
def S6 : MipsGPRReg< 22, "22">, DwarfRegNum<[22]>;
|
||||
def S7 : MipsGPRReg< 23, "23">, DwarfRegNum<[23]>;
|
||||
def T8 : MipsGPRReg< 24, "24">, DwarfRegNum<[24]>;
|
||||
def T9 : MipsGPRReg< 25, "25">, DwarfRegNum<[25]>;
|
||||
def K0 : MipsGPRReg< 26, "26">, DwarfRegNum<[26]>;
|
||||
def K1 : MipsGPRReg< 27, "27">, DwarfRegNum<[27]>;
|
||||
def GP : MipsGPRReg< 28, "GP">, DwarfRegNum<[28]>;
|
||||
def SP : MipsGPRReg< 29, "SP">, DwarfRegNum<[29]>;
|
||||
def FP : MipsGPRReg< 30, "FP">, DwarfRegNum<[30]>;
|
||||
def RA : MipsGPRReg< 31, "RA">, DwarfRegNum<[31]>;
|
||||
|
||||
/// Mips Single point precision FPU Registers
|
||||
def F0 : FPR< 0, "F0">, DwarfRegNum<[32]>;
|
||||
def F1 : FPR< 1, "F1">, DwarfRegNum<[33]>;
|
||||
def F2 : FPR< 2, "F2">, DwarfRegNum<[34]>;
|
||||
def F3 : FPR< 3, "F3">, DwarfRegNum<[35]>;
|
||||
def F4 : FPR< 4, "F4">, DwarfRegNum<[36]>;
|
||||
def F5 : FPR< 5, "F5">, DwarfRegNum<[37]>;
|
||||
def F6 : FPR< 6, "F6">, DwarfRegNum<[38]>;
|
||||
def F7 : FPR< 7, "F7">, DwarfRegNum<[39]>;
|
||||
def F8 : FPR< 8, "F8">, DwarfRegNum<[40]>;
|
||||
def F9 : FPR< 9, "F9">, DwarfRegNum<[41]>;
|
||||
def F10 : FPR<10, "F10">, DwarfRegNum<[42]>;
|
||||
def F11 : FPR<11, "F11">, DwarfRegNum<[43]>;
|
||||
def F12 : FPR<12, "F12">, DwarfRegNum<[44]>;
|
||||
def F13 : FPR<13, "F13">, DwarfRegNum<[45]>;
|
||||
def F14 : FPR<14, "F14">, DwarfRegNum<[46]>;
|
||||
def F15 : FPR<15, "F15">, DwarfRegNum<[47]>;
|
||||
def F16 : FPR<16, "F16">, DwarfRegNum<[48]>;
|
||||
def F17 : FPR<17, "F17">, DwarfRegNum<[49]>;
|
||||
def F18 : FPR<18, "F18">, DwarfRegNum<[50]>;
|
||||
def F19 : FPR<19, "F19">, DwarfRegNum<[51]>;
|
||||
def F20 : FPR<20, "F20">, DwarfRegNum<[52]>;
|
||||
def F21 : FPR<21, "F21">, DwarfRegNum<[53]>;
|
||||
def F22 : FPR<22, "F22">, DwarfRegNum<[54]>;
|
||||
def F23 : FPR<23, "F23">, DwarfRegNum<[55]>;
|
||||
def F24 : FPR<24, "F24">, DwarfRegNum<[56]>;
|
||||
def F25 : FPR<25, "F25">, DwarfRegNum<[57]>;
|
||||
def F26 : FPR<26, "F26">, DwarfRegNum<[58]>;
|
||||
def F27 : FPR<27, "F27">, DwarfRegNum<[59]>;
|
||||
def F28 : FPR<28, "F28">, DwarfRegNum<[60]>;
|
||||
def F29 : FPR<29, "F29">, DwarfRegNum<[61]>;
|
||||
def F30 : FPR<30, "F30">, DwarfRegNum<[62]>;
|
||||
def F31 : FPR<31, "F31">, DwarfRegNum<[63]>;
|
||||
|
||||
/// Mips Double point precision FPU Registers (aliased
|
||||
/// with the single precision to hold 64 bit values)
|
||||
def D0 : AFPR< 0, "F0", [F0, F1]>, DwarfRegNum<[32]>;
|
||||
def D1 : AFPR< 2, "F2", [F2, F3]>, DwarfRegNum<[34]>;
|
||||
def D2 : AFPR< 4, "F4", [F4, F5]>, DwarfRegNum<[36]>;
|
||||
def D3 : AFPR< 6, "F6", [F6, F7]>, DwarfRegNum<[38]>;
|
||||
def D4 : AFPR< 8, "F8", [F8, F9]>, DwarfRegNum<[40]>;
|
||||
def D5 : AFPR<10, "F10", [F10, F11]>, DwarfRegNum<[42]>;
|
||||
def D6 : AFPR<12, "F12", [F12, F13]>, DwarfRegNum<[44]>;
|
||||
def D7 : AFPR<14, "F14", [F14, F15]>, DwarfRegNum<[46]>;
|
||||
def D8 : AFPR<16, "F16", [F16, F17]>, DwarfRegNum<[48]>;
|
||||
def D9 : AFPR<18, "F18", [F18, F19]>, DwarfRegNum<[50]>;
|
||||
def D10 : AFPR<20, "F20", [F20, F21]>, DwarfRegNum<[52]>;
|
||||
def D11 : AFPR<22, "F22", [F22, F23]>, DwarfRegNum<[54]>;
|
||||
def D12 : AFPR<24, "F24", [F24, F25]>, DwarfRegNum<[56]>;
|
||||
def D13 : AFPR<26, "F26", [F26, F27]>, DwarfRegNum<[58]>;
|
||||
def D14 : AFPR<28, "F28", [F28, F29]>, DwarfRegNum<[60]>;
|
||||
def D15 : AFPR<30, "F30", [F30, F31]>, DwarfRegNum<[62]>;
|
||||
|
||||
// Status flags register
|
||||
def FCR31 : Register<"FCR31">;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Register Classes
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// CPU Registers Class
|
||||
def CPURegs : RegisterClass<"Mips", [i32], 32,
|
||||
// Return Values and Arguments
|
||||
[V0, V1, A0, A1, A2, A3,
|
||||
@ -83,51 +156,14 @@ def CPURegs : RegisterClass<"Mips", [i32], 32,
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating Point Unit Registers (Single Precision)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Mips Single point precision FPU Register Format
|
||||
class MipsFPUReg<bits<5> num, string n> : MipsReg<n> {
|
||||
let Num = num;
|
||||
}
|
||||
|
||||
/// Mips Single point precision FPU Registers
|
||||
def F0 : MipsFPUReg< 0, "F0">, DwarfRegNum<[32]>;
|
||||
def F1 : MipsFPUReg< 1, "F1">, DwarfRegNum<[33]>;
|
||||
def F2 : MipsFPUReg< 2, "F2">, DwarfRegNum<[34]>;
|
||||
def F3 : MipsFPUReg< 3, "F3">, DwarfRegNum<[35]>;
|
||||
def F4 : MipsFPUReg< 4, "F4">, DwarfRegNum<[36]>;
|
||||
def F5 : MipsFPUReg< 5, "F5">, DwarfRegNum<[37]>;
|
||||
def F6 : MipsFPUReg< 6, "F6">, DwarfRegNum<[38]>;
|
||||
def F7 : MipsFPUReg< 7, "F7">, DwarfRegNum<[39]>;
|
||||
def F8 : MipsFPUReg< 8, "F8">, DwarfRegNum<[40]>;
|
||||
def F9 : MipsFPUReg< 9, "F9">, DwarfRegNum<[41]>;
|
||||
def F10 : MipsFPUReg<10, "F10">, DwarfRegNum<[42]>;
|
||||
def F11 : MipsFPUReg<11, "F11">, DwarfRegNum<[43]>;
|
||||
def F12 : MipsFPUReg<12, "F12">, DwarfRegNum<[44]>;
|
||||
def F13 : MipsFPUReg<13, "F13">, DwarfRegNum<[45]>;
|
||||
def F14 : MipsFPUReg<14, "F14">, DwarfRegNum<[46]>;
|
||||
def F15 : MipsFPUReg<15, "F15">, DwarfRegNum<[47]>;
|
||||
def F16 : MipsFPUReg<16, "F16">, DwarfRegNum<[48]>;
|
||||
def F17 : MipsFPUReg<17, "F17">, DwarfRegNum<[49]>;
|
||||
def F18 : MipsFPUReg<18, "F18">, DwarfRegNum<[50]>;
|
||||
def F19 : MipsFPUReg<19, "F19">, DwarfRegNum<[51]>;
|
||||
def F20 : MipsFPUReg<20, "F20">, DwarfRegNum<[52]>;
|
||||
def F21 : MipsFPUReg<21, "F21">, DwarfRegNum<[53]>;
|
||||
def F22 : MipsFPUReg<22, "F22">, DwarfRegNum<[54]>;
|
||||
def F23 : MipsFPUReg<23, "F23">, DwarfRegNum<[55]>;
|
||||
def F24 : MipsFPUReg<24, "F24">, DwarfRegNum<[56]>;
|
||||
def F25 : MipsFPUReg<25, "F25">, DwarfRegNum<[57]>;
|
||||
def F26 : MipsFPUReg<26, "F26">, DwarfRegNum<[58]>;
|
||||
def F27 : MipsFPUReg<27, "F27">, DwarfRegNum<[59]>;
|
||||
def F28 : MipsFPUReg<28, "F28">, DwarfRegNum<[60]>;
|
||||
def F29 : MipsFPUReg<29, "F29">, DwarfRegNum<[61]>;
|
||||
def F30 : MipsFPUReg<30, "F30">, DwarfRegNum<[62]>;
|
||||
def F31 : MipsFPUReg<31, "F31">, DwarfRegNum<[63]>;
|
||||
|
||||
/// FPU Single Point Precision Registers Class
|
||||
def FPUDRegs : RegisterClass<"Mips", [f32], 32,
|
||||
// * 64bit fp:
|
||||
// - FGR64 = 32 64-bit registers (default mode)
|
||||
// - AFGR32/AFGR64 = 16 even 32-bit registers (32-bit compatible mode) for
|
||||
// single and double access.
|
||||
// * 32bit fp:
|
||||
// - AFGR32/AFGR64 = 16 even 32-bit registers - single and double
|
||||
// - FGR32 = 32 32-bit registers (within single-only mode)
|
||||
def FGR32 : RegisterClass<"Mips", [f32], 32,
|
||||
// Return Values and Arguments
|
||||
[F0, F1, F2, F3, F12, F13, F14, F15,
|
||||
// Not preserved across procedure calls
|
||||
@ -141,45 +177,37 @@ def FPUDRegs : RegisterClass<"Mips", [f32], 32,
|
||||
iterator allocation_order_end(const MachineFunction &MF) const;
|
||||
}];
|
||||
let MethodBodies = [{
|
||||
FPUDRegsClass::iterator
|
||||
FPUDRegsClass::allocation_order_end(const MachineFunction &MF) const {
|
||||
FGR32Class::iterator
|
||||
FGR32Class::allocation_order_end(const MachineFunction &MF) const {
|
||||
// The last register on the list above is reserved
|
||||
return end()-1;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating Point Unit Registers (Double Precision)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Mips Double point precision FPU Register Format
|
||||
class MipsFPUDReg<bits<5> num, string n, list<Register> aliases> : MipsReg<n> {
|
||||
let Num = num;
|
||||
let Aliases = aliases;
|
||||
def AFGR32 : RegisterClass<"Mips", [f32], 32,
|
||||
// Return Values and Arguments
|
||||
[F0, F2, F12, F14,
|
||||
// Not preserved across procedure calls
|
||||
F4, F6, F8, F10, F16, F18,
|
||||
// Callee save
|
||||
F20, F22, F24, F26, F28, F30,
|
||||
// Reserved
|
||||
F31]>
|
||||
{
|
||||
let MethodProtos = [{
|
||||
iterator allocation_order_end(const MachineFunction &MF) const;
|
||||
}];
|
||||
let MethodBodies = [{
|
||||
AFGR32Class::iterator
|
||||
AFGR32Class::allocation_order_end(const MachineFunction &MF) const {
|
||||
// The last register on the list above is reserved
|
||||
return end()-1;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/// Mips Double point precision FPU Registers (aliased
|
||||
/// with the single precision to hold 64 bit values)
|
||||
def D0 : MipsFPUDReg< 0, "F0", [F0, F1]>, DwarfRegNum<[32]>;
|
||||
def D1 : MipsFPUDReg< 2, "F2", [F2, F3]>, DwarfRegNum<[34]>;
|
||||
def D2 : MipsFPUDReg< 4, "F4", [F4, F5]>, DwarfRegNum<[36]>;
|
||||
def D3 : MipsFPUDReg< 6, "F6", [F6, F7]>, DwarfRegNum<[38]>;
|
||||
def D4 : MipsFPUDReg< 8, "F8", [F8, F9]>, DwarfRegNum<[40]>;
|
||||
def D5 : MipsFPUDReg<10, "F10", [F10, F11]>, DwarfRegNum<[42]>;
|
||||
def D6 : MipsFPUDReg<12, "F12", [F12, F13]>, DwarfRegNum<[44]>;
|
||||
def D7 : MipsFPUDReg<14, "F14", [F14, F15]>, DwarfRegNum<[46]>;
|
||||
def D8 : MipsFPUDReg<16, "F16", [F16, F17]>, DwarfRegNum<[48]>;
|
||||
def D9 : MipsFPUDReg<18, "F18", [F18, F19]>, DwarfRegNum<[50]>;
|
||||
def D10 : MipsFPUDReg<20, "F20", [F20, F21]>, DwarfRegNum<[52]>;
|
||||
def D11 : MipsFPUDReg<22, "F22", [F22, F23]>, DwarfRegNum<[54]>;
|
||||
def D12 : MipsFPUDReg<24, "F24", [F24, F25]>, DwarfRegNum<[56]>;
|
||||
def D13 : MipsFPUDReg<26, "F26", [F26, F27]>, DwarfRegNum<[58]>;
|
||||
def D14 : MipsFPUDReg<28, "F28", [F28, F29]>, DwarfRegNum<[60]>;
|
||||
def D15 : MipsFPUDReg<30, "F30", [F30, F31]>, DwarfRegNum<[62]>;
|
||||
|
||||
/// FPU Single Point Precision Registers Class
|
||||
def FPURegs : RegisterClass<"Mips", [f32], 32,
|
||||
def AFGR64 : RegisterClass<"Mips", [f64], 64,
|
||||
// Return Values and Arguments
|
||||
[D0, D1, D6, D7,
|
||||
// Not preserved across procedure calls
|
||||
@ -193,10 +221,15 @@ def FPURegs : RegisterClass<"Mips", [f32], 32,
|
||||
iterator allocation_order_end(const MachineFunction &MF) const;
|
||||
}];
|
||||
let MethodBodies = [{
|
||||
FPURegsClass::iterator
|
||||
FPURegsClass::allocation_order_end(const MachineFunction &MF) const {
|
||||
AFGR64Class::iterator
|
||||
AFGR64Class::allocation_order_end(const MachineFunction &MF) const {
|
||||
// The last register on the list above is reserved
|
||||
return end()-1;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def CCR : RegisterClass<"Mips", [i32], 32, [FCR31]> {
|
||||
let CopyCost = -1; // Don't allow copying of status registers.
|
||||
}
|
||||
|
||||
|
@ -14,15 +14,29 @@
|
||||
#include "MipsSubtarget.h"
|
||||
#include "Mips.h"
|
||||
#include "MipsGenSubtarget.inc"
|
||||
#include "llvm/Module.h"
|
||||
using namespace llvm;
|
||||
|
||||
MipsSubtarget::MipsSubtarget(const TargetMachine &TM, const Module &M,
|
||||
const std::string &FS, bool little) :
|
||||
IsMipsIII(false),
|
||||
IsLittle(little)
|
||||
MipsArchVersion(Mips1), MipsABI(O32), IsLittle(little), IsSingleFloat(false),
|
||||
IsFP64bit(false), IsGP64bit(false), HasAllegrexVFPU(false), IsAllegrex(false)
|
||||
{
|
||||
std::string CPU = "mips1";
|
||||
|
||||
// Parse features string.
|
||||
ParseSubtargetFeatures(FS, CPU);
|
||||
|
||||
// When only the target triple is specified and is
|
||||
// a allegrex target, set the features. We also match
|
||||
// big and little endian allegrex cores (dont really
|
||||
// know if a big one exists)
|
||||
const std::string& TT = M.getTargetTriple();
|
||||
if (TT.find("mipsallegrex") != std::string::npos) {
|
||||
MipsABI = EABI;
|
||||
IsSingleFloat = true;
|
||||
MipsArchVersion = Mips2;
|
||||
HasAllegrexVFPU = true; // Enables Allegrex Vector FPU (not supported yet)
|
||||
IsAllegrex = true;
|
||||
}
|
||||
}
|
||||
|
@ -26,11 +26,48 @@ class MipsSubtarget : public TargetSubtarget {
|
||||
|
||||
protected:
|
||||
|
||||
bool IsMipsIII;
|
||||
enum MipsArchEnum {
|
||||
Mips1, Mips2, Mips3, Mips4, Mips32, Mips32r2
|
||||
};
|
||||
|
||||
enum MipsABIEnum {
|
||||
O32, EABI
|
||||
};
|
||||
|
||||
// Mips architecture version
|
||||
MipsArchEnum MipsArchVersion;
|
||||
|
||||
// Mips supported ABIs
|
||||
MipsABIEnum MipsABI;
|
||||
|
||||
// IsLittle - The target is Little Endian
|
||||
bool IsLittle;
|
||||
|
||||
// IsSingleFloat - The target only supports single precision float
|
||||
// point operations. This enable the target to use all 32 32-bit
|
||||
// float point registers instead of only using even ones.
|
||||
bool IsSingleFloat;
|
||||
|
||||
// IsFP64bit - The target processor has 64-bit float point registers.
|
||||
bool IsFP64bit;
|
||||
|
||||
// IsFP64bit - General-purpose registers are 64 bits wide
|
||||
bool IsGP64bit;
|
||||
|
||||
// HasAllegrexVFPU - Allegrex processor has a vector float point unit.
|
||||
bool HasAllegrexVFPU;
|
||||
|
||||
// IsAllegrex - The target processor is a Allegrex core.
|
||||
bool IsAllegrex;
|
||||
|
||||
InstrItineraryData InstrItins;
|
||||
|
||||
public:
|
||||
|
||||
/// Only O32 and EABI supported right now.
|
||||
bool isABI_EABI() const { return MipsABI == EABI; }
|
||||
bool isABI_O32() const { return MipsABI == O32; }
|
||||
|
||||
/// This constructor initializes the data members to match that
|
||||
/// of the specified module.
|
||||
MipsSubtarget(const TargetMachine &TM, const Module &M,
|
||||
@ -40,12 +77,17 @@ public:
|
||||
/// subtarget options. Definition of function is auto generated by tblgen.
|
||||
void ParseSubtargetFeatures(const std::string &FS, const std::string &CPU);
|
||||
|
||||
/// isMipsIII - Return true if the selected CPU supports MipsIII ISA
|
||||
/// support.
|
||||
bool isMipsIII() const { return IsMipsIII; }
|
||||
bool hasMips2Ops() const { return MipsArchVersion >= Mips2; }
|
||||
|
||||
/// isMipsIII - Return true if the target is little endian.
|
||||
bool isLittle() const { return IsLittle; }
|
||||
bool isFP64bit() const { return IsFP64bit; };
|
||||
bool isGP64bit() const { return IsGP64bit; };
|
||||
bool isGP32bit() const { return !IsGP64bit; };
|
||||
bool isSingleFloat() const { return IsSingleFloat; };
|
||||
bool isNotSingleFloat() const { return !IsSingleFloat; };
|
||||
bool hasAllegrexVFPU() const { return HasAllegrexVFPU; };
|
||||
bool isAllegrex() const { return IsAllegrex; };
|
||||
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -34,8 +34,7 @@ createTargetAsmInfo() const
|
||||
// On function prologue, the stack is created by decrementing
|
||||
// its pointer. Once decremented, all references are done with positive
|
||||
// offset from the stack/frame pointer, so StackGrowsUp is used.
|
||||
// When using CodeModel::Large the behaviour
|
||||
//
|
||||
// Using CodeModel::Large enables different CALL behavior.
|
||||
MipsTargetMachine::
|
||||
MipsTargetMachine(const Module &M, const std::string &FS, bool isLittle=false):
|
||||
Subtarget(*this, M, FS, isLittle),
|
||||
@ -59,22 +58,33 @@ MipselTargetMachine(const Module &M, const std::string &FS) :
|
||||
unsigned MipsTargetMachine::
|
||||
getModuleMatchQuality(const Module &M)
|
||||
{
|
||||
// We strongly match "mips-*".
|
||||
// We strongly match "mips*-*".
|
||||
std::string TT = M.getTargetTriple();
|
||||
if (TT.size() >= 5 && std::string(TT.begin(), TT.begin()+5) == "mips-")
|
||||
return 20;
|
||||
|
||||
if (TT.size() >= 13 && std::string(TT.begin(),
|
||||
TT.begin()+13) == "mipsallegrex-")
|
||||
return 20;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return 0 and must specify -march to gen MIPSel code.
|
||||
// return 0 and must specify -march to gen MIPSEL code.
|
||||
unsigned MipselTargetMachine::
|
||||
getModuleMatchQuality(const Module &M)
|
||||
{
|
||||
// We strongly match "mipsel-*".
|
||||
// We strongly match "mips*el-*".
|
||||
std::string TT = M.getTargetTriple();
|
||||
if (TT.size() >= 7 && std::string(TT.begin(), TT.begin()+7) == "mipsel-")
|
||||
return 20;
|
||||
|
||||
if (TT.size() >= 15 && std::string(TT.begin(),
|
||||
TT.begin()+15) == "mipsallegrexel-")
|
||||
return 20;
|
||||
|
||||
if (TT.size() == 3 && std::string(TT.begin(), TT.begin()+3) == "psp")
|
||||
return 20;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user