Initial Mips support, here we go! =)

- Modifications from the last patch included
  (issues pointed by Evan Cheng are now fixed).
- Added more MipsI instructions.
- Added more patterns to match branch instructions.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@37461 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bruno Cardoso Lopes 2007-06-06 07:42:06 +00:00
parent 49fdfdb1e5
commit 972f5896e4
21 changed files with 2788 additions and 0 deletions

21
lib/Target/Mips/Makefile Normal file
View File

@ -0,0 +1,21 @@
##===- lib/Target/Mips/Makefile ----------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file was developed by Bruno Cardoso Lopes and is distributed under the
# University of Illinois Open Source License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../..
LIBRARYNAME = LLVMMips
TARGET = Mips
# Make sure that tblgen is run, first thing.
BUILT_SOURCES = MipsGenRegisterInfo.h.inc MipsGenRegisterNames.inc \
MipsGenRegisterInfo.inc MipsGenInstrNames.inc \
MipsGenInstrInfo.inc MipsGenAsmWriter.inc \
MipsGenDAGISel.inc MipsGenCallingConv.inc \
MipsGenSubtarget.inc
include $(LEVEL)/Makefile.common

38
lib/Target/Mips/Mips.h Normal file
View File

@ -0,0 +1,38 @@
//===-- Mips.h - Top-level interface for Mips representation ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the entry points for global functions defined in
// the LLVM Mips back-end.
//
//===----------------------------------------------------------------------===//
#ifndef TARGET_MIPS_H
#define TARGET_MIPS_H
#include <iosfwd>
namespace llvm {
class MipsTargetMachine;
class FunctionPassManager;
class FunctionPass;
class MachineCodeEmitter;
FunctionPass *createMipsCodePrinterPass(std::ostream &OS,
MipsTargetMachine &TM);
FunctionPass *createMipsISelDag(MipsTargetMachine &TM);
} // end namespace llvm;
// Defines symbolic names for Mips registers. This defines a mapping from
// register name to register number.
#include "MipsGenRegisterNames.inc"
// Defines symbolic names for the Mips instructions.
#include "MipsGenInstrNames.inc"
#endif

63
lib/Target/Mips/Mips.td Normal file
View File

@ -0,0 +1,63 @@
//===- Mips.td - Describe the Mips Target Machine ---------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Target-independent interfaces which we are implementing
//===----------------------------------------------------------------------===//
include "../Target.td"
//===----------------------------------------------------------------------===//
// Register File Description
//===----------------------------------------------------------------------===//
include "MipsRegisterInfo.td"
//===----------------------------------------------------------------------===//
// Subtarget features
//===----------------------------------------------------------------------===//
// TODO: dummy, needed to compile
def FeatureCIX : SubtargetFeature<"r3000", "isR3000", "true",
"Enable r3000 extentions">;
//===----------------------------------------------------------------------===//
// Instruction Description
//===----------------------------------------------------------------------===//
include "MipsInstrInfo.td"
def MipsInstrInfo : InstrInfo {
// Define how we want to layout our target-specific information field.
let TSFlagsFields = [];
let TSFlagsShifts = [];
}
//===----------------------------------------------------------------------===//
// Calling Conventions
//===----------------------------------------------------------------------===//
include "MipsCallingConv.td"
//===----------------------------------------------------------------------===//
// Mips processors supported.
//===----------------------------------------------------------------------===//
class Proc<string Name, list<SubtargetFeature> Features>
: Processor<Name, NoItineraries, Features>;
def : Proc<"generic", []>;
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
//===----------------------------------------------------------------------===//
def Mips : Target {
// Pull in Instruction Info:
let InstructionSet = MipsInstrInfo;
}

View File

@ -0,0 +1,294 @@
//===-- MipsAsmPrinter.cpp - Mips LLVM assembly writer --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to GAS-format MIPS assembly language.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mips-asm-printer"
#include "Mips.h"
#include "MipsInstrInfo.h"
#include "MipsTargetMachine.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Mangler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MathExtras.h"
#include <cctype>
using namespace llvm;
STATISTIC(EmittedInsts, "Number of machine instrs printed");
namespace {
struct VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter {
MipsAsmPrinter(std::ostream &O, MipsTargetMachine &TM,
const TargetAsmInfo *T):
AsmPrinter(O, TM, T) {}
virtual const char *getPassName() const {
return "Mips Assembly Printer";
}
void printOperand(const MachineInstr *MI, int opNum);
void printMemOperand(const MachineInstr *MI, int opNum,
const char *Modifier = 0);
bool printInstruction(const MachineInstr *MI); // autogenerated.
bool runOnMachineFunction(MachineFunction &F);
bool doInitialization(Module &M);
bool doFinalization(Module &M);
};
} // end of anonymous namespace
#include "MipsGenAsmWriter.inc"
/// createMipsCodePrinterPass - Returns a pass that prints the MIPS
/// assembly code for a MachineFunction to the given output stream,
/// using the given target machine description. This should work
/// regardless of whether the function is in SSA form.
FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o,
MipsTargetMachine &tm)
{
return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo());
}
/// runOnMachineFunction - This uses the printMachineInstruction()
/// method to print assembly for each instruction.
bool MipsAsmPrinter::
runOnMachineFunction(MachineFunction &MF)
{
SetupMachineFunction(MF);
// Print out constants referenced by the function
EmitConstantPool(MF.getConstantPool());
O << "\n\n";
// What's my mangled name?
CurrentFnName = Mang->getValueName(MF.getFunction());
// Print out the label for the function.
const Function *F = MF.getFunction();
SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
// On Mips GAS if .align #n is present, #n means the number of bits
// to be cleared to align. So, if we want 4 byte alignment, we must
// have .align 2
// TODO:
// add gas ".mask" and ".fmask"
EmitAlignment(1, F);
O << "\t.globl\t" << CurrentFnName << "\n";
O << "\t.ent\t" << CurrentFnName << "\n";
O << "\t.type\t" << CurrentFnName << ", @function\n";
O << CurrentFnName << ":\n";
// Print out code for the function.
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
I != E; ++I) {
// Print a label for the basic block.
if (I != MF.begin()) {
printBasicBlockLabel(I, true);
O << '\n';
}
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
II != E; ++II) {
// Print the assembly for the instruction.
O << "\t";
printInstruction(II);
++EmittedInsts;
}
}
// close function with asm directive
O << "\t.end\t" << CurrentFnName << "\n";
// We didn't modify anything.
return false;
}
void MipsAsmPrinter::
printOperand(const MachineInstr *MI, int opNum)
{
const MachineOperand &MO = MI->getOperand(opNum);
const MRegisterInfo &RI = *TM.getRegisterInfo();
bool closeP=false;
// %hi and %lo used on mips gas to break large constants
if (MI->getOpcode() == Mips::LUi && !MO.isRegister()
&& !MO.isImmediate()) {
O << "%hi(";
closeP = true;
} else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isRegister()
&& !MO.isImmediate()) {
O << "%lo(";
closeP = true;
}
switch (MO.getType())
{
case MachineOperand::MO_Register:
if (MRegisterInfo::isPhysicalRegister(MO.getReg()))
O << "$" << LowercaseString (RI.get(MO.getReg()).Name);
else
O << "$" << MO.getReg();
break;
case MachineOperand::MO_Immediate:
if ((MI->getOpcode() == Mips::SLTiu) || (MI->getOpcode() == Mips::ORi) ||
(MI->getOpcode() == Mips::LUi) || (MI->getOpcode() == Mips::ANDi))
O << (unsigned int)MO.getImmedValue();
else
O << (int)MO.getImmedValue();
break;
case MachineOperand::MO_MachineBasicBlock:
printBasicBlockLabel(MO.getMachineBasicBlock());
return;
case MachineOperand::MO_GlobalAddress:
O << Mang->getValueName(MO.getGlobal());
break;
case MachineOperand::MO_ExternalSymbol:
O << MO.getSymbolName();
break;
case MachineOperand::MO_ConstantPoolIndex:
O << TAI->getPrivateGlobalPrefix() << "CPI"
<< getFunctionNumber() << "_" << MO.getConstantPoolIndex();
break;
default:
O << "<unknown operand type>"; abort (); break;
}
if (closeP) O << ")";
}
void MipsAsmPrinter::
printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier)
{
// lw/sw $reg, MemOperand
// will turn into :
// lw/sw $reg, imm($reg)
printOperand(MI, opNum);
O << "(";
printOperand(MI, opNum+1);
O << ")";
}
bool MipsAsmPrinter::
doInitialization(Module &M)
{
Mang = new Mangler(M);
return false; // success
}
bool MipsAsmPrinter::
doFinalization(Module &M)
{
const TargetData *TD = TM.getTargetData();
// Print out module-level global variables here.
for (Module::const_global_iterator I = M.global_begin(),
E = M.global_end(); I != E; ++I)
// External global require no code
if (I->hasInitializer()) {
// Check to see if this is a special global
// used by LLVM, if so, emit it.
if (EmitSpecialLLVMGlobal(I))
continue;
O << "\n\n";
std::string name = Mang->getValueName(I);
Constant *C = I->getInitializer();
unsigned Size = TD->getTypeSize(C->getType());
unsigned Align = TD->getPrefTypeAlignment(C->getType());
if (C->isNullValue() && (I->hasLinkOnceLinkage() ||
I->hasInternalLinkage() || I->hasWeakLinkage()
/* FIXME: Verify correct */)) {
SwitchToDataSection(".data", I);
if (I->hasInternalLinkage())
O << "\t.local " << name << "\n";
O << "\t.comm " << name << ","
<< TD->getTypeSize(C->getType())
<< "," << Align << "\n";
} else {
switch (I->getLinkage())
{
case GlobalValue::LinkOnceLinkage:
case GlobalValue::WeakLinkage:
// FIXME: Verify correct for weak.
// Nonnull linkonce -> weak
O << "\t.weak " << name << "\n";
SwitchToDataSection("", I);
O << "\t.section\t\".llvm.linkonce.d." << name
<< "\",\"aw\",@progbits\n";
break;
case GlobalValue::AppendingLinkage:
// FIXME: appending linkage variables
// should go into a section of their name or
// something. For now, just emit them as external.
case GlobalValue::ExternalLinkage:
// If external or appending, declare as a global symbol
O << "\t.globl " << name << "\n";
case GlobalValue::InternalLinkage:
if (C->isNullValue())
SwitchToDataSection(".bss", I);
else
SwitchToDataSection(".data", I);
break;
case GlobalValue::GhostLinkage:
cerr << "Should not have any"
<< "unmaterialized functions!\n";
abort();
case GlobalValue::DLLImportLinkage:
cerr << "DLLImport linkage is"
<< "not supported by this target!\n";
abort();
case GlobalValue::DLLExportLinkage:
cerr << "DLLExport linkage is"
<< "not supported by this target!\n";
abort();
default:
assert(0 && "Unknown linkage type!");
}
O << "\t.align " << Align << "\n";
O << "\t.type " << name << ",@object\n";
O << "\t.size " << name << "," << Size << "\n";
O << name << ":\n";
EmitGlobalConstant(C);
}
}
AsmPrinter::doFinalization(M);
return false; // success
}

