1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

Support a list of CostPerUse values

This patch allows targets to define multiple cost
values for each register so that the cost model
can be more flexible and better used during the
register allocation as per the target requirements.

For AMDGPU the VGPR allocation will be more efficient
if the register cost can be associated dynamically
based on the calling convention.

Reviewed By: qcolombet

Differential Revision: https://reviews.llvm.org/D86836
This commit is contained in:
Christudasan Devadasan 2020-12-23 10:51:13 +05:30
parent c92db3d4c4
commit e86b7c773c
15 changed files with 275 additions and 70 deletions

View File

@ -66,6 +66,9 @@ class RegisterClassInfo {
std::unique_ptr<unsigned[]> PSetLimits;
// The register cost values.
ArrayRef<uint8_t> RegCosts;
// Compute all information about RC.
void compute(const TargetRegisterClass *RC) const;
@ -117,16 +120,14 @@ public:
}
/// Get the minimum register cost in RC's allocation order.
/// This is the smallest value returned by TRI->getCostPerUse(Reg) for all
/// This is the smallest value in RegCosts[Reg] for all
/// the registers in getOrder(RC).
unsigned getMinCost(const TargetRegisterClass *RC) {
return get(RC).MinCost;
}
uint8_t getMinCost(const TargetRegisterClass *RC) { return get(RC).MinCost; }
/// Get the position of the last cost change in getOrder(RC).
///
/// All registers in getOrder(RC).slice(getLastCostChange(RC)) will have the
/// same cost according to TRI->getCostPerUse().
/// same cost according to RegCosts[Reg].
unsigned getLastCostChange(const TargetRegisterClass *RC) {
return get(RC).LastCostChange;
}

View File

@ -209,8 +209,10 @@ public:
/// Extra information, not in MCRegisterDesc, about registers.
/// These are used by codegen, not by MC.
struct TargetRegisterInfoDesc {
unsigned CostPerUse; // Extra cost of instructions using register.
bool inAllocatableClass; // Register belongs to an allocatable regclass.
const uint8_t *CostPerUse; // Extra cost of instructions using register.
unsigned NumCosts; // Number of cost values associated with each register.
const bool
*InAllocatableClass; // Register belongs to an allocatable regclass.
};
/// Each TargetRegisterClass has a per register weight, and weight
@ -329,15 +331,19 @@ public:
BitVector getAllocatableSet(const MachineFunction &MF,
const TargetRegisterClass *RC = nullptr) const;
/// Return the additional cost of using this register instead
/// of other registers in its class.
unsigned getCostPerUse(MCRegister RegNo) const {
return InfoDesc[RegNo].CostPerUse;
/// Get a list of cost values for all registers that correspond to the index
/// returned by RegisterCostTableIndex.
ArrayRef<uint8_t> getRegisterCosts(const MachineFunction &MF) const {
unsigned Idx = getRegisterCostTableIndex(MF);
unsigned NumRegs = getNumRegs();
assert(Idx < InfoDesc->NumCosts && "CostPerUse index out of bounds");
return makeArrayRef(&InfoDesc->CostPerUse[Idx * NumRegs], NumRegs);
}
/// Return true if the register is in the allocation of any register class.
bool isInAllocatableClass(MCRegister RegNo) const {
return InfoDesc[RegNo].inAllocatableClass;
return InfoDesc->InAllocatableClass[RegNo];
}
/// Return the human-readable symbolic target-specific
@ -648,6 +654,13 @@ protected:
llvm_unreachable("Target has no sub-registers");
}
/// Return the register cost table index. This implementation is sufficient
/// for most architectures and can be overriden by targets in case there are
/// multiple cost values associated with each register.
virtual unsigned getRegisterCostTableIndex(const MachineFunction &MF) const {
return 0;
}
public:
/// Find a common super-register class if it exists.
///

View File

