diff --git a/llvm/test/TableGen/DisjointLeafAliasSubregs.td b/llvm/test/TableGen/DisjointLeafAliasSubregs.td new file mode 100644 index 0000000000000..bdf202f8a77bb --- /dev/null +++ b/llvm/test/TableGen/DisjointLeafAliasSubregs.td @@ -0,0 +1,87 @@ +// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK +// Checks that tablegen calculation of register unit's lanemask. +// It covers the scenario, where leaf aliasing registers are used to create +// disjoint subregs for defining new register (this case inspired from VE tablegen) +// +// For each such leaf register, a unique regUnit will be created that should rightfully +// denote its position in the super register via laneMask. whereas, both of will also +// have a common regUnit that accurately represents the ad hoc aliasing, even though its +// laneMask could be arbitrary which is still better situation. + +include "llvm/Target/Target.td" + +class MyReg subregs = [], list aliases = []> + : Register { + let Namespace = "Test"; + let SubRegs = subregs; + let Aliases = aliases; + let CoveredBySubRegs = 1; +} +class MyClass types, dag registers> + : RegisterClass<"Test", types, size, registers> { + let Size = size; +} + +def sub_i32 : SubRegIndex<32, 32>; // High 32 bit (32..63) +def sub_f32 : SubRegIndex<32>; // Low 32 bit (0..31) + +// Registers SW0 & SF0 are aliases + +// VE's Registers Example: +// SX0 -- SW0 (sub_f32) +// \- SF0 (sub_i32) +def SW0 : MyReg<"sw0", []>; + +def SF0 : MyReg<"sf0", [], [!cast("SW0")]>; + +let SubRegIndices = [sub_f32, sub_i32] in { + def SX0 : MyReg<"s0", [!cast("SW0"), !cast("SF0")]>; +} + +def I64 : MyClass<1, [i64], (add (sequence "SX%u", 0, 0))>; + +def TestTarget : Target; + +// CHECK: RegisterClass I64: +// CHECK: LaneMask: 0000000000000003 +// CHECK: HasDisjunctSubRegs: 1 +// CHECK: CoveredBySubRegs: 1 +// CHECK: Regs: SX0 +// CHECK: SubClasses: I64 +// CHECK: SuperClasses: + +// CHECK: SubRegIndex sub_f32: +// CHECK-NEXT: LaneMask: 0000000000000001 +// CHECK: SubRegIndex sub_i32: +// CHECK-NEXT: LaneMask: 0000000000000002 + +// CHECK: Register SF0: +// CHECK: CoveredBySubregs: 1 +// CHECK: HasDisjunctSubRegs: 0 +// CHECK: Native RegUnit: SF0 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF +// CHECK: Native RegUnit: SF0~SW0 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF + +// CHECK: Register SW0: +// CHECK: CoveredBySubregs: 1 +// CHECK: HasDisjunctSubRegs: 0 +// CHECK: Native RegUnit: SF0~SW0 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF +// CHECK: Native RegUnit: SW0 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF + +// CHECK: Register SX0: +// CHECK: HasDisjunctSubRegs: 1 +// CHECK: SubReg sub_f32 = SW0 +// CHECK: RegUnit SW0 : SF0~SW0 +// CHECK: RegUnit SW0 : SW0 +// CHECK: SubReg sub_i32 = SF0 +// CHECK: RegUnit SF0 : SF0 +// CHECK: RegUnit SF0 : SF0~SW0 +// CHECK: Native RegUnit: SF0 +// CHECK: LaneMask Value: 0000000000000002 +// CHECK: Native RegUnit: SF0~SW0 +// CHECK: LaneMask Value: 0000000000000000 +// CHECK: Native RegUnit: SW0 +// CHECK: LaneMask Value: 0000000000000001 \ No newline at end of file diff --git a/llvm/test/TableGen/DisjointNonLeafAliasSubregs.td b/llvm/test/TableGen/DisjointNonLeafAliasSubregs.td new file mode 100644 index 0000000000000..3d4601f8dee26 --- /dev/null +++ b/llvm/test/TableGen/DisjointNonLeafAliasSubregs.td @@ -0,0 +1,132 @@ +// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK +// Checks that tablegen calculation of register unit's lanemask. +// It covers the scenario, where non-leaf aliasing registers are used to create +// disjoint subregs for defining new register (this case inspired from VE tablegen) +// This test is inspired via hypothetical extrapolating VE's registers backend. +// +// This situation is identical to the test DisjoinLeafAliasSubregs.td, except the +// fact, that here the alias registers are not only used as mutually disjoint subregs +// to define new register, but also these alias registers are not necessarily the +// the leaf registers, implying they themselves are made out of subregs. +// +// Here also, the lanemask corresponding to unique regUnit will be accurately tell +// regUnit position, whereas the laneMask for common regunit, accounting for aliasing +// , could be still arbitrary based on the exact super register its part of. + +include "llvm/Target/Target.td" + +class MyReg subregs = [], list aliases = []> + : Register { + let Namespace = "Test"; + let SubRegs = subregs; + let Aliases = aliases; + let CoveredBySubRegs = 1; +} +class MyClass types, dag registers> + : RegisterClass<"Test", types, size, registers> { + let Size = size; +} + +def sub_i16 : SubRegIndex<16, 16>; // High 16 bit (16..31) +def sub_f16 : SubRegIndex<16>; // Low 16 bit (0..15) +def sub_i32 : SubRegIndex<32, 32>; // High 32 bit (32..63) +def sub_f32 : SubRegIndex<32>; // Low 32 bit (0..31) + +// Registers SW0 & SF0 are aliases + +// VE's Registers Extrapolated example: +// SX0 -- SW0 (sub_f32) -- SW0_LO16 (sub_f16) +// \ \- SW0_HI16 (sub_i16) +// \- SF0 (sub_i32) +def SW0_LO16 : MyReg<"sw0_lo16", []>; +def SW0_HI16 : MyReg<"sw0_hi16", []>; + +let SubRegIndices = [sub_f16, sub_i16] in { + def SW0 : MyReg<"sw1", [SW0_LO16, SW0_HI16]>; +} + +def SF0 : MyReg<"sf0", [], [!cast("SW0")]>; + +let SubRegIndices = [sub_f32, sub_i32] in { + def SX0 : MyReg<"s0", [!cast("SW0"), !cast("SF0")]>; +} + +def I64 : MyClass<1, [i64], (add (sequence "SX%u", 0, 0))>; + +def TestTarget : Target; + +// CHECK: RegisterClass I64: +// CHECK: LaneMask: 0000000000000007 +// CHECK: HasDisjunctSubRegs: 1 +// CHECK: CoveredBySubRegs: 1 +// CHECK: Regs: SX0 +// CHECK: SubClasses: I64 +// CHECK: SuperClasses: + +// CHECK: SubRegIndex sub_f16: +// CHECK-NEXT: LaneMask: 0000000000000001 +// CHECK: SubRegIndex sub_f32: +// CHECK-NEXT: LaneMask: 0000000000000003 +// CHECK: SubRegIndex sub_i16: +// CHECK-NEXT: LaneMask: 0000000000000002 +// CHECK: SubRegIndex sub_i32: +// CHECK-NEXT: LaneMask: 0000000000000004 + +// CHECK: Register SF0: +// CHECK: CoveredBySubregs: 1 +// CHECK: HasDisjunctSubRegs: 0 +// CHECK: Native RegUnit: SF0 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF +// CHECK: Native RegUnit: SF0~SW0 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF + +// CHECK: Register SW0: +// CHECK: CoveredBySubregs: 1 +// CHECK: HasDisjunctSubRegs: 1 +// CHECK: SubReg sub_f16 = SW0_LO16 +// CHECK: RegUnit SW0_LO16 : SW0_LO16 +// CHECK: SubReg sub_i16 = SW0_HI16 +// CHECK: RegUnit SW0_HI16 : SW0_HI16 +// CHECK: Native RegUnit: SF0~SW0 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF +// CHECK: Native RegUnit: SW0_LO16 +// CHECK: LaneMask Value: 0000000000000001 +// CHECK: Native RegUnit: SW0_HI16 +// CHECK: LaneMask Value: 0000000000000002 + +// CHECK: Register SX0: +// CHECK: CoveredBySubregs: 1 +// CHECK: HasDisjunctSubRegs: 1 +// CHECK: SubReg sub_f16 = SW0_LO16 +// CHECK: RegUnit SW0_LO16 : SW0_LO16 +// CHECK: SubReg sub_f32 = SW0 +// CHECK: RegUnit SW0 : SF0~SW0 +// CHECK: RegUnit SW0 : SW0_LO16 +// CHECK: RegUnit SW0 : SW0_HI16 +// CHECK: SubReg sub_i16 = SW0_HI16 +// CHECK: RegUnit SW0_HI16 : SW0_HI16 +// CHECK: SubReg sub_i32 = SF0 +// CHECK: RegUnit SF0 : SF0 +// CHECK: RegUnit SF0 : SF0~SW0 +// CHECK: Native RegUnit: SF0 +// CHECK: LaneMask Value: 0000000000000004 +// CHECK: Native RegUnit: SF0~SW0 +// CHECK: LaneMask Value: 0000000000000004 +// CHECK: Native RegUnit: SW0_LO16 +// CHECK: LaneMask Value: 0000000000000001 +// CHECK: Native RegUnit: SW0_HI16 +// CHECK: LaneMask Value: 0000000000000002 + +// CHECK: Register SW0_HI16: +// CHECK: CostPerUse: 0 +// CHECK: CoveredBySubregs: 1 +// CHECK: HasDisjunctSubRegs: 0 +// CHECK: Native RegUnit: SW0_HI16 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF + +// CHECK: Register SW0_LO16: +// CHECK: CostPerUse: 0 +// CHECK: CoveredBySubregs: 1 +// CHECK: HasDisjunctSubRegs: 0 +// CHECK: Native RegUnit: SW0_LO16 +// CHECK: LaneMask Value: FFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp index 639f94f79ecd7..9e1d1d99594c2 100644 --- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp @@ -424,20 +424,36 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { // These units correspond to the maximal cliques in the register overlap // graph which is optimal. // - // When there is ad hoc aliasing, we simply create one unit per edge in the - // undirected ad hoc aliasing graph. Technically, we could do better by - // identifying maximal cliques in the ad hoc graph, but cliques larger than 2 - // are extremely rare anyway (I've never seen one), so we don't bother with - // the added complexity. + // When there is ad hoc aliasing, while we create one unit per edge in the + // undirected ad hoc aliasing graph to represent aliasing, one unit per each + // node leaf register is needed extra to identify them uniquely, in case these + // aliasing register are used as subregister(with disjoint lanemasks) to have + // an accurate lanemask generation for these leaf register. + // For example, In VE, SX0 is made out of disjoint subregister SW0 & SF0 + // respectively, where SF0 is an alias for SW0. So while 2 register units will + // uniquely define these 2 subregister, the shared register unit will account + // for aliasing. + // + // Technically, we could do better by identifying maximal cliques in the ad + // hoc graph, but cliques larger than 2 are extremely rare anyway (I've never + // seen one), so we don't bother with the added complexity. + // + // Create a RegUnit for leaf register that uniquely defines it, which has + // explicit alias registers. + if (!ExplicitAliases.empty()) + RegUnits.set(RegBank.newRegUnit(this)); for (CodeGenRegister *AR : ExplicitAliases) { // Only visit each edge once. if (AR->SubRegsComplete) continue; // Create a RegUnit representing this alias edge, and add it to both // registers. - unsigned Unit = RegBank.newRegUnit(this, AR); - RegUnits.set(Unit); - AR->RegUnits.set(Unit); + unsigned SharedUnit = RegBank.newRegUnit(this, AR); + RegUnits.set(SharedUnit); + AR->RegUnits.set(SharedUnit); + + // Create a RegUnit that uniquely defines the alias leaf register nodes. + AR->RegUnits.set(RegBank.newRegUnit(AR)); } // Finally, create units for leaf registers without ad hoc aliases. Note that @@ -2669,12 +2685,23 @@ CodeGenRegBank::computeCoveredRegisters(ArrayRef Regs) { return BV; } -void CodeGenRegBank::printRegUnitNames(ArrayRef Units) const { - for (unsigned Unit : Units) { +void CodeGenRegBank::printRegUnitName(unsigned Unit) const { + if (Unit < NumNativeRegUnits) + dbgs() << ' ' << RegUnits[Unit].Roots[0]->getName(); + else + dbgs() << " #" << Unit; + + if (RegUnits[Unit].Roots[1]) { if (Unit < NumNativeRegUnits) - dbgs() << ' ' << RegUnits[Unit].Roots[0]->getName(); + dbgs() << '~' << RegUnits[Unit].Roots[1]->getName(); else - dbgs() << " #" << Unit; + dbgs() << "~#" << Unit; + } +} + +void CodeGenRegBank::printRegUnitNames(ArrayRef Units) const { + for (unsigned Unit : Units) { + printRegUnitName(Unit); } dbgs() << '\n'; } diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.h b/llvm/utils/TableGen/Common/CodeGenRegisters.h index 75d9a3f7a2c0f..648b48ad5efce 100644 --- a/llvm/utils/TableGen/Common/CodeGenRegisters.h +++ b/llvm/utils/TableGen/Common/CodeGenRegisters.h @@ -799,6 +799,9 @@ class CodeGenRegBank { RegUnit &getRegUnit(unsigned RUID) { return RegUnits[RUID]; } const RegUnit &getRegUnit(unsigned RUID) const { return RegUnits[RUID]; } + // Helper function to print information about a register unit. + void printRegUnitName(unsigned Unit) const; + std::list &getRegClasses() { return RegClasses; } const std::list &getRegClasses() const { diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp index 98f0d7eaaff38..0e6f78e83634e 100644 --- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -1933,6 +1933,20 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) { for (auto &[SubIdx, SubReg] : R.getSubRegs()) { OS << "\tSubReg " << SubIdx->getName() << " = " << SubReg->getName() << '\n'; + for (const auto &Unit : SubReg->getNativeRegUnits()) { + OS << "\tRegUnit " << SubReg->getName() << " : "; + RegBank.printRegUnitName(Unit); + OS << '\n'; + } + } + const auto &RUMasks = R.getRegUnitLaneMasks(); + unsigned u = 0; + for (const auto &Unit : R.getNativeRegUnits()) { + OS << "\tNative RegUnit: "; + RegBank.printRegUnitName(Unit); + OS << '\n'; + OS << "\tLaneMask Value: " << PrintLaneMask(RUMasks[u]) << '\n'; + ++u; } } }