View File

@ -0,0 +1,39 @@
//===- MipsCallingConv.td - Calling Conventions for Mips --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This describes the calling conventions for Mips architecture.
//===----------------------------------------------------------------------===//
/// CCIfSubtarget - Match if the current subtarget has a feature F.
class CCIfSubtarget<string F, CCAction A>:
CCIf<!strconcat("State.getTarget().getSubtarget<MipsSubtarget>().", F), A>;
//===----------------------------------------------------------------------===//
// Mips Return Value 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<[
// Promote i8/i16 arguments to i32.
CCIfType<[i8, i16], CCPromoteToType<i32>>,
// The first 4 integer arguments are passed in integer registers.
CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3]>>,
// Integer values get stored in stack slots that are 4 bytes in
// size and 4-byte aligned.
CCIfType<[i32], CCAssignToStack<4, 4>>
]>;

View File

@ -0,0 +1,272 @@
//===-- MipsISelDAGToDAG.cpp - A dag to dag inst selector for Mips --------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the MIPS target.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mips-isel"
#include "Mips.h"
#include "MipsISelLowering.h"
#include "MipsRegisterInfo.h"
#include "MipsSubtarget.h"
#include "MipsTargetMachine.h"
#include "llvm/GlobalValue.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Support/CFG.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include <queue>
#include <set>
using namespace llvm;
//===----------------------------------------------------------------------===//
// Instruction Selector Implementation
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// MipsDAGToDAGISel - MIPS specific code to select MIPS machine
// instructions for SelectionDAG operations.
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN MipsDAGToDAGISel : public SelectionDAGISel {
/// TM - Keep a reference to MipsTargetMachine.
MipsTargetMachine &TM;
/// MipsLowering - This object fully describes how to lower LLVM code to an
/// Mips-specific SelectionDAG.
MipsTargetLowering MipsLowering;
/// 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;
public:
MipsDAGToDAGISel(MipsTargetMachine &tm) :
SelectionDAGISel(MipsLowering),
TM(tm), MipsLowering(*TM.getTargetLowering()) {}
virtual void InstructionSelectBasicBlock(SelectionDAG &SD);
// Pass Name
virtual const char *getPassName() const {
return "MIPS DAG->DAG Pattern Instruction Selection";
}
private:
// Include the pieces autogenerated from the target description.
#include "MipsGenDAGISel.inc"
SDNode *Select(SDOperand N);
// Complex Pattern.
bool SelectAddr(SDOperand Op, SDOperand N,
SDOperand &Base, SDOperand &Offset);
// getI32Imm - Return a target constant with the specified
// value, of type i32.
inline SDOperand getI32Imm(unsigned Imm) {
return CurDAG->getTargetConstant(Imm, MVT::i32);
}
#ifndef NDEBUG
unsigned Indent;
#endif
};
}
/// InstructionSelectBasicBlock - This callback is invoked by
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
void MipsDAGToDAGISel::
InstructionSelectBasicBlock(SelectionDAG &SD)
{
DEBUG(BB->dump());
// Codegen the basic block.
#ifndef NDEBUG
DOUT << "===== Instruction selection begins:\n";
Indent = 0;
#endif
// Select target instructions for the DAG.
SD.setRoot(SelectRoot(SD.getRoot()));
#ifndef NDEBUG
DOUT << "===== Instruction selection ends:\n";
#endif
SD.RemoveDeadNodes();
// Emit machine code to BB.
ScheduleAndEmitDAG(SD);
}
/// ComplexPattern used on MipsInstrInfo
/// Used on Mips Load/Store instructions
bool MipsDAGToDAGISel::
SelectAddr(SDOperand Op, SDOperand Addr, SDOperand &Offset, SDOperand &Base)
{
// if Address is FI, get the TargetFrameIndex.
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
Offset = CurDAG->getTargetConstant(0, MVT::i32);
return true;
}
// TargetExternalSymbol and TargetGlobalAddress are
// lowered and their addresses go into registers, so
// they should not be touched here.
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
Addr.getOpcode() == ISD::TargetGlobalAddress))
return false;
// Operand is an result from an ADD.
if (Addr.getOpcode() == ISD::ADD)
{
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
{
if (Predicate_immSExt16(CN))
{
// If the first operand is a FI, get the TargetFI Node
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>
(Addr.getOperand(0))) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
} else {
Base = Addr.getOperand(0);
}
Offset = CurDAG->getTargetConstant(CN->getValue(), MVT::i32);
return true;
}
}
}
Base = Addr;
Offset = CurDAG->getTargetConstant(0, MVT::i32);
return true;
}
/// Select instructions not customized! Used for
/// expanded, promoted and normal instructions
SDNode* MipsDAGToDAGISel::
Select(SDOperand N)
{
SDNode *Node = N.Val;
unsigned Opcode = Node->getOpcode();
// Dump information about the Node being selected
#ifndef NDEBUG
DOUT << std::string(Indent, ' ') << "Selecting: ";
DEBUG(Node->dump(CurDAG));
DOUT << "\n";
Indent += 2;
#endif
// If we have a custom node, we already have selected!
if (Opcode >= ISD::BUILTIN_OP_END && Opcode < MipsISD::FIRST_NUMBER) {
#ifndef NDEBUG
DOUT << std::string(Indent-2, ' ') << "== ";
DEBUG(Node->dump(CurDAG));
DOUT << "\n";
Indent -= 2;
#endif
return NULL;
}
///
// Instruction Selection not handled by custom or by the
// auto-generated tablegen selection should be handled here
///
switch(Opcode) {
default: break;
/// Special Mul operations
case ISD::MULHS:
case ISD::MULHU: {
SDOperand MulOp1 = Node->getOperand(0);
SDOperand MulOp2 = Node->getOperand(1);
AddToISelQueue(MulOp1);
AddToISelQueue(MulOp2);
unsigned MulOp = (Opcode == ISD::MULHU ? Mips::MULTu : Mips::MULT);
SDNode *MulNode = CurDAG->getTargetNode(MulOp, MVT::Flag, MulOp1, MulOp2);
SDOperand MFInFlag = SDOperand(MulNode, 0);
return CurDAG->getTargetNode(Mips::MFHI, MVT::i32, MFInFlag);
}
/// Div operations
case ISD::SDIV:
case ISD::UDIV: {
SDOperand DivOp1 = Node->getOperand(0);
SDOperand DivOp2 = Node->getOperand(1);
AddToISelQueue(DivOp1);
AddToISelQueue(DivOp2);
unsigned DivOp = (Opcode == ISD::SDIV ? Mips::DIV : Mips::DIVu);
SDNode *DivNode = CurDAG->getTargetNode(DivOp, MVT::Flag, DivOp1, DivOp2);
SDOperand MFInFlag = SDOperand(DivNode, 0);
return CurDAG->getTargetNode(Mips::MFLO, MVT::i32, MFInFlag);
}
/// Rem operations
case ISD::SREM:
case ISD::UREM: {
SDOperand RemOp1 = Node->getOperand(0);
SDOperand RemOp2 = Node->getOperand(1);
AddToISelQueue(RemOp1);
AddToISelQueue(RemOp2);
unsigned RemOp = (Opcode == ISD::SREM ? Mips::DIV : Mips::DIVu);
SDNode *RemNode = CurDAG->getTargetNode(RemOp, MVT::Flag, RemOp1, RemOp2);
SDOperand MFInFlag = SDOperand(RemNode, 0);
return CurDAG->getTargetNode(Mips::MFHI, MVT::i32, MFInFlag);
}
}
// Select the default instruction
SDNode *ResNode = SelectCode(N);
#ifndef NDEBUG
DOUT << std::string(Indent-2, ' ') << "=> ";
if (ResNode == NULL || ResNode == N.Val)
DEBUG(N.Val->dump(CurDAG));
else
DEBUG(ResNode->dump(CurDAG));
DOUT << "\n";
Indent -= 2;
#endif
return ResNode;
}
/// createMipsISelDag - This pass converts a legalized DAG into a
/// MIPS-specific DAG, ready for instruction scheduling.
FunctionPass *llvm::createMipsISelDag(MipsTargetMachine &TM) {
return new MipsDAGToDAGISel(TM);
}

View File

