diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
| commit | 0b57cec536236d46e3dba9bd041533462f33dbb7 (patch) | |
| tree | 56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm-project/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp | |
| parent | 718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff) | |
Notes
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp b/contrib/llvm-project/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp new file mode 100644 index 000000000000..b100150175fc --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp @@ -0,0 +1,483 @@ +//===- ARMRegisterBankInfo.cpp -----------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the targeting of the RegisterBankInfo class for ARM. +/// \todo This should be generated by TableGen. +//===----------------------------------------------------------------------===// + +#include "ARMRegisterBankInfo.h" +#include "ARMInstrInfo.h" // For the register classes +#include "ARMSubtarget.h" +#include "llvm/CodeGen/GlobalISel/RegisterBank.h" +#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_TARGET_REGBANK_IMPL +#include "ARMGenRegisterBank.inc" + +using namespace llvm; + +// FIXME: TableGen this. +// If it grows too much and TableGen still isn't ready to do the job, extract it +// into an ARMGenRegisterBankInfo.def (similar to AArch64). +namespace llvm { +namespace ARM { +enum PartialMappingIdx { + PMI_GPR, + PMI_SPR, + PMI_DPR, + PMI_Min = PMI_GPR, +}; + +RegisterBankInfo::PartialMapping PartMappings[]{ + // GPR Partial Mapping + {0, 32, GPRRegBank}, + // SPR Partial Mapping + {0, 32, FPRRegBank}, + // DPR Partial Mapping + {0, 64, FPRRegBank}, +}; + +#ifndef NDEBUG +static bool checkPartMapping(const RegisterBankInfo::PartialMapping &PM, + unsigned Start, unsigned Length, + unsigned RegBankID) { + return PM.StartIdx == Start && PM.Length == Length && + PM.RegBank->getID() == RegBankID; +} + +static void checkPartialMappings() { + assert( + checkPartMapping(PartMappings[PMI_GPR - PMI_Min], 0, 32, GPRRegBankID) && + "Wrong mapping for GPR"); + assert( + checkPartMapping(PartMappings[PMI_SPR - PMI_Min], 0, 32, FPRRegBankID) && + "Wrong mapping for SPR"); + assert( + checkPartMapping(PartMappings[PMI_DPR - PMI_Min], 0, 64, FPRRegBankID) && + "Wrong mapping for DPR"); +} +#endif + +enum ValueMappingIdx { + InvalidIdx = 0, + GPR3OpsIdx = 1, + SPR3OpsIdx = 4, + DPR3OpsIdx = 7, +}; + +RegisterBankInfo::ValueMapping ValueMappings[] = { + // invalid + {nullptr, 0}, + // 3 ops in GPRs + {&PartMappings[PMI_GPR - PMI_Min], 1}, + {&PartMappings[PMI_GPR - PMI_Min], 1}, + {&PartMappings[PMI_GPR - PMI_Min], 1}, + // 3 ops in SPRs + {&PartMappings[PMI_SPR - PMI_Min], 1}, + {&PartMappings[PMI_SPR - PMI_Min], 1}, + {&PartMappings[PMI_SPR - PMI_Min], 1}, + // 3 ops in DPRs + {&PartMappings[PMI_DPR - PMI_Min], 1}, + {&PartMappings[PMI_DPR - PMI_Min], 1}, + {&PartMappings[PMI_DPR - PMI_Min], 1}}; + +#ifndef NDEBUG +static bool checkValueMapping(const RegisterBankInfo::ValueMapping &VM, + RegisterBankInfo::PartialMapping *BreakDown) { + return VM.NumBreakDowns == 1 && VM.BreakDown == BreakDown; +} + +static void checkValueMappings() { + assert(checkValueMapping(ValueMappings[GPR3OpsIdx], + &PartMappings[PMI_GPR - PMI_Min]) && + "Wrong value mapping for 3 GPR ops instruction"); + assert(checkValueMapping(ValueMappings[GPR3OpsIdx + 1], + &PartMappings[PMI_GPR - PMI_Min]) && + "Wrong value mapping for 3 GPR ops instruction"); + assert(checkValueMapping(ValueMappings[GPR3OpsIdx + 2], + &PartMappings[PMI_GPR - PMI_Min]) && + "Wrong value mapping for 3 GPR ops instruction"); + + assert(checkValueMapping(ValueMappings[SPR3OpsIdx], + &PartMappings[PMI_SPR - PMI_Min]) && + "Wrong value mapping for 3 SPR ops instruction"); + assert(checkValueMapping(ValueMappings[SPR3OpsIdx + 1], + &PartMappings[PMI_SPR - PMI_Min]) && + "Wrong value mapping for 3 SPR ops instruction"); + assert(checkValueMapping(ValueMappings[SPR3OpsIdx + 2], + &PartMappings[PMI_SPR - PMI_Min]) && + "Wrong value mapping for 3 SPR ops instruction"); + + assert(checkValueMapping(ValueMappings[DPR3OpsIdx], + &PartMappings[PMI_DPR - PMI_Min]) && + "Wrong value mapping for 3 DPR ops instruction"); + assert(checkValueMapping(ValueMappings[DPR3OpsIdx + 1], + &PartMappings[PMI_DPR - PMI_Min]) && + "Wrong value mapping for 3 DPR ops instruction"); + assert(checkValueMapping(ValueMappings[DPR3OpsIdx + 2], + &PartMappings[PMI_DPR - PMI_Min]) && + "Wrong value mapping for 3 DPR ops instruction"); +} +#endif +} // end namespace arm +} // end namespace llvm + +ARMRegisterBankInfo::ARMRegisterBankInfo(const TargetRegisterInfo &TRI) + : ARMGenRegisterBankInfo() { + static bool AlreadyInit = false; + // We have only one set of register banks, whatever the subtarget + // is. Therefore, the initialization of the RegBanks table should be + // done only once. Indeed the table of all register banks + // (ARM::RegBanks) is unique in the compiler. At some point, it + // will get tablegen'ed and the whole constructor becomes empty. + if (AlreadyInit) + return; + AlreadyInit = true; + + const RegisterBank &RBGPR = getRegBank(ARM::GPRRegBankID); + (void)RBGPR; + assert(&ARM::GPRRegBank == &RBGPR && "The order in RegBanks is messed up"); + + // Initialize the GPR bank. + assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRwithAPSRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnopcRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(ARM::rGPRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(ARM::tcGPRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPR_and_tcGPRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPREven_and_tGPR_and_tcGPRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPROdd_and_tcGPRRegClassID)) && + "Subclass not added?"); + assert(RBGPR.getSize() == 32 && "GPRs should hold up to 32-bit"); + +#ifndef NDEBUG + ARM::checkPartialMappings(); + ARM::checkValueMappings(); +#endif +} + +const RegisterBank &ARMRegisterBankInfo::getRegBankFromRegClass( + const TargetRegisterClass &RC) const { + using namespace ARM; + + switch (RC.getID()) { + case GPRRegClassID: + case GPRwithAPSRRegClassID: + case GPRnopcRegClassID: + case rGPRRegClassID: + case GPRspRegClassID: + case tGPR_and_tcGPRRegClassID: + case tcGPRRegClassID: + case tGPRRegClassID: + case tGPREvenRegClassID: + case tGPROddRegClassID: + case tGPR_and_tGPREvenRegClassID: + case tGPR_and_tGPROddRegClassID: + case tGPREven_and_tcGPRRegClassID: + case tGPREven_and_tGPR_and_tcGPRRegClassID: + case tGPROdd_and_tcGPRRegClassID: + return getRegBank(ARM::GPRRegBankID); + case HPRRegClassID: + case SPR_8RegClassID: + case SPRRegClassID: + case DPR_8RegClassID: + case DPRRegClassID: + case QPRRegClassID: + return getRegBank(ARM::FPRRegBankID); + default: + llvm_unreachable("Unsupported register kind"); + } + + llvm_unreachable("Switch should handle all register classes"); +} + +const RegisterBankInfo::InstructionMapping & +ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { + auto Opc = MI.getOpcode(); + + // Try the default logic for non-generic instructions that are either copies + // or already have some operands assigned to banks. + if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) { + const InstructionMapping &Mapping = getInstrMappingImpl(MI); + if (Mapping.isValid()) + return Mapping; + } + + using namespace TargetOpcode; + + const MachineFunction &MF = *MI.getParent()->getParent(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + unsigned NumOperands = MI.getNumOperands(); + const ValueMapping *OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx]; + + switch (Opc) { + case G_ADD: + case G_SUB: { + // Integer operations where the source and destination are in the + // same register class. + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + OperandsMapping = Ty.getSizeInBits() == 64 + ? &ARM::ValueMappings[ARM::DPR3OpsIdx] + : &ARM::ValueMappings[ARM::GPR3OpsIdx]; + break; + } + case G_MUL: + case G_AND: + case G_OR: + case G_XOR: + case G_LSHR: + case G_ASHR: + case G_SHL: + case G_SDIV: + case G_UDIV: + case G_SEXT: + case G_ZEXT: + case G_ANYEXT: + case G_GEP: + case G_INTTOPTR: + case G_PTRTOINT: + case G_CTLZ: + // FIXME: We're abusing the fact that everything lives in a GPR for now; in + // the real world we would use different mappings. + OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx]; + break; + case G_TRUNC: { + // In some cases we may end up with a G_TRUNC from a 64-bit value to a + // 32-bit value. This isn't a real floating point trunc (that would be a + // G_FPTRUNC). Instead it is an integer trunc in disguise, which can appear + // because the legalizer doesn't distinguish between integer and floating + // point values so it may leave some 64-bit integers un-narrowed. Until we + // have a more principled solution that doesn't let such things sneak all + // the way to this point, just map the source to a DPR and the destination + // to a GPR. + LLT LargeTy = MRI.getType(MI.getOperand(1).getReg()); + OperandsMapping = + LargeTy.getSizeInBits() <= 32 + ? &ARM::ValueMappings[ARM::GPR3OpsIdx] + : getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::DPR3OpsIdx]}); + break; + } + case G_LOAD: + case G_STORE: { + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + OperandsMapping = + Ty.getSizeInBits() == 64 + ? getOperandsMapping({&ARM::ValueMappings[ARM::DPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx]}) + : &ARM::ValueMappings[ARM::GPR3OpsIdx]; + break; + } + case G_FADD: + case G_FSUB: + case G_FMUL: + case G_FDIV: + case G_FNEG: { + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + OperandsMapping =Ty.getSizeInBits() == 64 + ? &ARM::ValueMappings[ARM::DPR3OpsIdx] + : &ARM::ValueMappings[ARM::SPR3OpsIdx]; + break; + } + case G_FMA: { + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + OperandsMapping = + Ty.getSizeInBits() == 64 + ? getOperandsMapping({&ARM::ValueMappings[ARM::DPR3OpsIdx], + &ARM::ValueMappings[ARM::DPR3OpsIdx], + &ARM::ValueMappings[ARM::DPR3OpsIdx], + &ARM::ValueMappings[ARM::DPR3OpsIdx]}) + : getOperandsMapping({&ARM::ValueMappings[ARM::SPR3OpsIdx], + &ARM::ValueMappings[ARM::SPR3OpsIdx], + &ARM::ValueMappings[ARM::SPR3OpsIdx], + &ARM::ValueMappings[ARM::SPR3OpsIdx]}); + break; + } + case G_FPEXT: { + LLT ToTy = MRI.getType(MI.getOperand(0).getReg()); + LLT FromTy = MRI.getType(MI.getOperand(1).getReg()); + if (ToTy.getSizeInBits() == 64 && FromTy.getSizeInBits() == 32) + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::DPR3OpsIdx], + &ARM::ValueMappings[ARM::SPR3OpsIdx]}); + break; + } + case G_FPTRUNC: { + LLT ToTy = MRI.getType(MI.getOperand(0).getReg()); + LLT FromTy = MRI.getType(MI.getOperand(1).getReg()); + if (ToTy.getSizeInBits() == 32 && FromTy.getSizeInBits() == 64) + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::SPR3OpsIdx], + &ARM::ValueMappings[ARM::DPR3OpsIdx]}); + break; + } + case G_FPTOSI: + case G_FPTOUI: { + LLT ToTy = MRI.getType(MI.getOperand(0).getReg()); + LLT FromTy = MRI.getType(MI.getOperand(1).getReg()); + if ((FromTy.getSizeInBits() == 32 || FromTy.getSizeInBits() == 64) && + ToTy.getSizeInBits() == 32) + OperandsMapping = + FromTy.getSizeInBits() == 64 + ? getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::DPR3OpsIdx]}) + : getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::SPR3OpsIdx]}); + break; + } + case G_SITOFP: + case G_UITOFP: { + LLT ToTy = MRI.getType(MI.getOperand(0).getReg()); + LLT FromTy = MRI.getType(MI.getOperand(1).getReg()); + if (FromTy.getSizeInBits() == 32 && + (ToTy.getSizeInBits() == 32 || ToTy.getSizeInBits() == 64)) + OperandsMapping = + ToTy.getSizeInBits() == 64 + ? getOperandsMapping({&ARM::ValueMappings[ARM::DPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx]}) + : getOperandsMapping({&ARM::ValueMappings[ARM::SPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx]}); + break; + } + case G_FCONSTANT: { + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + OperandsMapping = getOperandsMapping( + {Ty.getSizeInBits() == 64 ? &ARM::ValueMappings[ARM::DPR3OpsIdx] + : &ARM::ValueMappings[ARM::SPR3OpsIdx], + nullptr}); + break; + } + case G_CONSTANT: + case G_FRAME_INDEX: + case G_GLOBAL_VALUE: + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr}); + break; + case G_SELECT: { + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + (void)Ty; + LLT Ty2 = MRI.getType(MI.getOperand(1).getReg()); + (void)Ty2; + assert(Ty.getSizeInBits() == 32 && "Unsupported size for G_SELECT"); + assert(Ty2.getSizeInBits() == 1 && "Unsupported size for G_SELECT"); + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx]}); + break; + } + case G_ICMP: { + LLT Ty2 = MRI.getType(MI.getOperand(2).getReg()); + (void)Ty2; + assert(Ty2.getSizeInBits() == 32 && "Unsupported size for G_ICMP"); + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr, + &ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx]}); + break; + } + case G_FCMP: { + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + (void)Ty; + LLT Ty1 = MRI.getType(MI.getOperand(2).getReg()); + LLT Ty2 = MRI.getType(MI.getOperand(3).getReg()); + (void)Ty2; + assert(Ty.getSizeInBits() == 1 && "Unsupported size for G_FCMP"); + assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() && + "Mismatched operand sizes for G_FCMP"); + + unsigned Size = Ty1.getSizeInBits(); + assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP"); + + auto FPRValueMapping = Size == 32 ? &ARM::ValueMappings[ARM::SPR3OpsIdx] + : &ARM::ValueMappings[ARM::DPR3OpsIdx]; + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr, + FPRValueMapping, FPRValueMapping}); + break; + } + case G_MERGE_VALUES: { + // We only support G_MERGE_VALUES for creating a double precision floating + // point value out of two GPRs. + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + LLT Ty1 = MRI.getType(MI.getOperand(1).getReg()); + LLT Ty2 = MRI.getType(MI.getOperand(2).getReg()); + if (Ty.getSizeInBits() != 64 || Ty1.getSizeInBits() != 32 || + Ty2.getSizeInBits() != 32) + return getInvalidInstructionMapping(); + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::DPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx]}); + break; + } + case G_UNMERGE_VALUES: { + // We only support G_UNMERGE_VALUES for splitting a double precision + // floating point value into two GPRs. + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + LLT Ty1 = MRI.getType(MI.getOperand(1).getReg()); + LLT Ty2 = MRI.getType(MI.getOperand(2).getReg()); + if (Ty.getSizeInBits() != 32 || Ty1.getSizeInBits() != 32 || + Ty2.getSizeInBits() != 64) + return getInvalidInstructionMapping(); + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::DPR3OpsIdx]}); + break; + } + case G_BR: + OperandsMapping = getOperandsMapping({nullptr}); + break; + case G_BRCOND: + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr}); + break; + case DBG_VALUE: { + SmallVector<const ValueMapping *, 4> OperandBanks(NumOperands); + const MachineOperand &MaybeReg = MI.getOperand(0); + if (MaybeReg.isReg() && MaybeReg.getReg()) { + unsigned Size = MRI.getType(MaybeReg.getReg()).getSizeInBits(); + if (Size > 32 && Size != 64) + return getInvalidInstructionMapping(); + OperandBanks[0] = Size == 64 ? &ARM::ValueMappings[ARM::DPR3OpsIdx] + : &ARM::ValueMappings[ARM::GPR3OpsIdx]; + } + OperandsMapping = getOperandsMapping(OperandBanks); + break; + } + default: + return getInvalidInstructionMapping(); + } + +#ifndef NDEBUG + for (unsigned i = 0; i < NumOperands; i++) { + for (const auto &Mapping : OperandsMapping[i]) { + assert( + (Mapping.RegBank->getID() != ARM::FPRRegBankID || + MF.getSubtarget<ARMSubtarget>().hasVFP2Base()) && + "Trying to use floating point register bank on target without vfp"); + } + } +#endif + + return getInstructionMapping(DefaultMappingID, /*Cost=*/1, OperandsMapping, + NumOperands); +} |
