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:
Bruno Cardoso Lopes 2008-07-05 19:05:21 +00:00
parent 126d90770b
commit 225ca9cdd7
17 changed files with 1249 additions and 445 deletions

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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>
]>;

View File

@ -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);

View File

@ -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>();
}

View File

@ -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);

View 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))>;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 {

View File

@ -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"

View File

@ -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

View File

@ -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;
}

View File

@ -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.
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}