@ -0,0 +1,519 @@
//===-- MipsISelLowering.cpp - Mips DAG Lowering Implementation -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that Mips uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mips-lower"
#include "MipsISelLowering.h"
#include "MipsTargetMachine.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Intrinsics.h"
#include "llvm/CallingConv.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Support/Debug.h"
#include <queue>
#include <set>
using namespace llvm;
const char *MipsTargetLowering::
getTargetNodeName(unsigned Opcode) const
{
switch (Opcode)
{
case MipsISD::JmpLink : return "MipsISD::JmpLink";
case MipsISD::Hi : return "MipsISD::Hi";
case MipsISD::Lo : return "MipsISD::Lo";
case MipsISD::Ret : return "MipsISD::Ret";
default : return NULL;
}
}
MipsTargetLowering::
MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM)
{
// Mips does not have i1 type, so use i32 for
// setcc operations results (slt, sgt, ...).
setSetCCResultType(MVT::i32);
setSetCCResultContents(ZeroOrOneSetCCResult);
// Set up the register classes
addRegisterClass(MVT::i32, Mips::CPURegsRegisterClass);
// Custom
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
setOperationAction(ISD::RET, MVT::Other, Custom);
// Load extented operations for i1 types must be promoted
setLoadXAction(ISD::EXTLOAD, MVT::i1, Promote);
setLoadXAction(ISD::ZEXTLOAD, MVT::i1, Promote);
setLoadXAction(ISD::SEXTLOAD, MVT::i1, Promote);
// Store operations for i1 types must be promoted
setStoreXAction(MVT::i1, Promote);
// Mips does not have these NodeTypes below.
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
setOperationAction(ISD::BR_CC, MVT::Other, Expand);
setOperationAction(ISD::SELECT_CC, MVT::Other, Expand);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
setOperationAction(ISD::SELECT, MVT::i32, Expand);
// Mips not supported intrinsics.
setOperationAction(ISD::MEMMOVE, MVT::Other, Expand);
setOperationAction(ISD::MEMSET, MVT::Other, Expand);
setOperationAction(ISD::MEMCPY, MVT::Other, Expand);
setOperationAction(ISD::CTPOP, MVT::i32, Expand);
setOperationAction(ISD::CTTZ , MVT::i32, Expand);
setOperationAction(ISD::CTLZ , MVT::i32, Expand);
setOperationAction(ISD::ROTL , MVT::i32, Expand);
setOperationAction(ISD::ROTR , MVT::i32, Expand);
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
// We don't have line number support yet.
setOperationAction(ISD::LOCATION, MVT::Other, Expand);
setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
setOperationAction(ISD::LABEL, MVT::Other, Expand);
// Use the default for now
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
setStackPointerRegisterToSaveRestore(Mips::SP);
computeRegisterProperties();
}
SDOperand MipsTargetLowering::
LowerOperation(SDOperand Op, SelectionDAG &DAG)
{
switch (Op.getOpcode())
{
case ISD::CALL: return LowerCALL(Op, DAG);
case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG);
case ISD::RET: return LowerRET(Op, DAG);
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
}
return SDOperand();
}
//===----------------------------------------------------------------------===//
// Lower helper functions
//===----------------------------------------------------------------------===//
// AddLiveIn - This helper function adds the specified physical register to the
// MachineFunction as a live in value. It also creates a corresponding
// virtual register for it.
static unsigned
AddLiveIn(MachineFunction &MF, unsigned PReg, TargetRegisterClass *RC)
{
assert(RC->contains(PReg) && "Not the correct regclass!");
unsigned VReg = MF.getSSARegMap()->createVirtualRegister(RC);
MF.addLiveIn(PReg, VReg);
return VReg;
}
// Set up a frame object for the return address.
SDOperand MipsTargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) {
if (ReturnAddrIndex == 0) {
MachineFunction &MF = DAG.getMachineFunction();
ReturnAddrIndex = MF.getFrameInfo()->CreateFixedObject(4, 0);
}
return DAG.getFrameIndex(ReturnAddrIndex, getPointerTy());
}
//===----------------------------------------------------------------------===//
// Misc Lower Operation implementation
//===----------------------------------------------------------------------===//
SDOperand MipsTargetLowering::
LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG)
{
GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
SDOperand GA = DAG.getTargetGlobalAddress(GV, MVT::i32);
SDOperand Hi = DAG.getNode(MipsISD::Hi, MVT::i32, GA);
SDOperand Lo = DAG.getNode(MipsISD::Lo, MVT::i32, GA);
return DAG.getNode(ISD::ADD, MVT::i32, Lo, Hi);
}
SDOperand MipsTargetLowering::
LowerRETURNADDR(SDOperand Op, SelectionDAG &DAG) {
// Depths > 0 not supported yet!
if (cast<ConstantSDNode>(Op.getOperand(0))->getValue() > 0)
return SDOperand();
// Just load the return address
SDOperand RetAddrFI = getReturnAddressFrameIndex(DAG);
return DAG.getLoad(getPointerTy(), DAG.getEntryNode(), RetAddrFI, NULL, 0);
}
//===----------------------------------------------------------------------===//
// Calling Convention Implementation
//
// The lower operations present on calling convention works on this order:
// LowerCALL (virt regs --> phys regs, virt regs --> stack)
// LowerFORMAL_ARGUMENTS (phys --> virt regs, stack --> virt regs)
// LowerRET (virt regs --> phys regs)
// LowerCALL (phys regs --> virt regs)
//
//===----------------------------------------------------------------------===//
#include "MipsGenCallingConv.inc"
//===----------------------------------------------------------------------===//
// CALL Calling Convention Implementation
//===----------------------------------------------------------------------===//
/// Mips custom CALL implementation
SDOperand MipsTargetLowering::
LowerCALL(SDOperand Op, SelectionDAG &DAG)
{
unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue();
// By now, only CallingConv::C implemented
switch (CallingConv)
{
default:
assert(0 && "Unsupported calling convention");
case CallingConv::Fast:
case CallingConv::C:
return LowerCCCCallTo(Op, DAG, CallingConv);
}
}
/// LowerCCCCallTo - functions arguments are copied from virtual
/// regs to (physical regs)/(stack frame), CALLSEQ_START and
/// CALLSEQ_END are emitted.
/// TODO: isVarArg, isTailCall, sret, GOT, linkage types.
SDOperand MipsTargetLowering::
LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
{
SDOperand Chain = Op.getOperand(0);
SDOperand Callee = Op.getOperand(4);
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CC, getTargetMachine(), ArgLocs);
CCInfo.AnalyzeCallOperands(Op.Val, CC_Mips);
// Get a count of how many bytes are to be pushed on the stack.
unsigned NumBytes = CCInfo.getNextStackOffset();
Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes,
getPointerTy()));
SmallVector<std::pair<unsigned, SDOperand>, 8> RegsToPass;
SmallVector<SDOperand, 8> MemOpChains;
SDOperand StackPtr;
// Walk the register/memloc assignments, inserting copies/loads.
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
// Arguments start after the 5 first operands of ISD::CALL
SDOperand Arg = Op.getOperand(5+2*VA.getValNo());
// Promote the value if needed.
switch (VA.getLocInfo()) {
default: assert(0 && "Unknown loc info!");
case CCValAssign::Full: break;
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::SIGN_EXTEND, VA.getLocVT(), Arg);
break;
case CCValAssign::ZExt:
Arg = DAG.getNode(ISD::ZERO_EXTEND, VA.getLocVT(), Arg);
break;
case CCValAssign::AExt:
Arg = DAG.getNode(ISD::ANY_EXTEND, VA.getLocVT(), Arg);
break;
}
// Arguments that can be passed on register,
// must be kept at RegsToPass vector
if (VA.isRegLoc()) {
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
} else {
assert(VA.isMemLoc());
// Mips::SP holds our stack pointer
if (StackPtr.Val == 0)
StackPtr = DAG.getRegister(Mips::SP, getPointerTy());
SDOperand PtrOff = DAG.getConstant(VA.getLocMemOffset(),
getPointerTy());
// emit a ISD::ADD which emits the final
// stack location to place the parameter
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
// emit ISD::STORE whichs stores the
// parameter value to a stack Location
MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
}
}
// Transform all store nodes into one single node because
// all store nodes ar independent of each other.
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
&MemOpChains[0], MemOpChains.size());
// Build a sequence of copy-to-reg nodes chained together with token
// chain and flag operands which copy the outgoing args into registers.
// The InFlag in necessary since all emited instructions must be
// stuck together.
SDOperand InFlag;
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first,
RegsToPass[i].second, InFlag);
InFlag = Chain.getValue(1);
}
// If the callee is a GlobalAddress node (quite common, every direct
// call is) turn it into a TargetGlobalAddress node so that legalize
// doesn't hack it.
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy());
} else
if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy());
// MipsJmpLink = #chain, #target_address, #opt_in_flags...
// = Chain, Callee, Reg#1, Reg#2, ...
//
// Returns a chain & a flag for retval copy to use.
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag);
SmallVector<SDOperand, 8> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
// Add argument registers to the end of the list so that they are
// known live into the call.
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
RegsToPass[i].second.getValueType()));
if (InFlag.Val)
Ops.push_back(InFlag);
Chain = DAG.getNode(MipsISD::JmpLink, NodeTys, &Ops[0], Ops.size());
InFlag = Chain.getValue(1);
// Create the CALLSEQ_END node.
NodeTys = DAG.getVTList(MVT::Other, MVT::Flag);
Ops.clear();
Ops.push_back(Chain);
Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
Ops.push_back(InFlag);
Chain = DAG.getNode(ISD::CALLSEQ_END, NodeTys, &Ops[0], Ops.size());
InFlag = Chain.getValue(1);
// Handle result values, copying them out of physregs into vregs that we
// return.
return SDOperand(LowerCallResult(Chain, InFlag, Op.Val, CC, DAG), Op.ResNo);
}
/// LowerCallResult - Lower the result values of an ISD::CALL into the
/// appropriate copies out of appropriate physical registers. This assumes that
/// Chain/InFlag are the input chain/flag to use, and that TheCall is the call
/// being lowered. Returns a SDNode with the same number of values as the
/// ISD::CALL.
SDNode *MipsTargetLowering::
LowerCallResult(SDOperand Chain, SDOperand InFlag, SDNode *TheCall,
unsigned CallingConv, SelectionDAG &DAG) {
// Assign locations to each value returned by this call.
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallingConv, getTargetMachine(), RVLocs);
CCInfo.AnalyzeCallResult(TheCall, RetCC_Mips);
SmallVector<SDOperand, 8> ResultVals;
// returns void
if (!RVLocs.size())
return Chain.Val;
// Copy all of the result registers out of their specified physreg.
for (unsigned i = 0; i != RVLocs.size(); ++i) {
Chain = DAG.getCopyFromReg(Chain, RVLocs[i].getLocReg(),
RVLocs[i].getValVT(), InFlag).getValue(1);
InFlag = Chain.getValue(2);
ResultVals.push_back(Chain.getValue(0));
}
// Merge everything together with a MERGE_VALUES node.
ResultVals.push_back(Chain);
return DAG.getNode(ISD::MERGE_VALUES, TheCall->getVTList(),
&ResultVals[0], ResultVals.size()).Val;
}
//===----------------------------------------------------------------------===//
// FORMAL_ARGUMENTS Calling Convention Implementation
//===----------------------------------------------------------------------===//
/// Mips custom FORMAL_ARGUMENTS implementation
SDOperand MipsTargetLowering::
LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG)
{
unsigned CC = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
switch(CC)
{
default:
assert(0 && "Unsupported calling convention");
case CallingConv::C:
return LowerCCCArguments(Op, DAG);
}
}
/// LowerCCCArguments - transform physical registers into
/// virtual registers and generate load operations for
/// arguments places on the stack.
/// TODO: isVarArg, sret
SDOperand MipsTargetLowering::
LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
{
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
SDOperand Root = Op.getOperand(0);
// Assign locations to all of the incoming arguments.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(MF.getFunction()->getCallingConv(),
getTargetMachine(), ArgLocs);
CCInfo.AnalyzeFormalArguments(Op.Val, CC_Mips);
SmallVector<SDOperand, 8> ArgValues;
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
// Arguments stored on registers
if (VA.isRegLoc()) {
MVT::ValueType RegVT = VA.getLocVT();
TargetRegisterClass *RC;
if (RegVT == MVT::i32)
RC = Mips::CPURegsRegisterClass;
else
assert(0 && "support only Mips::CPURegsRegisterClass");
unsigned Reg = AddLiveIn(DAG.getMachineFunction(), VA.getLocReg(), RC);
// Transform the arguments stored on
// physical registers into virtual ones
SDOperand ArgValue = DAG.getCopyFromReg(Root, Reg, RegVT);
// If this is an 8 or 16-bit value, it is really passed promoted
// to 32 bits. Insert an assert[sz]ext to capture this, then
// truncate to the right size.
if (VA.getLocInfo() == CCValAssign::SExt)
ArgValue = DAG.getNode(ISD::AssertSext, RegVT, ArgValue,
DAG.getValueType(VA.getValVT()));
else if (VA.getLocInfo() == CCValAssign::ZExt)
ArgValue = DAG.getNode(ISD::AssertZext, RegVT, ArgValue,
DAG.getValueType(VA.getValVT()));
if (VA.getLocInfo() != CCValAssign::Full)
ArgValue = DAG.getNode(ISD::TRUNCATE, VA.getValVT(), ArgValue);
ArgValues.push_back(ArgValue);
} else {
// sanity check
assert(VA.isMemLoc());
// Create the frame index object for this incoming parameter...
int FI = MFI->CreateFixedObject(MVT::getSizeInBits(VA.getValVT())/8,
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));
}
}
ArgValues.push_back(Root);
ReturnAddrIndex = 0;
// Return the new list of results.
return DAG.getNode(ISD::MERGE_VALUES, Op.Val->getVTList(),
&ArgValues[0], ArgValues.size()).getValue(Op.ResNo);
}
//===----------------------------------------------------------------------===//
// Return Value Calling Convention Implementation
//===----------------------------------------------------------------------===//
SDOperand MipsTargetLowering::
LowerRET(SDOperand Op, SelectionDAG &DAG)
{
// CCValAssign - represent the assignment of
// the return value to a location
SmallVector<CCValAssign, 16> RVLocs;
unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv();
// CCState - Info about the registers and stack slot.
CCState CCInfo(CC, getTargetMachine(), RVLocs);
// Analize return values of ISD::RET
CCInfo.AnalyzeReturn(Op.Val, RetCC_Mips);
// If this is the first return lowered for this function, add
// the regs to the liveout set for the function.
if (DAG.getMachineFunction().liveout_empty()) {
for (unsigned i = 0; i != RVLocs.size(); ++i)
DAG.getMachineFunction().addLiveOut(RVLocs[i].getLocReg());
}
// The chain is always operand #0
SDOperand Chain = Op.getOperand(0);
SDOperand Flag;
// Copy the result values into the output registers.
for (unsigned i = 0; i != RVLocs.size(); ++i) {
CCValAssign &VA = RVLocs[i];
assert(VA.isRegLoc() && "Can only return in registers!");
// ISD::RET => ret chain, (regnum1,val1), ...
// So i*2+1 index only the regnums
Chain = DAG.getCopyToReg(Chain, VA.getLocReg(),
Op.getOperand(i*2+1), Flag);
// guarantee that all emitted copies are
// stuck together, avoiding something bad
Flag = Chain.getValue(1);
}
// Return on Mips is always a "jr $ra"
if (Flag.Val)
return DAG.getNode(MipsISD::Ret, MVT::Other,
Chain, DAG.getRegister(Mips::RA, MVT::i32), Flag);
else // Return Void
return DAG.getNode(MipsISD::Ret, MVT::Other,
Chain, DAG.getRegister(Mips::RA, MVT::i32));
}

