Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -3,21 +3,234 @@ #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/FastISel.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLibraryInfo.h" +#include "MipsRegisterInfo.h" #include "MipsISelLowering.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" using namespace llvm; namespace { +// All possible address modes, plus some. +typedef struct Address { + enum { RegBase, FrameIndexBase } BaseType; + + union { + unsigned Reg; + int FI; + } Base; + + int Offset; + + // Innocuous defaults for our address. + Address() : BaseType(RegBase), Offset(0) { Base.Reg = 0; } +} Address; + class MipsFastISel final : public FastISel { + /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can + /// make the right decision when generating code for different targets. + const MipsSubtarget *Subtarget; + Module &M; + const TargetMachine &TM; + const TargetInstrInfo &TII; + const TargetLowering &TLI; + MipsFunctionInfo *MFI; + + // Convenience variables to avoid some queries. + LLVMContext *Context; + + bool TargetSupported; + public: explicit MipsFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) - : FastISel(funcInfo, libInfo) {} - bool TargetSelectInstruction(const Instruction *I) override { return false; } + : FastISel(funcInfo, libInfo), + M(const_cast(*funcInfo.Fn->getParent())), + TM(funcInfo.MF->getTarget()), TII(*TM.getInstrInfo()), + TLI(*TM.getTargetLowering()) { + Subtarget = &TM.getSubtarget(); + MFI = funcInfo.MF->getInfo(); + Context = &funcInfo.Fn->getContext(); + TargetSupported = ((Subtarget->getRelocationModel() == Reloc::PIC_) && + (Subtarget->hasMips32r2() && (Subtarget->isABI_O32()))); + } + + bool TargetSelectInstruction(const Instruction *I) override; + unsigned TargetMaterializeConstant(const Constant *C) override; + + bool ComputeAddress(const Value *Obj, Address &Addr); + +private: + bool EmitStore(MVT VT, unsigned SrcReg, Address &Addr, + unsigned Alignment = 0); + bool SelectRet(const Instruction *I); + bool SelectStore(const Instruction *I); + + bool isTypeLegal(Type *Ty, MVT &VT); + bool isLoadTypeLegal(Type *Ty, MVT &VT); + + unsigned MaterializeFP(const ConstantFP *CFP, MVT VT); + unsigned MaterializeGV(const GlobalValue *GV, MVT VT); + unsigned MaterializeInt(const Constant *C, MVT VT); }; + +bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) { + EVT evt = TLI.getValueType(Ty, true); + // Only handle simple types. + if (evt == MVT::Other || !evt.isSimple()) + return false; + VT = evt.getSimpleVT(); + + // Handle all legal types, i.e. a register that will directly hold this + // value. + return TLI.isTypeLegal(VT); +} + +bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { + if (isTypeLegal(Ty, VT)) + return true; + return false; +} + +bool MipsFastISel::ComputeAddress(const Value *Obj, Address &Addr) { + if (isa(Obj)) + return false; + else if (isa(Obj)) + return false; + Addr.Base.Reg = getRegForValue(Obj); + return Addr.Base.Reg != 0; +} + +// Materialize a constant into a register, and return the register +// number (or zero if we failed to handle it). +unsigned MipsFastISel::TargetMaterializeConstant(const Constant *C) { + EVT CEVT = TLI.getValueType(C->getType(), true); + + // Only handle simple types. + if (!CEVT.isSimple()) + return 0; + MVT VT = CEVT.getSimpleVT(); + + if (const ConstantFP *CFP = dyn_cast(C)) + return MaterializeFP(CFP, VT); + else if (const GlobalValue *GV = dyn_cast(C)) + return MaterializeGV(GV, VT); + else if (isa(C)) + return MaterializeInt(C, VT); + + return 0; +} + +bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr, + unsigned Alignment) { + if (VT != MVT::i32) + return false; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::SW)) + .addReg(SrcReg) + .addReg(Addr.Base.Reg) + .addImm(Addr.Offset); + return true; +} + +bool MipsFastISel::SelectStore(const Instruction *I) { + Value *Op0 = I->getOperand(0); + unsigned SrcReg = 0; + + // Atomic stores need special handling. + if (cast(I)->isAtomic()) + return false; + + // Verify we have a legal type before going any further. + MVT VT; + if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT)) + return false; + + // Get the value to be stored into a register. + SrcReg = getRegForValue(Op0); + if (SrcReg == 0) + return false; + + // See if we can handle this address. + Address Addr; + if (!ComputeAddress(I->getOperand(1), Addr)) + return false; + + if (!EmitStore(VT, SrcReg, Addr, cast(I)->getAlignment())) + return false; + return true; +} + +bool MipsFastISel::SelectRet(const Instruction *I) { + const ReturnInst *Ret = cast(I); + + if (!FuncInfo.CanLowerReturn) + return false; + if (Ret->getNumOperands() > 0) { + return false; + } + unsigned RetOpc = Mips::RetRA; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(RetOpc)); + return true; +} + +bool MipsFastISel::TargetSelectInstruction(const Instruction *I) { + if (!TargetSupported) + return false; + switch (I->getOpcode()) { + default: + break; + case Instruction::Store: + return SelectStore(I); + case Instruction::Ret: + return SelectRet(I); + } + return false; +} +} + +unsigned MipsFastISel::MaterializeFP(const ConstantFP *CFP, MVT VT) { + return 0; +} + +unsigned MipsFastISel::MaterializeGV(const GlobalValue *GV, MVT VT) { + // For now 32-bit only. + if (VT != MVT::i32) + return 0; + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + unsigned DestReg = createResultReg(RC); + // FastISel TLS support on non-MachO is broken, punt to SelectionDAG. + const GlobalVariable *GVar = dyn_cast(GV); + bool IsThreadLocal = GVar && GVar->isThreadLocal(); + if (IsThreadLocal) + return 0; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LW), DestReg) + .addReg(MFI->getGlobalBaseReg()) + .addGlobalAddress(GV, 0, MipsII::MO_GOT); + return DestReg; + return 0; +} +unsigned MipsFastISel::MaterializeInt(const Constant *C, MVT VT) { + if (VT != MVT::i32) + return 0; + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + // If the constant is in range, use a load-immediate. + const ConstantInt *CI = cast(C); + if (isInt<16>(CI->getSExtValue())) { + unsigned Opc = Mips::ADDiu; + unsigned ImmReg = createResultReg(RC); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ImmReg) + .addReg(Mips::ZERO) + .addImm(CI->getSExtValue()); + return ImmReg; + } + return 0; } namespace llvm { Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -54,7 +54,7 @@ cl::opt EnableMipsFastISel("mips-fast-isel", cl::Hidden, cl::desc("Allow mips-fast-isel to be used"), - cl::init(false)); + cl::init(true)); static const MCPhysReg O32IntRegs[4] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 Index: test/CodeGen/Mips/Fast-ISel/nullvoid.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/nullvoid.ll @@ -0,0 +1,9 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +; Function Attrs: nounwind +define void @foo() { +entry: + ret void +; CHECK: jr $ra +} Index: test/CodeGen/Mips/Fast-ISel/simplestore.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/simplestore.ll @@ -0,0 +1,15 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +@abcd = external global i32 + +; Function Attrs: nounwind +define void @foo() { +entry: + store i32 12345, i32* @abcd, align 4 +; CHECK: addiu $[[REG1:[0-9]+]], $zero, 12345 +; CHECK: lw $[[REG2:[0-9]+]], %got(abcd)(${{[0-9]+}}) +; CHECK: sw $[[REG1]], 0($[[REG2]]) + ret void +} +