Skip to content

[Target][RISCV] Add HwMode support to subregister index size/offset. #86368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions llvm/include/llvm/Target/Target.td
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,27 @@ class RegInfoByHwMode<list<HwMode> Ms = [], list<RegInfo> Ts = []>
list<RegInfo> Objects = Ts;
}

class SubRegRange<int size, int offset = 0> {
int Size = size; // Sub register size in bits.
int Offset = offset; // Offset of the first bit of the sub-reg index.
}

class SubRegRangeByHwMode<list<HwMode> Ms = [], list<SubRegRange> Ts = []>
: HwModeSelect<Ms> {
// The length of this list must be the same as the length of Ms.
list<SubRegRange> Objects = Ts;
}

// SubRegIndex - Use instances of SubRegIndex to identify subregisters.
class SubRegIndex<int size, int offset = 0> {
string Namespace = "";

// The size/offset information, parameterized by a HW mode.
// If the HwModes provided for SubRegRanges does not include the DefaultMode,
// the/ Size and Offset fields below will be used for the default. Otherwise,
// the Size and Offset fields are ignored.
SubRegRangeByHwMode SubRegRanges;

// Size - Size (in bits) of the sub-registers represented by this index.
int Size = size;

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/TargetRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,13 +595,13 @@ bool TargetRegisterInfo::getCoveringSubRegIndexes(
unsigned TargetRegisterInfo::getSubRegIdxSize(unsigned Idx) const {
assert(Idx && Idx < getNumSubRegIndices() &&
"This is not a subregister index");
return SubRegIdxRanges[Idx].Size;
return SubRegIdxRanges[HwMode * getNumSubRegIndices() + Idx].Size;
}

unsigned TargetRegisterInfo::getSubRegIdxOffset(unsigned Idx) const {
assert(Idx && Idx < getNumSubRegIndices() &&
"This is not a subregister index");
return SubRegIdxRanges[Idx].Offset;
return SubRegIdxRanges[HwMode * getNumSubRegIndices() + Idx].Offset;
}

Register
Expand Down
11 changes: 8 additions & 3 deletions llvm/lib/Target/RISCV/RISCVRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,14 @@ def sub_vrm1_6 : ComposedSubRegIndex<sub_vrm2_3, sub_vrm1_0>;
def sub_vrm1_7 : ComposedSubRegIndex<sub_vrm2_3, sub_vrm1_1>;

// GPR sizes change with HwMode.
// FIXME: Support HwMode in SubRegIndex?
def sub_gpr_even : SubRegIndex<-1>;
def sub_gpr_odd : SubRegIndex<-1, -1>;
def sub_gpr_even : SubRegIndex<32> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave these as -1 so we never accidentally use 32 for non-RV32?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't 32 consistent with the size we pass to the non-HwMode part of this?

class GPRRegisterClass<dag regList>                                              
    : RegisterClass<"RISCV", [XLenVT, XLenFVT, i32], 32, regList> {              
  let RegInfos = XLenRI;                                                         
}    

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess if we do that then it's fine

let SubRegRanges = SubRegRangeByHwMode<[RV32, RV64],
[SubRegRange<32>, SubRegRange<64>]>;
}
def sub_gpr_odd : SubRegIndex<32, 32> {
let SubRegRanges = SubRegRangeByHwMode<[RV32, RV64],
[SubRegRange<32, 32>, SubRegRange<64, 64>]>;
}
} // Namespace = "RISCV"

// Integer registers
Expand Down
9 changes: 6 additions & 3 deletions llvm/test/TableGen/ConcatenatedSubregs.td
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,19 @@ def TestTarget : Target;
// CHECK-LABEL: RegisterClass DRegs:

// CHECK-LABEL: SubRegIndex ssub1:
// CHECK: Offset, Size: 16, 16
// CHECK: Offset: { Default:16 }
// CHECK: Size: { Default:16 }
// CHECK-LABEL: SubRegIndex sub0:
// CHECK-LABEL: SubRegIndex sub1:
// CHECK-LABEL: SubRegIndex sub2:
// Check inferred indexes:
// CHECK-LABEL: SubRegIndex ssub1_ssub2:
// CHECK: Offset, Size: 16, 65535
// CHECK: Offset: { Default:16 }
// CHECK: Size: { Default:65535 }
// CHECK-LABEL: SubRegIndex ssub3_ssub4:
// CHECK-LABEL: SubRegIndex ssub0_ssub1_ssub2_ssub3:
// CHECK: Offset, Size: 65535, 65535
// CHECK: Offset: { Default:65535 }
// CHECK: Size: { Default:65535 }
// CHECK-LABEL: SubRegIndex ssub1_ssub2_ssub3_ssub4:

// Check that all subregs are generated on some examples
Expand Down
75 changes: 75 additions & 0 deletions llvm/test/TableGen/HwModeSubRegs.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s
include "llvm/Target/Target.td"

def HasFeat : Predicate<"Subtarget->hasFeat()">;

def TestMode : HwMode<"+feat1", [HasFeat]>;

class MyReg<string n>
: Register<n> {
let Namespace = "Test";
}
class MyClass<int size, list<ValueType> types, dag registers>
: RegisterClass<"Test", types, size, registers> {
let Size = size;
}

def X0 : MyReg<"x0">;
def X1 : MyReg<"x1">;
def X2 : MyReg<"x2">;
def X3 : MyReg<"x3">;
def X4 : MyReg<"x4">;
def X5 : MyReg<"x5">;
def X6 : MyReg<"x6">;
def X7 : MyReg<"x7">;
def X8 : MyReg<"x8">;
def X9 : MyReg<"x9">;
def X10 : MyReg<"x10">;
def X11 : MyReg<"x11">;
def X12 : MyReg<"x12">;
def X13 : MyReg<"x13">;
def X14 : MyReg<"x14">;
def X15 : MyReg<"x15">;

def ModeVT : ValueTypeByHwMode<[DefaultMode, TestMode],
[i32, i64]>;
let RegInfos = RegInfoByHwMode<[DefaultMode, TestMode],
[RegInfo<32,32,32>, RegInfo<64,64,64>]> in
def XRegs : MyClass<32, [ModeVT], (sequence "X%u", 0, 15)>;

def sub_even : SubRegIndex<32> {
let SubRegRanges = SubRegRangeByHwMode<[DefaultMode, TestMode],
[SubRegRange<32>, SubRegRange<64>]>;
}
def sub_odd : SubRegIndex<32, 32> {
let SubRegRanges = SubRegRangeByHwMode<[DefaultMode, TestMode],
[SubRegRange<32, 32>, SubRegRange<64, 64>]>;
}

def XPairs : RegisterTuples<[sub_even, sub_odd],
[(decimate (rotl XRegs, 0), 2),
(decimate (rotl XRegs, 1), 2)]>;

let RegInfos = RegInfoByHwMode<[DefaultMode, TestMode],
[RegInfo<64,64,32>, RegInfo<128,128,64>]> in
def XPairsClass : MyClass<64, [untyped], (add XPairs)>;

def TestTarget : Target;

// CHECK-LABEL: RegisterClass XRegs:
// CHECK: SpillSize: { Default:32 TestMode:64 }
// CHECK: SpillAlignment: { Default:32 TestMode:64 }
// CHECK: Regs: X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15

// CHECK-LABEL: RegisterClass XPairsClass:
// CHECK: SpillSize: { Default:64 TestMode:128 }
// CHECK: SpillAlignment: { Default:32 TestMode:64 }
// CHECK: CoveredBySubRegs: 1
// CHECK: Regs: X0_X1 X2_X3 X4_X5 X6_X7 X8_X9 X10_X11 X12_X13 X14_X15

// CHECK-LABEL: SubRegIndex sub_even:
// CHECK: Offset: { Default:0 TestMode:0 }
// CHECK: Size: { Default:32 TestMode:64 }
// CHECK-LABEL: SubRegIndex sub_odd:
// CHECK: Offset: { Default:32 TestMode:64 }
// CHECK: Size: { Default:32 TestMode:64 }
79 changes: 53 additions & 26 deletions llvm/utils/TableGen/Common/CodeGenRegisters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,24 @@ using namespace llvm;
// CodeGenSubRegIndex
//===----------------------------------------------------------------------===//

CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum)
CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum,
const CodeGenHwModes &CGH)
: TheDef(R), EnumValue(Enum), AllSuperRegsCovered(true), Artificial(true) {
Name = std::string(R->getName());
if (R->getValue("Namespace"))
Namespace = std::string(R->getValueAsString("Namespace"));
Size = R->getValueAsInt("Size");
Offset = R->getValueAsInt("Offset");

if (const RecordVal *RV = R->getValue("SubRegRanges"))
if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue()))
Range = SubRegRangeByHwMode(DI->getDef(), CGH);
if (!Range.hasDefault())
Range.insertSubRegRangeForMode(DefaultMode, SubRegRange(R));
}

CodeGenSubRegIndex::CodeGenSubRegIndex(StringRef N, StringRef Nspace,
unsigned Enum)
: TheDef(nullptr), Name(std::string(N)), Namespace(std::string(Nspace)),
Size(-1), Offset(-1), EnumValue(Enum), AllSuperRegsCovered(true),
Range(SubRegRange(-1, -1)), EnumValue(Enum), AllSuperRegsCovered(true),
Artificial(true) {}