View File

@ -0,0 +1,83 @@
//===-- MipsISelLowering.h - Mips DAG Lowering Interface --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that Mips uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//
#ifndef MipsISELLOWERING_H
#define MipsISELLOWERING_H
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/Target/TargetLowering.h"
#include "Mips.h"
#include "MipsSubtarget.h"
namespace llvm {
namespace MipsISD {
enum NodeType {
// Start the numbering from where ISD NodeType finishes.
FIRST_NUMBER = ISD::BUILTIN_OP_END+Mips::INSTRUCTION_LIST_END,
// Jump and link (call)
JmpLink,
// Get the Higher 16 bits from a 32-bit immediate
// No relation with Mips Hi register
Hi,
// Get the Lower 16 bits from a 32-bit immediate
// No relation with Mips Lo register
Lo,
// Return
Ret
};
}
//===--------------------------------------------------------------------===//
// TargetLowering Implementation
//===--------------------------------------------------------------------===//
class MipsTargetLowering : public TargetLowering
{
// FrameIndex for return slot.
int ReturnAddrIndex;
// const MipsSubtarget &MipsSubTarget;
public:
MipsTargetLowering(MipsTargetMachine &TM);
/// LowerOperation - Provide custom lowering hooks for some operations.
virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
/// getTargetNodeName - This method returns the name of a target specific
// DAG node.
virtual const char *getTargetNodeName(unsigned Opcode) const;
private:
// Lower Operand helpers
SDOperand LowerCCCArguments(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC);
SDNode *LowerCallResult(SDOperand Chain, SDOperand InFlag, SDNode*TheCall,
unsigned CallingConv, SelectionDAG &DAG);
SDOperand getReturnAddressFrameIndex(SelectionDAG &DAG);
// Lower Operand specifics
SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerRETURNADDR(SDOperand Op, SelectionDAG &DAG);
};
}
#endif // MipsISELLOWERING_H

View File

@ -0,0 +1,96 @@
//===- MipsRegisterInfo.td - Mips Register defs -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Describe MIPS instructions format
//
// All the possible Mips fields are:
//
// opcode - operation code.
// rs - src reg.
// rt - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr).
// rd - dst reg, only used on 3 regs instr.
// shamt - only used on shift instructions, contains the shift amount.
// funct - combined with opcode field give us an operation code.
//
//===----------------------------------------------------------------------===//
// Generic Mips Format
class MipsInst<dag ops, string asmstr, list<dag> pattern>:
Instruction
{
field bits<32> Inst;
let Namespace = "Mips";
bits<6> opcode;
// Top 5 bits are the 'opcode' field
let Inst{31-26} = opcode;
dag OperandList = ops;
let AsmString = asmstr;
let Pattern = pattern;
}
//===----------------------------------------------------------------------===//
// Format R instruction class in Mips : <|opcode|rs|rt|rd|shamt|funct|>
//===----------------------------------------------------------------------===//
class FR<bits<6> op, bits<6> _funct, dag ops, string asmstr, list<dag> pattern>:
MipsInst<ops, asmstr, pattern>
{
bits<5> rd;
bits<5> rs;
bits<5> rt;
bits<5> shamt;
bits<6> funct;
let opcode = op;
let funct = _funct;
let Inst{25-21} = rs;
let Inst{20-16} = rt;
let Inst{15-11} = rd;
let Inst{10-6} = shamt;
let Inst{5-0} = funct;
}
//===----------------------------------------------------------------------===//
// Format I instruction class in Mips : <|opcode|rs|rt|immediate|>
//===----------------------------------------------------------------------===//
class FI<bits<6> op, dag ops, string asmstr, list<dag> pattern>:
MipsInst<ops, asmstr, pattern>
{
bits<5> rt;
bits<5> rs;
bits<16> imm16;
let opcode = op;
let Inst{25-21} = rs;
let Inst{20-16} = rt;
let Inst{15-0} = imm16;
}
//===----------------------------------------------------------------------===//
// Format J instruction class in Mips : <|opcode|address|>
//===----------------------------------------------------------------------===//
class FJ<bits<6> op, dag ops, string asmstr, list<dag> pattern>:
MipsInst<ops, asmstr, pattern>
{
bits<26> addr;
let opcode = op;
let Inst{25-0} = addr;
}

