implement (and document!) the first kind of MC assembler alias, which

just remaps one mnemonic to another.  Convert a few of the X86 aliases
from .cpp to .td code.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@117815 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2010-10-30 17:36:36 +00:00
parent 905b8f7614
commit 674c1dcca2
5 changed files with 120 additions and 22 deletions

View File

@ -1878,15 +1878,64 @@ We've tried hard to automate the generation of the assembler from the .td files
part of the manual and repetitive data entry can be factored and shared with the
compiler.</p>
</div>
<!-- ======================================================================= -->
<div class="doc_subsection" id="na_instparsing">Instruction Parsing</div>
<div class="doc_text"><p>To Be Written</p></div>
<!-- ======================================================================= -->
<div class="doc_subsection" id="na_instaliases">
Instruction Alias Processing
</div>
<div class="doc_text">
<p>Once the instruction is parsed, it enters the MatchInstructionImpl function.
The MatchInstructionImpl function performs alias processing and then does
actual matching.</p>
<p>Alias processing if the phase that canonicalizes different lexical forms of
the same instructions down to one representation. There are several different
kinds of alias that are possible to implement and they are listed below in the
order that they are processed (which is in order from simplest/weakest to most
complex/powerful). Generally you want to use the first alias mechanism that
meets the needs of your instruction, because it will allow a more concise
description.</p>
<!-- _______________________________________________________________________ -->
<div class="doc_subsubsection">Mnemonic Aliases</div>
<div class="doc_text">
<p>The first phase of alias processing is simple instruction mneomonic
remapping for classes of instructions which are allowed with two different
mneomonics. This phase is a simple and unconditionally remapping from one input
mnemonic to one output mnemonic. It isn't possible for this form of alias to
look at the operands at all, so the remapping must apply for all forms of a
given mnemonic. Mnemonic aliases are defined simply, for example X86 has:
</p>
<div class="doc_code">
<pre>
def : MnemonicAlias&lt;"cbw", "cbtw"&gt;;
def : MnemonicAlias&lt;"smovq", "movsq"&gt;;
def : MnemonicAlias&lt;"fldcww", "fldcw"&gt;;
def : MnemonicAlias&lt;"fucompi", "fucomip"&gt;;
def : MnemonicAlias&lt;"ud2a", "ud2"&gt;;
</pre>
</div>
<p>... and many others. With a MnemonicAlias definition, the mnemonic is
remapped simply and directly.</p>
</div>
<!-- ======================================================================= -->
<div class="doc_subsection">
<a name="proepicode">Prolog/Epilog Code Insertion</a>
</div>
<div class="doc_subsection" id="na_matching">Instruction Matching</div>
<div class="doc_text"><p>To Be Written</p></div>

View File

