X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FCodeGen%2FAsmPrinter%2FAsmPrinterInlineAsm.cpp;h=793e62960dd632bd6a13ed9b790ed633e7f32129;hb=6970be03d16d6b4d0073e60c4a987f1860e85cdb;hp=a85e97f2e282327c210c70474f3aba8f836005d9;hpb=65eeaad91d78b2a677ca889eaff60f6d807c7030;p=oota-llvm.git diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index a85e97f2e28..793e62960dd 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -1,4 +1,4 @@ -//===-- AsmPrinter.cpp - Common AsmPrinter code ---------------------------===// +//===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===// // // The LLVM Compiler Infrastructure // @@ -7,88 +7,266 @@ // //===----------------------------------------------------------------------===// // -// This file implements the AsmPrinter class. +// This file implements the inline assembler pieces of the AsmPrinter class. // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "asm-printer" -#include "llvm/InlineAsm.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCTargetAsmParser.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; +#define DEBUG_TYPE "asm-printer" + +namespace { + struct SrcMgrDiagInfo { + const MDNode *LocInfo; + LLVMContext::InlineAsmDiagHandlerTy DiagHandler; + void *DiagContext; + }; +} + +/// srcMgrDiagHandler - This callback is invoked when the SourceMgr for an +/// inline asm has an error in it. diagInfo is a pointer to the SrcMgrDiagInfo +/// struct above. +static void srcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) { + SrcMgrDiagInfo *DiagInfo = static_cast(diagInfo); + assert(DiagInfo && "Diagnostic context not passed down?"); + + // If the inline asm had metadata associated with it, pull out a location + // cookie corresponding to which line the error occurred on. + unsigned LocCookie = 0; + if (const MDNode *LocInfo = DiagInfo->LocInfo) { + unsigned ErrorLine = Diag.getLineNo()-1; + if (ErrorLine >= LocInfo->getNumOperands()) + ErrorLine = 0; + + if (LocInfo->getNumOperands() != 0) + if (const ConstantInt *CI = + mdconst::dyn_extract(LocInfo->getOperand(ErrorLine))) + LocCookie = CI->getZExtValue(); + } + + DiagInfo->DiagHandler(Diag, DiagInfo->DiagContext, LocCookie); +} + /// EmitInlineAsm - Emit a blob of inline asm to the output streamer. -void AsmPrinter::EmitInlineAsm(StringRef Str) const { +void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, + const MCTargetOptions &MCOptions, + const MDNode *LocMDNode, + InlineAsm::AsmDialect Dialect) const { assert(!Str.empty() && "Can't emit empty inline asm block"); - - // If the output streamer is actually a .s file, just emit the blob textually. + + // Remember if the buffer is nul terminated or not so we can avoid a copy. + bool isNullTerminated = Str.back() == 0; + if (isNullTerminated) + Str = Str.substr(0, Str.size()-1); + + // If the output streamer does not have mature MC support or the integrated + // assembler has been disabled, just emit the blob textually. + // Otherwise parse the asm and emit it via MC support. // This is useful in case the asm parser doesn't handle something but the // system assembler does. - if (OutStreamer.hasRawTextSupport()) { - OutStreamer.EmitRawText(Str); + const MCAsmInfo *MCAI = TM.getMCAsmInfo(); + assert(MCAI && "No MCAsmInfo"); + if (!MCAI->useIntegratedAssembler() && + !OutStreamer->isIntegratedAssemblerRequired()) { + emitInlineAsmStart(); + OutStreamer->EmitRawText(Str); + emitInlineAsmEnd(STI, nullptr); return; } - - errs() << "Inline asm not supported by this streamer!\n"; + + SourceMgr SrcMgr; + SrcMgrDiagInfo DiagInfo; + + // If the current LLVMContext has an inline asm handler, set it in SourceMgr. + LLVMContext &LLVMCtx = MMI->getModule()->getContext(); + bool HasDiagHandler = false; + if (LLVMCtx.getInlineAsmDiagnosticHandler() != nullptr) { + // If the source manager has an issue, we arrange for srcMgrDiagHandler + // to be invoked, getting DiagInfo passed into it. + DiagInfo.LocInfo = LocMDNode; + DiagInfo.DiagHandler = LLVMCtx.getInlineAsmDiagnosticHandler(); + DiagInfo.DiagContext = LLVMCtx.getInlineAsmDiagnosticContext(); + SrcMgr.setDiagHandler(srcMgrDiagHandler, &DiagInfo); + HasDiagHandler = true; + } + + std::unique_ptr Buffer; + if (isNullTerminated) + Buffer = MemoryBuffer::getMemBuffer(Str, ""); + else + Buffer = MemoryBuffer::getMemBufferCopy(Str, ""); + + // Tell SrcMgr about this buffer, it takes ownership of the buffer. + SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc()); + + std::unique_ptr Parser( + createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI)); + + // Create a temporary copy of the original STI because the parser may modify + // it. For example, when switching between arm and thumb mode. If the target + // needs to emit code to return to the original state it can do so in + // emitInlineAsmEnd(). + MCSubtargetInfo TmpSTI = STI; + + // We create a new MCInstrInfo here since we might be at the module level + // and not have a MachineFunction to initialize the TargetInstrInfo from and + // we only need MCInstrInfo for asm parsing. We create one unconditionally + // because it's not subtarget dependent. + std::unique_ptr MII(TM.getTarget().createMCInstrInfo()); + std::unique_ptr TAP(TM.getTarget().createMCAsmParser( + TmpSTI, *Parser, *MII, MCOptions)); + if (!TAP) + report_fatal_error("Inline asm not supported by this streamer because" + " we don't have an asm parser for this target\n"); + Parser->setAssemblerDialect(Dialect); + Parser->setTargetParser(*TAP.get()); + if (MF) { + const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); + TAP->SetFrameRegister(TRI->getFrameRegister(*MF)); + } + + emitInlineAsmStart(); + // Don't implicitly switch to the text section before the asm. + int Res = Parser->Run(/*NoInitialTextSection*/ true, + /*NoFinalize*/ true); + emitInlineAsmEnd(STI, &TmpSTI); + if (Res && !HasDiagHandler) + report_fatal_error("Error parsing inline asm\n"); } +static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, + MachineModuleInfo *MMI, int InlineAsmVariant, + AsmPrinter *AP, unsigned LocCookie, + raw_ostream &OS) { + // Switch to the inline assembly variant. + OS << "\t.intel_syntax\n\t"; -/// EmitInlineAsm - This method formats and emits the specified machine -/// instruction that is an inline asm. -void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { - assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); - + const char *LastEmitted = AsmStr; // One past the last character emitted. unsigned NumOperands = MI->getNumOperands(); - - // Count the number of register definitions to find the asm string. - unsigned NumDefs = 0; - for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); - ++NumDefs) - assert(NumDefs != NumOperands-1 && "No asm string?"); - - assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?"); - // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. - const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); + 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 this asmstr is empty, just print the #APP/#NOAPP markers. - // These are useful to see where empty asm's wound up. - if (AsmStr[0] == 0) { - if (!OutStreamer.hasRawTextSupport()) return; + 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; - OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ - MAI->getInlineAsmStart()); - OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ - MAI->getInlineAsmEnd()); - return; - } + // Handle escapes. + switch (*LastEmitted) { + default: Done = false; break; + case '$': + ++LastEmitted; // Consume second '$' character. + break; + } + if (Done) break; - // Emit the #APP start marker. This has to happen even if verbose-asm isn't - // enabled, so we use EmitRawText. - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ - MAI->getInlineAsmStart()); + const char *IDStart = LastEmitted; + const char *IDEnd = IDStart; + while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; - // Emit the inline asm to a temporary string so we can emit it through - // EmitInlineAsm. - SmallString<256> StringData; - raw_svector_ostream OS(StringData); - - OS << '\t'; + unsigned Val; + if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) + report_fatal_error("Bad $ operand number in inline asm string: '" + + Twine(AsmStr) + "'"); + LastEmitted = IDEnd; - // The variant of the current asmprinter. - int AsmPrinterVariant = MAI->getAssemblerDialect(); + if (Val >= NumOperands-1) + report_fatal_error("Invalid $ operand number in inline asm string: '" + + Twine(AsmStr) + "'"); + // Okay, we finally have a value number. Ask the target to print this + // operand! + 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. + + if (InlineAsm::isMemKind(OpFlags)) { + Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant, + /*Modifier*/ nullptr, OS); + } else { + Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, + /*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; + } + } + } + OS << "\n\t.att_syntax\n" << (char)0; // null terminate string. +} + +static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, + MachineModuleInfo *MMI, int InlineAsmVariant, + int AsmPrinterVariant, AsmPrinter *AP, + unsigned 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(); + + OS << '\t'; + while (*LastEmitted) { switch (*LastEmitted) { default: { @@ -104,7 +282,7 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { } case '\n': ++LastEmitted; // Consume newline character. - OS << '\n'; // Indent code with newline. + OS << '\n'; // Indent code with newline. break; case '$': { ++LastEmitted; // Consume '$' character. @@ -120,10 +298,9 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { break; case '(': // $( -> same as GCC's { character. ++LastEmitted; // Consume '(' character. - if (CurVariant != -1) { - llvm_report_error("Nested variants found in inline asm string: '" - + std::string(AsmStr) + "'"); - } + 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 '|': @@ -137,18 +314,18 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { ++LastEmitted; // consume ')' character. if (CurVariant == -1) OS << '}'; // this is gcc's behavior for } outside a variant - else + 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. @@ -156,58 +333,55 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { ++LastEmitted; const char *StrStart = LastEmitted; const char *StrEnd = strchr(StrStart, '}'); - if (StrEnd == 0) - llvm_report_error(Twine("Unterminated ${:foo} operand in inline asm" - " string: '") + Twine(AsmStr) + "'"); - + if (!StrEnd) + report_fatal_error("Unterminated ${:foo} operand in inline asm" + " string: '" + Twine(AsmStr) + "'"); + std::string Val(StrStart, StrEnd); - PrintSpecial(MI, OS, Val.c_str()); + AP->PrintSpecial(MI, OS, Val.c_str()); LastEmitted = StrEnd+1; break; } - + const char *IDStart = LastEmitted; const char *IDEnd = IDStart; - while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; - + while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; + unsigned Val; if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) - llvm_report_error("Bad $ operand number in inline asm string: '" - + std::string(AsmStr) + "'"); + report_fatal_error("Bad $ operand number in inline asm string: '" + + Twine(AsmStr) + "'"); LastEmitted = IDEnd; - + 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) { - llvm_report_error("Bad ${:} expression in inline asm string: '" - + std::string(AsmStr) + "'"); - } - + if (*LastEmitted == 0) + report_fatal_error("Bad ${:} expression in inline asm string: '" + + Twine(AsmStr) + "'"); + Modifier[0] = *LastEmitted; ++LastEmitted; // Consume modifier character. } - - if (*LastEmitted != '}') { - llvm_report_error("Bad ${} expression in inline asm string: '" - + std::string(AsmStr) + "'"); - } + + if (*LastEmitted != '}') + report_fatal_error("Bad ${} expression in inline asm string: '" + + Twine(AsmStr) + "'"); ++LastEmitted; // Consume '}' character. } - - if (Val >= NumOperands-1) { - llvm_report_error("Invalid $ operand number in inline asm string: '" - + std::string(AsmStr) + "'"); - } - + + if (Val >= NumOperands-1) + report_fatal_error("Invalid $ operand number in inline asm string: '" + + Twine(AsmStr) + "'"); + // Okay, we finally have a value number. Ask the target to print this // operand! if (CurVariant == -1 || CurVariant == AsmPrinterVariant) { - unsigned OpNo = 1; + unsigned OpNo = InlineAsm::MIOp_FirstOperand; bool Error = false; @@ -218,48 +392,115 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; } - if (OpNo >= MI->getNumOperands()) { + // 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. - if (Modifier[0] == 'l') // labels are target independent + if (Modifier[0] == 'l') { // Labels are target independent. // FIXME: What if the operand isn't an MBB, report error? - OS << *MI->getOperand(OpNo).getMBB()->getSymbol(); - else { - AsmPrinter *AP = const_cast(this); - if ((OpFlags & 7) == 4) { - Error = AP->PrintAsmMemoryOperand(MI, OpNo, AsmPrinterVariant, - Modifier[0] ? Modifier : 0, + const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol(); + Sym->print(OS, AP->MAI); + } else { + if (InlineAsm::isMemKind(OpFlags)) { + Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant, + Modifier[0] ? Modifier : nullptr, OS); } else { - Error = AP->PrintAsmOperand(MI, OpNo, AsmPrinterVariant, - Modifier[0] ? Modifier : 0, OS); + Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, + Modifier[0] ? Modifier : nullptr, OS); } } } if (Error) { std::string msg; raw_string_ostream Msg(msg); - Msg << "Invalid operand found in inline asm: '" << AsmStr << "'\n"; - MI->print(Msg); - llvm_report_error(Msg.str()); + Msg << "invalid operand in inline asm: '" << AsmStr << "'"; + MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); } } break; } } } - OS << "\n"; - - EmitInlineAsm(OS.str()); - + OS << '\n' << (char)0; // null terminate string. +} + +/// EmitInlineAsm - This method formats and emits the specified machine +/// instruction that is an inline asm. +void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { + assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); + + // Count the number of register definitions to find the asm string. + unsigned NumDefs = 0; + for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); + ++NumDefs) + assert(NumDefs != MI->getNumOperands()-2 && "No asm string?"); + + assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?"); + + // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. + const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); + + // If this asmstr is empty, just print the #APP/#NOAPP markers. + // These are useful to see where empty asm's wound up. + if (AsmStr[0] == 0) { + OutStreamer->emitRawComment(MAI->getInlineAsmStart()); + OutStreamer->emitRawComment(MAI->getInlineAsmEnd()); + return; + } + + // Emit the #APP start marker. This has to happen even if verbose-asm isn't + // enabled, so we use emitRawComment. + OutStreamer->emitRawComment(MAI->getInlineAsmStart()); + + // Get the !srcloc metadata node if we have it, and decode the loc cookie from + // it. + unsigned LocCookie = 0; + const MDNode *LocMD = nullptr; + for (unsigned i = MI->getNumOperands(); i != 0; --i) { + if (MI->getOperand(i-1).isMetadata() && + (LocMD = MI->getOperand(i-1).getMetadata()) && + LocMD->getNumOperands() != 0) { + if (const ConstantInt *CI = + mdconst::dyn_extract(LocMD->getOperand(0))) { + LocCookie = CI->getZExtValue(); + break; + } + } + } + + // Emit the inline asm to a temporary string so we can emit it through + // EmitInlineAsm. + SmallString<256> StringData; + raw_svector_ostream OS(StringData); + + // The variant of the current asmprinter. + int AsmPrinterVariant = MAI->getAssemblerDialect(); + InlineAsm::AsmDialect InlineAsmVariant = MI->getInlineAsmDialect(); + AsmPrinter *AP = const_cast(this); + if (InlineAsmVariant == InlineAsm::AD_ATT) + EmitGCCInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AsmPrinterVariant, + AP, LocCookie, OS); + else + EmitMSInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AP, LocCookie, OS); + + // Reset SanitizeAddress based on the function's attribute. + MCTargetOptions MCOptions = TM.Options.MCOptions; + MCOptions.SanitizeAddress = + MF->getFunction()->hasFnAttribute(Attribute::SanitizeAddress); + + EmitInlineAsm(OS.str(), getSubtargetInfo(), MCOptions, LocMD, + MI->getInlineAsmDialect()); + // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't - // enabled, so we use EmitRawText. - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ - MAI->getInlineAsmEnd()); + // enabled, so we use emitRawComment. + OutStreamer->emitRawComment(MAI->getInlineAsmEnd()); } @@ -271,14 +512,15 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { /// for their own strange codes. void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, const char *Code) const { + const DataLayout *DL = TM.getDataLayout(); if (!strcmp(Code, "private")) { - OS << MAI->getPrivateGlobalPrefix(); + OS << DL->getPrivateGlobalPrefix(); } else if (!strcmp(Code, "comment")) { OS << MAI->getCommentString(); } else if (!strcmp(Code, "uid")) { // Comparing the address of MI isn't sufficient, because machineinstrs may // be allocated to the same address across functions. - + // If this is a new LastFn instruction, bump the counter. if (LastMI != MI || LastFn != getFunctionNumber()) { ++Counter; @@ -291,8 +533,8 @@ void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, raw_string_ostream Msg(msg); Msg << "Unknown special formatter '" << Code << "' for machine instr: " << *MI; - llvm_report_error(Msg.str()); - } + report_fatal_error(Msg.str()); + } } /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM @@ -301,7 +543,26 @@ void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) { - // Target doesn't support this yet! + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + const MachineOperand &MO = MI->getOperand(OpNo); + switch (ExtraCode[0]) { + default: + return true; // Unknown modifier. + case 'c': // Substitute immediate value without immediate syntax + if (MO.getType() != MachineOperand::MO_Immediate) + return true; + O << MO.getImm(); + return false; + case 'n': // Negate the immediate constant. + if (MO.getType() != MachineOperand::MO_Immediate) + return true; + O << -MO.getImm(); + return false; + } + } return true; } @@ -312,3 +573,7 @@ bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, return true; } +void AsmPrinter::emitInlineAsmStart() const {} + +void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, + const MCSubtargetInfo *EndInfo) const {}