std::string CodeGenSubRegIndex::getQualifiedName() const {
Expand All @@ -81,7 +86,7 @@ void CodeGenSubRegIndex::updateComponents(CodeGenRegBank &RegBank) {
"ComposedOf must have exactly two entries");
CodeGenSubRegIndex *A = RegBank.getSubRegIdx(Comps[0]);
CodeGenSubRegIndex *B = RegBank.getSubRegIdx(Comps[1]);
CodeGenSubRegIndex *X = A->addComposite(B, this);
CodeGenSubRegIndex *X = A->addComposite(B, this, RegBank.getHwModes());
if (X)
PrintFatalError(TheDef->getLoc(), "Ambiguous ComposedOf entries");
}
Expand Down Expand Up @@ -518,7 +523,8 @@ void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {

// Each part of Cand is a sub-register of this. Make the full Cand also
// a sub-register with a concatenated sub-register index.
CodeGenSubRegIndex *Concat = RegBank.getConcatSubRegIndex(Parts);
CodeGenSubRegIndex *Concat =
RegBank.getConcatSubRegIndex(Parts, RegBank.getHwModes());
std::pair<CodeGenSubRegIndex *, CodeGenRegister *> NewSubReg =
std::pair(Concat, Cand);

Expand All @@ -542,7 +548,7 @@ void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {
PrintFatalError(TheDef->getLoc(), "No SubRegIndex for " +
SubReg.second->getName() +
" in " + getName());
NewIdx->addComposite(SubReg.first, SubIdx);
NewIdx->addComposite(SubReg.first, SubIdx, RegBank.getHwModes());
}
}
}
Expand Down Expand Up @@ -1315,7 +1321,7 @@ CodeGenSubRegIndex *CodeGenRegBank::getSubRegIdx(Record *Def) {
CodeGenSubRegIndex *&Idx = Def2SubRegIdx[Def];
if (Idx)
return Idx;
SubRegIndices.emplace_back(Def, SubRegIndices.size() + 1);
SubRegIndices.emplace_back(Def, SubRegIndices.size() + 1, getHwModes());
Idx = &SubRegIndices.back();
return Idx;
}
Expand Down Expand Up @@ -1379,12 +1385,13 @@ CodeGenRegBank::getCompositeSubRegIndex(CodeGenSubRegIndex *A,
// None exists, synthesize one.
std::string Name = A->getName() + "_then_" + B->getName();
Comp = createSubRegIndex(Name, A->getNamespace());
A->addComposite(B, Comp);
A->addComposite(B, Comp, getHwModes());
return Comp;
}

