Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 5ef1349

Browse files
committed
[TableGen] Modify the AsmMatcherEmitter to only apply the table growth from r252440 to the Hexagon target.
This restores the previous behavior of not including the mnemonic in the classes table for every target that starts instruction lines with the mnemonic. Not only did the table size increase by 1 entry, but the class enum increased in size which caused every class in the array to increase in size. It also grew the size of the function that parsers tokens into classes by a substantial amount. This adds a new HasMnemonicFirst flag to all AsmParsers. It's set to 1 by default and Hexagon target overrides it to 0. For the X86 target alone this recovers 324KB of size on the llvm-mc executable. I believe the current state is still a bad design choice for the Hexagon target as it causes most of the parsing to do a linear search through the entire match table to comparing operands against every instruction until it finds one that works. At least for the other targets we do a binary search based on mnemonic over which to do the linear scan. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256669 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 1159059 commit 5ef1349

File tree

3 files changed

+119
-63
lines changed

3 files changed

+119
-63
lines changed

include/llvm/Target/Target.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,10 @@ class AsmParser {
936936
// ShouldEmitMatchRegisterName - Set to false if the target needs a hand
937937
// written register name matcher
938938
bit ShouldEmitMatchRegisterName = 1;
939+
940+
// HasMnemonicFirst - Set to false if target instructions don't always
941+
// start with a mnemonic as the first token.
942+
bit HasMnemonicFirst = 1;
939943
}
940944
def DefaultAsmParser : AsmParser;
941945

lib/Target/Hexagon/Hexagon.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ def : Proc<"hexagonv60", HexagonModelV60,
251251
// Declare the target which we are implementing
252252
//===----------------------------------------------------------------------===//
253253

