[MIPS GlobalISel] Select add i32, i32

Add the minimal support necessary to lower a function that returns the
sum of two i32 values.
Support argument/return lowering of i32 values through registers only.
Add tablegen for regbankselect and instructionselect.

Patch by Petar Avramovic.

Differential Revision: https://reviews.llvm.org/D44304

llvm-svn: 329819
This commit is contained in:
Petar Jovanovic 2018-04-11 15:12:32 +00:00
parent 5ba379557d
commit 366857a23a
16 changed files with 537 additions and 13 deletions

View File

@ -6,9 +6,11 @@ tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv)
tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel)
tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM MipsGenFastISel.inc -gen-fast-isel)
tablegen(LLVM MipsGenGlobalISel.inc -gen-global-isel)
tablegen(LLVM MipsGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM MipsGenMCCodeEmitter.inc -gen-emitter)
tablegen(LLVM MipsGenMCPseudoLowering.inc -gen-pseudo-lowering)
tablegen(LLVM MipsGenRegisterBank.inc -gen-register-bank)
tablegen(LLVM MipsGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM MipsGenSubtargetInfo.inc -gen-subtarget)

View File

@ -59,6 +59,7 @@ include "MipsRegisterInfo.td"
include "MipsSchedule.td"
include "MipsInstrInfo.td"
include "MipsCallingConv.td"
include "MipsRegisterBanks.td"
// Avoid forward declaration issues.
include "MipsScheduleP5600.td"

View File

@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "MipsCallLowering.h"
#include "MipsCCState.h"
#include "MipsISelLowering.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
@ -22,13 +23,125 @@ using namespace llvm;
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<CCValAssign> ArgLocs,
ArrayRef<CallLowering::ArgInfo> 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<CCValAssign> ArgLocs,
ArrayRef<CallLowering::ArgInfo> 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<CCValAssign> ArgLocs,
ArrayRef<CallLowering::ArgInfo> 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<CCValAssign> ArgLocs,
ArrayRef<CallLowering::ArgInfo> 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<MipsTargetLowering>();
SmallVector<ArgInfo, 8> RetInfos;
SmallVector<unsigned, 8> OrigArgIndices;
ArgInfo ArgRetInfo(VReg, Val->getType());
setArgFlags(ArgRetInfo, AttributeList::ReturnIndex, DL, F);
splitToValueTypes(ArgRetInfo, 0, RetInfos, OrigArgIndices);
SmallVector<ISD::OutputArg, 8> 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<CCValAssign, 16> 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 @@ bool MipsCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
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<MipsTargetLowering>();
SmallVector<ArgInfo, 8> ArgInfos;
SmallVector<unsigned, 8> 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<ISD::InputArg, 8> 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<CCValAssign, 16> 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<ArgInfo> Args,
ArrayRef<unsigned> OrigArgIndices, const FunTy &PushBack) const {
MachineFunction &MF = MIRBuilder.getMF();
const Function &F = MF.getFunction();
const DataLayout &DL = F.getParent()->getDataLayout();
const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
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<ArgInfo> &SplitArgs,
SmallVectorImpl<unsigned> &SplitArgsOrigIndices) const {
// TODO : perform structure and array split. For now we only deal with
// types that pass isSupportedType check.
SplitArgs.push_back(OrigArg);
SplitArgsOrigIndices.push_back(OriginalIndex);
}

View File

@ -26,6 +26,22 @@ class MipsTargetLowering;
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 @@ public:
bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
ArrayRef<unsigned> VRegs) const override;
private:
using FunTy =
std::function<void(ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used,
unsigned origIdx, unsigned partOffs)>;
/// Based on registers available on target machine split or extend
/// type if needed, also change pointer type to appropriate integer
/// type. Lambda will fill some info so we can tell MipsCCState to
/// assign physical registers.
void subTargetRegTypeForCallingConv(MachineIRBuilder &MIRBuilder,
ArrayRef<ArgInfo> Args,
ArrayRef<unsigned> OrigArgIndices,
const FunTy &PushBack) const;
/// Split structures and arrays, save original argument indices since
/// Mips calling conv needs info about original argument type.
void splitToValueTypes(const ArgInfo &OrigArg, unsigned OriginalIndex,
SmallVectorImpl<ArgInfo> &SplitArgs,
SmallVectorImpl<unsigned> &SplitArgsOrigIndices) const;
};
} // end namespace llvm

View File

@ -2833,6 +2833,13 @@ static bool CC_MipsO32(unsigned ValNo, MVT ValVT, MVT LocVT,
#include "MipsGenCallingConv.inc"
CCAssignFn *MipsTargetLowering::CCAssignFnForCall() const{
return CC_Mips;
}
CCAssignFn *MipsTargetLowering::CCAssignFnForReturn() const{
return RetCC_Mips;
}
//===----------------------------------------------------------------------===//
// Call Calling Convention Implementation
//===----------------------------------------------------------------------===//

View File

@ -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/SelectionDAG.h"
@ -365,6 +366,10 @@ class TargetRegisterClass;
return getTargetMachine().isPositionIndependent();
}
CCAssignFn *CCAssignFnForCall() const;
CCAssignFn *CCAssignFnForReturn() const;
protected:
SDValue getGlobalReg(SelectionDAG &DAG, EVT Ty) const;

View File

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

View File

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

View File

@ -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
MipsGenRegisterBankInfo::MipsGenRegisterBankInfo()
: RegisterBankInfo(nullptr, 0) {}
#define DEBUG_TYPE "registerbankinfo"
#include "MipsGenRegisterBank.inc"
namespace llvm {
namespace Mips {
enum PartialMappingIdx {
PMI_GPR,
PMI_Min = PMI_GPR,
};
RegisterBankInfo::PartialMapping PartMappings[]{
{0, 32, GPRBRegBank}
};
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::GPRBRegBankID);
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);
}

View File

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

View File

@ -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 GPRBRegBank : RegisterBank<"GPRB", [GPR32]>;

View File

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

View File

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

View File

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

View File

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

View File

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