[llvm] [X86] Pool sparse disassembler opcode rows (PR #202666)
David Zbarsky via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 07:02:13 PDT 2026
https://github.com/dzbarsky created https://github.com/llvm/llvm-project/pull/202666
The XOP, 3DNow, and VEX/EVEX map 4-7 decoder tables contain 1,760 context rows but only 266 distinct values. Keep the four common opcode maps as direct tables and intern rows only for these eight sparse maps.
This reduces fully stripped arm64 llvm-mc from 8,333,344 to 6,797,728 bytes, saving 1,535,616 bytes (18.43%). X86Disassembler.cpp.o decreases by 1,525,328 bytes (52.36%); constant data falls by 1,526,328 bytes while text grows by 848 bytes. The stripped all-tools multicall binary decreases from 145,103,200 to 143,567,584 bytes, saving 1,535,616 bytes (1.058%).
All 184 X86 disassembler tests pass. Output is byte-identical for 13,511 maintained-test sequences, 2,228,224 systematic opcode and ModR/M sequences, and 720,896 sparse-map sequences.
LLVM has no dedicated X86 decoder benchmark. The maintained-test workload measured 0.349 seconds patched versus 0.346 seconds baseline user CPU (+0.9%); the sparse-map workload measured 0.132 versus 0.131 seconds (+0.8%), both within run-to-run noise.
Work towards #202616
>From 11f728261deb4f5a894291607c5dee5dae2f0c95 Mon Sep 17 00:00:00 2001
From: David Zbarsky <dzbarsky at gmail.com>
Date: Mon, 8 Jun 2026 15:15:37 -0400
Subject: [PATCH] [X86] Pool sparse disassembler opcode rows
The XOP, 3DNow, and VEX/EVEX map 4-7 decoder tables contain 1,760 context rows but only 266 distinct values. Keep the four common opcode maps as direct tables and intern rows only for these eight sparse maps.
This reduces fully stripped arm64 llvm-mc from 8,333,344 to 6,797,728 bytes, saving 1,535,616 bytes (18.43%). X86Disassembler.cpp.o decreases by 1,525,328 bytes (52.36%); constant data falls by 1,526,328 bytes while text grows by 848 bytes. The stripped all-tools multicall binary decreases from 145,103,200 to 143,567,584 bytes, saving 1,535,616 bytes (1.058%).
All 184 X86 disassembler tests pass. Output is byte-identical for 13,511 maintained-test sequences, 2,228,224 systematic opcode and ModR/M sequences, and 720,896 sparse-map sequences.
LLVM has no dedicated X86 decoder benchmark. The maintained-test workload measured 0.349 seconds patched versus 0.346 seconds baseline user CPU (+0.9%); the sparse-map workload measured 0.132 versus 0.131 seconds (+0.8%), both within run-to-run noise.
---
.../Support/X86DisassemblerDecoderCommon.h | 22 +--
.../X86/Disassembler/X86Disassembler.cpp | 125 +++++-------------
llvm/utils/TableGen/DisassemblerEmitter.cpp | 13 +-
llvm/utils/TableGen/X86DisassemblerTables.cpp | 115 ++++++++++++----
llvm/utils/TableGen/X86DisassemblerTables.h | 34 +----
5 files changed, 141 insertions(+), 168 deletions(-)
diff --git a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
index 6f6f65dc075f3..199c3b17b7f22 100644
--- a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
+++ b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
@@ -26,14 +26,9 @@ namespace llvm::X86Disassembler {
#define TWOBYTE_SYM x86DisassemblerTwoByteOpcodes
#define THREEBYTE38_SYM x86DisassemblerThreeByte38Opcodes
#define THREEBYTE3A_SYM x86DisassemblerThreeByte3AOpcodes
-#define XOP8_MAP_SYM x86DisassemblerXOP8Opcodes
-#define XOP9_MAP_SYM x86DisassemblerXOP9Opcodes
-#define XOPA_MAP_SYM x86DisassemblerXOPAOpcodes
-#define THREEDNOW_MAP_SYM x86Disassembler3DNowOpcodes
-#define MAP4_SYM x86DisassemblerMap4Opcodes
-#define MAP5_SYM x86DisassemblerMap5Opcodes
-#define MAP6_SYM x86DisassemblerMap6Opcodes
-#define MAP7_SYM x86DisassemblerMap7Opcodes
+#define SPARSE_OPCODE_DECISIONS_SYM x86DisassemblerSparseOpcodeDecisions
+#define SPARSE_OPCODE_DECISION_INDICES_SYM \
+ x86DisassemblerSparseOpcodeDecisionIndices
#define INSTRUCTIONS_STR "x86DisassemblerInstrSpecifiers"
#define CONTEXTS_STR "x86DisassemblerContexts"
@@ -41,14 +36,9 @@ namespace llvm::X86Disassembler {
#define TWOBYTE_STR "x86DisassemblerTwoByteOpcodes"
#define THREEBYTE38_STR "x86DisassemblerThreeByte38Opcodes"
#define THREEBYTE3A_STR "x86DisassemblerThreeByte3AOpcodes"
-#define XOP8_MAP_STR "x86DisassemblerXOP8Opcodes"
-#define XOP9_MAP_STR "x86DisassemblerXOP9Opcodes"
-#define XOPA_MAP_STR "x86DisassemblerXOPAOpcodes"
-#define THREEDNOW_MAP_STR "x86Disassembler3DNowOpcodes"
-#define MAP4_STR "x86DisassemblerMap4Opcodes"
-#define MAP5_STR "x86DisassemblerMap5Opcodes"
-#define MAP6_STR "x86DisassemblerMap6Opcodes"
-#define MAP7_STR "x86DisassemblerMap7Opcodes"
+#define SPARSE_OPCODE_DECISIONS_STR "x86DisassemblerSparseOpcodeDecisions"
+#define SPARSE_OPCODE_DECISION_INDICES_STR \
+ "x86DisassemblerSparseOpcodeDecisionIndices"
// Attributes of an instruction that must be known before the opcode can be
// processed correctly. Most of these indicate the presence of particular
diff --git a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
index 7d2b5eb900133..d499dc43dcab6 100644
--- a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
+++ b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
@@ -85,6 +85,7 @@
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
@@ -121,70 +122,54 @@ struct ContextDecision {
#include "X86GenDisassemblerTables.inc"
-static InstrUID decode(OpcodeType type, InstructionContext insnContext,
- uint8_t opcode, uint8_t modRM) {
- const struct ModRMDecision *dec;
-
- switch (type) {
+static const ModRMDecision &
+getDecision(OpcodeType Type, InstructionContext Context, uint8_t Opcode) {
+ const OpcodeDecision *Decision;
+ switch (Type) {
case ONEBYTE:
- dec = &ONEBYTE_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
+ Decision = &ONEBYTE_SYM.opcodeDecisions[Context];
break;
case TWOBYTE:
- dec = &TWOBYTE_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
+ Decision = &TWOBYTE_SYM.opcodeDecisions[Context];
break;
case THREEBYTE_38:
- dec = &THREEBYTE38_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
+ Decision = &THREEBYTE38_SYM.opcodeDecisions[Context];
break;
case THREEBYTE_3A:
- dec = &THREEBYTE3A_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
- break;
- case XOP8_MAP:
- dec = &XOP8_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
- break;
- case XOP9_MAP:
- dec = &XOP9_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
- break;
- case XOPA_MAP:
- dec = &XOPA_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
- break;
- case THREEDNOW_MAP:
- dec =
- &THREEDNOW_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
- break;
- case MAP4:
- dec = &MAP4_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
+ Decision = &THREEBYTE3A_SYM.opcodeDecisions[Context];
break;
- case MAP5:
- dec = &MAP5_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
- break;
- case MAP6:
- dec = &MAP6_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
- break;
- case MAP7:
- dec = &MAP7_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
+ default:
+ static_assert(XOP8_MAP == 4 && MAP7 == 11);
+ unsigned DecisionIndex =
+ SPARSE_OPCODE_DECISION_INDICES_SYM[Type - XOP8_MAP][Context];
+ Decision = &SPARSE_OPCODE_DECISIONS_SYM[DecisionIndex];
break;
}
+ return Decision->modRMDecisions[Opcode];
+}
- switch (dec->modrm_type) {
+static LLVM_ATTRIBUTE_NOINLINE InstrUID
+decodeModRM(const ModRMDecision &Decision, uint8_t ModRM) {
+ switch (Decision.modrm_type) {
default:
llvm_unreachable("Corrupt table! Unknown modrm_type");
return 0;
case MODRM_ONEENTRY:
- return modRMTable[dec->instructionIDs];
+ llvm_unreachable("MODRM_ONEENTRY does not require a ModR/M byte");
case MODRM_SPLITRM:
- if (modFromModRM(modRM) == 0x3)
- return modRMTable[dec->instructionIDs + 1];
- return modRMTable[dec->instructionIDs];
+ if (modFromModRM(ModRM) == 0x3)
+ return modRMTable[Decision.instructionIDs + 1];
+ return modRMTable[Decision.instructionIDs];
case MODRM_SPLITREG:
- if (modFromModRM(modRM) == 0x3)
- return modRMTable[dec->instructionIDs + ((modRM & 0x38) >> 3) + 8];
- return modRMTable[dec->instructionIDs + ((modRM & 0x38) >> 3)];
+ if (modFromModRM(ModRM) == 0x3)
+ return modRMTable[Decision.instructionIDs + ((ModRM & 0x38) >> 3) + 8];
+ return modRMTable[Decision.instructionIDs + ((ModRM & 0x38) >> 3)];
case MODRM_SPLITMISC:
- if (modFromModRM(modRM) == 0x3)
- return modRMTable[dec->instructionIDs + (modRM & 0x3f) + 8];
- return modRMTable[dec->instructionIDs + ((modRM & 0x38) >> 3)];
+ if (modFromModRM(ModRM) == 0x3)
+ return modRMTable[Decision.instructionIDs + (ModRM & 0x3f) + 8];
+ return modRMTable[Decision.instructionIDs + ((ModRM & 0x38) >> 3)];
case MODRM_FULL:
- return modRMTable[dec->instructionIDs + modRM];
+ return modRMTable[Decision.instructionIDs + ModRM];
}
}
@@ -1094,55 +1079,15 @@ static int getInstructionIDWithAttrMask(uint16_t *instructionID,
struct InternalInstruction *insn,
uint16_t attrMask) {
auto insnCtx = InstructionContext(x86DisassemblerContexts[attrMask]);
- const ContextDecision *decision;
- switch (insn->opcodeType) {
- case ONEBYTE:
- decision = &ONEBYTE_SYM;
- break;
- case TWOBYTE:
- decision = &TWOBYTE_SYM;
- break;
- case THREEBYTE_38:
- decision = &THREEBYTE38_SYM;
- break;
- case THREEBYTE_3A:
- decision = &THREEBYTE3A_SYM;
- break;
- case XOP8_MAP:
- decision = &XOP8_MAP_SYM;
- break;
- case XOP9_MAP:
- decision = &XOP9_MAP_SYM;
- break;
- case XOPA_MAP:
- decision = &XOPA_MAP_SYM;
- break;
- case THREEDNOW_MAP:
- decision = &THREEDNOW_MAP_SYM;
- break;
- case MAP4:
- decision = &MAP4_SYM;
- break;
- case MAP5:
- decision = &MAP5_SYM;
- break;
- case MAP6:
- decision = &MAP6_SYM;
- break;
- case MAP7:
- decision = &MAP7_SYM;
- break;
- }
+ const ModRMDecision &Decision =
+ getDecision(insn->opcodeType, insnCtx, insn->opcode);
- if (decision->opcodeDecisions[insnCtx]
- .modRMDecisions[insn->opcode]
- .modrm_type != MODRM_ONEENTRY) {
+ if (Decision.modrm_type != MODRM_ONEENTRY) {
if (readModRM(insn))
return -1;
- *instructionID =
- decode(insn->opcodeType, insnCtx, insn->opcode, insn->modRM);
+ *instructionID = decodeModRM(Decision, insn->modRM);
} else {
- *instructionID = decode(insn->opcodeType, insnCtx, insn->opcode, 0);
+ *instructionID = modRMTable[Decision.instructionIDs];
}
return 0;
diff --git a/llvm/utils/TableGen/DisassemblerEmitter.cpp b/llvm/utils/TableGen/DisassemblerEmitter.cpp
index 5bc259a5fc8a4..8b505653752bd 100644
--- a/llvm/utils/TableGen/DisassemblerEmitter.cpp
+++ b/llvm/utils/TableGen/DisassemblerEmitter.cpp
@@ -41,12 +41,13 @@ using namespace llvm::X86Disassembler;
/// all cases as a 64-bit instruction with only OPSIZE set. (The XS prefix
/// may have effects on its execution, but does not change the instruction
/// returned.) This allows considerable space savings in other tables.
-/// - Six tables (ONEBYTE_SYM, TWOBYTE_SYM, THREEBYTE38_SYM, THREEBYTE3A_SYM,
-/// THREEBYTEA6_SYM, and THREEBYTEA7_SYM contain the hierarchy that the
-/// decoder traverses while decoding an instruction. At the lowest level of
-/// this hierarchy are instruction UIDs, 16-bit integers that can be used to
-/// uniquely identify the instruction and correspond exactly to its position
-/// in the list of CodeGenInstructions for the target.
+/// - The common opcode maps use direct context tables. The remaining sparse
+/// maps share unique rows in SPARSE_OPCODE_DECISIONS_SYM, with
+/// SPARSE_OPCODE_DECISION_INDICES_SYM mapping each sparse map and instruction
+/// context to a row. At the lowest level of this hierarchy are instruction
+/// UIDs, 16-bit integers that can be used to uniquely identify the
+/// instruction and correspond exactly to its position in the list of
+/// CodeGenInstructions for the target.
/// - One table (INSTRUCTIONS_SYM) contains information about the operands of
/// each instruction and how to decode them.
///
diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp
index 483fc58fcfba4..970706f4ef5e9 100644
--- a/llvm/utils/TableGen/X86DisassemblerTables.cpp
+++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp
@@ -20,6 +20,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
+#include <array>
#include <map>
using namespace llvm;
@@ -641,7 +642,7 @@ static inline bool outranks(InstructionContext upper,
///
/// @param decision - The decision to be compacted.
/// @return - The compactest available representation for the decision.
-static ModRMDecisionType getDecisionType(ModRMDecision &decision) {
+static ModRMDecisionType getDecisionType(const ModRMDecision &decision) {
bool satisfiesOneEntry = true;
bool satisfiesSplitRM = true;
bool satisfiesSplitReg = true;
@@ -841,20 +842,17 @@ void DisassemblerTables::emitContextDecision(raw_ostream &o1, raw_ostream &o2,
const char *name) const {
o2.indent(i2) << "static const struct ContextDecision " << name
<< " = {{/* opcodeDecisions */\n";
- i2++;
-
- for (unsigned index = 0; index < IC_max; ++index) {
- o2.indent(i2) << "/*";
- o2 << stringForContext((InstructionContext)index);
- o2 << "*/ ";
+ ++i2;
+ for (unsigned Index = 0; Index < IC_max; ++Index) {
+ o2.indent(i2) << "/*" << stringForContext(InstructionContext(Index))
+ << "*/ ";
emitOpcodeDecision(o1, o2, i1, i2, ModRMTableNum,
- decision.opcodeDecisions[index]);
+ decision.opcodeDecisions[Index]);
}
- i2--;
- o2.indent(i2) << "}};"
- << "\n";
+ --i2;
+ o2.indent(i2) << "}};\n";
}
void DisassemblerTables::emitInstructionInfo(raw_ostream &o,
@@ -1052,21 +1050,90 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2,
unsigned &i1, unsigned &i2,
unsigned &ModRMTableNum) const {
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[0], ONEBYTE_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[1], TWOBYTE_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[2],
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[ONEBYTE],
+ ONEBYTE_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[TWOBYTE],
+ TWOBYTE_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[THREEBYTE_38],
THREEBYTE38_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[3],
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[THREEBYTE_3A],
THREEBYTE3A_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[4], XOP8_MAP_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[5], XOP9_MAP_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[6], XOPA_MAP_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[7],
- THREEDNOW_MAP_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[8], MAP4_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[9], MAP5_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[10], MAP6_STR);
- emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[11], MAP7_STR);
+
+ using OpcodeDecisionKey = std::vector<uint16_t>;
+ std::map<OpcodeDecisionKey, unsigned> OpcodeDecisionMap;
+ std::array<std::array<unsigned, IC_max>, MAP7 - XOP8_MAP + 1> Indices;
+
+ o2 << "static const struct OpcodeDecision " SPARSE_OPCODE_DECISIONS_STR
+ "[] = {\n";
+ ++i2;
+
+ for (unsigned TableIndex = XOP8_MAP; TableIndex <= MAP7; ++TableIndex) {
+ for (unsigned ContextIndex = 0; ContextIndex < IC_max; ++ContextIndex) {
+ OpcodeDecision &Decision =
+ Tables[TableIndex]->opcodeDecisions[ContextIndex];
+ OpcodeDecisionKey Key;
+
+ for (const ModRMDecision &ModRM : Decision.modRMDecisions) {
+ ModRMDecisionType Type = getDecisionType(ModRM);
+ Key.push_back(Type);
+
+ switch (Type) {
+ default:
+ llvm_unreachable("Unknown decision type");
+ case MODRM_ONEENTRY:
+ Key.push_back(ModRM.instructionIDs[0]);
+ break;
+ case MODRM_SPLITRM:
+ Key.push_back(ModRM.instructionIDs[0x00]);
+ Key.push_back(ModRM.instructionIDs[0xc0]);
+ break;
+ case MODRM_SPLITREG:
+ for (unsigned Index = 0; Index < 64; Index += 8)
+ Key.push_back(ModRM.instructionIDs[Index]);
+ for (unsigned Index = 0xc0; Index < 256; Index += 8)
+ Key.push_back(ModRM.instructionIDs[Index]);
+ break;
+ case MODRM_SPLITMISC:
+ for (unsigned Index = 0; Index < 64; Index += 8)
+ Key.push_back(ModRM.instructionIDs[Index]);
+ for (unsigned Index = 0xc0; Index < 256; ++Index)
+ Key.push_back(ModRM.instructionIDs[Index]);
+ break;
+ case MODRM_FULL:
+ llvm::append_range(Key, ModRM.instructionIDs);
+ break;
+ }
+ }
+
+ auto [It, Inserted] = OpcodeDecisionMap.try_emplace(
+ std::move(Key), OpcodeDecisionMap.size());
+ Indices[TableIndex - XOP8_MAP][ContextIndex] = It->second;
+ if (Inserted)
+ emitOpcodeDecision(o1, o2, i1, i2, ModRMTableNum, Decision);
+ }
+ }
+
+ --i2;
+ o2 << "};\n\n";
+
+ assert(OpcodeDecisionMap.size() <= UINT16_MAX &&
+ "Too many unique sparse opcode decisions");
+ o2 << "static const uint16_t " SPARSE_OPCODE_DECISION_INDICES_STR
+ "[][IC_max] = {\n";
+ ++i2;
+ for (const auto &Table : Indices) {
+ o2.indent(i2) << "{\n";
+ ++i2;
+ for (unsigned ContextIndex = 0; ContextIndex < IC_max; ++ContextIndex) {
+ o2.indent(i2) << Table[ContextIndex] << ", // "
+ << stringForContext(InstructionContext(ContextIndex))
+ << "\n";
+ }
+ --i2;
+ o2.indent(i2) << "},\n";
+ }
+ --i2;
+ o2 << "};\n";
}
void DisassemblerTables::emit(raw_ostream &o) const {
diff --git a/llvm/utils/TableGen/X86DisassemblerTables.h b/llvm/utils/TableGen/X86DisassemblerTables.h
index 325bb572b0587..cc075dc203877 100644
--- a/llvm/utils/TableGen/X86DisassemblerTables.h
+++ b/llvm/utils/TableGen/X86DisassemblerTables.h
@@ -123,36 +123,6 @@ class DisassemblerTables {
unsigned &i2, unsigned &ModRMTableNum,
OpcodeDecision &decision) const;
- /// emitContextDecision - Emits a ContextDecision and all its subsidiary
- /// Opcode and ModRMDecisions. A ContextDecision is printed as:
- ///
- /// struct ContextDecision NAME = {
- /// { /* OpcodeDecisions */
- /// /* IC */
- /// { /* struct OpcodeDecision */
- /// ...
- /// },
- /// ...
- /// }
- /// }
- ///
- /// NAME is the name of the ContextDecision (typically one of the four names
- /// ONEBYTE_SYM, TWOBYTE_SYM, THREEBYTE38_SYM, THREEBYTE3A_SYM from
- /// X86DisassemblerDecoderCommon.h).
- /// IC is one of the contexts in InstructionContext. There is an opcode
- /// decision for each possible context.
- /// The OpcodeDecision structures are printed as described in the
- /// documentation for emitOpcodeDecision.
- ///
- /// @param o1 - The output stream to print the ID tables generated by
- /// emitModRMDecision() to.
- /// @param o2 - The output stream to print the decision structure to.
- /// @param i1 - The indent level to use with stream o1.
- /// @param i2 - The indent level to use with stream o2.
- /// @param ModRMTableNum - next table number for adding to ModRMTable.
- /// @param decision - The ContextDecision to emit along with its subsidiary
- /// structures.
- /// @param name - The name for the ContextDecision.
void emitContextDecision(raw_ostream &o1, raw_ostream &o2, unsigned &i1,
unsigned &i2, unsigned &ModRMTableNum,
ContextDecision &decision, const char *name) const;
@@ -205,8 +175,8 @@ class DisassemblerTables {
/// @param i - The indent level for use with the stream.
void emitContextTable(raw_ostream &o, uint32_t &i) const;
- /// emitContextDecisions - Prints all four ContextDecision structures using
- /// emitContextDecision().
+ /// emitContextDecisions - Prints direct tables for the common opcode maps,
+ /// then a pool and index table for the remaining sparse maps.
///
/// @param o1 - The output stream to print the ID tables generated by
/// emitModRMDecision() to.
More information about the llvm-commits
mailing list