@ -168,8 +168,15 @@ class Register<string n, list<string> altNames = []> {
// minimize the number of instructions using a register with a CostPerUse.
// This is used by the ARC target, by the ARM Thumb and x86-64 targets, where
// some registers require larger instruction encodings, by the RISC-V target,
// where some registers preclude using some C instructions.
int CostPerUse = 0;
// where some registers preclude using some C instructions. By making it a
// list, targets can have multiple cost models associated with each register
// and can choose one specific cost model per Machine Function by overriding
// TargetRegisterInfo::getRegisterCostTableIndex. Every target register will
// finally have an equal number of cost values which is the max of costPerUse
// values specified. Any mismatch in the cost values for a register will be
// filled with zeros. Restricted the cost type to uint8_t in the
// generated table. It will considerably reduce the table size.
list<int> CostPerUse = [0];
// CoveredBySubRegs - When this bit is set, the value of this register is
// completely determined by the value of its sub-registers. For example, the

View File

@ -406,6 +406,10 @@ class RAGreedy : public MachineFunctionPass,
/// Set of broken hints that may be reconciled later because of eviction.
SmallSetVector<LiveInterval *, 8> SetOfBrokenHints;
/// The register cost values. This list will be recreated for each Machine
/// Function
ArrayRef<uint8_t> RegCosts;
public:
RAGreedy();
@ -483,7 +487,7 @@ private:
SmallVectorImpl<Register>&,
const SmallVirtRegSet&);
unsigned tryEvict(LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register>&, unsigned,
SmallVectorImpl<Register> &, uint8_t,
const SmallVirtRegSet &);
MCRegister tryRegionSplit(LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &);
@ -501,7 +505,7 @@ private:
/// time.
MCRegister tryAssignCSRFirstTime(LiveInterval &VirtReg,
AllocationOrder &Order, MCRegister PhysReg,
unsigned &CostPerUseLimit,
uint8_t &CostPerUseLimit,
SmallVectorImpl<Register> &NewVRegs);
void initializeCSRCost();
unsigned tryBlockSplit(LiveInterval&, AllocationOrder&,
@ -797,7 +801,7 @@ Register RAGreedy::tryAssign(LiveInterval &VirtReg,
}
// Try to evict interference from a cheaper alternative.
unsigned Cost = TRI->getCostPerUse(PhysReg);
uint8_t Cost = RegCosts[PhysReg];
// Most registers have 0 additional cost.
if (!Cost)
@ -1109,10 +1113,9 @@ bool RAGreedy::isUnusedCalleeSavedReg(MCRegister PhysReg) const {
/// @param VirtReg Currently unassigned virtual register.
/// @param Order Physregs to try.
/// @return Physreg to assign VirtReg, or 0.
unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
AllocationOrder &Order,
unsigned RAGreedy::tryEvict(LiveInterval &VirtReg, AllocationOrder &Order,
SmallVectorImpl<Register> &NewVRegs,
unsigned CostPerUseLimit,
uint8_t CostPerUseLimit,
const SmallVirtRegSet &FixedRegisters) {
NamedRegionTimer T("evict", "Evict", TimerGroupName, TimerGroupDescription,
TimePassesIsEnabled);
@ -1125,13 +1128,13 @@ unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
// When we are just looking for a reduced cost per use, don't break any
// hints, and only evict smaller spill weights.
if (CostPerUseLimit < ~0u) {
if (CostPerUseLimit < uint8_t(~0u)) {
BestCost.BrokenHints = 0;
BestCost.MaxWeight = VirtReg.weight();
// Check of any registers in RC are below CostPerUseLimit.
const TargetRegisterClass *RC = MRI->getRegClass(VirtReg.reg());
unsigned MinCost = RegClassInfo.getMinCost(RC);
uint8_t MinCost = RegClassInfo.getMinCost(RC);
if (MinCost >= CostPerUseLimit) {
LLVM_DEBUG(dbgs() << TRI->getRegClassName(RC) << " minimum cost = "
<< MinCost << ", no cheaper registers to be found.\n");
@ -1140,7 +1143,7 @@ unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
// It is normal for register classes to have a long tail of registers with
// the same cost. We don't need to look at them if they're too expensive.
if (TRI->getCostPerUse(Order.getOrder().back()) >= CostPerUseLimit) {
if (RegCosts[Order.getOrder().back()] >= CostPerUseLimit) {
OrderLimit = RegClassInfo.getLastCostChange(RC);
LLVM_DEBUG(dbgs() << "Only trying the first " << OrderLimit
<< " regs.\n");
@ -1151,7 +1154,7 @@ unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
++I) {
MCRegister PhysReg = *I;
assert(PhysReg);
if (TRI->getCostPerUse(PhysReg) >= CostPerUseLimit)
if (RegCosts[PhysReg] >= CostPerUseLimit)
continue;
// The first use of a callee-saved register in a function has cost 1.
// Don't start using a CSR when the CostPerUseLimit is low.
@ -2793,7 +2796,7 @@ MCRegister RAGreedy::selectOrSplit(LiveInterval &VirtReg,
/// to use the CSR; otherwise return 0.
MCRegister
RAGreedy::tryAssignCSRFirstTime(LiveInterval &VirtReg, AllocationOrder &Order,
MCRegister PhysReg, unsigned &CostPerUseLimit,
MCRegister PhysReg, uint8_t &CostPerUseLimit,
SmallVectorImpl<Register> &NewVRegs) {
if (getStage(VirtReg) == RS_Spill && VirtReg.isSpillable()) {
// We choose spill over using the CSR for the first time if the spill cost
@ -3024,7 +3027,7 @@ MCRegister RAGreedy::selectOrSplitImpl(LiveInterval &VirtReg,
SmallVectorImpl<Register> &NewVRegs,
SmallVirtRegSet &FixedRegisters,
unsigned Depth) {
unsigned CostPerUseLimit = ~0u;
uint8_t CostPerUseLimit = uint8_t(~0u);
// First try assigning a free register.
auto Order =
AllocationOrder::create(VirtReg.reg(), *VRM, RegClassInfo, Matrix);
@ -3241,6 +3244,8 @@ bool RAGreedy::runOnMachineFunction(MachineFunction &mf) {
initializeCSRCost();
RegCosts = TRI->getRegisterCosts(*MF);
VRAI = std::make_unique<VirtRegAuxInfo>(*MF, *LIS, *VRM, *Loops, *MBFI);
VRAI->calculateSpillWeightsAndHints();

View File

@ -68,6 +68,8 @@ void RegisterClassInfo::runOnMachineFunction(const MachineFunction &mf) {
}
CalleeSavedRegs = CSR;
RegCosts = TRI->getRegisterCosts(*MF);
// Different reserved registers?
const BitVector &RR = MF->getRegInfo().getReservedRegs();
if (Reserved.size() != RR.size() || RR != Reserved) {
@ -100,8 +102,8 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
unsigned N = 0;
SmallVector<MCPhysReg, 16> CSRAlias;
unsigned MinCost = 0xff;
unsigned LastCost = ~0u;
uint8_t MinCost = uint8_t(~0u);
uint8_t LastCost = uint8_t(~0u);
unsigned LastCostChange = 0;
// FIXME: Once targets reserve registers instead of removing them from the
@ -112,7 +114,7 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
// Remove reserved registers from the allocation order.
if (Reserved.test(PhysReg))
continue;
unsigned Cost = TRI->getCostPerUse(PhysReg);
uint8_t Cost = RegCosts[PhysReg];
MinCost = std::min(MinCost, Cost);
if (CalleeSavedAliases[PhysReg] &&
@ -132,7 +134,7 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
// CSR aliases go after the volatile registers, preserve the target's order.
for (unsigned i = 0, e = CSRAlias.size(); i != e; ++i) {
unsigned PhysReg = CSRAlias[i];
unsigned Cost = TRI->getCostPerUse(PhysReg);
uint8_t Cost = RegCosts[PhysReg];
if (Cost != LastCost)
LastCostChange = N;
RCI.Order[N++] = PhysReg;
@ -149,7 +151,7 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
if (Super != RC && getNumAllocatableRegs(Super) > RCI.NumRegs)
RCI.ProperSubClass = true;
RCI.MinCost = uint8_t(MinCost);
RCI.MinCost = MinCost;
RCI.LastCostChange = LastCostChange;
LLVM_DEBUG({

View File

@ -29,7 +29,7 @@ def R0 : Core< 0, "%r0">, DwarfRegNum<[0]>;
def R1 : Core< 1, "%r1">, DwarfRegNum<[1]>;
def R2 : Core< 2, "%r2">, DwarfRegNum<[2]>;
def R3 : Core< 3, "%r3">, DwarfRegNum<[3]>;
let CostPerUse=1 in {
let CostPerUse=[1] in {
def R4 : Core< 4, "%r4">, DwarfRegNum<[4]>;
def R5 : Core< 5, "%r5">, DwarfRegNum<[5]>;
def R6 : Core< 6, "%r6">, DwarfRegNum<[6]>;
@ -44,7 +44,7 @@ def R13 : Core<13, "%r13">, DwarfRegNum<[13]>;
def R14 : Core<14, "%r14">, DwarfRegNum<[14]>;
def R15 : Core<15, "%r15">, DwarfRegNum<[15]>;
let CostPerUse=1 in {
let CostPerUse=[1] in {
def R16 : Core<16, "%r16">, DwarfRegNum<[16]>;
def R17 : Core<17, "%r17">, DwarfRegNum<[17]>;
def R18 : Core<18, "%r18">, DwarfRegNum<[18]>;

View File

@ -83,7 +83,7 @@ def R5 : ARMReg< 5, "r5">, DwarfRegNum<[5]>;
def R6 : ARMReg< 6, "r6">, DwarfRegNum<[6]>;
def R7 : ARMReg< 7, "r7">, DwarfRegNum<[7]>;
// These require 32-bit instructions.
let CostPerUse = 1 in {
let CostPerUse = [1] in {
def R8 : ARMReg< 8, "r8">, DwarfRegNum<[8]>;
def R9 : ARMReg< 9, "r9">, DwarfRegNum<[9]>;
def R10 : ARMReg<10, "r10">, DwarfRegNum<[10]>;

View File

@ -78,7 +78,7 @@ def sub_vrm4_1 : SubRegIndex<256, -1>;
let RegAltNameIndices = [ABIRegAltName] in {
def X0 : RISCVReg<0, "x0", ["zero"]>, DwarfRegNum<[0]>;
let CostPerUse = 1 in {
let CostPerUse = [1] in {
def X1 : RISCVReg<1, "x1", ["ra"]>, DwarfRegNum<[1]>;
def X2 : RISCVReg<2, "x2", ["sp"]>, DwarfRegNum<[2]>;
def X3 : RISCVReg<3, "x3", ["gp"]>, DwarfRegNum<[3]>;
@ -95,7 +95,7 @@ let RegAltNameIndices = [ABIRegAltName] in {
def X13 : RISCVReg<13,"x13", ["a3"]>, DwarfRegNum<[13]>;
def X14 : RISCVReg<14,"x14", ["a4"]>, DwarfRegNum<[14]>;
def X15 : RISCVReg<15,"x15", ["a5"]>, DwarfRegNum<[15]>;
let CostPerUse = 1 in {
let CostPerUse = [1] in {
def X16 : RISCVReg<16,"x16", ["a6"]>, DwarfRegNum<[16]>;
def X17 : RISCVReg<17,"x17", ["a7"]>, DwarfRegNum<[17]>;
def X18 : RISCVReg<18,"x18", ["s2"]>, DwarfRegNum<[18]>;

View File

@ -61,7 +61,7 @@ def CH : X86Reg<"ch", 5>;
def BH : X86Reg<"bh", 7>;
// X86-64 only, requires REX.
let CostPerUse = 1 in {
let CostPerUse = [1] in {
def SIL : X86Reg<"sil", 6>;
def DIL : X86Reg<"dil", 7>;
def BPL : X86Reg<"bpl", 5>;
@ -126,7 +126,7 @@ def SP : X86Reg<"sp", 4, [SPL,SPH]>;
def IP : X86Reg<"ip", 0>;
// X86-64 only, requires REX.
let SubRegIndices = [sub_8bit, sub_8bit_hi_phony], CostPerUse = 1,
let SubRegIndices = [sub_8bit, sub_8bit_hi_phony], CostPerUse = [1],
CoveredBySubRegs = 1 in {
def R8W : X86Reg<"r8w", 8, [R8B,R8BH]>;
def R9W : X86Reg<"r9w", 9, [R9B,R9BH]>;
@ -152,7 +152,7 @@ def EIP : X86Reg<"eip", 0, [IP, HIP]>, DwarfRegNum<[-2, 8, 8]>;
}
// X86-64 only, requires REX
let SubRegIndices = [sub_16bit, sub_16bit_hi], CostPerUse = 1,
let SubRegIndices = [sub_16bit, sub_16bit_hi], CostPerUse = [1],
CoveredBySubRegs = 1 in {
def R8D : X86Reg<"r8d", 8, [R8W,R8WH]>;
def R9D : X86Reg<"r9d", 9, [R9W,R9WH]>;
@ -176,7 +176,7 @@ def RBP : X86Reg<"rbp", 5, [EBP]>, DwarfRegNum<[6, -2, -2]>;
def RSP : X86Reg<"rsp", 4, [ESP]>, DwarfRegNum<[7, -2, -2]>;
// These also require REX.
let CostPerUse = 1 in {
let CostPerUse = [1] in {
def R8 : X86Reg<"r8", 8, [R8D]>, DwarfRegNum<[ 8, -2, -2]>;
def R9 : X86Reg<"r9", 9, [R9D]>, DwarfRegNum<[ 9, -2, -2]>;
def R10 : X86Reg<"r10", 10, [R10D]>, DwarfRegNum<[10, -2, -2]>;
@ -219,7 +219,7 @@ def XMM6: X86Reg<"xmm6", 6>, DwarfRegNum<[23, 27, 27]>;
def XMM7: X86Reg<"xmm7", 7>, DwarfRegNum<[24, 28, 28]>;
// X86-64 only
let CostPerUse = 1 in {
let CostPerUse = [1] in {
def XMM8: X86Reg<"xmm8", 8>, DwarfRegNum<[25, -2, -2]>;
def XMM9: X86Reg<"xmm9", 9>, DwarfRegNum<[26, -2, -2]>;
def XMM10: X86Reg<"xmm10", 10>, DwarfRegNum<[27, -2, -2]>;

View File

@ -0,0 +1,34 @@
// RUN: llvm-tblgen -gen-register-info -I %p/../../include -I %p/Common %s | FileCheck %s
// Checks two CostPerUse values for the registers.
include "llvm/Target/Target.td"
let Namespace = "MyTarget" in {
foreach Index = 0-3 in {
// Adding two cost values per register.
let CostPerUse = [1, Index] in {
def S#Index : Register <"s"#Index>;
}
}
// CostPerUse by default to 0.
def D0 : Register<"d0">;
def D1 : Register<"d1">;
} // Namespace = "MyTarget"
def SRegs : RegisterClass<"MyTarget", [i32], 32, (sequence "S%u", 0, 3)>;
def DRegs : RegisterClass<"MyTarget", [i32], 32, (sequence "D%u", 0, 1)>;
def MyTarget : Target;
// CHECK: static const uint8_t CostPerUseTable[] = {
// CHECK-NEXT: 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 2, 3, };
// CHECK: static const bool InAllocatableClassTable[] = {
// CHECK-NEXT: false, true, true, true, true, true, true, };
// CHECK: static const TargetRegisterInfoDesc MyTargetRegInfoDesc = { // Extra Descriptors
// CHECK-NEXT: CostPerUseTable, 2, InAllocatableClassTable};
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc, RegisterClasses, RegisterClasses+2,

View File

@ -0,0 +1,71 @@
// RUN: llvm-tblgen -gen-register-info -I %p/../../include -I %p/Common %s | FileCheck %s
// Checks the cost values for the register tuple.
include "llvm/Target/Target.td"
class MyClass<int size, list<ValueType> types, dag registers>
: RegisterClass<"MyTarget", types, size, registers> {
let Size = size;
}
class Indexes<int N> {
list<int> all = [0, 1, 2, 3];
list<int> slice =
!foldl([]<int>, all, acc, cur,
!listconcat(acc, !if(!lt(cur, N), [cur], [])));
}
foreach Index = 0-3 in {
def sub#Index : SubRegIndex<32, !shl(Index, 5)>;
}
foreach Size = {2,4} in {
foreach Index = Indexes<!add(5, !mul(Size, -1))>.slice in {
def !foldl("", Indexes<Size>.slice, acc, cur,
!strconcat(acc#!if(!eq(acc,""),"","_"), "sub"#!add(cur, Index))) :
SubRegIndex<!mul(Size, 32), !shl(Index, 5)> {
let CoveringSubRegIndices =
!foldl([]<SubRegIndex>, Indexes<Size>.slice, acc, cur,
!listconcat(acc, [!cast<SubRegIndex>(sub#!add(cur, Index))]));
}
}
}
let Namespace = "MyTarget" in {
foreach Index = 0-15 in {
// Adding two cost values per register.
let CostPerUse = [Index, !shl(Index, 1)] in {
def S#Index : Register <"s"#Index>;
}
}
} // Namespace = "MyTarget"
def GPR32 : MyClass<32, [i32], (sequence "S%u", 0, 15)>;
def GPR64 : RegisterTuples<[sub0, sub1],
[(decimate (shl GPR32, 0), 1),
(decimate (shl GPR32, 1), 1)
]>;
def GPR128 : RegisterTuples<[sub0, sub1, sub2, sub3],
[
(decimate (shl GPR32, 0), 1),
(decimate (shl GPR32, 1), 1),
(decimate (shl GPR32, 2), 1),
(decimate (shl GPR32, 3), 1)
]>;
def GPR_64 : MyClass<64, [v2i32], (add GPR64)>;
def GPR_128 : MyClass<128, [v4i32], (add GPR128)>;
def MyTarget : Target;
// CHECK: static const uint8_t CostPerUseTable[] = {
// CHECK-NEXT: 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, };
// CHECK: static const TargetRegisterInfoDesc MyTargetRegInfoDesc = { // Extra Descriptors
// CHECK-NEXT: CostPerUseTable, 2, InAllocatableClassTable};
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc, RegisterClasses, RegisterClasses+3,

View File

@ -0,0 +1,36 @@
// RUN: llvm-tblgen -gen-register-info -I %p/../../include -I %p/Common %s | FileCheck %s
// Checks the CostPerUse value for the registers.
include "llvm/Target/Target.td"
let Namespace = "MyTarget" in {
foreach Index = 0-3 in {
// Adds register cost value 1.
let CostPerUse = [1] in {
def S#Index : Register <"s"#Index>;
}
}
// CostPerUse by default to 0.
def D0 : Register<"d0">;
def D1 : Register<"d1">;
} // Namespace = "MyTarget"
def SRegs : RegisterClass<"MyTarget", [i32], 32, (sequence "S%u", 0, 3)>;
def DRegs : RegisterClass<"MyTarget", [i32], 32, (sequence "D%u", 0, 1)>;
def MyTarget : Target;
// CHECK: static const uint8_t CostPerUseTable[] = {
// CHECK-NEXT: 0, 0, 0, 1, 1, 1, 1, };
// CHECK: static const bool InAllocatableClassTable[] = {
// CHECK-NEXT: false, true, true, true, true, true, true, };
// CHECK: static const TargetRegisterInfoDesc MyTargetRegInfoDesc = { // Extra Descriptors
// CHECK-NEXT: CostPerUseTable, 1, InAllocatableClassTable};
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc, RegisterClasses, RegisterClasses+2,

View File

@ -154,14 +154,11 @@ void CodeGenSubRegIndex::computeConcatTransitiveClosure() {
//===----------------------------------------------------------------------===//
CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum)
: TheDef(R),
EnumValue(Enum),
CostPerUse(R->getValueAsInt("CostPerUse")),
: TheDef(R), EnumValue(Enum),
CostPerUse(R->getValueAsListOfInts("CostPerUse")),
CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")),
HasDisjunctSubRegs(false),
SubRegsComplete(false),
SuperRegsComplete(false),
TopoSig(~0u) {
HasDisjunctSubRegs(false), SubRegsComplete(false),
SuperRegsComplete(false), TopoSig(~0u) {
Artificial = R->getValueAsBit("isArtificial");
}
@ -646,16 +643,18 @@ struct TupleExpander : SetTheory::Expander {
std::string Name;
Record *Proto = Lists[0][n];
std::vector<Init*> Tuple;
unsigned CostPerUse = 0;
for (unsigned i = 0; i != Dim; ++i) {
Record *Reg = Lists[i][n];
if (i) Name += '_';
Name += Reg->getName();
Tuple.push_back(DefInit::get(Reg));
CostPerUse = std::max(CostPerUse,
unsigned(Reg->getValueAsInt("CostPerUse")));
}
// Take the cost list of the first register in the tuple.
ListInit *CostList = Proto->getValueAsListInit("CostPerUse");
SmallVector<Init *, 2> CostPerUse;
CostPerUse.insert(CostPerUse.end(), CostList->begin(), CostList->end());
StringInit *AsmName = StringInit::get("");
if (!RegNames.empty()) {
if (RegNames.size() <= n)
@ -697,7 +696,7 @@ struct TupleExpander : SetTheory::Expander {
// CostPerUse is aggregated from all Tuple members.
if (Field == "CostPerUse")
RV.setValue(IntInit::get(CostPerUse));
RV.setValue(ListInit::get(CostPerUse, CostList->getElementType()));
// Composite registers are always covered by sub-registers.
if (Field == "CoveredBySubRegs")

View File

@ -151,7 +151,7 @@ namespace llvm {
struct CodeGenRegister {
Record *TheDef;
unsigned EnumValue;
unsigned CostPerUse;
std::vector<int64_t> CostPerUse;
bool CoveredBySubRegs;
bool HasDisjunctSubRegs;
bool Artificial;

View File

@ -1441,19 +1441,52 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Emit extra information about registers.
const std::string &TargetName = std::string(Target.getName());
OS << "\nstatic const TargetRegisterInfoDesc "
<< TargetName << "RegInfoDesc[] = { // Extra Descriptors\n";
OS << " { 0, false },\n";
const auto &Regs = RegBank.getRegisters();
for (const auto &Reg : Regs) {
OS << " { ";
OS << Reg.CostPerUse << ", "
<< ( AllocatableRegs.count(Reg.TheDef) != 0 ? "true" : "false" )
<< " },\n";
}
OS << "};\n"; // End of register descriptors...
unsigned NumRegCosts = 1;
for (const auto &Reg : Regs)
NumRegCosts = std::max((size_t)NumRegCosts, Reg.CostPerUse.size());
std::vector<unsigned> AllRegCostPerUse;
llvm::BitVector InAllocClass(Regs.size() + 1, false);
AllRegCostPerUse.insert(AllRegCostPerUse.end(), NumRegCosts, 0);
// Populate the vector RegCosts with the CostPerUse list of the registers
// in the order they are read. Have at most NumRegCosts entries for
// each register. Fill with zero for values which are not explicitly given.
for (const auto &Reg : Regs) {
auto Costs = Reg.CostPerUse;
AllRegCostPerUse.insert(AllRegCostPerUse.end(), Costs.begin(), Costs.end());
if (NumRegCosts > Costs.size())
AllRegCostPerUse.insert(AllRegCostPerUse.end(),
NumRegCosts - Costs.size(), 0);
if (AllocatableRegs.count(Reg.TheDef))
InAllocClass.set(Reg.EnumValue);
}
// Emit the cost values as a 1D-array after grouping them by their indices,
// i.e. the costs for all registers corresponds to index 0, 1, 2, etc.
// Size of the emitted array should be NumRegCosts * (Regs.size() + 1).
OS << "\nstatic const uint8_t "
<< "CostPerUseTable[] = { \n";
for (unsigned int I = 0; I < NumRegCosts; ++I) {
for (unsigned J = I, E = AllRegCostPerUse.size(); J < E; J += NumRegCosts)
OS << AllRegCostPerUse[J] << ", ";
}
OS << "};\n\n";
OS << "\nstatic const bool "
<< "InAllocatableClassTable[] = { \n";
for (unsigned I = 0, E = InAllocClass.size(); I < E; ++I) {
OS << (InAllocClass[I] ? "true" : "false") << ", ";
}
OS << "};\n\n";
OS << "\nstatic const TargetRegisterInfoDesc " << TargetName
<< "RegInfoDesc = { // Extra Descriptors\n";
OS << "CostPerUseTable, " << NumRegCosts << ", "
<< "InAllocatableClassTable";
OS << "};\n\n"; // End of register descriptors...
std::string ClassName = Target.getName().str() + "GenRegisterInfo";
@ -1513,10 +1546,11 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
EmitRegMappingTables(OS, Regs, true);
OS << ClassName << "::\n" << ClassName
OS << ClassName << "::\n"
<< ClassName
<< "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour,\n"
" unsigned PC, unsigned HwMode)\n"
<< " : TargetRegisterInfo(" << TargetName << "RegInfoDesc"
<< " : TargetRegisterInfo(&" << TargetName << "RegInfoDesc"
<< ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() << ",\n"
<< " SubRegIndexNameTable, SubRegIndexLaneMaskTable,\n"
<< " ";
@ -1679,7 +1713,10 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) {
for (const CodeGenRegister &R : RegBank.getRegisters()) {
OS << "Register " << R.getName() << ":\n";
OS << "\tCostPerUse: " << R.CostPerUse << '\n';
OS << "\tCostPerUse: ";
for (const auto &Cost : R.CostPerUse)
OS << Cost << " ";
OS << '\n';
OS << "\tCoveredBySubregs: " << R.CoveredBySubRegs << '\n';
OS << "\tHasDisjunctSubRegs: " << R.HasDisjunctSubRegs << '\n';
for (std::pair<CodeGenSubRegIndex*,CodeGenRegister*> P : R.getSubRegs()) {