mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-30 23:20:54 +00:00
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:
parent
47cf4eda9f
commit
6609913b7d
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user