diff --git a/llvm/include/llvm/CodeGen/RegisterClassInfo.h b/llvm/include/llvm/CodeGen/RegisterClassInfo.h --- a/llvm/include/llvm/CodeGen/RegisterClassInfo.h +++ b/llvm/include/llvm/CodeGen/RegisterClassInfo.h @@ -66,6 +66,9 @@ std::unique_ptr PSetLimits; + // The register cost values. + ArrayRef RegCosts; + // Compute all information about RC. void compute(const TargetRegisterClass *RC) const; @@ -117,16 +120,14 @@ } /// 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; } diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h --- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h +++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h @@ -209,8 +209,10 @@ /// 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 @@ 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 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 @@ 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. /// diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -168,8 +168,15 @@ // 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 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 diff --git a/llvm/lib/CodeGen/RegAllocGreedy.cpp b/llvm/lib/CodeGen/RegAllocGreedy.cpp --- a/llvm/lib/CodeGen/RegAllocGreedy.cpp +++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp @@ -406,6 +406,10 @@ /// Set of broken hints that may be reconciled later because of eviction. SmallSetVector SetOfBrokenHints; + /// The register cost values. This list will be recreated for each Machine + /// Function + ArrayRef RegCosts; + public: RAGreedy(); @@ -482,9 +486,9 @@ Register tryAssign(LiveInterval&, AllocationOrder&, SmallVectorImpl&, const SmallVirtRegSet&); - unsigned tryEvict(LiveInterval&, AllocationOrder&, - SmallVectorImpl&, unsigned, - const SmallVirtRegSet&); + unsigned tryEvict(LiveInterval &, AllocationOrder &, + SmallVectorImpl &, uint8_t, + const SmallVirtRegSet &); MCRegister tryRegionSplit(LiveInterval &, AllocationOrder &, SmallVectorImpl &); /// Calculate cost of region splitting. @@ -501,7 +505,7 @@ /// time. MCRegister tryAssignCSRFirstTime(LiveInterval &VirtReg, AllocationOrder &Order, MCRegister PhysReg, - unsigned &CostPerUseLimit, + uint8_t &CostPerUseLimit, SmallVectorImpl &NewVRegs); void initializeCSRCost(); unsigned tryBlockSplit(LiveInterval&, AllocationOrder&, @@ -797,7 +801,7 @@ } // 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 @@ /// @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 &NewVRegs, - unsigned CostPerUseLimit, + uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) { NamedRegionTimer T("evict", "Evict", TimerGroupName, TimerGroupDescription, TimePassesIsEnabled); @@ -1125,13 +1128,13 @@ // 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 @@ // 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 @@ ++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 @@ /// to use the CSR; otherwise return 0. MCRegister RAGreedy::tryAssignCSRFirstTime(LiveInterval &VirtReg, AllocationOrder &Order, - MCRegister PhysReg, unsigned &CostPerUseLimit, + MCRegister PhysReg, uint8_t &CostPerUseLimit, SmallVectorImpl &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 @@ SmallVectorImpl &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 @@ initializeCSRCost(); + RegCosts = TRI->getRegisterCosts(*MF); + VRAI = std::make_unique(*MF, *LIS, *VRM, *Loops, *MBFI); VRAI->calculateSpillWeightsAndHints(); diff --git a/llvm/lib/CodeGen/RegisterClassInfo.cpp b/llvm/lib/CodeGen/RegisterClassInfo.cpp --- a/llvm/lib/CodeGen/RegisterClassInfo.cpp +++ b/llvm/lib/CodeGen/RegisterClassInfo.cpp @@ -68,6 +68,8 @@ } 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 @@ unsigned N = 0; SmallVector 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 @@ // 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 @@ // 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 @@ if (Super != RC && getNumAllocatableRegs(Super) > RCI.NumRegs) RCI.ProperSubClass = true; - RCI.MinCost = uint8_t(MinCost); + RCI.MinCost = MinCost; RCI.LastCostChange = LastCostChange; LLVM_DEBUG({ diff --git a/llvm/lib/Target/ARC/ARCRegisterInfo.td b/llvm/lib/Target/ARC/ARCRegisterInfo.td --- a/llvm/lib/Target/ARC/ARCRegisterInfo.td +++ b/llvm/lib/Target/ARC/ARCRegisterInfo.td @@ -29,7 +29,7 @@ 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 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]>; diff --git a/llvm/lib/Target/ARM/ARMRegisterInfo.td b/llvm/lib/Target/ARM/ARMRegisterInfo.td --- a/llvm/lib/Target/ARM/ARMRegisterInfo.td +++ b/llvm/lib/Target/ARM/ARMRegisterInfo.td @@ -83,7 +83,7 @@ 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]>; diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td @@ -78,7 +78,7 @@ 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 @@ 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]>; diff --git a/llvm/lib/Target/X86/X86RegisterInfo.td b/llvm/lib/Target/X86/X86RegisterInfo.td --- a/llvm/lib/Target/X86/X86RegisterInfo.td +++ b/llvm/lib/Target/X86/X86RegisterInfo.td @@ -61,7 +61,7 @@ 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 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 @@ } // 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 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 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]>; diff --git a/llvm/test/TableGen/RegisterInfoEmitter-regcost-list.td b/llvm/test/TableGen/RegisterInfoEmitter-regcost-list.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/RegisterInfoEmitter-regcost-list.td @@ -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, diff --git a/llvm/test/TableGen/RegisterInfoEmitter-regcost-tuple.td b/llvm/test/TableGen/RegisterInfoEmitter-regcost-tuple.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/RegisterInfoEmitter-regcost-tuple.td @@ -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 types, dag registers> + : RegisterClass<"MyTarget", types, size, registers> { + let Size = size; +} + +class Indexes { + list all = [0, 1, 2, 3]; + list slice = + !foldl([], 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.slice in { + def !foldl("", Indexes.slice, acc, cur, + !strconcat(acc#!if(!eq(acc,""),"","_"), "sub"#!add(cur, Index))) : + SubRegIndex { + let CoveringSubRegIndices = + !foldl([], Indexes.slice, acc, cur, + !listconcat(acc, [!cast(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, diff --git a/llvm/test/TableGen/RegisterInfoEmitter-regcost.td b/llvm/test/TableGen/RegisterInfoEmitter-regcost.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/RegisterInfoEmitter-regcost.td @@ -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, diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h --- a/llvm/utils/TableGen/CodeGenRegisters.h +++ b/llvm/utils/TableGen/CodeGenRegisters.h @@ -151,7 +151,7 @@ struct CodeGenRegister { Record *TheDef; unsigned EnumValue; - unsigned CostPerUse; + std::vector CostPerUse; bool CoveredBySubRegs; bool HasDisjunctSubRegs; bool Artificial; diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp --- a/llvm/utils/TableGen/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/CodeGenRegisters.cpp @@ -154,14 +154,11 @@ //===----------------------------------------------------------------------===// CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum) - : TheDef(R), - EnumValue(Enum), - CostPerUse(R->getValueAsInt("CostPerUse")), - CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")), - HasDisjunctSubRegs(false), - SubRegsComplete(false), - SuperRegsComplete(false), - TopoSig(~0u) { + : TheDef(R), EnumValue(Enum), + CostPerUse(R->getValueAsListOfInts("CostPerUse")), + CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")), + HasDisjunctSubRegs(false), SubRegsComplete(false), + SuperRegsComplete(false), TopoSig(~0u) { Artificial = R->getValueAsBit("isArtificial"); } @@ -646,16 +643,18 @@ std::string Name; Record *Proto = Lists[0][n]; std::vector 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 CostPerUse; + CostPerUse.insert(CostPerUse.end(), CostList->begin(), CostList->end()); + StringInit *AsmName = StringInit::get(""); if (!RegNames.empty()) { if (RegNames.size() <= n) @@ -697,7 +696,7 @@ // 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") diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp --- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -1441,19 +1441,52 @@ // 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(); + unsigned NumRegCosts = 1; + for (const auto &Reg : Regs) + NumRegCosts = std::max((size_t)NumRegCosts, Reg.CostPerUse.size()); + + std::vector 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) { - OS << " { "; - OS << Reg.CostPerUse << ", " - << ( AllocatableRegs.count(Reg.TheDef) != 0 ? "true" : "false" ) - << " },\n"; + 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"; // End of register descriptors... + 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 @@ 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 @@ 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 P : R.getSubRegs()) {