Index: llvm/trunk/include/llvm/TableGen/StringMatcher.h =================================================================== --- llvm/trunk/include/llvm/TableGen/StringMatcher.h +++ llvm/trunk/include/llvm/TableGen/StringMatcher.h @@ -43,11 +43,12 @@ const std::vector &matches, raw_ostream &os) : StrVariableName(strVariableName), Matches(matches), OS(os) {} - void Emit(unsigned Indent = 0) const; + void Emit(unsigned Indent = 0, bool IgnoreDuplicates = false) const; private: - bool EmitStringMatcherForChar(const std::vector &Matches, - unsigned CharNo, unsigned IndentCount) const; + bool EmitStringMatcherForChar(const std::vector &Matches, + unsigned CharNo, unsigned IndentCount, + bool IgnoreDuplicates) const; }; } // end namespace llvm Index: llvm/trunk/include/llvm/Target/Target.td =================================================================== --- llvm/trunk/include/llvm/Target/Target.td +++ llvm/trunk/include/llvm/Target/Target.td @@ -1174,6 +1174,14 @@ // several registers share the same alias (i.e. not a 1:1 mapping). bit ShouldEmitMatchRegisterAltName = 0; + // Set to true if MatchRegisterName and MatchRegisterAltName functions + // should be generated even if there are duplicate register names. The + // target is responsible for coercing aliased registers as necessary + // (e.g. in validateTargetOperandClass), and there are no guarantees about + // which numeric register identifier will be returned in the case of + // multiple matches. + bit AllowDuplicateRegisterNames = 0; + // HasMnemonicFirst - Set to false if target instructions don't always // start with a mnemonic as the first token. bit HasMnemonicFirst = 1; Index: llvm/trunk/lib/TableGen/StringMatcher.cpp =================================================================== --- llvm/trunk/lib/TableGen/StringMatcher.cpp +++ llvm/trunk/lib/TableGen/StringMatcher.cpp @@ -46,17 +46,18 @@ /// code to verify that CharNo and later are the same. /// /// \return - True if control can leave the emitted code fragment. -bool StringMatcher:: -EmitStringMatcherForChar(const std::vector &Matches, - unsigned CharNo, unsigned IndentCount) const { +bool StringMatcher::EmitStringMatcherForChar( + const std::vector &Matches, unsigned CharNo, + unsigned IndentCount, bool IgnoreDuplicates) const { assert(!Matches.empty() && "Must have at least one string to match!"); - std::string Indent(IndentCount*2+4, ' '); + std::string Indent(IndentCount * 2 + 4, ' '); // If we have verified that the entire string matches, we're done: output the // matching code. if (CharNo == Matches[0]->first.size()) { - assert(Matches.size() == 1 && "Had duplicate keys to match on"); - + if (Matches.size() > 1 && !IgnoreDuplicates) + report_fatal_error("Had duplicate keys to match on"); + // If the to-execute code has \n's in it, indent each subsequent line. StringRef Code = Matches[0]->second; @@ -100,8 +101,9 @@ << NumChars << ") != 0)\n"; OS << Indent << " break;\n"; } - - return EmitStringMatcherForChar(Matches, FirstNonCommonLetter, IndentCount); + + return EmitStringMatcherForChar(Matches, FirstNonCommonLetter, IndentCount, + IgnoreDuplicates); } // Otherwise, we have multiple possible things, emit a switch on the @@ -116,7 +118,8 @@ << LI->second.size() << " string"; if (LI->second.size() != 1) OS << 's'; OS << " to match.\n"; - if (EmitStringMatcherForChar(LI->second, CharNo+1, IndentCount+1)) + if (EmitStringMatcherForChar(LI->second, CharNo + 1, IndentCount + 1, + IgnoreDuplicates)) OS << Indent << " break;\n"; } @@ -126,7 +129,7 @@ /// Emit - Top level entry point. /// -void StringMatcher::Emit(unsigned Indent) const { +void StringMatcher::Emit(unsigned Indent, bool IgnoreDuplicates) const { // If nothing to match, just fall through. if (Matches.empty()) return; @@ -146,7 +149,7 @@ OS.indent(Indent*2+2) << "case " << LI->first << ":\t // " << LI->second.size() << " string" << (LI->second.size() == 1 ? "" : "s") << " to match.\n"; - if (EmitStringMatcherForChar(LI->second, 0, Indent)) + if (EmitStringMatcherForChar(LI->second, 0, Indent, IgnoreDuplicates)) OS.indent(Indent*2+4) << "break;\n"; } Index: llvm/trunk/test/TableGen/AllowDuplicateRegisterNames.td =================================================================== --- llvm/trunk/test/TableGen/AllowDuplicateRegisterNames.td +++ llvm/trunk/test/TableGen/AllowDuplicateRegisterNames.td @@ -0,0 +1,86 @@ +// RUN: llvm-tblgen -gen-asm-matcher -I %p/../../include %s | FileCheck %s + +// Check that MatchRegisterName and MatchRegisterAltName are generated +// correctly when multiple registers are defined with the same name and +// AllowDuplicateRegisterNames is set. + +include "llvm/Target/Target.td" + +def ArchInstrInfo : InstrInfo; + +def ArchAsmParser : AsmParser { + let AllowDuplicateRegisterNames = 1; + let ShouldEmitMatchRegisterAltName = 1; +} + +def Arch : Target { + let InstructionSet = ArchInstrInfo; + let AssemblyParsers = [ArchAsmParser]; +} + +let Namespace = "Arch" in { +class ArchReg alt, list altidx> + : Register { + let AltNames = alt; + let RegAltNameIndices = altidx; +} + +def ABIRegAltName : RegAltNameIndex; + +foreach i = 0-3 in { + def R#i#_32 : ArchReg<"r"#i, ["x"#i], [ABIRegAltName]>; + def R#i#_64 : ArchReg<"r"#i, ["x"#i], [ABIRegAltName]>; +} +} // Namespace = "Arch" + +def GPR32 : RegisterClass<"Arch", [i32], 32, (add + (sequence "R%u_32", 0, 3) +)>; + +def GPR64 : RegisterClass<"Arch", [i64], 64, (add + (sequence "R%u_64", 0, 3) +)>; + +// CHECK: static unsigned MatchRegisterName(StringRef Name) { +// CHECK: switch (Name.size()) { +// CHECK: default: break; +// CHECK: case 2: // 8 strings to match. +// CHECK: if (Name[0] != 'r') +// CHECK: break; +// CHECK: switch (Name[1]) { +// CHECK: default: break; +// CHECK: case '0': // 2 strings to match. +// CHECK: return 1; // "r0" +// CHECK: case '1': // 2 strings to match. +// CHECK: return 3; // "r1" +// CHECK: case '2': // 2 strings to match. +// CHECK: return 5; // "r2" +// CHECK: case '3': // 2 strings to match. +// CHECK: return 7; // "r3" +// CHECK: } +// CHECK: break; +// CHECK: } +// CHECK: return 0; +// CHECK: } + +// CHECK: static unsigned MatchRegisterAltName(StringRef Name) { +// CHECK: switch (Name.size()) { +// CHECK: default: break; +// CHECK: case 2: // 8 strings to match. +// CHECK: if (Name[0] != 'x') +// CHECK: break; +// CHECK: switch (Name[1]) { +// CHECK: default: break; +// CHECK: case '0': // 2 strings to match. +// CHECK: return 1; // "x0" +// CHECK: case '1': // 2 strings to match. +// CHECK: return 3; // "x1" +// CHECK: case '2': // 2 strings to match. +// CHECK: return 5; // "x2" +// CHECK: case '3': // 2 strings to match. +// CHECK: return 7; // "x3" +// CHECK: } +// CHECK: break; +// CHECK: } +// CHECK: return 0; +// CHECK: } Index: llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp +++ llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp @@ -2438,7 +2438,9 @@ OS << "static unsigned MatchRegisterName(StringRef Name) {\n"; - StringMatcher("Name", Matches, OS).Emit(); + bool IgnoreDuplicates = + AsmParser->getValueAsBit("AllowDuplicateRegisterNames"); + StringMatcher("Name", Matches, OS).Emit(0, IgnoreDuplicates); OS << " return 0;\n"; OS << "}\n\n"; @@ -2469,7 +2471,9 @@ OS << "static unsigned MatchRegisterAltName(StringRef Name) {\n"; - StringMatcher("Name", Matches, OS).Emit(); + bool IgnoreDuplicates = + AsmParser->getValueAsBit("AllowDuplicateRegisterNames"); + StringMatcher("Name", Matches, OS).Emit(0, IgnoreDuplicates); OS << " return 0;\n"; OS << "}\n\n";