diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt --- a/llvm/lib/Target/RISCV/CMakeLists.txt +++ b/llvm/lib/Target/RISCV/CMakeLists.txt @@ -5,6 +5,7 @@ tablegen(LLVM RISCVGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter) +tablegen(LLVM RISCVGenCallingConv.inc -gen-callingconv) tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel) tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM RISCVGenGlobalISel.inc -gen-global-isel) @@ -20,6 +21,7 @@ add_llvm_target(RISCVCodeGen RISCVAsmPrinter.cpp + RISCVCallingConv.cpp RISCVCallLowering.cpp RISCVExpandAtomicPseudoInsts.cpp RISCVExpandPseudoInsts.cpp diff --git a/llvm/lib/Target/RISCV/RISCVCallLowering.cpp b/llvm/lib/Target/RISCV/RISCVCallLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVCallLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVCallLowering.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "RISCVCallingConv.h" #include "RISCVCallLowering.h" #include "RISCVISelLowering.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" @@ -21,15 +22,102 @@ RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI) : CallLowering(&TLI) {} +static bool isSupportedType(const DataLayout DL, + const RISCVTargetLowering &TLI, Type *Ty) { + EVT VT = TLI.getValueType(DL, Ty); + return VT.isInteger() && VT.getSimpleVT().getSizeInBits() == 32; +} + +namespace { +struct OutgoingArgHandler : public CallLowering::OutgoingValueHandler { + OutgoingArgHandler(MachineIRBuilder &MIRBuilder, + MachineRegisterInfo &MRI, MachineInstrBuilder MIB, + CCAssignFn *AssignFn) + : OutgoingValueHandler(MIRBuilder, MRI, AssignFn), MIB(MIB) {} + + Register getStackAddress(uint64_t Size, int64_t Offset, + MachinePointerInfo &MPO) { + llvm_unreachable("Don't know how to get a stack address yet"); + } + + void assignValueToReg(Register ValVReg, Register PhysReg, + CCValAssign &VA) { + assert(VA.isRegLoc() && "Value shouldn't be assigned to a register"); + assert(VA.getLocReg() == PhysReg && "Assign to a wrong register"); + + assert(VA.getValVT().getFixedSizeInBits() == 32 && + VA.getLocVT().getFixedSizeInBits() == 32 && + "Unsupported data type. For now, only 32 bits data type is supported"); + + MIRBuilder.buildCopy(PhysReg, ValVReg); + MIB.addUse(PhysReg, RegState::Implicit); + } + + void assignValueToAddress(Register ValVReg, Register Addr, + uint64_t Size, MachinePointerInfo &MPO, + CCValAssign &VA) override { + llvm_unreachable("For now, assign value to address is not supported"); + } + + MachineInstrBuilder MIB; +}; + +struct IncomingArgHandler : public CallLowering::IncomingValueHandler { + IncomingArgHandler(MachineIRBuilder &MIRBuilder, + MachineRegisterInfo &MRI, CCAssignFn *AssignFn) + : IncomingValueHandler(MIRBuilder, MRI, AssignFn) {} + + void assignValueToAddress(Register ValVReg, Register Addr, + uint64_t Size, MachinePointerInfo &MPO, + CCValAssign &VA) override { + llvm_unreachable("For now, assign value to address is not supported"); + } + + void assignValueToReg(Register ValVReg, Register PhysReg, + CCValAssign &VA) { + assert(VA.isRegLoc() && "Value shouldn't be assigned to a register"); + assert(VA.getLocReg() == PhysReg && "Assign to a wrong register"); + + assert(VA.getValVT().getFixedSizeInBits() == 32 && + VA.getLocVT().getFixedSizeInBits() == 32 && + "Unsupported data type. For now, only 32 bits data type is supported"); + + MIRBuilder.buildCopy(ValVReg, PhysReg); + MIRBuilder.getMRI()->addLiveIn(PhysReg); + MIRBuilder.getMBB().addLiveIn(PhysReg); + } + + Register getStackAddress(uint64_t Size, int64_t Offset, + MachinePointerInfo &MPO) { + llvm_unreachable("Don't know how to get a stack address yet"); + } +}; + +} // End of anonymous namespace. + bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, ArrayRef VRegs) const { - MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET); + const RISCVTargetLowering &TLI = *getTLI(); + MachineFunction &MF = MIRBuilder.getMF(); + const DataLayout &DL = MF.getDataLayout(); if (Val != nullptr) { - return false; + if (!isSupportedType(DL, TLI, Val->getType())) + return false; + + SmallVector RetArgs; + ArgInfo RetArg(VRegs, Val->getType()); + setArgFlags(RetArg, AttributeList::ReturnIndex, DL, MF.getFunction()); + RetArgs.push_back(RetArg); + + OutgoingArgHandler RetHandler(MIRBuilder, MF.getRegInfo(), + Ret, Ret_CC_RISCV32); + if (!handleAssignments(MIRBuilder, RetArgs, RetHandler)) + return false; } + MIRBuilder.insertInstr(Ret); return true; } @@ -38,10 +126,39 @@ MachineIRBuilder &MIRBuilder, const Function &F, ArrayRef> VRegs) const { + const RISCVTargetLowering &TLI = *getTLI(); + MachineFunction &MF = MIRBuilder.getMF(); + const DataLayout &DL = MF.getDataLayout(); + if (F.arg_empty()) return true; - return false; + if (F.isVarArg()) + return false; + + // stick to 8 arguments for now + if (F.arg_size() > 8) + return false; + + for (auto &Arg : F.args()) { + if (!isSupportedType(DL, TLI, Arg.getType())) + return false; + } + + CCAssignFn *AssignFn = CC_RISCV32; + SmallVector ArgInfos; + unsigned Idx = 0; + for (auto &Arg : F.args()) { + ArgInfo OriArgInfo(VRegs[Idx], Arg.getType()); + setArgFlags(OriArgInfo, Idx + AttributeList::FirstArgIndex, DL, F); + ArgInfos.push_back(OriArgInfo); + + Idx++; + } + + IncomingArgHandler ArgHandler(MIRBuilder, MF.getRegInfo(), + CC_RISCV32); + return handleAssignments(MIRBuilder, ArgInfos, ArgHandler); } bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.h b/llvm/lib/Target/RISCV/RISCVCallingConv.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/RISCV/RISCVCallingConv.h @@ -0,0 +1,30 @@ +//=== RISCVCallingConv.h - ARM Custom Calling Convention Routines -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the entry points for RISCV calling convention analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCVCALLINGCONV_H +#define LLVM_LIB_TARGET_RISCV_RISCVCALLINGCONV_H + +#include "llvm/CodeGen/CallingConvLower.h" + +namespace llvm { + +bool CC_RISCV32(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, + CCState &State); + +bool Ret_CC_RISCV32(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, + CCState &State); + +} + +#endif \ No newline at end of file diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp @@ -0,0 +1,18 @@ +//=== RISCVCallingConv.h - ARM Custom Calling Convention Routines -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the entry points for RISCV calling convention analysis. +// +//===----------------------------------------------------------------------===// + +#include "RISCV.h" +#include "RISCVSubtarget.h" +#include "RISCVRegisterInfo.h" +#include "RISCVCallingConv.h" + +#include "RISCVGenCallingConv.inc" \ No newline at end of file diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.td b/llvm/lib/Target/RISCV/RISCVCallingConv.td --- a/llvm/lib/Target/RISCV/RISCVCallingConv.td +++ b/llvm/lib/Target/RISCV/RISCVCallingConv.td @@ -63,3 +63,17 @@ (sequence "F%u_D", 28, 31), (sequence "F%u_D", 8, 9), (sequence "F%u_D", 18, 27))>; + +let Entry = 1 in { + def CC_RISCV32: CallingConv<[ + CCIfType<[i32], CCAssignToReg<[X10, X11, X12, X13, X14, X15, X16, X17]>>, + CCIfType<[i32], CCAssignToStack<4, 4>> + ]>; +} + +let Entry = 1 in { +def Ret_CC_RISCV32: CallingConv<[ + CCIfType<[i32], CCAssignToReg<[X10]>>, + CCIfType<[i64], CCAssignToReg<[X10, X11]>> + ]>; +} \ No newline at end of file diff --git a/llvm/lib/Target/RISCV/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/RISCVInstructionSelector.cpp --- a/llvm/lib/Target/RISCV/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstructionSelector.cpp @@ -81,10 +81,36 @@ { } +static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, + MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) { + Register DstReg = I.getOperand(0).getReg(); + if (Register::isPhysicalRegister(DstReg)) + return true; + + Register SrcReg = I.getOperand(1).getReg(); + const unsigned DstRegSize = RBI.getSizeInBits(DstReg, MRI, TRI); + const unsigned SrcRegSize = RBI.getSizeInBits(SrcReg, MRI, TRI); + assert(DstRegSize == SrcRegSize && "Copy with different size is not supported"); + + // No need to constrain SrcReg. It will get constrained when + // we hit another of its uses or its defs. + // Copies do not have constraints. + if (!RBI.constrainGenericRegister(DstReg, RISCV::GPRRegClass, MRI)) { + LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) + << " operand\n"); + return false; + } + return true; +} + bool RISCVInstructionSelector::select(MachineInstr &I) { if (!isPreISelGenericOpcode(I.getOpcode())) { // Certain non-generic instructions also need some special handling. + if (I.isCopy()) { + return selectCopy(I, TII, I.getMF()->getRegInfo(), TRI, RBI); + } return true; } diff --git a/llvm/lib/Target/RISCV/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/RISCVLegalizerInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVLegalizerInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVLegalizerInfo.cpp @@ -11,13 +11,19 @@ //===----------------------------------------------------------------------===// #include "RISCVLegalizerInfo.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Type.h" using namespace llvm; +using namespace LegalizeActions; RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) { + using namespace TargetOpcode; + const LLT s32 = LLT::scalar(32); + + setAction({G_ADD, s32}, Legal); computeTables(); } diff --git a/llvm/lib/Target/RISCV/RISCVRegisterBankInfo.h b/llvm/lib/Target/RISCV/RISCVRegisterBankInfo.h --- a/llvm/lib/Target/RISCV/RISCVRegisterBankInfo.h +++ b/llvm/lib/Target/RISCV/RISCVRegisterBankInfo.h @@ -32,6 +32,12 @@ class RISCVRegisterBankInfo final : public RISCVGenRegisterBankInfo { public: RISCVRegisterBankInfo(const TargetRegisterInfo &TRI); + + const RegisterBank &getRegBankFromRegClass(const TargetRegisterClass &RC, + LLT) const override; + + const InstructionMapping & + getInstrMapping(const MachineInstr &MI) const override; }; } // end namespace llvm #endif diff --git a/llvm/lib/Target/RISCV/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterBankInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVRegisterBankInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVRegisterBankInfo.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "RISCVRegisterBankInfo.h" +#include "RISCVInstrInfo.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" @@ -22,5 +23,65 @@ using namespace llvm; +namespace llvm { +namespace RISCV { + +RegisterBankInfo::PartialMapping PartMappings[] { {0, 32, GPRRegBank} }; + +RegisterBankInfo::ValueMapping ValueMappings[] { + // The instruction at most has 3 operands + {&PartMappings[0], 1}, {&PartMappings[0], 1}, {&PartMappings[0], 1} +}; + +} // End of namespace RISCV +} // End of namespace RISCV + RISCVRegisterBankInfo::RISCVRegisterBankInfo(const TargetRegisterInfo &TRI) - : RISCVGenRegisterBankInfo() {} + : RISCVGenRegisterBankInfo() { + static llvm::once_flag InitializeRegisterBankFlag; + static auto InitializeRegisterBankOnce = [&]() { + const RegisterBank &RBGPR = getRegBank(RISCV::GPRRegBankID); + (void)RBGPR; + assert(&RISCV::GPRRegBank == &RBGPR && + "The order in RegBanks is messed up"); + assert(RBGPR.covers(*TRI.getRegClass(RISCV::GPRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(RISCV::GPRNoX0RegClassID)) && + "Subclass not added?"); + }; + llvm::call_once(InitializeRegisterBankFlag, InitializeRegisterBankOnce); +} + +const RegisterBank & +RISCVRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC, + LLT) const { + using namespace RISCV; + switch (RC.getID()) { + case GPRRegClassID: + case GPRC_and_GPRTCRegClassID: + return GPRRegBank; + default: + llvm_unreachable("Unsupported register kind"); + } +} + +const RegisterBankInfo::InstructionMapping & +RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { + unsigned Opcode = MI.getOpcode(); + + if (!isPreISelGenericOpcode(Opcode)) { + const InstructionMapping &Mapping = getInstrMappingImpl(MI); + if (Mapping.isValid()) + return Mapping; + } + + ValueMapping *OperandsMapping = &RISCV::ValueMappings[0]; + unsigned NumOperands = MI.getNumOperands(); + + if (Opcode == TargetOpcode::G_ADD) { + OperandsMapping = &RISCV::ValueMappings[0]; + } + + return getInstructionMapping(DefaultMappingID, /*Cost*/1, OperandsMapping, + NumOperands); +} diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select.mir @@ -0,0 +1,67 @@ +# RUN: llc -mtriple=riscv32 -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s +--- | + define void @test_add() { + ret void + } + +... +--- +name: test_add +# CHECK-LABEL: name: test_add +alignment: 4 +exposesReturnsTwice: false +legalized: true +regBankSelected: true +selected: false +# CHECK: selected: true +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +registers: + - { id: 0, class: gprb, preferred-register: '' } + - { id: 1, class: gprb, preferred-register: '' } + - { id: 2, class: gprb, preferred-register: '' } +liveins: + - { reg: '$x10', virtual-reg: '' } + - { reg: '$x11', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.0: + liveins: $x10, $x11 + + %0:gprb(s32) = COPY $x10 + ; CHECK: [[VREGX:%[0-9]+]]:gpr = COPY $x10 + %1:gprb(s32) = COPY $x11 + ; CHECK: [[VREGY:%[0-9]+]]:gpr = COPY $x11 + %2:gprb(s32) = G_ADD %0, %1 + ; CHECK: [[VREGSUM:%[0-9]+]]:gpr = ADD [[VREGX]], [[VREGY]] + $x10 = COPY %2(s32) + ; CHECK: $x10 = COPY [[VREGSUM]] + PseudoRET implicit $x10 + ; CHECK: PseudoRET implicit $x10 + +... diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator.ll @@ -0,0 +1,16 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +define i32 @test_add(i32 %x, i32 %y) { +; RV32I-LABEL: name: test_add +; RV32I: liveins: $x10, $x11 +; RV32I: [[VREGX:%[0-9]+]]:_(s32) = COPY $x10 +; RV32I: [[VREGY:%[0-9]+]]:_(s32) = COPY $x11 +; RV32I: [[SUM:%[0-9]+]]:_(s32) = G_ADD [[VREGX]], [[VREGY]] +; RV32I: $x10 = COPY [[SUM]] +; RV32I: PseudoRET implicit $x10 +entry: + %sum = add i32 %x, %y + ret i32 %sum +} \ No newline at end of file diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/isel.ll b/llvm/test/CodeGen/RISCV/GlobalISel/isel.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/isel.ll @@ -0,0 +1,12 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -global-isel -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +define i32 @test_add(i32 %x, i32 %y) { +; RV32I-LABEL: test_add: +; RV32I: add a0, a0, a1 +; RV32I: ret +entry: + %sum = add i32 %x, %y + ret i32 %sum +} \ No newline at end of file diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer.mir @@ -0,0 +1,60 @@ +# RUN: llc -mtriple=riscv32 -global-isel -run-pass=legalizer %s -o - | FileCheck %s +--- | + define void @test_add() { ret void } +... +--- +name: test_add +# CHECK-LABEL: name: test_add +alignment: 4 +exposesReturnsTwice: false +legalized: false +# CHECK: legalized: true +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } +liveins: + - { reg: '$x10', virtual-reg: '' } + - { reg: '$x11', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.1: + liveins: $x10, $x11 + + %0:_(s32) = COPY $x10 + %1:_(s32) = COPY $x11 + %2:_(s32) = G_ADD %0, %1 + ; CHECK: {{%[0-9]+}}:_(s32) = G_ADD {{%[0-9]+, %[0-9]+}} + $x10 = COPY %2(s32) + PseudoRET implicit $x10 +... + diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect.mir b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect.mir @@ -0,0 +1,64 @@ +# RUN: llc -mtriple riscv32-- -global-isel -run-pass=regbankselect %s -o - | FileCheck %s +--- | + + define void @test_add() { ret void } + +... +--- +name: test_add +# CHECK-LABEL: name: test_add +alignment: 4 +exposesReturnsTwice: false +legalized: true +regBankSelected: false +# CHECK: regBankSelected: true +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } +# CHECK: registers: +# CHECK: - { id: 0, class: gprb, preferred-register: '' } +# CHECK: - { id: 1, class: gprb, preferred-register: '' } +# CHECK: - { id: 2, class: gprb, preferred-register: '' } +liveins: + - { reg: '$x10', virtual-reg: '' } + - { reg: '$x11', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.0: + liveins: $x10, $x11 + + %0:_(s32) = COPY $x10 + %1:_(s32) = COPY $x11 + %2:_(s32) = G_ADD %0, %1 + $x10 = COPY %2(s32) + PseudoRET implicit $x10 + \ No newline at end of file