Index: lib/Target/Mips/CMakeLists.txt =================================================================== --- lib/Target/Mips/CMakeLists.txt +++ lib/Target/Mips/CMakeLists.txt @@ -11,6 +11,8 @@ tablegen(LLVM MipsGenSubtargetInfo.inc -gen-subtarget) tablegen(LLVM MipsGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM MipsGenMCPseudoLowering.inc -gen-pseudo-lowering) +tablegen(LLVM MipsGenRegisterBank.inc -gen-register-bank) +tablegen(LLVM MipsGenGlobalISel.inc -gen-global-isel) add_public_tablegen_target(MipsCommonTableGen) add_llvm_target(MipsCodeGen Index: lib/Target/Mips/Mips.td =================================================================== --- lib/Target/Mips/Mips.td +++ lib/Target/Mips/Mips.td @@ -56,6 +56,7 @@ include "MipsSchedule.td" include "MipsInstrInfo.td" include "MipsCallingConv.td" +include "MipsRegisterBanks.td" // Avoid forward declaration issues. include "MipsScheduleP5600.td" Index: lib/Target/Mips/MipsCallLowering.h =================================================================== --- lib/Target/Mips/MipsCallLowering.h +++ lib/Target/Mips/MipsCallLowering.h @@ -26,6 +26,22 @@ class MipsCallLowering : public CallLowering { public: + class MipsHandler { + public: + MipsHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI) + : MIRBuilder(MIRBuilder), MRI(MRI) {} + + virtual ~MipsHandler() = default; + + protected: + virtual void assignValueToReg(unsigned ValVReg, unsigned PhysReg) = 0; + + bool assign(const CCValAssign &VA, unsigned vreg); + + MachineIRBuilder &MIRBuilder; + MachineRegisterInfo &MRI; + }; + MipsCallLowering(const MipsTargetLowering &TLI); bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val, @@ -33,6 +49,26 @@ bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F, ArrayRef VRegs) const override; + +private: + using FunTy = + std::function; + + /// Based on registers available on target machine split or extend type + /// if needed, lambda will fill some info so we can tell MipsCCState to + /// assign physical registers. + void subTargetRegTypeForCallingConv(MachineIRBuilder &MIRBuilder, + ArrayRef Args, + ArrayRef OrigArgIndices, + const FunTy &PushBack) const; + + /// Split structures and arrays, change pointer type to appropriate integer + /// type, save original argument indices since Mips calling conv needs info + /// about original argument type. + void splitToValueTypes(const ArgInfo &OrigArg, unsigned OriginalIndex, + SmallVectorImpl &SplitArgs, + SmallVectorImpl &SplitArgsOrigIndices) const; }; } // end namespace llvm Index: lib/Target/Mips/MipsCallLowering.cpp =================================================================== --- lib/Target/Mips/MipsCallLowering.cpp +++ lib/Target/Mips/MipsCallLowering.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "MipsCallLowering.h" +#include "MipsCCState.h" #include "MipsISelLowering.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" @@ -22,13 +23,125 @@ MipsCallLowering::MipsCallLowering(const MipsTargetLowering &TLI) : CallLowering(&TLI) {} +bool MipsCallLowering::MipsHandler::assign(const CCValAssign &VA, + unsigned vreg) { + if (VA.isRegLoc()) { + assignValueToReg(vreg, VA.getLocReg()); + } else { + return false; + } + return true; +} + +namespace { +class IncomingValueHandler : public MipsCallLowering::MipsHandler { +public: + IncomingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI) + : MipsHandler(MIRBuilder, MRI) {} + + bool handle(ArrayRef ArgLocs, + ArrayRef Args); + +private: + virtual void assignValueToReg(unsigned ValVReg, unsigned PhysReg) override; + + void markPhysRegUsed(unsigned PhysReg) { + MIRBuilder.getMBB().addLiveIn(PhysReg); + } +}; +} // end anonymous namespace + +void IncomingValueHandler::assignValueToReg(unsigned ValVReg, + unsigned PhysReg) { + MIRBuilder.buildCopy(ValVReg, PhysReg); + markPhysRegUsed(PhysReg); +} + +bool IncomingValueHandler::handle(ArrayRef ArgLocs, + ArrayRef Args) { + for (unsigned i = 0, ArgsSize = Args.size(); i < ArgsSize; ++i) { + if (!assign(ArgLocs[i], Args[i].Reg)) + return false; + } + return true; +} + +namespace { +class OutgoingValueHandler : public MipsCallLowering::MipsHandler { +public: + OutgoingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, + MachineInstrBuilder &MIB) + : MipsHandler(MIRBuilder, MRI), MIB(MIB) {} + + bool handle(ArrayRef ArgLocs, + ArrayRef Args); + +private: + virtual void assignValueToReg(unsigned ValVReg, unsigned PhysReg) override; + + MachineInstrBuilder &MIB; +}; +} // end anonymous namespace + +void OutgoingValueHandler::assignValueToReg(unsigned ValVReg, + unsigned PhysReg) { + MIRBuilder.buildCopy(PhysReg, ValVReg); + MIB.addUse(PhysReg, RegState::Implicit); +} + +bool OutgoingValueHandler::handle(ArrayRef ArgLocs, + ArrayRef Args) { + for (unsigned i = 0; i < Args.size(); ++i) { + if (!assign(ArgLocs[i], Args[i].Reg)) + return false; + } + return true; +} + +static bool isSupportedType(Type *T) { + if (T->isIntegerTy() && T->getScalarSizeInBits() == 32) + return true; + return false; +} + bool MipsCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, unsigned VReg) const { MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Mips::RetRA); if (Val != nullptr) { - return false; + if (!isSupportedType(Val->getType())) + return false; + + MachineFunction &MF = MIRBuilder.getMF(); + const Function &F = MF.getFunction(); + const DataLayout &DL = MF.getDataLayout(); + const MipsTargetLowering &TLI = *getTLI(); + + SmallVector RetInfos; + SmallVector OrigArgIndices; + + ArgInfo ArgRetInfo(VReg, Val->getType()); + setArgFlags(ArgRetInfo, AttributeList::ReturnIndex, DL, F); + splitToValueTypes(ArgRetInfo, 0, RetInfos, OrigArgIndices); + + SmallVector Outs; + subTargetRegTypeForCallingConv( + MIRBuilder, RetInfos, OrigArgIndices, + [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, + unsigned origIdx, unsigned partOffs) { + Outs.emplace_back(flags, vt, argvt, used, origIdx, partOffs); + }); + + SmallVector ArgLocs; + MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, + F.getContext()); + CCInfo.AnalyzeReturn(Outs, TLI.CCAssignFnForReturn()); + + OutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret); + if (!RetHandler.handle(ArgLocs, RetInfos)) { + return false; + } } MIRBuilder.insertInstr(Ret); return true; @@ -42,6 +155,80 @@ if (F.arg_empty()) return true; - // Function had args, but we didn't lower them. - return false; + if (F.isVarArg()) { + return false; + } + + for (auto &Arg : F.args()) { + if (!isSupportedType(Arg.getType())) + return false; + } + + MachineFunction &MF = MIRBuilder.getMF(); + const DataLayout &DL = MF.getDataLayout(); + const MipsTargetLowering &TLI = *getTLI(); + + SmallVector ArgInfos; + SmallVector OrigArgIndices; + unsigned i = 0; + for (auto &Arg : F.args()) { + ArgInfo AInfo(VRegs[i], Arg.getType()); + setArgFlags(AInfo, i + AttributeList::FirstArgIndex, DL, F); + splitToValueTypes(AInfo, i, ArgInfos, OrigArgIndices); + ++i; + } + + SmallVector Ins; + subTargetRegTypeForCallingConv( + MIRBuilder, ArgInfos, OrigArgIndices, + [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, unsigned origIdx, + unsigned partOffs) { + Ins.emplace_back(flags, vt, argvt, used, origIdx, partOffs); + }); + + SmallVector ArgLocs; + MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, + F.getContext()); + + CCInfo.AnalyzeFormalArguments(Ins, TLI.CCAssignFnForCall()); + + IncomingValueHandler Handler(MIRBuilder, MIRBuilder.getMF().getRegInfo()); + if (!Handler.handle(ArgLocs, ArgInfos)) + return false; + + return true; +} + +void MipsCallLowering::subTargetRegTypeForCallingConv( + MachineIRBuilder &MIRBuilder, ArrayRef Args, + ArrayRef OrigArgIndices, const FunTy &PushBack) const { + MachineFunction &MF = MIRBuilder.getMF(); + const Function &F = MF.getFunction(); + const DataLayout &DL = F.getParent()->getDataLayout(); + const MipsTargetLowering &TLI = *getTLI(); + + unsigned ArgNo = 0; + for (auto &Arg : Args) { + + EVT VT = TLI.getValueType(DL, Arg.Ty); + MVT RegisterVT = TLI.getRegisterTypeForCallingConv(F.getContext(), VT); + + ISD::ArgFlagsTy Flags = Arg.Flags; + Flags.setOrigAlign(TLI.getABIAlignmentForCallingConv(Arg.Ty, DL)); + + PushBack(Flags, RegisterVT, VT, true, OrigArgIndices[ArgNo], 0); + + ++ArgNo; + } +} + +void MipsCallLowering::splitToValueTypes( + const ArgInfo &OrigArg, unsigned OriginalIndex, + SmallVectorImpl &SplitArgs, + SmallVectorImpl &SplitArgsOrigIndices) const { + + // TODO : change pointer type to integer, later perform structure and array + // split. For now we only deal types that pass isSupportedType check. + SplitArgs.push_back(OrigArg); + SplitArgsOrigIndices.push_back(OriginalIndex); } Index: lib/Target/Mips/MipsISelLowering.h =================================================================== --- lib/Target/Mips/MipsISelLowering.h +++ lib/Target/Mips/MipsISelLowering.h @@ -19,6 +19,7 @@ #include "MCTargetDesc/MipsBaseInfo.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "Mips.h" +#include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineValueType.h" @@ -365,6 +366,10 @@ return getTargetMachine().isPositionIndependent(); } + CCAssignFn *CCAssignFnForCall() const; + + CCAssignFn *CCAssignFnForReturn() const; + protected: SDValue getGlobalReg(SelectionDAG &DAG, EVT Ty) const; Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -2833,6 +2833,13 @@ #include "MipsGenCallingConv.inc" + CCAssignFn *MipsTargetLowering::CCAssignFnForCall() const{ + return CC_Mips; + } + + CCAssignFn *MipsTargetLowering::CCAssignFnForReturn() const{ + return RetCC_Mips; + } //===----------------------------------------------------------------------===// // Call Calling Convention Implementation //===----------------------------------------------------------------------===// Index: lib/Target/Mips/MipsInstructionSelector.cpp =================================================================== --- lib/Target/Mips/MipsInstructionSelector.cpp +++ lib/Target/Mips/MipsInstructionSelector.cpp @@ -15,41 +15,101 @@ #include "MipsRegisterBankInfo.h" #include "MipsSubtarget.h" #include "MipsTargetMachine.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" #include "llvm/Support/Debug.h" +#define DEBUG_TYPE "Mips-isel" + using namespace llvm; namespace { +#define GET_GLOBALISEL_PREDICATE_BITSET +#include "MipsGenGlobalISel.inc" +#undef GET_GLOBALISEL_PREDICATE_BITSET + class MipsInstructionSelector : public InstructionSelector { public: MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI, const MipsRegisterBankInfo &RBI); bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override; + static const char *getName() { return DEBUG_TYPE; } private: + bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; + + const MipsTargetMachine &TM; + const MipsSubtarget &STI; const MipsInstrInfo &TII; const MipsRegisterInfo &TRI; + const MipsRegisterBankInfo &RBI; + +#define GET_GLOBALISEL_PREDICATES_DECL +#include "MipsGenGlobalISel.inc" +#undef GET_GLOBALISEL_PREDICATES_DECL + +#define GET_GLOBALISEL_TEMPORARIES_DECL +#include "MipsGenGlobalISel.inc" +#undef GET_GLOBALISEL_TEMPORARIES_DECL }; } // end anonymous namespace +#define GET_GLOBALISEL_IMPL +#include "MipsGenGlobalISel.inc" +#undef GET_GLOBALISEL_IMPL + MipsInstructionSelector::MipsInstructionSelector( const MipsTargetMachine &TM, const MipsSubtarget &STI, const MipsRegisterBankInfo &RBI) - : InstructionSelector(), TII(*STI.getInstrInfo()), - TRI(*STI.getRegisterInfo()) {} + : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), + TRI(*STI.getRegisterInfo()), RBI(RBI), + +#define GET_GLOBALISEL_PREDICATES_INIT +#include "MipsGenGlobalISel.inc" +#undef GET_GLOBALISEL_PREDICATES_INIT +#define GET_GLOBALISEL_TEMPORARIES_INIT +#include "MipsGenGlobalISel.inc" +#undef GET_GLOBALISEL_TEMPORARIES_INIT +{ +} + +static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, + MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) { + unsigned DstReg = I.getOperand(0).getReg(); + if (TargetRegisterInfo::isPhysicalRegister(DstReg)) + return true; + + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + + if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { + DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) + << " operand\n"); + return false; + } + return true; +} bool MipsInstructionSelector::select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const { + MachineBasicBlock &MBB = *I.getParent(); + MachineFunction &MF = *MBB.getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + if (!isPreISelGenericOpcode(I.getOpcode())) { - // Not global isel generic opcode. - // TODO: select copy + if (I.isCopy()) + return selectCopy(I, TII, MRI, TRI, RBI); + return true; } + if (selectImpl(I, CoverageInfo)) { + return true; + } // We didn't select anything. return false; } Index: lib/Target/Mips/MipsLegalizerInfo.cpp =================================================================== --- lib/Target/Mips/MipsLegalizerInfo.cpp +++ lib/Target/Mips/MipsLegalizerInfo.cpp @@ -20,5 +20,11 @@ using namespace llvm; MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) { + using namespace TargetOpcode; + + const LLT s32 = LLT::scalar(32); + + getActionDefinitionsBuilder(G_ADD).legalFor({s32}); + computeTables(); } Index: lib/Target/Mips/MipsRegisterBankInfo.h =================================================================== --- lib/Target/Mips/MipsRegisterBankInfo.h +++ lib/Target/Mips/MipsRegisterBankInfo.h @@ -16,20 +16,28 @@ #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" +#define GET_REGBANK_DECLARATIONS +#include "MipsGenRegisterBank.inc" + namespace llvm { class TargetRegisterInfo; class MipsGenRegisterBankInfo : public RegisterBankInfo { -// TODO: This should be auto-generated by TableGen. -public: - MipsGenRegisterBankInfo(); +#define GET_TARGET_REGBANK_CLASS +#include "MipsGenRegisterBank.inc" }; /// This class provides the information for the target register banks. class MipsRegisterBankInfo final : public MipsGenRegisterBankInfo { public: MipsRegisterBankInfo(const TargetRegisterInfo &TRI); + + const RegisterBank & + getRegBankFromRegClass(const TargetRegisterClass &RC) const override; + + const InstructionMapping & + getInstrMapping(const MachineInstr &MI) const override; }; } // end namespace llvm #endif Index: lib/Target/Mips/MipsRegisterBankInfo.cpp =================================================================== --- lib/Target/Mips/MipsRegisterBankInfo.cpp +++ lib/Target/Mips/MipsRegisterBankInfo.cpp @@ -11,16 +11,84 @@ /// \todo This should be generated by TableGen. //===----------------------------------------------------------------------===// +#include "MipsInstrInfo.h" #include "MipsRegisterBankInfo.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h" -using namespace llvm; +#define GET_TARGET_REGBANK_IMPL + +#define DEBUG_TYPE "registerbankinfo" + +#include "MipsGenRegisterBank.inc" + +namespace llvm { +namespace Mips { +enum PartialMappingIdx { + PMI_GPR, + PMI_Min = PMI_GPR, +}; + +RegisterBankInfo::PartialMapping PartMappings[]{ + {0, 32, GPRRegBank} +}; -MipsGenRegisterBankInfo::MipsGenRegisterBankInfo() - : RegisterBankInfo(nullptr, 0) {} +enum ValueMappingIdx { InvalidIdx = 0, GPRIdx = 1 }; + +RegisterBankInfo::ValueMapping ValueMappings[] = { + // invalid + {nullptr, 0}, + // 3 operands in GPRs + {&PartMappings[PMI_GPR - PMI_Min], 1}, + {&PartMappings[PMI_GPR - PMI_Min], 1}, + {&PartMappings[PMI_GPR - PMI_Min], 1}}; + +} // end namespace Mips +} // end namespace llvm + +using namespace llvm; MipsRegisterBankInfo::MipsRegisterBankInfo(const TargetRegisterInfo &TRI) : MipsGenRegisterBankInfo() {} + +const RegisterBank &MipsRegisterBankInfo::getRegBankFromRegClass( + const TargetRegisterClass &RC) const { + using namespace Mips; + + switch (RC.getID()) { + case Mips::GPR32RegClassID: + case Mips::CPU16Regs_and_GPRMM16ZeroRegClassID: + case Mips::GPRMM16MoveP_and_CPU16Regs_and_GPRMM16ZeroRegClassID: + return getRegBank(Mips::GPRRegBankID); + default: + llvm_unreachable("Register class not supported"); + } +} + +const RegisterBankInfo::InstructionMapping & +MipsRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { + + unsigned Opc = MI.getOpcode(); + + const RegisterBankInfo::InstructionMapping &Mapping = getInstrMappingImpl(MI); + if (Mapping.isValid()) + return Mapping; + + using namespace TargetOpcode; + + unsigned NumOperands = MI.getNumOperands(); + const ValueMapping *OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx]; + + switch (Opc) { + case G_ADD: + OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx]; + break; + default: + return getInvalidInstructionMapping(); + } + + return getInstructionMapping(DefaultMappingID, /*Cost=*/1, OperandsMapping, + NumOperands); +} Index: lib/Target/Mips/MipsRegisterBanks.td =================================================================== --- /dev/null +++ lib/Target/Mips/MipsRegisterBanks.td @@ -0,0 +1,13 @@ +//===- MipsRegisterBank.td ---------------------------------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +def GPRRegBank : RegisterBank<"GPRb", [GPR32]>; Index: test/CodeGen/Mips/GlobalISel/instruction-select/add.mir =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/instruction-select/add.mir @@ -0,0 +1,35 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 +--- | + + define void @add_i32(i32 %x, i32 %y) {entry: ret void} + +... +--- +name: add_i32 +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: gprb } + - { id: 1, class: gprb } + - { id: 2, class: gprb } +body: | + bb.0.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: add_i32 + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:gpr32 = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:gpr32 = COPY $a1 + ; MIPS32: [[ADDu:%[0-9]+]]:gpr32 = ADDu [[COPY]], [[COPY1]] + ; MIPS32: $v0 = COPY [[ADDu]] + ; MIPS32: RetRA implicit $v0 + %0:gprb(s32) = COPY $a0 + %1:gprb(s32) = COPY $a1 + %2:gprb(s32) = G_ADD %0, %1 + $v0 = COPY %2(s32) + RetRA implicit $v0 + +... Index: test/CodeGen/Mips/GlobalISel/irtranslator/add.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/irtranslator/add.ll @@ -0,0 +1,16 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 + +define i32 @add_i32(i32 %x, i32 %y) { + ; MIPS32-LABEL: name: add_i32 + ; MIPS32: bb.1.entry: + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[COPY1]] + ; MIPS32: $v0 = COPY [[ADD]](s32) + ; MIPS32: RetRA implicit $v0 +entry: + %z = add i32 %x, %y + ret i32 %z +} Index: test/CodeGen/Mips/GlobalISel/legalizer/add.mir =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/legalizer/add.mir @@ -0,0 +1,34 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -run-pass=legalizer -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 +--- | + + define void @add_i32(i32 %x, i32 %y) {entry: ret void} + +... +--- +name: add_i32 +alignment: 2 +legalized: true +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: add_i32 + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[COPY1]] + ; MIPS32: $v0 = COPY [[ADD]](s32) + ; MIPS32: RetRA implicit $v0 + %0:_(s32) = COPY $a0 + %1:_(s32) = COPY $a1 + %2:_(s32) = G_ADD %0, %1 + $v0 = COPY %2(s32) + RetRA implicit $v0 + +... Index: test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll @@ -0,0 +1,12 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32 +define i32 @add_i32(i32 %x, i32 %y) { +; MIPS32-LABEL: add_i32: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: addu $2, $4, $5 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %z = add i32 %x, %y + ret i32 %z +} Index: test/CodeGen/Mips/GlobalISel/regbankselect/add.mir =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/regbankselect/add.mir @@ -0,0 +1,34 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -run-pass=regbankselect -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 +--- | + + define void @add_i32(i32 %x, i32 %y) {entry: ret void} + +... +--- +name: add_i32 +alignment: 2 +legalized: true +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: add_i32 + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:gprb(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:gprb(s32) = COPY $a1 + ; MIPS32: [[ADD:%[0-9]+]]:gprb(s32) = G_ADD [[COPY]], [[COPY1]] + ; MIPS32: $v0 = COPY [[ADD]](s32) + ; MIPS32: RetRA implicit $v0 + %0:_(s32) = COPY $a0 + %1:_(s32) = COPY $a1 + %2:_(s32) = G_ADD %0, %1 + $v0 = COPY %2(s32) + RetRA implicit $v0 + +...