Implement smart printing of inline asm strings, handling variants and

substituted operands.  For this testcase:

int %test(int %A, int %B) {
  %C = call int asm "xyz $0, $1, $2", "=r,r,r"(int %A, int %B)
  ret int %C
}

we now emit:

_test:
        or r2, r3, r3
        or r3, r4, r4
        xyz r2, r2, r3  ;; look here
        or r3, r2, r2
        blr

... note the substituted operands. :)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@25886 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2006-02-01 22:41:11 +00:00
parent 47cf4eda9f
commit 6609913b7d

View File

@ -20,6 +20,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
#include <iostream>
#include <cerrno>
using namespace llvm;
AsmPrinter::AsmPrinter(std::ostream &o, TargetMachine &tm)
@ -468,12 +469,118 @@ void AsmPrinter::printInlineAsm(const MachineInstr *MI) const {
assert(NumDefs != NumOperands-1 && "No asm string?");
assert(MI->getOperand(NumDefs).isExternalSymbol() && "No asm string?");
// Disassemble the AsmStr, printing out the literal pieces, the operands, etc.
const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
// The variant of the current asmprinter: FIXME: change.
int AsmPrinterVariant = 0;
O << AsmStr << "\n";
// Use a virtual "printAsmOperand" method, which takes the constraint
// string? Must pass the constraint string to here if needed.
int CurVariant = -1; // The number of the {.|.|.} region we are in.
const char *LastEmitted = AsmStr; // One past the last character emitted.
while (*LastEmitted) {
switch (*LastEmitted) {
default: {
// Not a special case, emit the string section literally.
const char *LiteralEnd = LastEmitted+1;
while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
*LiteralEnd != '}' && *LiteralEnd != '$')
++LiteralEnd;
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
O.write(LastEmitted, LiteralEnd-LastEmitted);
LastEmitted = LiteralEnd;
break;
}
case '$': {
++LastEmitted; // Consume '$' character.
if (*LastEmitted == '$') { // $$ -> $
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
O << '$';
++LastEmitted; // Consume second '$' character.
break;
}
bool HasCurlyBraces = false;
if (*LastEmitted == '{') { // ${variable}
++LastEmitted; // Consume '{' character.
HasCurlyBraces = true;
}
const char *IDStart = LastEmitted;
char *IDEnd;
long Val = strtol(IDStart, &IDEnd, 10); // We only accept numbers for IDs.
if (!isdigit(*IDStart) || (Val == 0 && errno == EINVAL)) {
std::cerr << "Bad $ operand number in inline asm string: '"
<< AsmStr << "'\n";
exit(1);
}
LastEmitted = IDEnd;
if (HasCurlyBraces) {
if (*LastEmitted != '}') {
std::cerr << "Bad ${} expression in inline asm string: '"
<< AsmStr << "'\n";
exit(1);
}
++LastEmitted; // Consume '}' character.
}
if ((unsigned)Val >= NumOperands-1) {
std::cerr << "Invalid $ operand number in inline asm string: '"
<< AsmStr << "'\n";
exit(1);
}
// Okay, we finally have an operand number. Ask the target to print this
// operand!
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
if (const_cast<AsmPrinter*>(this)->
PrintAsmOperand(MI, Val+1, AsmPrinterVariant)) {
std::cerr << "Invalid operand found in inline asm: '"
<< AsmStr << "'\n";
MI->dump();
exit(1);
}
break;
}
case '{':
++LastEmitted; // Consume '{' character.
if (CurVariant != -1) {
std::cerr << "Nested variants found in inline asm string: '"
<< AsmStr << "'\n";
exit(1);
}
CurVariant = 0; // We're in the first variant now.
break;
case '|':
++LastEmitted; // consume '|' character.
if (CurVariant == -1) {
std::cerr << "Found '|' character outside of variant in inline asm "
<< "string: '" << AsmStr << "'\n";
exit(1);
}
++CurVariant; // We're in the next variant.
break;
case '}':
++LastEmitted; // consume '}' character.
if (CurVariant == -1) {
std::cerr << "Found '}' character outside of variant in inline asm "
<< "string: '" << AsmStr << "'\n";
exit(1);
}
CurVariant = -1;
break;
}
}
O << "\n";
}
/// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
/// instruction, using the specified assembler variant. Targets should
/// overried this to format as appropriate.
bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant) {
// Target doesn't support this yet!
return true;
}