Path: blob/main/contrib/llvm-project/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
96383 views
//===-- RISCVRegisterBankInfo.cpp -------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8/// This file implements the targeting of the RegisterBankInfo class for RISC-V.9/// \todo This should be generated by TableGen.10//===----------------------------------------------------------------------===//1112#include "RISCVRegisterBankInfo.h"13#include "MCTargetDesc/RISCVMCTargetDesc.h"14#include "RISCVSubtarget.h"15#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"16#include "llvm/CodeGen/MachineRegisterInfo.h"17#include "llvm/CodeGen/RegisterBank.h"18#include "llvm/CodeGen/RegisterBankInfo.h"19#include "llvm/CodeGen/TargetRegisterInfo.h"2021#define GET_TARGET_REGBANK_IMPL22#include "RISCVGenRegisterBank.inc"2324namespace llvm {25namespace RISCV {2627const RegisterBankInfo::PartialMapping PartMappings[] = {28// clang-format off29{0, 32, GPRBRegBank},30{0, 64, GPRBRegBank},31{0, 16, FPRBRegBank},32{0, 32, FPRBRegBank},33{0, 64, FPRBRegBank},34{0, 64, VRBRegBank},35{0, 128, VRBRegBank},36{0, 256, VRBRegBank},37{0, 512, VRBRegBank},38// clang-format on39};4041enum PartialMappingIdx {42PMI_GPRB32 = 0,43PMI_GPRB64 = 1,44PMI_FPRB16 = 2,45PMI_FPRB32 = 3,46PMI_FPRB64 = 4,47PMI_VRB64 = 5,48PMI_VRB128 = 6,49PMI_VRB256 = 7,50PMI_VRB512 = 8,51};5253const RegisterBankInfo::ValueMapping ValueMappings[] = {54// Invalid value mapping.55{nullptr, 0},56// Maximum 3 GPR operands; 32 bit.57{&PartMappings[PMI_GPRB32], 1},58{&PartMappings[PMI_GPRB32], 1},59{&PartMappings[PMI_GPRB32], 1},60// Maximum 3 GPR operands; 64 bit.61{&PartMappings[PMI_GPRB64], 1},62{&PartMappings[PMI_GPRB64], 1},63{&PartMappings[PMI_GPRB64], 1},64// Maximum 3 FPR operands; 16 bit.65{&PartMappings[PMI_FPRB16], 1},66{&PartMappings[PMI_FPRB16], 1},67{&PartMappings[PMI_FPRB16], 1},68// Maximum 3 FPR operands; 32 bit.69{&PartMappings[PMI_FPRB32], 1},70{&PartMappings[PMI_FPRB32], 1},71{&PartMappings[PMI_FPRB32], 1},72// Maximum 3 FPR operands; 64 bit.73{&PartMappings[PMI_FPRB64], 1},74{&PartMappings[PMI_FPRB64], 1},75{&PartMappings[PMI_FPRB64], 1},76// Maximum 3 VR LMUL={1, MF2, MF4, MF8} operands.77{&PartMappings[PMI_VRB64], 1},78{&PartMappings[PMI_VRB64], 1},79{&PartMappings[PMI_VRB64], 1},80// Maximum 3 VR LMUL=2 operands.81{&PartMappings[PMI_VRB128], 1},82{&PartMappings[PMI_VRB128], 1},83{&PartMappings[PMI_VRB128], 1},84// Maximum 3 VR LMUL=4 operands.85{&PartMappings[PMI_VRB256], 1},86{&PartMappings[PMI_VRB256], 1},87{&PartMappings[PMI_VRB256], 1},88// Maximum 3 VR LMUL=8 operands.89{&PartMappings[PMI_VRB512], 1},90{&PartMappings[PMI_VRB512], 1},91{&PartMappings[PMI_VRB512], 1},92};9394enum ValueMappingIdx {95InvalidIdx = 0,96GPRB32Idx = 1,97GPRB64Idx = 4,98FPRB16Idx = 7,99FPRB32Idx = 10,100FPRB64Idx = 13,101VRB64Idx = 16,102VRB128Idx = 19,103VRB256Idx = 22,104VRB512Idx = 25,105};106} // namespace RISCV107} // namespace llvm108109using namespace llvm;110111RISCVRegisterBankInfo::RISCVRegisterBankInfo(unsigned HwMode)112: RISCVGenRegisterBankInfo(HwMode) {}113114const RegisterBank &115RISCVRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,116LLT Ty) const {117switch (RC.getID()) {118default:119llvm_unreachable("Register class not supported");120case RISCV::GPRRegClassID:121case RISCV::GPRF16RegClassID:122case RISCV::GPRF32RegClassID:123case RISCV::GPRNoX0RegClassID:124case RISCV::GPRNoX0X2RegClassID:125case RISCV::GPRJALRRegClassID:126case RISCV::GPRJALRNonX7RegClassID:127case RISCV::GPRTCRegClassID:128case RISCV::GPRTCNonX7RegClassID:129case RISCV::GPRC_and_GPRTCRegClassID:130case RISCV::GPRCRegClassID:131case RISCV::GPRC_and_SR07RegClassID:132case RISCV::SR07RegClassID:133case RISCV::SPRegClassID:134case RISCV::GPRX0RegClassID:135return getRegBank(RISCV::GPRBRegBankID);136case RISCV::FPR64RegClassID:137case RISCV::FPR16RegClassID:138case RISCV::FPR32RegClassID:139case RISCV::FPR64CRegClassID:140case RISCV::FPR32CRegClassID:141return getRegBank(RISCV::FPRBRegBankID);142case RISCV::VMRegClassID:143case RISCV::VRRegClassID:144case RISCV::VRNoV0RegClassID:145case RISCV::VRM2RegClassID:146case RISCV::VRM2NoV0RegClassID:147case RISCV::VRM4RegClassID:148case RISCV::VRM4NoV0RegClassID:149case RISCV::VMV0RegClassID:150case RISCV::VRM2_with_sub_vrm1_0_in_VMV0RegClassID:151case RISCV::VRM4_with_sub_vrm1_0_in_VMV0RegClassID:152case RISCV::VRM8RegClassID:153case RISCV::VRM8NoV0RegClassID:154case RISCV::VRM8_with_sub_vrm1_0_in_VMV0RegClassID:155return getRegBank(RISCV::VRBRegBankID);156}157}158159static const RegisterBankInfo::ValueMapping *getFPValueMapping(unsigned Size) {160unsigned Idx;161switch (Size) {162default:163llvm_unreachable("Unexpected size");164case 16:165Idx = RISCV::FPRB16Idx;166break;167case 32:168Idx = RISCV::FPRB32Idx;169break;170case 64:171Idx = RISCV::FPRB64Idx;172break;173}174return &RISCV::ValueMappings[Idx];175}176177// TODO: Make this more like AArch64?178bool RISCVRegisterBankInfo::hasFPConstraints(179const MachineInstr &MI, const MachineRegisterInfo &MRI,180const TargetRegisterInfo &TRI) const {181if (isPreISelGenericFloatingPointOpcode(MI.getOpcode()))182return true;183184// If we have a copy instruction, we could be feeding floating point185// instructions.186if (MI.getOpcode() != TargetOpcode::COPY)187return false;188189return getRegBank(MI.getOperand(0).getReg(), MRI, TRI) == &RISCV::FPRBRegBank;190}191192bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,193const MachineRegisterInfo &MRI,194const TargetRegisterInfo &TRI) const {195switch (MI.getOpcode()) {196case TargetOpcode::G_FPTOSI:197case TargetOpcode::G_FPTOUI:198case TargetOpcode::G_FCMP:199return true;200default:201break;202}203204return hasFPConstraints(MI, MRI, TRI);205}206207bool RISCVRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,208const MachineRegisterInfo &MRI,209const TargetRegisterInfo &TRI) const {210switch (MI.getOpcode()) {211case TargetOpcode::G_SITOFP:212case TargetOpcode::G_UITOFP:213return true;214default:215break;216}217218return hasFPConstraints(MI, MRI, TRI);219}220221bool RISCVRegisterBankInfo::anyUseOnlyUseFP(222Register Def, const MachineRegisterInfo &MRI,223const TargetRegisterInfo &TRI) const {224return any_of(225MRI.use_nodbg_instructions(Def),226[&](const MachineInstr &UseMI) { return onlyUsesFP(UseMI, MRI, TRI); });227}228229static const RegisterBankInfo::ValueMapping *getVRBValueMapping(unsigned Size) {230unsigned Idx;231232if (Size <= 64)233Idx = RISCV::VRB64Idx;234else if (Size == 128)235Idx = RISCV::VRB128Idx;236else if (Size == 256)237Idx = RISCV::VRB256Idx;238else if (Size == 512)239Idx = RISCV::VRB512Idx;240else241llvm::report_fatal_error("Invalid Size");242243return &RISCV::ValueMappings[Idx];244}245246const RegisterBankInfo::InstructionMapping &247RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {248const unsigned Opc = MI.getOpcode();249250// Try the default logic for non-generic instructions that are either copies251// or already have some operands assigned to banks.252if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {253const InstructionMapping &Mapping = getInstrMappingImpl(MI);254if (Mapping.isValid())255return Mapping;256}257258const MachineFunction &MF = *MI.getParent()->getParent();259const MachineRegisterInfo &MRI = MF.getRegInfo();260const TargetSubtargetInfo &STI = MF.getSubtarget();261const TargetRegisterInfo &TRI = *STI.getRegisterInfo();262263unsigned GPRSize = getMaximumSize(RISCV::GPRBRegBankID);264assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size");265266unsigned NumOperands = MI.getNumOperands();267const ValueMapping *GPRValueMapping =268&RISCV::ValueMappings[GPRSize == 64 ? RISCV::GPRB64Idx269: RISCV::GPRB32Idx];270271switch (Opc) {272case TargetOpcode::G_ADD:273case TargetOpcode::G_SUB:274case TargetOpcode::G_SHL:275case TargetOpcode::G_ASHR:276case TargetOpcode::G_LSHR:277case TargetOpcode::G_AND:278case TargetOpcode::G_OR:279case TargetOpcode::G_XOR:280case TargetOpcode::G_MUL:281case TargetOpcode::G_SDIV:282case TargetOpcode::G_SREM:283case TargetOpcode::G_SMULH:284case TargetOpcode::G_SMAX:285case TargetOpcode::G_SMIN:286case TargetOpcode::G_UDIV:287case TargetOpcode::G_UREM:288case TargetOpcode::G_UMULH:289case TargetOpcode::G_UMAX:290case TargetOpcode::G_UMIN:291case TargetOpcode::G_PTR_ADD:292case TargetOpcode::G_PTRTOINT:293case TargetOpcode::G_INTTOPTR:294case TargetOpcode::G_FADD:295case TargetOpcode::G_FSUB:296case TargetOpcode::G_FMUL:297case TargetOpcode::G_FDIV:298case TargetOpcode::G_FABS:299case TargetOpcode::G_FNEG:300case TargetOpcode::G_FSQRT:301case TargetOpcode::G_FMAXNUM:302case TargetOpcode::G_FMINNUM: {303LLT Ty = MRI.getType(MI.getOperand(0).getReg());304TypeSize Size = Ty.getSizeInBits();305306const ValueMapping *Mapping;307if (Ty.isVector())308Mapping = getVRBValueMapping(Size.getKnownMinValue());309else if (isPreISelGenericFloatingPointOpcode(Opc))310Mapping = getFPValueMapping(Size.getFixedValue());311else312Mapping = GPRValueMapping;313314#ifndef NDEBUG315// Make sure all the operands are using similar size and type.316for (unsigned Idx = 1; Idx != NumOperands; ++Idx) {317LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg());318assert(Ty.isVector() == OpTy.isVector() &&319"Operand has incompatible type");320// Don't check size for GPR.321if (OpTy.isVector() || isPreISelGenericFloatingPointOpcode(Opc))322assert(Size == OpTy.getSizeInBits() && "Operand has incompatible size");323}324#endif // End NDEBUG325326return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);327}328case TargetOpcode::G_SEXTLOAD:329case TargetOpcode::G_ZEXTLOAD:330return getInstructionMapping(DefaultMappingID, /*Cost=*/1, GPRValueMapping,331NumOperands);332case TargetOpcode::G_IMPLICIT_DEF: {333Register Dst = MI.getOperand(0).getReg();334LLT DstTy = MRI.getType(Dst);335unsigned DstMinSize = DstTy.getSizeInBits().getKnownMinValue();336auto Mapping = GPRValueMapping;337// FIXME: May need to do a better job determining when to use FPRB.338// For example, the look through COPY case:339// %0:_(s32) = G_IMPLICIT_DEF340// %1:_(s32) = COPY %0341// $f10_d = COPY %1(s32)342if (DstTy.isVector())343Mapping = getVRBValueMapping(DstMinSize);344else if (anyUseOnlyUseFP(Dst, MRI, TRI))345Mapping = getFPValueMapping(DstMinSize);346347return getInstructionMapping(DefaultMappingID, /*Cost=*/1, Mapping,348NumOperands);349}350}351352SmallVector<const ValueMapping *, 4> OpdsMapping(NumOperands);353354switch (Opc) {355case TargetOpcode::G_LOAD: {356LLT Ty = MRI.getType(MI.getOperand(0).getReg());357OpdsMapping[0] = GPRValueMapping;358OpdsMapping[1] = GPRValueMapping;359// Use FPR64 for s64 loads on rv32.360if (GPRSize == 32 && Ty.getSizeInBits() == 64) {361assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());362OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());363break;364}365366// Check if that load feeds fp instructions.367// In that case, we want the default mapping to be on FPR368// instead of blind map every scalar to GPR.369if (anyUseOnlyUseFP(MI.getOperand(0).getReg(), MRI, TRI))370// If we have at least one direct use in a FP instruction,371// assume this was a floating point load in the IR. If it was372// not, we would have had a bitcast before reaching that373// instruction.374OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());375376break;377}378case TargetOpcode::G_STORE: {379LLT Ty = MRI.getType(MI.getOperand(0).getReg());380OpdsMapping[0] = GPRValueMapping;381OpdsMapping[1] = GPRValueMapping;382// Use FPR64 for s64 stores on rv32.383if (GPRSize == 32 && Ty.getSizeInBits() == 64) {384assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());385OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());386break;387}388389MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());390if (onlyDefinesFP(*DefMI, MRI, TRI))391OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());392break;393}394case TargetOpcode::G_SELECT: {395LLT Ty = MRI.getType(MI.getOperand(0).getReg());396397if (Ty.isVector()) {398auto &Sel = cast<GSelect>(MI);399LLT TestTy = MRI.getType(Sel.getCondReg());400assert(TestTy.isVector() && "Unexpected condition argument type");401OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] =402getVRBValueMapping(Ty.getSizeInBits().getKnownMinValue());403OpdsMapping[1] =404getVRBValueMapping(TestTy.getSizeInBits().getKnownMinValue());405break;406}407408// Try to minimize the number of copies. If we have more floating point409// constrained values than not, then we'll put everything on FPR. Otherwise,410// everything has to be on GPR.411unsigned NumFP = 0;412413// Use FPR64 for s64 select on rv32.414if (GPRSize == 32 && Ty.getSizeInBits() == 64) {415NumFP = 3;416} else {417// Check if the uses of the result always produce floating point values.418//419// For example:420//421// %z = G_SELECT %cond %x %y422// fpr = G_FOO %z ...423if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),424[&](const MachineInstr &UseMI) {425return onlyUsesFP(UseMI, MRI, TRI);426}))427++NumFP;428429// Check if the defs of the source values always produce floating point430// values.431//432// For example:433//434// %x = G_SOMETHING_ALWAYS_FLOAT %a ...435// %z = G_SELECT %cond %x %y436//437// Also check whether or not the sources have already been decided to be438// FPR. Keep track of this.439//440// This doesn't check the condition, since the condition is always an441// integer.442for (unsigned Idx = 2; Idx < 4; ++Idx) {443Register VReg = MI.getOperand(Idx).getReg();444MachineInstr *DefMI = MRI.getVRegDef(VReg);445if (getRegBank(VReg, MRI, TRI) == &RISCV::FPRBRegBank ||446onlyDefinesFP(*DefMI, MRI, TRI))447++NumFP;448}449}450451// Condition operand is always GPR.452OpdsMapping[1] = GPRValueMapping;453454const ValueMapping *Mapping = GPRValueMapping;455if (NumFP >= 2)456Mapping = getFPValueMapping(Ty.getSizeInBits());457458OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] = Mapping;459break;460}461case TargetOpcode::G_FPTOSI:462case TargetOpcode::G_FPTOUI:463case RISCV::G_FCLASS: {464LLT Ty = MRI.getType(MI.getOperand(1).getReg());465OpdsMapping[0] = GPRValueMapping;466OpdsMapping[1] = getFPValueMapping(Ty.getSizeInBits());467break;468}469case TargetOpcode::G_SITOFP:470case TargetOpcode::G_UITOFP: {471LLT Ty = MRI.getType(MI.getOperand(0).getReg());472OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());473OpdsMapping[1] = GPRValueMapping;474break;475}476case TargetOpcode::G_FCMP: {477LLT Ty = MRI.getType(MI.getOperand(2).getReg());478479unsigned Size = Ty.getSizeInBits();480481OpdsMapping[0] = GPRValueMapping;482OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);483break;484}485case TargetOpcode::G_MERGE_VALUES: {486// Use FPR64 for s64 merge on rv32.487LLT Ty = MRI.getType(MI.getOperand(0).getReg());488if (GPRSize == 32 && Ty.getSizeInBits() == 64) {489assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());490OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());491OpdsMapping[1] = GPRValueMapping;492OpdsMapping[2] = GPRValueMapping;493}494break;495}496case TargetOpcode::G_UNMERGE_VALUES: {497// Use FPR64 for s64 unmerge on rv32.498LLT Ty = MRI.getType(MI.getOperand(2).getReg());499if (GPRSize == 32 && Ty.getSizeInBits() == 64) {500assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());501OpdsMapping[0] = GPRValueMapping;502OpdsMapping[1] = GPRValueMapping;503OpdsMapping[2] = getFPValueMapping(Ty.getSizeInBits());504}505break;506}507default:508// By default map all scalars to GPR.509for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {510auto &MO = MI.getOperand(Idx);511if (!MO.isReg() || !MO.getReg())512continue;513LLT Ty = MRI.getType(MO.getReg());514if (!Ty.isValid())515continue;516517if (Ty.isVector())518OpdsMapping[Idx] =519getVRBValueMapping(Ty.getSizeInBits().getKnownMinValue());520else if (isPreISelGenericFloatingPointOpcode(Opc))521OpdsMapping[Idx] = getFPValueMapping(Ty.getSizeInBits());522else523OpdsMapping[Idx] = GPRValueMapping;524}525break;526}527528return getInstructionMapping(DefaultMappingID, /*Cost=*/1,529getOperandsMapping(OpdsMapping), NumOperands);530}531532533