View File

@ -0,0 +1,114 @@
//===- MipsInstrInfo.cpp - Mips Instruction Information ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and 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.
//
//===----------------------------------------------------------------------===//
#include "Mips.h"
#include "MipsInstrInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "MipsGenInstrInfo.inc"
using namespace llvm;
// TODO: Add the subtarget support on this constructor
MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm)
: TargetInstrInfo(MipsInsts, sizeof(MipsInsts)/sizeof(MipsInsts[0])),
TM(tm), RI(*this) {}
static bool isZeroImm(const MachineOperand &op) {
return op.isImmediate() && op.getImmedValue() == 0;
}
/// Return true if the instruction is a register to register move and
/// leave the source and dest operands in the passed parameters.
bool MipsInstrInfo::
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.getOperand(1).getReg() == Mips::ZERO) {
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(2).getReg();
return true;
} else if (MI.getOperand(2).getReg() == Mips::ZERO) {
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(1).getReg();
return true;
}
}
// addiu $dst, $src, 0
if (MI.getOpcode() == Mips::ADDiu)
{
if ((MI.getOperand(1).isRegister()) && (isZeroImm(MI.getOperand(2)))) {
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(1).getReg();
return true;
}
}
return false;
}
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned MipsInstrInfo::
isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const
{
// TODO: add lhu, lbu ???
if (MI->getOpcode() == Mips::LW)
{
if ((MI->getOperand(2).isFrameIndex()) && // is a stack slot
(MI->getOperand(1).isImmediate()) && // the imm is zero
(isZeroImm(MI->getOperand(1))))
{
FrameIndex = MI->getOperand(2).getFrameIndex();
return MI->getOperand(0).getReg();
}
}
return 0;
}
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned MipsInstrInfo::
isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) const
{
// TODO: add sb, sh ???
if (MI->getOpcode() == Mips::SW) {
if ((MI->getOperand(0).isFrameIndex()) && // is a stack slot
(MI->getOperand(1).isImmediate()) && // the imm is zero
(isZeroImm(MI->getOperand(1))))
{
FrameIndex = MI->getOperand(0).getFrameIndex();
return MI->getOperand(2).getReg();
}
}
return 0;
}
unsigned MipsInstrInfo::
InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, const std::vector<MachineOperand> &Cond)
const
{
// TODO: add Mips::J here.
assert(0 && "Cant handle any kind of branches!");
return 1;
}

View File

@ -0,0 +1,63 @@
//===- MipsInstrInfo.h - Mips Instruction Information -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and 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.
//
//===----------------------------------------------------------------------===//
#ifndef MIPSINSTRUCTIONINFO_H
#define MIPSINSTRUCTIONINFO_H
#include "Mips.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "MipsRegisterInfo.h"
namespace llvm {
class MipsInstrInfo : public TargetInstrInfo
{
MipsTargetMachine &TM;
const MipsRegisterInfo RI;
public:
MipsInstrInfo(MipsTargetMachine &TM);
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
/// such, whenever a client has an instance of instruction info, it should
/// always be able to get register info as well (through this method).
///
virtual const MRegisterInfo &getRegisterInfo() const { return RI; }
/// Return true if the instruction is a register to register move and
/// leave the source and dest operands in the passed parameters.
///
virtual bool isMoveInstr(const MachineInstr &MI,
unsigned &SrcReg, unsigned &DstReg) const;
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
virtual unsigned isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const;
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
virtual unsigned isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) const;
virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
const std::vector<MachineOperand> &Cond) const;
};
}
#endif

View File

