Skip to content

[TableGen] Introduce a less aggressive suppression for HwMode Decoder… #86060

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 2 commits into from
Apr 1, 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
9 changes: 4 additions & 5 deletions llvm/test/TableGen/HwModeEncodeDecode2.td
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | \
// RUN: FileCheck %s --check-prefix=DECODER
// RUN: llvm-tblgen -gen-disassembler --suppress-per-hwmode-duplicates -I \
// RUN: llvm-tblgen -gen-disassembler --suppress-per-hwmode-duplicates=O2 -I \
// RUN: %p/../../include %s | FileCheck %s --check-prefix=DECODER-SUPPRESS

// Test duplicate table suppression for per-HwMode decoders.
Expand Down Expand Up @@ -105,11 +105,10 @@ let OutOperandList = (outs) in {
// DECODER-DAG: Opcode: fooTypeEncA:baz
// DECODER-DAG: Opcode: bar


// DECODER-SUPPRESS-LABEL: DecoderTableAlt_AllModes32[] =
// DECODER-SUPPRESS-DAG: Opcode: unrelated
// DECODER-SUPPRESS-LABEL: DecoderTable_AllModes32[] =
// DECODER-SUPPRESS-LABEL: DecoderTable32[] =
// DECODER-SUPPRESS-DAG: Opcode: bar
// DECODER-SUPPRESS-LABEL: DecoderTableAlt32[] =
// DECODER-SUPPRESS-DAG: Opcode: unrelated
// DECODER-SUPPRESS-LABEL: DecoderTable_ModeA32[] =
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncA:foo
// DECODER-SUPPRESS-NOT: Opcode: bar
Expand Down
71 changes: 49 additions & 22 deletions llvm/test/TableGen/HwModeEncodeDecode3.td
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// RUN: FileCheck %s --check-prefix=ENCODER
// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | \
// RUN: FileCheck %s --check-prefix=DECODER
// RUN: llvm-tblgen -gen-disassembler --suppress-per-hwmode-duplicates -I \
// RUN: %p/../../include %s | FileCheck %s --check-prefix=DECODER-SUPPRESS
// RUN: llvm-tblgen -gen-disassembler --suppress-per-hwmode-duplicates=O1 -I \
// RUN: %p/../../include %s | FileCheck %s --check-prefix=DECODER-SUPPRESS-O1
// RUN: llvm-tblgen -gen-disassembler --suppress-per-hwmode-duplicates=O2 -I \
// RUN: %p/../../include %s | FileCheck %s --check-prefix=DECODER-SUPPRESS-O2

include "llvm/Target/Target.td"

Expand Down Expand Up @@ -99,16 +101,20 @@ def unrelated: Instruction {
}


// DECODER-LABEL: DecoderTableAlt_DefaultMode32[] =
// Under default settings, using 'HwMode' to dictate instruction encodings results in
// significant duplication of DecoderTables. The three tables ‘DecoderTableAlt32’,
// ‘DecoderTableAlt_ModeA32’, and ‘DecoderTableAlt_ModeB32’ are exact duplicates and
// could effectively be merged into one.
// DECODER-LABEL: DecoderTable32[] =
// DECODER-DAG: Opcode: bar
// DECODER-LABEL: DecoderTable64[] =
// DECODER-DAG: Opcode: fooTypeEncDefault:foo
// DECODER-LABEL: DecoderTableAlt32[] =
// DECODER-DAG: Opcode: unrelated
// DECODER-LABEL: DecoderTableAlt_ModeA32[] =
// DECODER-DAG: Opcode: unrelated
// DECODER-LABEL: DecoderTableAlt_ModeB32[] =
// DECODER-DAG: Opcode: unrelated
// DECODER-LABEL: DecoderTable_DefaultMode32[] =
// DECODER-DAG: Opcode: bar
// DECODER-LABEL: DecoderTable_DefaultMode64[] =
// DECODER-DAG: Opcode: fooTypeEncDefault:foo
// DECODER-LABEL: DecoderTable_ModeA32[] =
// DECODER-DAG: Opcode: fooTypeEncA:foo
// DECODER-DAG: Opcode: bar
Expand All @@ -117,21 +123,42 @@ def unrelated: Instruction {
// DECODER-DAG: Opcode: fooTypeEncA:baz
// DECODER-DAG: Opcode: bar


// DECODER-SUPPRESS-LABEL: DecoderTableAlt_AllModes32[] =
// DECODER-SUPPRESS-DAG: Opcode: unrelated
// DECODER-SUPPRESS-LABEL: DecoderTable_AllModes32[] =
// DECODER-SUPPRESS-DAG: Opcode: bar
// DECODER-SUPPRESS-LABEL: DecoderTable_DefaultMode64[] =
// DECODER-SUPPRESS-NOT: Opcode: bar
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncDefault:foo
// DECODER-SUPPRESS-LABEL: DecoderTable_ModeA32[] =
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncA:foo
// DECODER-SUPPRESS-NOT: Opcode: bar
// DECODER-SUPPRESS-LABEL: DecoderTable_ModeB32[] =
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncB:foo
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncA:baz
// DECODER-SUPPRESS-NOT: Opcode: bar
// Under the 'O1' optimization level, unnecessary duplicate tables will be eliminated,
// reducing the three ‘Alt’ tables down to just one.
// DECODER-SUPPRESS-O1-LABEL: DecoderTable32[] =
// DECODER-SUPPRESS-O1-DAG: Opcode: bar
// DECODER-SUPPRESS-O1-LABEL: DecoderTable64[] =
// DECODER-SUPPRESS-O1-DAG: Opcode: fooTypeEncDefault:foo
// DECODER-SUPPRESS-O1-LABEL: DecoderTableAlt32[] =
// DECODER-SUPPRESS-O1-DAG: Opcode: unrelated
// DECODER-SUPPRESS-O1-LABEL: DecoderTable_ModeA32[] =
// DECODER-SUPPRESS-O1-DAG: Opcode: fooTypeEncA:foo
// DECODER-SUPPRESS-O1-DAG: Opcode: bar
// DECODER-SUPPRESS-O1-LABEL: DecoderTable_ModeB32[] =
// DECODER-SUPPRESS-O1-DAG: Opcode: fooTypeEncB:foo
// DECODER-SUPPRESS-O1-DAG: Opcode: fooTypeEncA:baz
// DECODER-SUPPRESS-O1-DAG: Opcode: bar

// Under the 'O2' optimization condition, instructions possessing the 'EncodingByHwMode'
// attribute will be extracted from their original DecoderNamespace and placed into their
// respective HwMode tables. Meanwhile, other instructions that do not have the 'EncodingByHwMode'
// attribute but are within the same DecoderNamespace will be stored in the 'Default' table. This
// approach will significantly reduce instruction redundancy, but it necessitates users to thoroughly
// consider the interplay between HwMode and DecoderNamespace for their instructions.
// DECODER-SUPPRESS-O2-LABEL: DecoderTable32[] =
// DECODER-SUPPRESS-O2-DAG: Opcode: bar
// DECODER-SUPPRESS-O2-LABEL: DecoderTable64[] =
// DECODER-SUPPRESS-O2-NOT: Opcode: bar
// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncDefault:foo
// DECODER-SUPPRESS-O2-LABEL: DecoderTableAlt32[] =
// DECODER-SUPPRESS-O2-DAG: Opcode: unrelated
// DECODER-SUPPRESS-O2-LABEL: DecoderTable_ModeA32[] =
// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncA:foo
// DECODER-SUPPRESS-O2-NOT: Opcode: bar
// DECODER-SUPPRESS-O2-LABEL: DecoderTable_ModeB32[] =
// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncB:foo
// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncA:baz
// DECODER-SUPPRESS-O2-NOT: Opcode: bar

// ENCODER-LABEL: static const uint64_t InstBits_DefaultMode[] = {
// ENCODER: UINT64_C(2), // bar
Expand Down
104 changes: 84 additions & 20 deletions llvm/utils/TableGen/DecoderEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,27 @@ using namespace llvm;

extern cl::OptionCategory DisassemblerEmitterCat;

cl::opt<bool> DecoderEmitterSuppressDuplicates(
enum SuppressLevel {
SUPPRESSION_DISABLE,
SUPPRESSION_LEVEL1,
SUPPRESSION_LEVEL2
};

cl::opt<SuppressLevel> DecoderEmitterSuppressDuplicates(
"suppress-per-hwmode-duplicates",
cl::desc("Suppress duplication of instrs into per-HwMode decoder tables"),
cl::init(false), cl::cat(DisassemblerEmitterCat));
cl::values(
clEnumValN(
SUPPRESSION_DISABLE, "O0",
"Do not prevent DecoderTable duplications caused by HwModes"),
clEnumValN(
SUPPRESSION_LEVEL1, "O1",
"Remove duplicate DecoderTable entries generated due to HwModes"),
clEnumValN(
SUPPRESSION_LEVEL2, "O2",
"Extract HwModes-specific instructions into new DecoderTables, "
"significantly reducing Table Duplications")),
cl::init(SUPPRESSION_DISABLE), cl::cat(DisassemblerEmitterCat));

namespace {

Expand Down Expand Up @@ -128,6 +145,7 @@ struct EncodingIDAndOpcode {
};

using EncodingIDsVec = std::vector<EncodingIDAndOpcode>;
using NamespacesHwModesMap = std::map<std::string, std::set<StringRef>>;

raw_ostream &operator<<(raw_ostream &OS, const EncodingAndInst &Value) {
if (Value.EncodingDef != Value.Inst->TheDef)
Expand Down Expand Up @@ -2417,21 +2435,65 @@ static bool Check(DecodeStatus &Out, DecodeStatus In) {

// Collect all HwModes referenced by the target for encoding purposes,
// returning a vector of corresponding names.
static void
collectHwModesReferencedForEncodings(const CodeGenHwModes &HWM,
std::vector<StringRef> &Names) {
static void collectHwModesReferencedForEncodings(
const CodeGenHwModes &HWM, std::vector<StringRef> &Names,
NamespacesHwModesMap &NamespacesWithHwModes) {
SmallBitVector BV(HWM.getNumModeIds());
for (const auto &MS : HWM.getHwModeSelects()) {
for (const HwModeSelect::PairType &P : MS.second.Items) {
if (P.second->isSubClassOf("InstructionEncoding"))
if (P.second->isSubClassOf("InstructionEncoding")) {
std::string DecoderNamespace =
std::string(P.second->getValueAsString("DecoderNamespace"));
if (P.first == DefaultMode) {
NamespacesWithHwModes[DecoderNamespace].insert("");
} else {
NamespacesWithHwModes[DecoderNamespace].insert(
HWM.getMode(P.first).Name);
}
BV.set(P.first);
}
}
}
transform(BV.set_bits(), std::back_inserter(Names), [&HWM](const int &M) {
if (M == DefaultMode)
return StringRef("");
return HWM.getModeName(M, /*IncludeDefault=*/true);
});
}

static void
handleHwModesUnrelatedEncodings(const CodeGenInstruction *Instr,
const std::vector<StringRef> &HwModeNames,
NamespacesHwModesMap &NamespacesWithHwModes,
std::vector<EncodingAndInst> &GlobalEncodings) {
const Record *InstDef = Instr->TheDef;

switch (DecoderEmitterSuppressDuplicates) {
case SUPPRESSION_DISABLE: {
for (StringRef HwModeName : HwModeNames)
GlobalEncodings.emplace_back(InstDef, Instr, HwModeName);
break;
}
case SUPPRESSION_LEVEL1: {
std::string DecoderNamespace =
std::string(InstDef->getValueAsString("DecoderNamespace"));
auto It = NamespacesWithHwModes.find(DecoderNamespace);
if (It != NamespacesWithHwModes.end()) {
for (StringRef HwModeName : It->second)
GlobalEncodings.emplace_back(InstDef, Instr, HwModeName);
} else {
// Only emit the encoding once, as it's DecoderNamespace doesn't
// contain any HwModes.
GlobalEncodings.emplace_back(InstDef, Instr, "");
}
break;
}
case SUPPRESSION_LEVEL2:
GlobalEncodings.emplace_back(InstDef, Instr, "");
break;
}
}

// Emits disassembler code for instruction decoding.
void DecoderEmitter::run(raw_ostream &o) {
formatted_raw_ostream OS(o);
Expand All @@ -2457,10 +2519,12 @@ namespace llvm {
// Parameterize the decoders based on namespace and instruction width.

// First, collect all encoding-related HwModes referenced by the target.
// And establish a mapping table between DecoderNamespace and HwMode.
// If HwModeNames is empty, add the empty string so we always have one HwMode.
const CodeGenHwModes &HWM = Target.getHwModes();
std::vector<StringRef> HwModeNames;
collectHwModesReferencedForEncodings(HWM, HwModeNames);
NamespacesHwModesMap NamespacesWithHwModes;
collectHwModesReferencedForEncodings(HWM, HwModeNames, NamespacesWithHwModes);
if (HwModeNames.empty())
HwModeNames.push_back("");

Expand All @@ -2471,22 +2535,22 @@ namespace llvm {
if (const RecordVal *RV = InstDef->getValue("EncodingInfos")) {
if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
EncodingInfoByHwMode EBM(DI->getDef(), HWM);
for (auto &KV : EBM)
NumberedEncodings.emplace_back(
KV.second, NumberedInstruction,
HWM.getModeName(KV.first, /*IncludeDefault=*/true));
for (auto &[ModeId, Encoding] : EBM) {
// DecoderTables with DefaultMode should not have any suffix.
if (ModeId == DefaultMode) {
NumberedEncodings.emplace_back(Encoding, NumberedInstruction, "");
} else {
NumberedEncodings.emplace_back(Encoding, NumberedInstruction,
HWM.getMode(ModeId).Name);
}
}
continue;
}
}
// This instruction is encoded the same on all HwModes. Emit it for all
// HwModes by default, otherwise leave it in a single common table.
if (DecoderEmitterSuppressDuplicates) {
NumberedEncodings.emplace_back(InstDef, NumberedInstruction, "AllModes");
} else {
for (StringRef HwModeName : HwModeNames)
NumberedEncodings.emplace_back(InstDef, NumberedInstruction,
HwModeName);
}
// This instruction is encoded the same on all HwModes.
// According to user needs, provide varying degrees of suppression.
handleHwModesUnrelatedEncodings(NumberedInstruction, HwModeNames,
NamespacesWithHwModes, NumberedEncodings);
}
for (const auto &NumberedAlias :
RK.getAllDerivedDefinitions("AdditionalEncoding"))
Expand Down