CodeGenSubRegIndex *CodeGenRegBank::getConcatSubRegIndex(
const SmallVector<CodeGenSubRegIndex *, 8> &Parts) {
const SmallVector<CodeGenSubRegIndex *, 8> &Parts,
const CodeGenHwModes &CGH) {
assert(Parts.size() > 1 && "Need two parts to concatenate");
#ifndef NDEBUG
for (CodeGenSubRegIndex *Idx : Parts) {
Expand All @@ -1399,28 +1406,47 @@ CodeGenSubRegIndex *CodeGenRegBank::getConcatSubRegIndex(

// None exists, synthesize one.
std::string Name = Parts.front()->getName();
// Determine whether all parts are contiguous.
bool IsContinuous = true;
unsigned Size = Parts.front()->Size;
unsigned LastOffset = Parts.front()->Offset;
unsigned LastSize = Parts.front()->Size;
const unsigned UnknownSize = (uint16_t)-1;

for (unsigned i = 1, e = Parts.size(); i != e; ++i) {
Name += '_';
Name += Parts[i]->getName();
if (Size == UnknownSize || Parts[i]->Size == UnknownSize)
Size = UnknownSize;
else
Size += Parts[i]->Size;
if (LastSize == UnknownSize || Parts[i]->Offset != (LastOffset + LastSize))
IsContinuous = false;
LastOffset = Parts[i]->Offset;
LastSize = Parts[i]->Size;
}

Idx = createSubRegIndex(Name, Parts.front()->getNamespace());
Idx->Size = Size;
Idx->Offset = IsContinuous ? Parts.front()->Offset : -1;
Idx->ConcatenationOf.assign(Parts.begin(), Parts.end());

unsigned NumModes = CGH.getNumModeIds();
for (unsigned M = 0; M < NumModes; ++M) {
const CodeGenSubRegIndex *Part = Parts.front();

// Determine whether all parts are contiguous.
bool IsContinuous = true;
const SubRegRange &FirstPartRange = Part->Range.get(M);
unsigned Size = FirstPartRange.Size;
unsigned LastOffset = FirstPartRange.Offset;
unsigned LastSize = FirstPartRange.Size;

for (unsigned i = 1, e = Parts.size(); i != e; ++i) {
Part = Parts[i];
Name += '_';
Name += Part->getName();

const SubRegRange &PartRange = Part->Range.get(M);
if (Size == UnknownSize || PartRange.Size == UnknownSize)
Size = UnknownSize;
else
Size += PartRange.Size;
if (LastSize == UnknownSize ||
PartRange.Offset != (LastOffset + LastSize))
IsContinuous = false;
LastOffset = PartRange.Offset;
LastSize = PartRange.Size;
}
unsigned Offset = IsContinuous ? FirstPartRange.Offset : -1;
Idx->Range.get(M) = SubRegRange(Size, Offset);
}

return Idx;
}

Expand Down Expand Up @@ -1504,7 +1530,8 @@ void CodeGenRegBank::computeComposites() {
assert(Idx3 && "Sub-register doesn't have an index");

// Conflicting composition? Emit a warning but allow it.
if (CodeGenSubRegIndex *Prev = Idx1->addComposite(Idx2, Idx3)) {
if (CodeGenSubRegIndex *Prev =
Idx1->addComposite(Idx2, Idx3, getHwModes())) {
// If the composition was not user-defined, always emit a warning.
if (!UserDefined.count({Idx1, Idx2}) ||
agree(compose(Idx1, Idx2), SubRegAction.at(Idx3)))
Expand Down
43 changes: 33 additions & 10 deletions llvm/utils/TableGen/Common/CodeGenRegisters.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ class CodeGenSubRegIndex {
std::string Namespace;

public:
uint16_t Size;
uint16_t Offset;
SubRegRangeByHwMode Range;
const unsigned EnumValue;
mutable LaneBitmask LaneMask;
mutable SmallVector<MaskRolPair, 1> CompositionLaneMaskTransform;
Expand All @@ -86,7 +85,7 @@ class CodeGenSubRegIndex {
// indexes are not used to create new register classes.
bool Artificial;

CodeGenSubRegIndex(Record *R, unsigned Enum);
CodeGenSubRegIndex(Record *R, unsigned Enum, const CodeGenHwModes &CGH);
CodeGenSubRegIndex(StringRef N, StringRef Nspace, unsigned Enum);
CodeGenSubRegIndex(CodeGenSubRegIndex &) = delete;

Expand All @@ -108,19 +107,42 @@ class CodeGenSubRegIndex {

// Add a composite subreg index: this+A = B.
// Return a conflicting composite, or NULL
CodeGenSubRegIndex *addComposite(CodeGenSubRegIndex *A,
CodeGenSubRegIndex *B) {
CodeGenSubRegIndex *addComposite(CodeGenSubRegIndex *A, CodeGenSubRegIndex *B,
const CodeGenHwModes &CGH) {
assert(A && B);
std::pair<CompMap::iterator, bool> Ins = Composed.insert(std::pair(A, B));

// Synthetic subreg indices that aren't contiguous (for instance ARM
// register tuples) don't have a bit range, so it's OK to let
// B->Offset == -1. For the other cases, accumulate the offset and set
// the size here. Only do so if there is no offset yet though.
if ((Offset != (uint16_t)-1 && A->Offset != (uint16_t)-1) &&
(B->Offset == (uint16_t)-1)) {
B->Offset = Offset + A->Offset;
B->Size = A->Size;
unsigned NumModes = CGH.getNumModeIds();
// Skip default mode.
for (unsigned M = 0; M < NumModes; ++M) {
// Handle DefaultMode last.
if (M == DefaultMode)
continue;
SubRegRange &Range = this->Range.get(M);
SubRegRange &ARange = A->Range.get(M);
SubRegRange &BRange = B->Range.get(M);

if (Range.Offset != (uint16_t)-1 && ARange.Offset != (uint16_t)-1 &&
BRange.Offset == (uint16_t)-1) {
BRange.Offset = Range.Offset + ARange.Offset;
BRange.Size = ARange.Size;
}
}

// Now handle default.
SubRegRange &Range = this->Range.get(DefaultMode);
SubRegRange &ARange = A->Range.get(DefaultMode);
SubRegRange &BRange = B->Range.get(DefaultMode);
if (Range.Offset != (uint16_t)-1 && ARange.Offset != (uint16_t)-1 &&
BRange.Offset == (uint16_t)-1) {
BRange.Offset = Range.Offset + ARange.Offset;
BRange.Size = ARange.Size;
}

return (Ins.second || Ins.first->second == B) ? nullptr : Ins.first->second;
}

Expand Down Expand Up @@ -681,7 +703,8 @@ class CodeGenRegBank {
// Find or create a sub-register index representing the concatenation of
// non-overlapping sibling indices.
CodeGenSubRegIndex *
getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &);
getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &,
const CodeGenHwModes &CGH);

const std::deque<CodeGenRegister> &getRegisters() const { return Registers; }

Expand Down
Loading