forked from OSchip/llvm-project
[asm] Merge EmitMSInlineAsmStr() and EmitGCCInlineAsmStr()
This basically reverts 1778831a3d
, which split them.
Since they were split 9 years ago, EmitGCCInlineAsmStr() grew a bunch of
features that usually weren't added to EmitMSInlineAsmStr(), and
that was usually a mistake. D71677, D113932, D114167 are all examples
of where things were backported to EmitMSInlineAsmStr().
The names were also not great. EmitMSInlineAsmStr() used to be called for `asm
inteldialect`, which clang produces for Microsoft-style __asm { ... } blocks as
well for GCC-style __asm__ / asm statements with -masm=intel. On the other hand,
EmitGCCInlineAsmStr() used to be called for `asm`, whic clang produces for
GCC-style __asm__ / asm statements with -masm=att (the default).
It's also less code (23 insertions, 188 deletions).
No behavior change.
Differential Revision: https://reviews.llvm.org/D114330
This commit is contained in:
parent
7c2d51474a
commit
2fb3c05b34
|
@ -128,194 +128,29 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
|
|||
emitInlineAsmEnd(STI, &TAP->getSTI());
|
||||
}
|
||||
|
||||
static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
||||
MachineModuleInfo *MMI, const MCAsmInfo *MAI,
|
||||
AsmPrinter *AP, uint64_t LocCookie,
|
||||
raw_ostream &OS) {
|
||||
// Switch to the inline assembly variant.
|
||||
OS << "\t.intel_syntax\n\t";
|
||||
static void EmitInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
||||
MachineModuleInfo *MMI, const MCAsmInfo *MAI,
|
||||
AsmPrinter *AP, uint64_t LocCookie,
|
||||
raw_ostream &OS) {
|
||||
bool InputIsIntelDialect = MI->getInlineAsmDialect() == InlineAsm::AD_Intel;
|
||||
|
||||
int CurVariant = -1; // The number of the {.|.|.} region we are in.
|
||||
const char *LastEmitted = AsmStr; // One past the last character emitted.
|
||||
unsigned NumOperands = MI->getNumOperands();
|
||||
int AsmPrinterVariant = 1; // X86MCAsmInfo.cpp's AsmWriterFlavorTy::Intel.
|
||||
|
||||
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 != '\n')
|
||||
++LiteralEnd;
|
||||
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
|
||||
OS.write(LastEmitted, LiteralEnd - LastEmitted);
|
||||
LastEmitted = LiteralEnd;
|
||||
break;
|
||||
}
|
||||
case '\n':
|
||||
++LastEmitted; // Consume newline character.
|
||||
OS << '\n'; // Indent code with newline.
|
||||
break;
|
||||
case '$': {
|
||||
++LastEmitted; // Consume '$' character.
|
||||
bool Done = true;
|
||||
|
||||
// Handle escapes.
|
||||
switch (*LastEmitted) {
|
||||
default: Done = false; break;
|
||||
case '$':
|
||||
++LastEmitted; // Consume second '$' character.
|
||||
break;
|
||||
case '(': // $( -> same as GCC's { character.
|
||||
++LastEmitted; // Consume '(' character.
|
||||
if (CurVariant != -1)
|
||||
report_fatal_error("Nested variants found in inline asm string: '" +
|
||||
Twine(AsmStr) + "'");
|
||||
CurVariant = 0; // We're in the first variant now.
|
||||
break;
|
||||
case '|':
|
||||
++LastEmitted; // Consume '|' character.
|
||||
if (CurVariant == -1)
|
||||
OS << '|'; // This is gcc's behavior for | outside a variant.
|
||||
else
|
||||
++CurVariant; // We're in the next variant.
|
||||
break;
|
||||
case ')': // $) -> same as GCC's } char.
|
||||
++LastEmitted; // Consume ')' character.
|
||||
if (CurVariant == -1)
|
||||
OS << '}'; // This is gcc's behavior for } outside a variant.
|
||||
else
|
||||
CurVariant = -1;
|
||||
break;
|
||||
}
|
||||
if (Done) break;
|
||||
|
||||
bool HasCurlyBraces = false;
|
||||
if (*LastEmitted == '{') { // ${variable}
|
||||
++LastEmitted; // Consume '{' character.
|
||||
HasCurlyBraces = true;
|
||||
}
|
||||
|
||||
// If we have ${:foo}, then this is not a real operand reference, it is a
|
||||
// "magic" string reference, just like in .td files. Arrange to call
|
||||
// PrintSpecial.
|
||||
if (HasCurlyBraces && *LastEmitted == ':') {
|
||||
++LastEmitted;
|
||||
const char *StrStart = LastEmitted;
|
||||
const char *StrEnd = strchr(StrStart, '}');
|
||||
if (!StrEnd)
|
||||
report_fatal_error("Unterminated ${:foo} operand in inline asm"
|
||||
" string: '" + Twine(AsmStr) + "'");
|
||||
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
|
||||
AP->PrintSpecial(MI, OS, StringRef(StrStart, StrEnd - StrStart));
|
||||
LastEmitted = StrEnd+1;
|
||||
break;
|
||||
}
|
||||
|
||||
const char *IDStart = LastEmitted;
|
||||
const char *IDEnd = IDStart;
|
||||
while (isDigit(*IDEnd))
|
||||
++IDEnd;
|
||||
|
||||
unsigned Val;
|
||||
if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
|
||||
report_fatal_error("Bad $ operand number in inline asm string: '" +
|
||||
Twine(AsmStr) + "'");
|
||||
LastEmitted = IDEnd;
|
||||
|
||||
if (Val >= NumOperands - 1)
|
||||
report_fatal_error("Invalid $ operand number in inline asm string: '" +
|
||||
Twine(AsmStr) + "'");
|
||||
|
||||
char Modifier[2] = { 0, 0 };
|
||||
|
||||
if (HasCurlyBraces) {
|
||||
// If we have curly braces, check for a modifier character. This
|
||||
// supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
|
||||
if (*LastEmitted == ':') {
|
||||
++LastEmitted; // Consume ':' character.
|
||||
if (*LastEmitted == 0)
|
||||
report_fatal_error("Bad ${:} expression in inline asm string: '" +
|
||||
Twine(AsmStr) + "'");
|
||||
|
||||
Modifier[0] = *LastEmitted;
|
||||
++LastEmitted; // Consume modifier character.
|
||||
}
|
||||
|
||||
if (*LastEmitted != '}')
|
||||
report_fatal_error("Bad ${} expression in inline asm string: '" +
|
||||
Twine(AsmStr) + "'");
|
||||
++LastEmitted; // Consume '}' character.
|
||||
}
|
||||
|
||||
// Okay, we finally have a value number. Ask the target to print this
|
||||
// operand!
|
||||
if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
|
||||
unsigned OpNo = InlineAsm::MIOp_FirstOperand;
|
||||
|
||||
bool Error = false;
|
||||
|
||||
// Scan to find the machine operand number for the operand.
|
||||
for (; Val; --Val) {
|
||||
if (OpNo >= MI->getNumOperands())
|
||||
break;
|
||||
unsigned OpFlags = MI->getOperand(OpNo).getImm();
|
||||
OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
|
||||
}
|
||||
|
||||
// We may have a location metadata attached to the end of the
|
||||
// instruction, and at no point should see metadata at any
|
||||
// other point while processing. It's an error if so.
|
||||
if (OpNo >= MI->getNumOperands() || MI->getOperand(OpNo).isMetadata()) {
|
||||
Error = true;
|
||||
} else {
|
||||
unsigned OpFlags = MI->getOperand(OpNo).getImm();
|
||||
++OpNo; // Skip over the ID number.
|
||||
|
||||
// FIXME: Shouldn't arch-independent output template handling go into
|
||||
// PrintAsmOperand?
|
||||
// Labels are target independent.
|
||||
if (MI->getOperand(OpNo).isBlockAddress()) {
|
||||
const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress();
|
||||
MCSymbol *Sym = AP->GetBlockAddressSymbol(BA);
|
||||
Sym->print(OS, AP->MAI);
|
||||
MMI->getContext().registerInlineAsmLabel(Sym);
|
||||
} else if (MI->getOperand(OpNo).isMBB()) {
|
||||
const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol();
|
||||
Sym->print(OS, AP->MAI);
|
||||
} else if (InlineAsm::isMemKind(OpFlags)) {
|
||||
Error = AP->PrintAsmMemoryOperand(
|
||||
MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
|
||||
} else {
|
||||
Error = AP->PrintAsmOperand(MI, OpNo,
|
||||
Modifier[0] ? Modifier : nullptr, OS);
|
||||
}
|
||||
}
|
||||
if (Error) {
|
||||
std::string msg;
|
||||
raw_string_ostream Msg(msg);
|
||||
Msg << "invalid operand in inline asm: '" << AsmStr << "'";
|
||||
MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (InputIsIntelDialect) {
|
||||
// Switch to the inline assembly variant.
|
||||
OS << "\t.intel_syntax\n\t";
|
||||
}
|
||||
OS << "\n\t.att_syntax\n" << (char)0; // null terminate string.
|
||||
}
|
||||
|
||||
static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
||||
MachineModuleInfo *MMI, const MCAsmInfo *MAI,
|
||||
AsmPrinter *AP, uint64_t LocCookie,
|
||||
raw_ostream &OS) {
|
||||
int CurVariant = -1; // The number of the {.|.|.} region we are in.
|
||||
const char *LastEmitted = AsmStr; // One past the last character emitted.
|
||||
unsigned NumOperands = MI->getNumOperands();
|
||||
int AsmPrinterVariant = MMI->getTarget().unqualifiedInlineAsmVariant();
|
||||
|
||||
if (MAI->getEmitGNUAsmStartIndentationMarker())
|
||||
int AsmPrinterVariant;
|
||||
if (InputIsIntelDialect)
|
||||
AsmPrinterVariant = 1; // X86MCAsmInfo.cpp's AsmWriterFlavorTy::Intel.
|
||||
else
|
||||
AsmPrinterVariant = MMI->getTarget().unqualifiedInlineAsmVariant();
|
||||
|
||||
// FIXME: Should this happen for `asm inteldialect` as well?
|
||||
if (!InputIsIntelDialect && MAI->getEmitGNUAsmStartIndentationMarker())
|
||||
OS << '\t';
|
||||
|
||||
while (*LastEmitted) {
|
||||
|
@ -343,8 +178,9 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
|||
switch (*LastEmitted) {
|
||||
default: Done = false; break;
|
||||
case '$': // $$ -> $
|
||||
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
|
||||
OS << '$';
|
||||
if (!InputIsIntelDialect)
|
||||
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
|
||||
OS << '$';
|
||||
++LastEmitted; // Consume second '$' character.
|
||||
break;
|
||||
case '(': // $( -> same as GCC's { character.
|
||||
|
@ -483,6 +319,8 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (InputIsIntelDialect)
|
||||
OS << "\n\t.att_syntax";
|
||||
OS << '\n' << (char)0; // null terminate string.
|
||||
}
|
||||
|
||||
|
@ -536,10 +374,7 @@ void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const {
|
|||
raw_svector_ostream OS(StringData);
|
||||
|
||||
AsmPrinter *AP = const_cast<AsmPrinter*>(this);
|
||||
if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT)
|
||||
EmitGCCInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS);
|
||||
else
|
||||
EmitMSInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS);
|
||||
EmitInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS);
|
||||
|
||||
// Emit warnings if we use reserved registers on the clobber list, as
|
||||
// that might lead to undefined behaviour.
|
||||
|
|
Loading…
Reference in New Issue