From 5b309afaf0691c1c9ec0ec1c3e196a5314c0e385 Mon Sep 17 00:00:00 2001 From: vikashgu Date: Fri, 9 May 2025 06:04:19 +0000 Subject: [PATCH 1/3] [CodeGen] For ad hoc aliasing, now each lead node register will have register unit defined that uniquely identifies them, alongwith a an addtional register unit per edge in ad hoc alias graph that shows the register overlap between the connected aliasing leaf register nodes It solves the issue of using the aliasing register as the immediate subregister of a register, thus need to have disjoint lanemask, which is now possible by virtue of uniquely defined register units. At the same time, aliasing is accounted by the shared register unit, having lanemask as 0x0 just as previously, not a problem now. --- .../TableGen/Common/CodeGenRegisters.cpp | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp index 639f94f79ecd7..fc2e14787cafc 100644 --- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp @@ -424,20 +424,33 @@ 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. 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 now corresponds uniquely to each of the both + // alias leaf register nodes. + RegUnits.set(RegBank.newRegUnit(this)); + AR->RegUnits.set(RegBank.newRegUnit(AR)); } // Finally, create units for leaf registers without ad hoc aliases. Note that @@ -2675,6 +2688,13 @@ void CodeGenRegBank::printRegUnitNames(ArrayRef Units) const { dbgs() << ' ' << RegUnits[Unit].Roots[0]->getName(); else dbgs() << " #" << Unit; + + if (RegUnits[Unit].Roots[1]) { + if (Unit < NumNativeRegUnits) + dbgs() << '~' << RegUnits[Unit].Roots[1]->getName(); + else + dbgs() << "~#" << Unit; + } } dbgs() << '\n'; } From d8ef3abfbd23f4a73e5e86403fe30e8be4f80e6f Mon Sep 17 00:00:00 2001 From: vikashgu Date: Fri, 9 May 2025 12:31:41 +0000 Subject: [PATCH 2/3] Adding regUnit for leaf registers having aliases only once. --- llvm/utils/TableGen/Common/CodeGenRegisters.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp index fc2e14787cafc..0bd5cd7112be3 100644 --- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp @@ -437,6 +437,11 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { // 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 (RegUnits.empty() && !ExplicitAliases.empty()) + RegUnits.set(RegBank.newRegUnit(this)); for (CodeGenRegister *AR : ExplicitAliases) { // Only visit each edge once. if (AR->SubRegsComplete) @@ -447,9 +452,7 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { RegUnits.set(SharedUnit); AR->RegUnits.set(SharedUnit); - // Create a RegUnit that now corresponds uniquely to each of the both - // alias leaf register nodes. - RegUnits.set(RegBank.newRegUnit(this)); + // Create a RegUnit that uniquely defines the alias leaf register nodes. AR->RegUnits.set(RegBank.newRegUnit(AR)); } From e8040820c513143f285a5ce9197f2f8180eddb1b Mon Sep 17 00:00:00 2001 From: vikashgu Date: Mon, 12 May 2025 11:49:32 +0000 Subject: [PATCH 3/3] Added tableGen test cases, alongwith modified implementation to deal with aliases. --- .../test/TableGen/DisjointLeafAliasSubregs.td | 87 ++++++++++++ .../TableGen/DisjointNonLeafAliasSubregs.td | 132 ++++++++++++++++++ .../TableGen/Common/CodeGenRegisters.cpp | 26 ++-- llvm/utils/TableGen/Common/CodeGenRegisters.h | 3 + llvm/utils/TableGen/RegisterInfoEmitter.cpp | 14 ++ 5 files changed, 251 insertions(+), 11 deletions(-) create mode 100644 llvm/test/TableGen/DisjointLeafAliasSubregs.td create mode 100644 llvm/test/TableGen/DisjointNonLeafAliasSubregs.td 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 0bd5cd7112be3..9e1d1d99594c2 100644 --- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp @@ -440,7 +440,7 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { // // Create a RegUnit for leaf register that uniquely defines it, which has // explicit alias registers. - if (RegUnits.empty() && !ExplicitAliases.empty()) + if (!ExplicitAliases.empty()) RegUnits.set(RegBank.newRegUnit(this)); for (CodeGenRegister *AR : ExplicitAliases) { // Only visit each edge once. @@ -2685,19 +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; + } +} - if (RegUnits[Unit].Roots[1]) { - if (Unit < NumNativeRegUnits) - dbgs() << '~' << RegUnits[Unit].Roots[1]->getName(); - else - 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; } } }