Skip to content

Commit 3cf7efe

Browse files
committed
[TableGen] Allow mnemonics with uppercase letters to be matched
The assembly parser "canonicalizes" the mnemonics it processes at an early level by making them lowercase. The goal of this is presumably to allow assembly to be case-insensitive. However, if one declares an instruction with a mnemonic using uppercase letters, then it will never get matched, since the generated lookup tables for the AsmMatcherEmitter didn't lower() their inputs. This made it difficult to have instructions that get printed using a mnemonic that includes uppercase letters, since they could not be parsed. To fix this problem, this patch adds a few calls to lower() to make the lookup tables used in AsmMatcherEmitter be case-insensitive. This allows instruction mnemonics with uppercase letters to be parsed. Differential Revision: https://reviews.llvm.org/D85858
1 parent 36ebabc commit 3cf7efe

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: llvm-tblgen -gen-asm-matcher -I %p/../../include %s | FileCheck %s --check-prefix=MATCHER
2+
// RUN: llvm-tblgen -gen-asm-writer -I %p/../../include %s | FileCheck %s --check-prefix=WRITER
3+
4+
// Check that an instruction that uses mixed upper/lower case in its mnemonic
5+
// is printed as-is, and is parsed in its "canonicalized" lowercase form.
6+
7+
include "llvm/Target/Target.td"
8+
9+
def ArchInstrInfo : InstrInfo { }
10+
11+
def Arch : Target {
12+
let InstructionSet = ArchInstrInfo;
13+
}
14+
15+
def Reg : Register<"reg">;
16+
def RegClass : RegisterClass<"foo", [i32], 0, (add Reg)>;
17+
18+
// Define instructions that demonstrate case-insensitivity.
19+
// In case-sensitive ASCII order, "BInst" < "aInst".
20+
// In case-insensitive order, "aInst" < "BInst".
21+
// If the matcher really treats the mnemonics in a case-insensitive way,
22+
// then we should see "aInst" appearing before "BInst", despite the
23+
// fact that "BInst" would appear before "aInst" in ASCIIbetical order.
24+
def AlphabeticallySecondInst : Instruction {
25+
let Size = 2;
26+
let OutOperandList = (outs);
27+
let InOperandList = (ins);
28+
let AsmString = "BInst";
29+
}
30+
31+
def AlphabeticallyFirstInst : Instruction {
32+
let Size = 2;
33+
let OutOperandList = (outs);
34+
let InOperandList = (ins);
35+
let AsmString = "aInst";
36+
}
37+
38+
// Check that the matcher lower()s the mnemonics it matches.
39+
// MATCHER: static const char *const MnemonicTable =
40+
// MATCHER-NEXT: "\005ainst\005binst";
41+
42+
// Check that aInst appears before BInst in the match table.
43+
// This shows that the mnemonics are sorted in a case-insensitive way,
44+
// since otherwise "B" would be less than "a" by ASCII order.
45+
// MATCHER: static const MatchEntry MatchTable0[] = {
46+
// MATCHER-NEXT: /* aInst */, ::AlphabeticallyFirstInst
47+
// MATCHER-NEXT: /* BInst */, ::AlphabeticallySecondInst
48+
// MATCHER-NEXT: };
49+
50+
// Check that the writer preserves the case of the mnemonics.
51+
// WRITER: static const char AsmStrs[] = {
52+
// WRITER: "BInst\0"
53+
// WRITER-NEXT: "aInst\0"
54+
// WRITER-NEXT: };
55+

llvm/utils/TableGen/AsmMatcherEmitter.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ struct MatchableInfo {
612612
/// operator< - Compare two matchables.
613613
bool operator<(const MatchableInfo &RHS) const {
614614
// The primary comparator is the instruction mnemonic.
615-
if (int Cmp = Mnemonic.compare(RHS.Mnemonic))
615+
if (int Cmp = Mnemonic.compare_lower(RHS.Mnemonic))
616616
return Cmp == -1;
617617

618618
if (AsmOperands.size() != RHS.AsmOperands.size())
@@ -2880,7 +2880,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
28802880
OS << " { ";
28812881

28822882
// Store a pascal-style length byte in the mnemonic.
2883-
std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str();
2883+
std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.lower();
28842884
OS << StringTable.GetOrAddStringOffset(LenMnemonic, false)
28852885
<< " /* " << II.Mnemonic << " */, ";
28862886

@@ -3324,7 +3324,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
33243324
HasDeprecation |= MI->HasDeprecation;
33253325

33263326
// Store a pascal-style length byte in the mnemonic.
3327-
std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.str();
3327+
std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.lower();
33283328
MaxMnemonicIndex = std::max(MaxMnemonicIndex,
33293329
StringTable.GetOrAddStringOffset(LenMnemonic, false));
33303330
}
@@ -3438,7 +3438,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
34383438
continue;
34393439

34403440
// Store a pascal-style length byte in the mnemonic.
3441-
std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.str();
3441+
std::string LenMnemonic =
3442+
char(MI->Mnemonic.size()) + MI->Mnemonic.lower();
34423443
OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false)
34433444
<< " /* " << MI->Mnemonic << " */, "
34443445
<< Target.getInstNamespace() << "::"

0 commit comments

Comments
 (0)