@ -530,6 +530,25 @@ class AsmParser {
def DefaultAsmParser : AsmParser;
/// MnemonicAlias - This class allows targets to define assembler mnemonic
/// aliases. This should be used when all forms of one mnemonic are accepted
/// with a different mnemonic. For example, X86 allows:
/// sal %al, 1 -> shl %al, 1
/// sal %ax, %cl -> shl %ax, %cl
/// sal %eax, %cl -> shl %eax, %cl
/// etc. Though "sal" is accepted with many forms, all of them are directly
/// translated to a shl, so it can be handled with (in the case of X86, it
/// actually has one for each suffix as well):
/// def : MnemonicAlias<"sal", "shl">;
///
/// Mnemonic aliases are mapped before any other translation in the match phase.
///
class MnemonicAlias<string From, string To> {
string FromMnemonic = From;
string ToMnemonic = To;
}
//===----------------------------------------------------------------------===//
// AsmWriter - This class can be implemented by targets that need to customize
// the format of the .s file writer.

View File

@ -632,17 +632,6 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
.Case("repe", "rep")
.Case("repz", "rep")
.Case("repnz", "repne")
.Case("iret", "iretl")
.Case("sysret", "sysretl")
.Case("cbw", "cbtw")
.Case("cwd", "cwtd")
.Case("cdq", "cltd")
.Case("cwde", "cwtl")
.Case("cdqe", "cltq")
.Case("smovb", "movsb")
.Case("smovw", "movsw")
.Case("smovl", "movsl")
.Case("smovq", "movsq")
.Case("push", Is64Bit ? "pushq" : "pushl")
.Case("pop", Is64Bit ? "popq" : "popl")
.Case("pushf", Is64Bit ? "pushfq" : "pushfl")
@ -704,14 +693,10 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
.Case("movzx", "movzb") // FIXME: Not correct.
.Case("fildq", "fildll")
.Case("fcompi", "fcomip")
.Case("fucompi", "fucomip")
.Case("fldcww", "fldcw")
.Case("fnstcww", "fnstcw")
.Case("fstcww", "fstcw")
.Case("fnstsww", "fnstsw")
.Case("fstsww", "fstsw")
.Case("verrw", "verr")
.Case("ud2a", "ud2")
.Default(Name);
// FIXME: Hack to recognize cmp<comparison code>{ss,sd,ps,pd}.

View File

@ -1254,3 +1254,26 @@ include "X86InstrSystem.td"
// Compiler Pseudo Instructions and Pat Patterns
include "X86InstrCompiler.td"
//===----------------------------------------------------------------------===//
// Assembler Aliases
//===----------------------------------------------------------------------===//
def : MnemonicAlias<"iret", "iretl">;
def : MnemonicAlias<"sysret", "sysretl">;
def : MnemonicAlias<"cbw", "cbtw">;
def : MnemonicAlias<"cwd", "cwtd">;
def : MnemonicAlias<"cdq", "cltd">;
def : MnemonicAlias<"cwde", "cwtl">;
def : MnemonicAlias<"cdqe", "cltq">;
def : MnemonicAlias<"smovb", "movsb">;
def : MnemonicAlias<"smovw", "movsw">;
def : MnemonicAlias<"smovl", "movsl">;
def : MnemonicAlias<"smovq", "movsq">;
def : MnemonicAlias<"fldcww", "fldcw">;
def : MnemonicAlias<"fucompi", "fucomip">;
def : MnemonicAlias<"ud2a", "ud2">;
def : MnemonicAlias<"verrw", "verr">;

View File

@ -1514,6 +1514,26 @@ static void EmitComputeAvailableFeatures(CodeGenTarget &Target,
OS << "}\n\n";
}
/// EmitMnemonicAliases - If the target has any MnemonicAlias<> definitions,
/// emit them.
static void EmitMnemonicAliases(raw_ostream &OS) {
std::vector<Record*> Aliases =
Records.getAllDerivedDefinitions("MnemonicAlias");
if (Aliases.empty()) return;
OS << " // Process all MnemonicAliases to remap the mnemonic.\n";
std::vector<StringMatcher::StringPair> Cases;
for (unsigned i = 0, e = Aliases.size(); i != e; ++i) {
Record *R = Aliases[i];
Cases.push_back(std::make_pair(R->getValueAsString("FromMnemonic"),
"Mnemonic = \"" +
R->getValueAsString("ToMnemonic") +
"\"; break;"));
}
StringMatcher("Mnemonic", Cases, OS).Emit();
}
void AsmMatcherEmitter::run(raw_ostream &OS) {
CodeGenTarget Target;
Record *AsmParser = Target.getAsmParser();
@ -1701,6 +1721,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " // Get the current feature set.\n";
OS << " unsigned AvailableFeatures = getAvailableFeatures();\n\n";
OS << " // Get the instruction mnemonic, which is the first token.\n";
OS << " StringRef Mnemonic = ((" << Target.getName()
<< "Operand*)Operands[0])->getToken();\n\n";
EmitMnemonicAliases(OS);
// Emit code to compute the class list for this operand vector.
OS << " // Eliminate obvious mismatches.\n";
OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n";
@ -1725,10 +1751,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< "i != e; ++i)\n";
OS << " Classes[i] = InvalidMatchClass;\n\n";
OS << " // Get the instruction mnemonic, which is the first token.\n";
OS << " StringRef Mnemonic = ((" << Target.getName()
<< "Operand*)Operands[0])->getToken();\n\n";
OS << " // Some state to try to produce better error messages.\n";
OS << " bool HadMatchOtherThanFeatures = false;\n\n";
OS << " // Set ErrorInfo to the operand that mismatches if it is \n";