@ -0,0 +1,468 @@
//===- MipsInstrInfo.td - Mips Register defs --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Instruction format superclass
//===----------------------------------------------------------------------===//
include "MipsInstrFormats.td"
//===----------------------------------------------------------------------===//
// Mips profiles and nodes
//===----------------------------------------------------------------------===//
// Call
def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain,
SDNPOutFlag]>;
// Hi and Lo nodes are created to let easy manipulation of 16-bit when
// handling 32-bit immediates. They are used on MipsISelLowering to
// lower stuff like GlobalAddress, ExternalSymbol, ...
// This two nodes have nothing to do with Mips Registers Hi and Lo.
def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>;
def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>;
// Return
def SDT_MipsRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain,
SDNPOptInFlag]>;
// These are target-independent nodes, but have target-specific formats.
def SDT_MipsCallSeq : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeq,
[SDNPHasChain, SDNPOutFlag]>;
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeq,
[SDNPHasChain, SDNPOutFlag]>;
// Instruction operand types
def brtarget : Operand<OtherVT>;
def calltarget : Operand<i32>;
def uimm16 : Operand<i32>;
def simm16 : Operand<i32>;
def shamt : Operand<i32>;
// Address operand
def mem : Operand<i32> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops simm16, CPURegs);
}
//===----------------------------------------------------------------------===//
// Mips Patterns and Transformations
//===----------------------------------------------------------------------===//
// Transformation Function - get the lower 16 bits.
def LO16 : SDNodeXForm<imm, [{
return getI32Imm((unsigned)N->getValue() & 0xFFFF);
}]>;
// Transformation Function - get the higher 16 bits.
def HI16 : SDNodeXForm<imm, [{
return getI32Imm((unsigned)N->getValue() >> 16);
}]>;
// Node immediate fits as 16-bit sign extended on target immediate.
// e.g. addi, andi
def immSExt16 : PatLeaf<(imm), [{
if (N->getValueType(0) == MVT::i32)
return (int32_t)N->getValue() == (short)N->getValue();
else
return (int64_t)N->getValue() == (short)N->getValue();
}]>;
// Node immediate fits as 16-bit zero extended on target immediate.
// The LO16 param means that only the lower 16 bits of the node
// immediate are caught.
// e.g. addiu, sltiu
def immZExt16 : PatLeaf<(imm), [{
return (uint64_t)N->getValue() == (unsigned short)N->getValue();
}], LO16>;
// Node immediate must have only it's 16 high bits set.
// The HI16 param means that only the higher 16 bits of the node
// immediate are caught.
// e.g. lui
def imm16ShiftedZExt : PatLeaf<(imm), [{
return (N->getValue() & ~uint64_t(0xFFFF0000)) == 0;
}], HI16>;
// shamt field must fit in 5 bits.
def immZExt5 : PatLeaf<(imm), [{
return N->getValue() == ((N->getValue()) & 0x1f) ;
}]>;
// Mips Address Mode! SDNode frameindex could possibily be a match
// since load and store instructions from stack used it.
def addr : ComplexPattern<i32, 2, "SelectAddr", [frameindex], []>;
//===----------------------------------------------------------------------===//
// Instructions specific format
//===----------------------------------------------------------------------===//
// Arithmetic 3 register operands
let isCommutable = 1 in
class ArithR< bits<6> op, bits<6> func, string instr_asm, SDNode OpNode>:
FR< op,
func,
(ops CPURegs:$dst, CPURegs:$b, CPURegs:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))] >;
let isCommutable = 1 in
class ArithOverflowR< bits<6> op, bits<6> func, string instr_asm>:
FR< op,
func,
(ops CPURegs:$dst, CPURegs:$b, CPURegs:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[]>;
// Arithmetic 2 register operands
let isCommutable = 1 in
class ArithI<bits<6> op, string instr_asm, SDNode OpNode,
Operand Od, PatLeaf imm_type> :
FI< op,
(ops CPURegs:$dst, CPURegs:$b, Od:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (OpNode CPURegs:$b, imm_type:$c))] >;
// Arithmetic Multiply ADD/SUB
let rd=0 in
class MArithR<bits<6> func, string instr_asm> :
FR< 0x1c,
func,
(ops CPURegs:$rs, CPURegs:$rt),
!strconcat(instr_asm, " $rs, $rt"),
[]>;
// Logical
class LogicR<bits<6> func, string instr_asm, SDNode OpNode>:
FR< 0x00,
func,
(ops CPURegs:$dst, CPURegs:$b, CPURegs:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))] >;
class LogicI<bits<6> op, string instr_asm, SDNode OpNode>:
FI< op,
(ops CPURegs:$dst, CPURegs:$b, uimm16:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (OpNode CPURegs:$b, immSExt16:$c))]>;
class LogicNOR<bits<6> op, bits<6> func, string instr_asm>:
FR< op,
func,
(ops CPURegs:$dst, CPURegs:$b, CPURegs:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (not (or CPURegs:$b, CPURegs:$c)))] >;
// Shifts
let rt = 0 in
class LogicR_shift_imm<bits<6> func, string instr_asm, SDNode OpNode>:
FR< 0x00,
func,
(ops CPURegs:$dst, CPURegs:$b, shamt:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (OpNode CPURegs:$b, immZExt5:$c))] >;
class LogicR_shift_reg<bits<6> func, string instr_asm, SDNode OpNode>:
FR< 0x00,
func,
(ops CPURegs:$dst, CPURegs:$b, CPURegs:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))] >;
// Load Upper Imediate
class LoadUpper<bits<6> op, string instr_asm>:
FI< op,
(ops CPURegs:$dst, uimm16:$imm),
!strconcat(instr_asm, " $dst, $imm"),
[(set CPURegs:$dst, imm16ShiftedZExt:$imm)]>;
// Memory Load/Store
let isLoad = 1 in
class LoadM<bits<6> op, string instr_asm, PatFrag OpNode>:
FI< op,
(ops CPURegs:$dst, mem:$addr),
!strconcat(instr_asm, " $dst, $addr"),
[(set CPURegs:$dst, (OpNode addr:$addr))]>;
let isStore = 1 in
class StoreM<bits<6> op, string instr_asm, PatFrag OpNode>:
FI< op,
(ops CPURegs:$dst, mem:$addr),
!strconcat(instr_asm, " $dst, $addr"),
[(OpNode CPURegs:$dst, addr:$addr)]>;
// Conditional Branch
let isBranch = 1, noResults=1, isTerminator=1 in
class CBranch<bits<6> op, string instr_asm, PatFrag cond_op>:
FI< op,
(ops CPURegs:$a, CPURegs:$b, brtarget:$offset),
!strconcat(instr_asm, " $a, $b, $offset"),
[(brcond (cond_op CPURegs:$a, CPURegs:$b), bb:$offset)]>;
class SetCC_R<bits<6> op, bits<6> func, string instr_asm,
PatFrag cond_op>:
FR< op,
func,
(ops CPURegs:$dst, CPURegs:$b, CPURegs:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (cond_op CPURegs:$b, CPURegs:$c))]>;
class SetCC_I<bits<6> op, string instr_asm, PatFrag cond_op,
Operand Od, PatLeaf imm_type>:
FI< op,
(ops CPURegs:$dst, CPURegs:$b, Od:$c),
!strconcat(instr_asm, " $dst, $b, $c"),
[(set CPURegs:$dst, (cond_op CPURegs:$b, imm_type:$c))]>;
// Unconditional branch
let hasCtrlDep=1, noResults=1, isTerminator=1 in
class JumpFJ<bits<6> op, string instr_asm>:
FJ< op,
(ops brtarget:$target),
!strconcat(instr_asm, " $target"),
[(br bb:$target)]>;
let hasCtrlDep=1, noResults=1, isTerminator=1, rd=0 in
class JumpFR<bits<6> op, bits<6> func, string instr_asm>:
FR< op,
func,
(ops CPURegs:$target),
!strconcat(instr_asm, " $target"),
[]>;
// Jump and Link (Call)
let isCall=1 in
class JumpLink<bits<6> op, string instr_asm>:
FJ< op,
(ops calltarget:$target),
!strconcat(instr_asm, " $target"),
[(MipsJmpLink imm:$target)]>;
let isCall=1 in
class JumpLinkReg<bits<6> op, bits<6> func, string instr_asm>:
FR< op,
func,
(ops CPURegs:$rd, CPURegs:$rs),
!strconcat(instr_asm, " $rs, $rd"),
[]>;
// Mul, Div
class MulDiv<bits<6> func, string instr_asm>:
FR< 0x00,
func,
(ops CPURegs:$a, CPURegs:$b),
!strconcat(instr_asm, " $a, $b"),
[]>;
// Move from Hi/Lo
class MoveFromTo<bits<6> func, string instr_asm>:
FR< 0x00,
func,
(ops CPURegs:$dst),
!strconcat(instr_asm, " $dst"),
[]>;
// Count Leading Ones/Zeros in Word
class CountLeading<bits<6> func, string instr_asm>:
FR< 0x1c,
func,
(ops CPURegs:$dst, CPURegs:$src),
!strconcat(instr_asm, " $dst, $src"),
[]>;
//===----------------------------------------------------------------------===//
// Pseudo instructions
//===----------------------------------------------------------------------===//
class Pseudo<dag ops, string asmstr, list<dag> pattern>:
MipsInst<ops, asmstr, pattern>;
// As stack alignment is always done with addiu, we need a 16-bit immediate
def ADJCALLSTACKDOWN : Pseudo<(ops uimm16:$amt),
"!ADJCALLSTACKDOWN $amt",
[(callseq_start imm:$amt)]>, Imp<[SP],[SP]>;
def ADJCALLSTACKUP : Pseudo<(ops uimm16:$amt),
"!ADJCALLSTACKUP $amt",
[(callseq_end imm:$amt)]>, Imp<[SP],[SP]>;
def IMPLICIT_DEF_CPURegs : Pseudo<(ops CPURegs:$dst),
"!IMPLICIT_DEF $dst",
[(set CPURegs:$dst, (undef))]>;
//===----------------------------------------------------------------------===//
// Instruction definition
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Mips32 I
//===----------------------------------------------------------------------===//
// Arithmetic
def ADDi : ArithI<0x08, "addi", add, simm16, immZExt16>;
def ADDiu : ArithI<0x09, "addiu", add, uimm16, immSExt16>;
def MUL : ArithR<0x1c, 0x02, "mul", mul>;
def ADDu : ArithR<0x00, 0x21, "addu", add>;
def SUBu : ArithR<0x00, 0x23, "subu", sub>;
def ADD : ArithOverflowR<0x00, 0x20, "add">;
def SUB : ArithOverflowR<0x00, 0x22, "sub">;
def MADD : MArithR<0x00, "madd">;
def MADDU : MArithR<0x01, "maddu">;
def MSUB : MArithR<0x04, "msub">;
def MSUBU : MArithR<0x05, "msubu">;
// Logical
def AND : LogicR<0x24, "and", and>;
def OR : LogicR<0x25, "or", or>;
def XOR : LogicR<0x26, "xor", xor>;
def ANDi : LogicI<0x0c, "andi", and>;
def ORi : LogicI<0x0d, "ori", or>;
def XORi : LogicI<0x0e, "xori", xor>;
def NOR : LogicNOR<0x00, 0x27, "nor">;
// Shifts
def SLL : LogicR_shift_imm<0x00, "sll", shl>;
def SRL : LogicR_shift_imm<0x02, "srl", srl>;
def SRA : LogicR_shift_imm<0x03, "sra", sra>;
def SLLV : LogicR_shift_reg<0x04, "sllv", shl>;
def SRLV : LogicR_shift_reg<0x06, "srlv", srl>;
def SRAV : LogicR_shift_reg<0x07, "srav", sra>;
// Load Upper Immediate
def LUi : LoadUpper<0x0f, "lui">;
// Load/Store
def LB : LoadM<0x20, "lb", sextloadi8>;
def LBu : LoadM<0x24, "lbu", zextloadi8>;
def LH : LoadM<0x21, "lh", sextloadi16>;
def LHu : LoadM<0x25, "lhu", zextloadi16>;
def LW : LoadM<0x23, "lw", load>;
def SB : StoreM<0x28, "sb", truncstorei8>;
def SH : StoreM<0x29, "sh", truncstorei16>;
def SW : StoreM<0x2b, "sw", store>;
// Conditional Branch
def BEQ : CBranch<0x04, "beq", seteq>;
def BNE : CBranch<0x05, "bne", setne>;
def SLT : SetCC_R<0x00, 0x2a, "slt", setlt>;
def SLTu : SetCC_R<0x00, 0x2b, "sltu", setult>;
def SLTi : SetCC_I<0x0a, "slti", setlt, simm16, immSExt16>;
def SLTiu : SetCC_I<0x0b, "sltiu", setult, uimm16, immZExt16>;
// Unconditional jump
def J : JumpFJ<0x02, "j">;
def JR : JumpFR<0x00, 0x08, "jr">;
// Jump and Link (Call)
def JAL : JumpLink<0x03, "jal">;
def JALR : JumpLinkReg<0x00, 0x09, "jalr">;
// MulDiv and Move From Hi/Lo operations, have
// their correpondent SDNodes created on ISelDAG.
// Special Mul, Div operations
def MULT : MulDiv<0x18, "mult">;
def MULTu : MulDiv<0x19, "multu">;
def DIV : MulDiv<0x1a, "div">;
def DIVu : MulDiv<0x1b, "divu">;
// Move From Hi/Lo
def MFHI : MoveFromTo<0x10, "mfhi">;
def MFLO : MoveFromTo<0x12, "mflo">;
def MTHI : MoveFromTo<0x11, "mthi">;
def MTLO : MoveFromTo<0x13, "mtlo">;
// Count Leading
def CLO : CountLeading<0x21, "clo">;
def CLZ : CountLeading<0x20, "clz">;
// No operation
let addr=0 in
def NOOP : FJ<0, (ops), "nop", []>;
// Ret instruction - as mips does not have "ret" a
// jr $ra must be generated.
let isReturn=1, isTerminator=1, hasDelaySlot=1, noResults=1,
isBarrier=1, hasCtrlDep=1, rs=0, rt=0, shamt=0 in
{
def RET : FR <0x00, 0x02, (ops CPURegs:$target),
"jr $target", [(MipsRet CPURegs:$target)]>;
}
//===----------------------------------------------------------------------===//
// Arbitrary patterns that map to one or more instructions
//===----------------------------------------------------------------------===//
// Small immediates
def : Pat<(i32 immSExt16:$in),
(ORi ZERO, imm:$in)>;
// Arbitrary immediates
def : Pat<(i32 imm:$imm),
(ORi (LUi (HI16 imm:$imm)), (LO16 imm:$imm))>;
// Call
def : Pat<(MipsJmpLink (i32 tglobaladdr:$dst)),
(JAL tglobaladdr:$dst)>;
def : Pat<(MipsJmpLink (i32 texternalsym:$dst)),
(JAL texternalsym:$dst)>;
// GlobalAddress, Constant Pool, ExternalSymbol, and JumpTable
def : Pat<(MipsHi tglobaladdr:$in), (LUi tglobaladdr:$in)>;
def : Pat<(MipsLo tglobaladdr:$in), (ADDiu ZERO, tglobaladdr:$in)>;
// When extracting the address from GlobalAddress we
// need something of the form "addiu $reg, %lo(addr)"
def : Pat<(add CPURegs:$a, (MipsLo tglobaladdr:$in)),
(ADDiu CPURegs:$a, tglobaladdr:$in)>;
// Mips does not have not, so we increase the operation
def : Pat<(not CPURegs:$in),
(NOR CPURegs:$in, CPURegs:$in)>;
// extended load and stores
def : Pat<(i32 (extloadi8 addr:$src)), (LBu addr:$src)>;
def : Pat<(i32 (extloadi16 addr:$src)), (LHu addr:$src)>;
def : Pat<(truncstorei1 CPURegs:$src, addr:$addr),
(SB CPURegs:$src, addr:$src)>;
// Conditional branch patterns.
// cond branches patterns, 2 register operands signed.
def : Pat<(brcond (setlt CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
(BNE (SLT CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>;
def : Pat<(brcond (setle CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
(BEQ (SLT CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>;
def : Pat<(brcond (setgt CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
(BNE (SLT CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>;
def : Pat<(brcond (setge CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
(BEQ (SLT CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>;
// cond branches patterns, 2 register operands unsigned.
def : Pat<(brcond (setult CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
(BNE (SLTu CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>;
def : Pat<(brcond (setule CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
(BEQ (SLTu CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>;
def : Pat<(brcond (setugt CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
(BNE (SLTu CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>;
def : Pat<(brcond (setuge CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
(BEQ (SLTu CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>;
// cond branches patterns, reg/imm operands signed.
def : Pat<(brcond (setult CPURegs:$lhs, immSExt16:$rhs), bb:$dst),
(BNE (SLTi CPURegs:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>;
def : Pat<(brcond (setuge CPURegs:$lhs, immSExt16:$rhs), bb:$dst),
(BEQ (SLTi CPURegs:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>;
// cond branches patterns, reg/imm operands unsigned.
def : Pat<(brcond (setult CPURegs:$lhs, immZExt16:$rhs), bb:$dst),
(BNE (SLTiu CPURegs:$lhs, immZExt16:$rhs), ZERO, bb:$dst)>;
def : Pat<(brcond (setuge CPURegs:$lhs, immZExt16:$rhs), bb:$dst),
(BEQ (SLTiu CPURegs:$lhs, immZExt16:$rhs), ZERO, bb:$dst)>;

View File

@ -0,0 +1,288 @@
//===- MipsRegisterInfo.cpp - MIPS Register Information -== -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the MIPS implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mips-reg-info"
#include "Mips.h"
#include "MipsRegisterInfo.h"
#include "llvm/Constants.h"
#include "llvm/Type.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/CommandLine.h"
#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) {}
void MipsRegisterInfo::
storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned SrcReg, int FI,
const TargetRegisterClass *RC) const
{
if (RC == Mips::CPURegsRegisterClass)
BuildMI(MBB, I, TII.get(Mips::SW)).addFrameIndex(FI)
.addImm(0).addReg(SrcReg, false, false, true);
else
assert(0 && "Can't store this register to stack slot");
}
void MipsRegisterInfo::
loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned DestReg, int FI,
const TargetRegisterClass *RC) const
{
if (RC == Mips::CPURegsRegisterClass)
BuildMI(MBB, I, TII.get(Mips::LW), DestReg).addImm(0).addFrameIndex(FI);
else
assert(0 && "Can't load this register from stack slot");
}
void MipsRegisterInfo::
copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned DestReg, unsigned SrcReg,
const TargetRegisterClass *RC) const
{
if (RC == Mips::CPURegsRegisterClass)
BuildMI(MBB, I, TII.get(Mips::ADDu), DestReg).addReg(Mips::ZERO)
.addReg(SrcReg);
else
assert (0 && "Can't copy this register");
}
void MipsRegisterInfo::reMaterialize(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned DestReg,
const MachineInstr *Orig) const
{
MachineInstr *MI = Orig->clone();
MI->getOperand(0).setReg(DestReg);
MBB.insert(I, MI);
}
MachineInstr *MipsRegisterInfo::
foldMemoryOperand(MachineInstr* MI, unsigned OpNum, int FI) const
{
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 (OpNum == 0) // COPY -> STORE
NewMI = BuildMI(TII.get(Mips::SW)).addFrameIndex(FI)
.addImm(0).addReg(MI->getOperand(2).getReg());
else // COPY -> LOAD
NewMI = BuildMI(TII.get(Mips::LW), MI->getOperand(0)
.getReg()).addImm(0).addFrameIndex(FI);
}
break;
}
if (NewMI)
NewMI->copyKillDeadInfo(MI);
return NewMI;
}
/// Mips Callee Saved Registers
const unsigned* MipsRegisterInfo::
getCalleeSavedRegs() const
{
// Mips calle-save register range is $16-$26(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;
}
/// Mips Callee Saved Register Classes
const TargetRegisterClass* const*
MipsRegisterInfo::getCalleeSavedRegClasses() const
{
static const TargetRegisterClass * const CalleeSavedRegClasses[] = {
&Mips::CPURegsRegClass, &Mips::CPURegsRegClass,
&Mips::CPURegsRegClass, &Mips::CPURegsRegClass,
&Mips::CPURegsRegClass, &Mips::CPURegsRegClass,
&Mips::CPURegsRegClass, &Mips::CPURegsRegClass, 0
};
return CalleeSavedRegClasses;
}
BitVector MipsRegisterInfo::
getReservedRegs(const MachineFunction &MF) const
{
BitVector Reserved(getNumRegs());
Reserved.set(Mips::ZERO);
Reserved.set(Mips::AT);
Reserved.set(Mips::K0);
Reserved.set(Mips::K1);
Reserved.set(Mips::GP);
Reserved.set(Mips::SP);
Reserved.set(Mips::FP);
Reserved.set(Mips::RA);
return Reserved;
}
//===----------------------------------------------------------------------===//
// Stack Frame Processing methods
//===----------------------------------------------------------------------===//
// True if target has frame pointer
bool MipsRegisterInfo::
hasFP(const MachineFunction &MF) const {
return false;
}
// This function eliminate ADJCALLSTACKDOWN,
// ADJCALLSTACKUP pseudo instructions
void MipsRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
// Simply discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions.
MBB.erase(I);
}
// FrameIndex represent objects inside a abstract stack.
// We must replace FrameIndex with an stack/frame pointer
// direct reference.
void MipsRegisterInfo::
eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj,
RegScavenger *RS) const
{
unsigned i = 0;
MachineInstr &MI = *II;
MachineFunction &MF = *MI.getParent()->getParent();
while (!MI.getOperand(i).isFrameIndex()) {
++i;
assert(i < MI.getNumOperands() &&
"Instr doesn't have FrameIndex operand!");
}
// FrameInfo addressable stack objects are accessed
// using neg. offsets, so we must add with the stack
// size to obtain $sp relative address.
int FrameIndex = MI.getOperand(i).getFrameIndex();
int stackSize = MF.getFrameInfo()->getStackSize();
int spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
#ifndef NDEBUG
DOUT << "\n<--------->\n";
MI.print(DOUT);
DOUT << "FrameIndex : " << FrameIndex << "\n";
DOUT << "spOffset : " << spOffset << "\n";
DOUT << "stackSize : " << stackSize << "\n";
#endif
// If the FrameIndex points to a positive SPOffset this
// means we are inside the callee and getting the arguments
// from the caller stack
int Offset = (-(stackSize)) + spOffset;
#ifndef NDEBUG
DOUT << "Offset : " << Offset << "\n";
DOUT << "<--------->\n";
#endif
MI.getOperand(i-1).ChangeToImmediate(Offset);
MI.getOperand(i).ChangeToRegister(Mips::SP,false);
}
void MipsRegisterInfo::
emitPrologue(MachineFunction &MF) const
{
MachineBasicBlock &MBB = MF.front();
MachineFrameInfo *MFI = MF.getFrameInfo();
// Get the number of bytes to allocate from the FrameInfo
int NumBytes = (int) MFI->getStackSize();
// Do we need to allocate space on the stack?
if (NumBytes == 0) return;
// FIXME: is Stack Align needed here ?? (maybe it's done before...)
unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
NumBytes = -((NumBytes+Align-1)/Align*Align);
// Update frame info to pretend that this is part of the stack...
MFI->setStackSize(NumBytes);
// adjust stack : addi sp, sp, (-imm)
BuildMI(MBB, MBB.begin(), TII.get(Mips::ADDi), Mips::SP)
.addReg(Mips::SP).addImm(NumBytes);
}
void MipsRegisterInfo::
emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const
{
MachineBasicBlock::iterator MBBI = prior(MBB.end());
MachineFrameInfo *MFI = MF.getFrameInfo();
// Get the number of bytes from FrameInfo
int NumBytes = (int) MFI->getStackSize();
// adjust stack : insert addi sp, sp, (imm)
if (NumBytes) {
BuildMI(MBB, MBBI, TII.get(Mips::ADDi), Mips::SP)
.addReg(Mips::SP).addImm(-NumBytes);
}
}
void MipsRegisterInfo::
processFunctionBeforeFrameFinalized(MachineFunction &MF) const {}
unsigned MipsRegisterInfo::
getRARegister() const {
return Mips::RA;
}
unsigned MipsRegisterInfo::
getFrameRegister(MachineFunction &MF) const {
assert(0 && "What is the frame register");
return Mips::FP;
}
unsigned MipsRegisterInfo::
getEHExceptionRegister() const {
assert(0 && "What is the exception register");
return 0;
}
unsigned MipsRegisterInfo::
getEHHandlerRegister() const {
assert(0 && "What is the exception handler register");
return 0;
}
#include "MipsGenRegisterInfo.inc"

View File

@ -0,0 +1,83 @@
//===- MipsRegisterInfo.h - Mips Register Information Impl ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mips implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef MIPSREGISTERINFO_H
#define MIPSREGISTERINFO_H
#include "llvm/Target/MRegisterInfo.h"
#include "MipsGenRegisterInfo.h.inc"
namespace llvm {
class TargetInstrInfo;
class Type;
struct MipsRegisterInfo : public MipsGenRegisterInfo {
const TargetInstrInfo &TII;
MipsRegisterInfo(const TargetInstrInfo &tii);
/// Code Generation virtual methods...
void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned SrcReg, int FrameIndex,
const TargetRegisterClass *RC) const;
void loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned DestReg, int FrameIndex,
const TargetRegisterClass *RC) const;
void reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
unsigned DestReg, const MachineInstr *Orig) const;
MachineInstr* foldMemoryOperand(MachineInstr* MI, unsigned OpNum,
int FrameIndex) const;
void copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
unsigned DestReg, unsigned SrcReg,
const TargetRegisterClass *RC) const;
const unsigned *getCalleeSavedRegs() const;
const TargetRegisterClass* const* getCalleeSavedRegClasses() const;
BitVector getReservedRegs(const MachineFunction &MF) const;
bool hasFP(const MachineFunction &MF) const;
void eliminateCallFramePseudoInstr(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const;
void eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, RegScavenger *RS = NULL) const;
void processFunctionBeforeFrameFinalized(MachineFunction &MF) const;
void emitPrologue(MachineFunction &MF) const;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;
// Debug information queries.
unsigned getRARegister() const;
unsigned getFrameRegister(MachineFunction &MF) const;
// Exception handling queries.
unsigned getEHExceptionRegister() const;
unsigned getEHHandlerRegister() const;
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,80 @@
//===- MipsRegisterInfo.td - Mips Register defs -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Declarations that describe the MIPS register file
//===----------------------------------------------------------------------===//
// We have banks of 32 registers each.
class MipsReg<string n> : Register<n> {
field bits<5> Num;
let Namespace = "Mips";
}
// 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>;
// CPU Registers Class
def CPURegs : RegisterClass<"Mips", [i32], 32,
// Return Values and Arguments
[V0, V1, A0, A1, A2, A3,
// Not preserved across procedure calls
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9,
// Callee save
S0, S1, S2, S3, S4, S5, S6, S7,
// Reserved
ZERO, AT, K0, K1, GP, SP, FP, RA]>
{
let MethodProtos = [{
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
CPURegsClass::iterator
CPURegsClass::allocation_order_end(const MachineFunction &MF) const {
// The last 8 registers on the list above are reserved
return end()-8;
}
}];
}

View File

@ -0,0 +1,26 @@
//===- MipsSubtarget.cpp - Mips Subtarget Information -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Mips specific subclass of TargetSubtarget.
//
//===----------------------------------------------------------------------===//
#include "MipsSubtarget.h"
#include "Mips.h"
#include "MipsGenSubtarget.inc"
using namespace llvm;
MipsSubtarget::MipsSubtarget(const TargetMachine &TM, const Module &M,
const std::string &FS) : isR3000(false)
{
std::string CPU = "generic";
// Parse features string.
ParseSubtargetFeatures(FS, CPU);
}

View File

@ -0,0 +1,43 @@
//=====-- MipsSubtarget.h - Define Subtarget for the Mips -----*- C++ -*--====//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the Mips specific subclass of TargetSubtarget.
//
//===----------------------------------------------------------------------===//
#ifndef MIPSSUBTARGET_H
#define MIPSSUBTARGET_H
#include "llvm/Target/TargetSubtarget.h"
#include "llvm/Target/TargetMachine.h"
#include <string>
namespace llvm {
class Module;
class MipsSubtarget : public TargetSubtarget {
protected:
bool isR3000;
public:
/// This constructor initializes the data members to match that
/// of the specified module.
///
MipsSubtarget(const TargetMachine &TM, const Module &M,
const std::string &FS);
/// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen.
void ParseSubtargetFeatures(const std::string &FS, const std::string &CPU);
bool IsR3000() const { return isR3000; }
};
} // End llvm namespace
#endif

View File

@ -0,0 +1,22 @@
//===-- MipsTargetAsmInfo.cpp - Mips asm properties -------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the declarations of the MipsTargetAsmInfo properties.
//
//===----------------------------------------------------------------------===//
#include "MipsTargetAsmInfo.h"
using namespace llvm;
MipsTargetAsmInfo::MipsTargetAsmInfo(const MipsTargetMachine &TM) {
Data16bitsDirective = "\t.half\t";
Data32bitsDirective = "\t.word\t";
CommentString = "#";
}

View File

@ -0,0 +1,30 @@
//=====-- MipsTargetAsmInfo.h - Mips asm properties -----------*- C++ -*--====//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the declaration of the MipsTargetAsmInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef MIPSTARGETASMINFO_H
#define MIPSTARGETASMINFO_H
#include "llvm/Target/TargetAsmInfo.h"
namespace llvm {
// Forward declaration.
class MipsTargetMachine;
struct MipsTargetAsmInfo : public TargetAsmInfo {
MipsTargetAsmInfo(const MipsTargetMachine &TM);
};
} // namespace llvm
#endif

View File

@ -0,0 +1,81 @@
//===-- MipsTargetMachine.cpp - Define TargetMachine for Mips -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implements the info about Mips target spec.
//
//===----------------------------------------------------------------------===//
#include "Mips.h"
#include "MipsTargetAsmInfo.h"
#include "MipsTargetMachine.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Target/TargetMachineRegistry.h"
using namespace llvm;
namespace {
// Register the target.
RegisterTarget<MipsTargetMachine> X("mips", " Mips");
}
const TargetAsmInfo *MipsTargetMachine::
createTargetAsmInfo() const
{
return new MipsTargetAsmInfo(*this);
}
// DataLayout --> Big-endian, 32-bit pointer/ABI/alignment
// FrameInfo --> StackGrowsDown, 8 bytes aligned, LOA : -4 (Ra : 0)
MipsTargetMachine::
MipsTargetMachine(const Module &M, const std::string &FS):
Subtarget(*this, M, FS), DataLayout("E-p:32:32:32"),
InstrInfo(*this), FrameInfo(TargetFrameInfo::StackGrowsDown, 8, -4),
TLInfo(*this) {}
// return 0 and must specify -march to gen MIPS code.
unsigned MipsTargetMachine::
getModuleMatchQuality(const Module &M)
{
// We strongly match "mips-*".
std::string TT = M.getTargetTriple();
if (TT.size() >= 5 && std::string(TT.begin(), TT.begin()+5) == "mips-")
return 20;
return 0;
}
// Install an instruction selector pass using
// the ISelDag to gen Mips code.
bool MipsTargetMachine::
addInstSelector(FunctionPassManager &PM, bool Fast)
{
PM.add(createMipsISelDag(*this));
return false;
}
// Implemented by targets that want to run passes immediately before
// machine code is emitted. return true if -print-machineinstrs should
// print out the code after the passes.
// TODO: Delay slot must be implemented here.
bool MipsTargetMachine::
addPreEmitPass(FunctionPassManager &PM, bool Fast)
{
return false;
}
// Implements the AssemblyEmitter for the target. Must return
// true if AssemblyEmitter is supported
bool MipsTargetMachine::
addAssemblyEmitter(FunctionPassManager &PM, bool Fast,
std::ostream &Out)
{
// Output assembly language.
PM.add(createMipsCodePrinterPass(Out, *this));
return false;
}

View File

@ -0,0 +1,65 @@
//===-- MipsTargetMachine.h - Define TargetMachine for Mips -00--*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the Mips specific subclass of TargetMachine.
//
//===----------------------------------------------------------------------===//
#ifndef MIPSTARGETMACHINE_H
#define MIPSTARGETMACHINE_H
#include "MipsSubtarget.h"
#include "MipsInstrInfo.h"
#include "MipsISelLowering.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetFrameInfo.h"
namespace llvm {
class MipsTargetMachine : public LLVMTargetMachine {
MipsSubtarget Subtarget;
const TargetData DataLayout; // Calculates type size & alignment
MipsInstrInfo InstrInfo;
TargetFrameInfo FrameInfo;
MipsTargetLowering TLInfo;
protected:
virtual const TargetAsmInfo *createTargetAsmInfo() const;
public:
MipsTargetMachine(const Module &M, const std::string &FS);
virtual const MipsInstrInfo *getInstrInfo() const
{ return &InstrInfo; }
virtual const TargetFrameInfo *getFrameInfo() const
{ return &FrameInfo; }
virtual const TargetSubtarget *getSubtargetImpl() const
{ return &Subtarget; }
virtual const TargetData *getTargetData() const
{ return &DataLayout;}
virtual const MRegisterInfo *getRegisterInfo() const {
return &InstrInfo.getRegisterInfo();
}
virtual MipsTargetLowering *getTargetLowering() const {
return const_cast<MipsTargetLowering*>(&TLInfo);
}
static unsigned getModuleMatchQuality(const Module &M);
// Pass Pipeline Configuration
virtual bool addInstSelector(FunctionPassManager &PM, bool Fast);
virtual bool addPreEmitPass(FunctionPassManager &PM, bool Fast);
virtual bool addAssemblyEmitter(FunctionPassManager &PM, bool Fast,
std::ostream &Out);
};
} // End llvm namespace
#endif