254+
def HexagonAsmParser : AsmParser {
255+
bit HasMnemonicFirst = 0;
256+
}
257+
254258
def HexagonAsmParserVariant : AsmParserVariant {
255259
int Variant = 0;
256260
string TokenizingCharacters = "#()=:.<>!+*";
@@ -259,5 +263,6 @@ def HexagonAsmParserVariant : AsmParserVariant {
259263
def Hexagon : Target {
260264
// Pull in Instruction Info:
261265
let InstructionSet = HexagonInstrInfo;
266+
let AssemblyParsers = [HexagonAsmParser];
262267
let AssemblyParserVariants = [HexagonAsmParserVariant];
263268
}

utils/TableGen/AsmMatcherEmitter.cpp

Lines changed: 110 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,8 @@ struct MatchableInfo {
493493

494494
void initialize(const AsmMatcherInfo &Info,
495495
SmallPtrSetImpl<Record*> &SingletonRegisters,
496-
AsmVariantInfo const &Variant);
496+
AsmVariantInfo const &Variant,
497+
bool HasMnemonicFirst);
497498

498499
/// validate - Return true if this matchable is a valid thing to match against
499500
/// and perform a bunch of validity checking.
@@ -836,14 +837,33 @@ extractSingletonRegisterForAsmOperand(MatchableInfo::AsmOperand &Op,
836837

837838
void MatchableInfo::initialize(const AsmMatcherInfo &Info,
838839
SmallPtrSetImpl<Record*> &SingletonRegisters,
839-
AsmVariantInfo const &Variant) {
840+
AsmVariantInfo const &Variant,
841+
bool HasMnemonicFirst) {
840842
AsmVariantID = Variant.AsmVariantNo;
841843
AsmString =
842844
CodeGenInstruction::FlattenAsmStringVariants(AsmString,
843845
Variant.AsmVariantNo);
844846

845847
tokenizeAsmString(Info, Variant);
846848

849+
// The first token of the instruction is the mnemonic, which must be a
850+
// simple string, not a $foo variable or a singleton register.
851+
if (AsmOperands.empty())
852+
PrintFatalError(TheDef->getLoc(),
853+
"Instruction '" + TheDef->getName() + "' has no tokens");
854+
855+
assert(!AsmOperands[0].Token.empty());
856+
if (HasMnemonicFirst) {
857+
Mnemonic = AsmOperands[0].Token;
858+
if (Mnemonic[0] == '$')
859+
PrintFatalError(TheDef->getLoc(),
860+
"Invalid instruction mnemonic '" + Mnemonic + "'!");
861+
862+
// Remove the first operand, it is tracked in the mnemonic field.
863+
AsmOperands.erase(AsmOperands.begin());
864+
} else if (AsmOperands[0].Token[0] != '$')
865+
Mnemonic = AsmOperands[0].Token;
866+
847867
// Compute the require features.
848868
for (Record *Predicate : TheDef->getValueAsListOfDefs("Predicates"))
849869
if (const SubtargetFeatureInfo *Feature =
@@ -953,15 +973,6 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info,
953973
}
954974
if (InTok && Prev != String.size())
955975
addAsmOperand(String.substr(Prev), IsIsolatedToken);
956-
957-
// The first token of the instruction is the mnemonic, which must be a
958-
// simple string, not a $foo variable or a singleton register.
959-
if (AsmOperands.empty())
960-
PrintFatalError(TheDef->getLoc(),
961-
"Instruction '" + TheDef->getName() + "' has no tokens");
962-
assert(!AsmOperands[0].Token.empty());
963-
if (AsmOperands[0].Token[0] != '$')
964-
Mnemonic = AsmOperands[0].Token;
965976
}
966977

967978
bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const {
@@ -1369,6 +1380,8 @@ void AsmMatcherInfo::buildInfo() {
13691380
assert(SubtargetFeatures.size() <= 64 && "Too many subtarget features!");
13701381
}
13711382

1383+
bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst");
1384+
13721385
// Parse the instructions; we need to do this first so that we can gather the
13731386
// singleton register classes.
13741387
SmallPtrSet<Record*, 16> SingletonRegisters;
@@ -1400,7 +1413,7 @@ void AsmMatcherInfo::buildInfo() {
14001413

14011414
auto II = llvm::make_unique<MatchableInfo>(*CGI);
14021415

1403-
II->initialize(*this, SingletonRegisters, Variant);
1416+
II->initialize(*this, SingletonRegisters, Variant, HasMnemonicFirst);
14041417

14051418
// Ignore instructions which shouldn't be matched and diagnose invalid
14061419
// instruction definitions with an error.
@@ -1428,7 +1441,7 @@ void AsmMatcherInfo::buildInfo() {
14281441

14291442
auto II = llvm::make_unique<MatchableInfo>(std::move(Alias));
14301443

1431-
II->initialize(*this, SingletonRegisters, Variant);
1444+
II->initialize(*this, SingletonRegisters, Variant, HasMnemonicFirst);
14321445

14331446
// Validate the alias definitions.
14341447
II->validate(CommentDelimiter, false);
@@ -1734,7 +1747,7 @@ static unsigned getConverterOperandID(const std::string &Name,
17341747

17351748
static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
17361749
std::vector<std::unique_ptr<MatchableInfo>> &Infos,
1737-
raw_ostream &OS) {
1750+
bool HasMnemonicFirst, raw_ostream &OS) {
17381751
SmallSetVector<std::string, 16> OperandConversionKinds;
17391752
SmallSetVector<std::string, 16> InstructionConversionKinds;
17401753
std::vector<std::vector<uint8_t> > ConversionTable;
@@ -1868,7 +1881,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
18681881

18691882
// Add the operand entry to the instruction kind conversion row.
18701883
ConversionRow.push_back(ID);
1871-
ConversionRow.push_back(OpInfo.AsmOperandNum);
1884+
ConversionRow.push_back(OpInfo.AsmOperandNum + HasMnemonicFirst);
18721885

18731886
if (!IsNewConverter)
18741887
break;
@@ -2472,7 +2485,7 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info,
24722485
static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
24732486
const AsmMatcherInfo &Info, StringRef ClassName,
24742487
StringToOffsetTable &StringTable,
2475-
unsigned MaxMnemonicIndex) {
2488+
unsigned MaxMnemonicIndex, bool HasMnemonicFirst) {
24762489
unsigned MaxMask = 0;
24772490
for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) {
24782491
MaxMask |= OMI.OperandMask;
@@ -2586,19 +2599,25 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
25862599
OS << " uint64_t AvailableFeatures = getAvailableFeatures();\n\n";
25872600

25882601
OS << " // Get the next operand index.\n";
2589-
OS << " unsigned NextOpNum = Operands.size();\n";
2602+
OS << " unsigned NextOpNum = Operands.size()"
2603+
<< (HasMnemonicFirst ? " - 1" : "") << ";\n";
25902604

25912605
// Emit code to search the table.
25922606
OS << " // Search the table.\n";
2593-
OS << " std::pair<const OperandMatchEntry*, const OperandMatchEntry*>";
2594-
OS << " MnemonicRange\n";
2595-
OS << " (OperandMatchTable, OperandMatchTable+";
2596-
OS << Info.OperandMatchInfo.size() << ");\n";
2597-
OS << " if(!Mnemonic.empty())\n";
2598-
OS << " MnemonicRange = std::equal_range(OperandMatchTable,";
2599-
OS << " OperandMatchTable+"
2600-
<< Info.OperandMatchInfo.size() << ", Mnemonic,\n"
2601-
<< " LessOpcodeOperand());\n\n";
2607+
if (HasMnemonicFirst) {
2608+
OS << " auto MnemonicRange =\n";
2609+
OS << " std::equal_range(std::begin(OperandMatchTable), "
2610+
"std::end(OperandMatchTable),\n";
2611+
OS << " Mnemonic, LessOpcodeOperand());\n\n";
2612+
} else {
2613+
OS << " auto MnemonicRange = std::make_pair(std::begin(OperandMatchTable),"
2614+
" std::end(OperandMatchTable));\n";
2615+
OS << " if (!Mnemonic.empty())\n";
2616+
OS << " MnemonicRange =\n";
2617+
OS << " std::equal_range(std::begin(OperandMatchTable), "
2618+
"std::end(OperandMatchTable),\n";
2619+
OS << " Mnemonic, LessOpcodeOperand());\n\n";
2620+
}
26022621

26032622
OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
26042623
OS << " return MatchOperand_NoMatch;\n\n";
@@ -2683,6 +2702,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
26832702
// Compute the information on the custom operand parsing.
26842703
Info.buildOperandMatchInfo();
26852704

2705+
bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst");
2706+
26862707
// Write the output.
26872708

26882709
// Information for the class declaration.
@@ -2697,7 +2718,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
26972718
<< "&Operands);\n";
26982719
OS << " void convertToMapAndConstraints(unsigned Kind,\n ";
26992720
OS << " const OperandVector &Operands) override;\n";
2700-
OS << " bool mnemonicIsValid(StringRef Mnemonic, unsigned VariantID);\n";
2721+
if (HasMnemonicFirst)
2722+
OS << " bool mnemonicIsValid(StringRef Mnemonic, unsigned VariantID);\n";
27012723
OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n"
27022724
<< " MCInst &Inst,\n"
27032725
<< " uint64_t &ErrorInfo,"
@@ -2758,7 +2780,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
27582780
// Generate the convertToMCInst function to convert operands into an MCInst.
27592781
// Also, generate the convertToMapAndConstraints function for MS-style inline
27602782
// assembly. The latter doesn't actually generate a MCInst.
2761-
emitConvertFuncs(Target, ClassName, Info.Matchables, OS);
2783+
emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst, OS);
27622784

27632785
// Emit the enumeration for classes which participate in matching.
27642786
emitMatchClassEnumeration(Target, Info.Classes, OS);
@@ -2880,24 +2902,26 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
28802902
}
28812903

28822904
// A method to determine if a mnemonic is in the list.
2883-
OS << "bool " << Target.getName() << ClassName << "::\n"
2884-
<< "mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) {\n";
2885-
OS << " // Find the appropriate table for this asm variant.\n";
2886-
OS << " const MatchEntry *Start, *End;\n";
2887-
OS << " switch (VariantID) {\n";
2888-
OS << " default: llvm_unreachable(\"invalid variant!\");\n";
2889-
for (unsigned VC = 0; VC != VariantCount; ++VC) {
2890-
Record *AsmVariant = Target.getAsmParserVariant(VC);
2891-
int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
2892-
OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC
2893-
<< "); End = std::end(MatchTable" << VC << "); break;\n";
2905+
if (HasMnemonicFirst) {
2906+
OS << "bool " << Target.getName() << ClassName << "::\n"
2907+
<< "mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) {\n";
2908+
OS << " // Find the appropriate table for this asm variant.\n";
2909+
OS << " const MatchEntry *Start, *End;\n";
2910+
OS << " switch (VariantID) {\n";
2911+
OS << " default: llvm_unreachable(\"invalid variant!\");\n";
2912+
for (unsigned VC = 0; VC != VariantCount; ++VC) {
2913+
Record *AsmVariant = Target.getAsmParserVariant(VC);
2914+
int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
2915+
OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC
2916+
<< "); End = std::end(MatchTable" << VC << "); break;\n";
2917+
}
2918+
OS << " }\n";
2919+
OS << " // Search the table.\n";
2920+
OS << " auto MnemonicRange = ";
2921+
OS << "std::equal_range(Start, End, Mnemonic, LessOpcode());\n";
2922+
OS << " return MnemonicRange.first != MnemonicRange.second;\n";
2923+
OS << "}\n\n";
28942924
}
2895-
OS << " }\n";
2896-
OS << " // Search the table.\n";
2897-
OS << " std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =\n";
2898-
OS << " std::equal_range(Start, End, Mnemonic, LessOpcode());\n";
2899-
OS << " return MnemonicRange.first != MnemonicRange.second;\n";
2900-
OS << "}\n\n";
29012925

29022926
// Finally, build the match function.
29032927
OS << "unsigned " << Target.getName() << ClassName << "::\n"
@@ -2906,8 +2930,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
29062930
<< " bool matchingInlineAsm, unsigned VariantID) {\n";
29072931

29082932
OS << " // Eliminate obvious mismatches.\n";
2909-
OS << " if (Operands.size() > " << MaxNumOperands << ") {\n";
2910-
OS << " ErrorInfo = " << MaxNumOperands << ";\n";
2933+
OS << " if (Operands.size() > "
2934+
<< (MaxNumOperands + HasMnemonicFirst) << ") {\n";
2935+
OS << " ErrorInfo = "
2936+
<< (MaxNumOperands + HasMnemonicFirst) << ";\n";
29112937
OS << " return Match_InvalidOperand;\n";
29122938
OS << " }\n\n";
29132939

@@ -2916,10 +2942,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
29162942
OS << " uint64_t AvailableFeatures = getAvailableFeatures();\n\n";
29172943

29182944
OS << " // Get the instruction mnemonic, which is the first token.\n";
2919-
OS << " StringRef Mnemonic;\n";
2920-
OS << " if (Operands[0]->isToken())\n";
2921-
OS << " Mnemonic = ((" << Target.getName()
2922-
<< "Operand&)*Operands[0]).getToken();\n\n";
2945+
if (HasMnemonicFirst) {
2946+
OS << " StringRef Mnemonic = ((" << Target.getName()
2947+
<< "Operand&)*Operands[0]).getToken();\n\n";
2948+
} else {
2949+
OS << " StringRef Mnemonic;\n";
2950+
OS << " if (Operands[0]->isToken())\n";
2951+
OS << " Mnemonic = ((" << Target.getName()
2952+
<< "Operand&)*Operands[0]).getToken();\n\n";
2953+
}
29232954

29242955
if (HasMnemonicAliases) {
29252956
OS << " // Process all MnemonicAliases to remap the mnemonic.\n";
@@ -2948,12 +2979,18 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
29482979
<< "); End = std::end(MatchTable" << VC << "); break;\n";
29492980
}
29502981
OS << " }\n";
2982+
29512983
OS << " // Search the table.\n";
2952-
OS << " std::pair<const MatchEntry*, const MatchEntry*> "
2953-
"MnemonicRange(Start, End);\n";
2954-
OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n";
2955-
OS << " if (!Mnemonic.empty())\n";
2956-
OS << " MnemonicRange = std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n";
2984+
if (HasMnemonicFirst) {
2985+
OS << " auto MnemonicRange = "
2986+
"std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n";
2987+
} else {
2988+
OS << " auto MnemonicRange = std::make_pair(Start, End);\n";
2989+
OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n";
2990+
OS << " if (!Mnemonic.empty())\n";
2991+
OS << " MnemonicRange = "
2992+
"std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n";
2993+
}
29572994

29582995
OS << " // Return a more specific error code if no mnemonics match.\n";
29592996
OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
@@ -2963,16 +3000,25 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
29633000
<< "*ie = MnemonicRange.second;\n";
29643001
OS << " it != ie; ++it) {\n";
29653002

3003+
if (HasMnemonicFirst) {
3004+
OS << " // equal_range guarantees that instruction mnemonic matches.\n";
3005+
OS << " assert(Mnemonic == it->getMnemonic());\n";
3006+
}
3007+
29663008
// Emit check that the subclasses match.
29673009
OS << " bool OperandsValid = true;\n";
2968-
OS << " for (unsigned i = SIndex; i != " << MaxNumOperands << "; ++i) {\n";
3010+
OS << " for (unsigned i = " << (HasMnemonicFirst ? "0" : "SIndex")
3011+
<< "; i != " << MaxNumOperands << "; ++i) {\n";
29693012
OS << " auto Formal = static_cast<MatchClassKind>(it->Classes[i]);\n";
2970-
OS << " if (i >= Operands.size()) {\n";
3013+
OS << " if (i" << (HasMnemonicFirst ? "+1" : "")
3014+
<< " >= Operands.size()) {\n";
29713015
OS << " OperandsValid = (Formal == " <<"InvalidMatchClass);\n";
2972-
OS << " if (!OperandsValid) ErrorInfo = i;\n";
3016+
OS << " if (!OperandsValid) ErrorInfo = i"
3017+
<< (HasMnemonicFirst ? "+1" : "") << ";\n";
29733018
OS << " break;\n";
29743019
OS << " }\n";
2975-
OS << " MCParsedAsmOperand &Actual = *Operands[i];\n";
3020+
OS << " MCParsedAsmOperand &Actual = *Operands[i"
3021+
<< (HasMnemonicFirst ? "+1" : "") << "];\n";
29763022
OS << " unsigned Diag = validateOperandClass(Actual, Formal);\n";
29773023
OS << " if (Diag == Match_Success)\n";
29783024
OS << " continue;\n";
@@ -2988,8 +3034,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
29883034
OS << " // If we already had a match that only failed due to a\n";
29893035
OS << " // target predicate, that diagnostic is preferred.\n";
29903036
OS << " if (!HadMatchOtherThanPredicate &&\n";
2991-
OS << " (it == MnemonicRange.first || ErrorInfo <= i)) {\n";
2992-
OS << " ErrorInfo = i;\n";
3037+
OS << " (it == MnemonicRange.first || ErrorInfo <= i"
3038+
<< (HasMnemonicFirst ? "+1" : "") << ")) {\n";
3039+
OS << " ErrorInfo = i" << (HasMnemonicFirst ? "+1" : "") << ";\n";
29933040
OS << " // InvalidOperand is the default. Prefer specificity.\n";
29943041
OS << " if (Diag != Match_InvalidOperand)\n";
29953042
OS << " RetCode = Diag;\n";
@@ -3064,7 +3111,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
30643111

30653112
if (!Info.OperandMatchInfo.empty())
30663113
emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable,
3067-
MaxMnemonicIndex);
3114+
MaxMnemonicIndex, HasMnemonicFirst);
30683115

30693116
OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n";
30703117
}

0 commit comments

Comments
 (0)