LLVM API Documentation
00001 //===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the inline assembler pieces of the AsmPrinter class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "llvm/CodeGen/AsmPrinter.h" 00015 #include "llvm/ADT/SmallString.h" 00016 #include "llvm/ADT/Twine.h" 00017 #include "llvm/CodeGen/MachineBasicBlock.h" 00018 #include "llvm/CodeGen/MachineFunction.h" 00019 #include "llvm/CodeGen/MachineModuleInfo.h" 00020 #include "llvm/IR/Constants.h" 00021 #include "llvm/IR/DataLayout.h" 00022 #include "llvm/IR/InlineAsm.h" 00023 #include "llvm/IR/LLVMContext.h" 00024 #include "llvm/IR/Module.h" 00025 #include "llvm/MC/MCAsmInfo.h" 00026 #include "llvm/MC/MCStreamer.h" 00027 #include "llvm/MC/MCSubtargetInfo.h" 00028 #include "llvm/MC/MCSymbol.h" 00029 #include "llvm/MC/MCTargetAsmParser.h" 00030 #include "llvm/Support/ErrorHandling.h" 00031 #include "llvm/Support/MemoryBuffer.h" 00032 #include "llvm/Support/SourceMgr.h" 00033 #include "llvm/Support/TargetRegistry.h" 00034 #include "llvm/Support/raw_ostream.h" 00035 #include "llvm/Target/TargetMachine.h" 00036 #include "llvm/Target/TargetRegisterInfo.h" 00037 #include "llvm/Target/TargetSubtargetInfo.h" 00038 using namespace llvm; 00039 00040 #define DEBUG_TYPE "asm-printer" 00041 00042 namespace { 00043 struct SrcMgrDiagInfo { 00044 const MDNode *LocInfo; 00045 LLVMContext::InlineAsmDiagHandlerTy DiagHandler; 00046 void *DiagContext; 00047 }; 00048 } 00049 00050 /// srcMgrDiagHandler - This callback is invoked when the SourceMgr for an 00051 /// inline asm has an error in it. diagInfo is a pointer to the SrcMgrDiagInfo 00052 /// struct above. 00053 static void srcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) { 00054 SrcMgrDiagInfo *DiagInfo = static_cast<SrcMgrDiagInfo *>(diagInfo); 00055 assert(DiagInfo && "Diagnostic context not passed down?"); 00056 00057 // If the inline asm had metadata associated with it, pull out a location 00058 // cookie corresponding to which line the error occurred on. 00059 unsigned LocCookie = 0; 00060 if (const MDNode *LocInfo = DiagInfo->LocInfo) { 00061 unsigned ErrorLine = Diag.getLineNo()-1; 00062 if (ErrorLine >= LocInfo->getNumOperands()) 00063 ErrorLine = 0; 00064 00065 if (LocInfo->getNumOperands() != 0) 00066 if (const ConstantInt *CI = 00067 dyn_cast<ConstantInt>(LocInfo->getOperand(ErrorLine))) 00068 LocCookie = CI->getZExtValue(); 00069 } 00070 00071 DiagInfo->DiagHandler(Diag, DiagInfo->DiagContext, LocCookie); 00072 } 00073 00074 /// EmitInlineAsm - Emit a blob of inline asm to the output streamer. 00075 void AsmPrinter::EmitInlineAsm(StringRef Str, const MDNode *LocMDNode, 00076 InlineAsm::AsmDialect Dialect) const { 00077 assert(!Str.empty() && "Can't emit empty inline asm block"); 00078 00079 // Remember if the buffer is nul terminated or not so we can avoid a copy. 00080 bool isNullTerminated = Str.back() == 0; 00081 if (isNullTerminated) 00082 Str = Str.substr(0, Str.size()-1); 00083 00084 // If the output streamer does not have mature MC support or the integrated 00085 // assembler has been disabled, just emit the blob textually. 00086 // Otherwise parse the asm and emit it via MC support. 00087 // This is useful in case the asm parser doesn't handle something but the 00088 // system assembler does. 00089 const MCAsmInfo *MCAI = TM.getMCAsmInfo(); 00090 assert(MCAI && "No MCAsmInfo"); 00091 if (!MCAI->useIntegratedAssembler() && 00092 !OutStreamer.isIntegratedAssemblerRequired()) { 00093 OutStreamer.EmitRawText(Str); 00094 emitInlineAsmEnd(TM.getSubtarget<MCSubtargetInfo>(), nullptr); 00095 return; 00096 } 00097 00098 SourceMgr SrcMgr; 00099 SrcMgrDiagInfo DiagInfo; 00100 00101 // If the current LLVMContext has an inline asm handler, set it in SourceMgr. 00102 LLVMContext &LLVMCtx = MMI->getModule()->getContext(); 00103 bool HasDiagHandler = false; 00104 if (LLVMCtx.getInlineAsmDiagnosticHandler() != nullptr) { 00105 // If the source manager has an issue, we arrange for srcMgrDiagHandler 00106 // to be invoked, getting DiagInfo passed into it. 00107 DiagInfo.LocInfo = LocMDNode; 00108 DiagInfo.DiagHandler = LLVMCtx.getInlineAsmDiagnosticHandler(); 00109 DiagInfo.DiagContext = LLVMCtx.getInlineAsmDiagnosticContext(); 00110 SrcMgr.setDiagHandler(srcMgrDiagHandler, &DiagInfo); 00111 HasDiagHandler = true; 00112 } 00113 00114 std::unique_ptr<MemoryBuffer> Buffer; 00115 if (isNullTerminated) 00116 Buffer = MemoryBuffer::getMemBuffer(Str, "<inline asm>"); 00117 else 00118 Buffer = MemoryBuffer::getMemBufferCopy(Str, "<inline asm>"); 00119 00120 // Tell SrcMgr about this buffer, it takes ownership of the buffer. 00121 SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc()); 00122 00123 std::unique_ptr<MCAsmParser> Parser( 00124 createMCAsmParser(SrcMgr, OutContext, OutStreamer, *MAI)); 00125 00126 // Initialize the parser with a fresh subtarget info. It is better to use a 00127 // new STI here because the parser may modify it and we do not want those 00128 // modifications to persist after parsing the inlineasm. The modifications 00129 // made by the parser will be seen by the code emitters because it passes 00130 // the current STI down to the EncodeInstruction() method. 00131 std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo( 00132 TM.getTargetTriple(), TM.getTargetCPU(), TM.getTargetFeatureString())); 00133 00134 // Preserve a copy of the original STI because the parser may modify it. For 00135 // example, when switching between arm and thumb mode. If the target needs to 00136 // emit code to return to the original state it can do so in 00137 // emitInlineAsmEnd(). 00138 MCSubtargetInfo STIOrig = *STI; 00139 00140 MCTargetOptions MCOptions; 00141 if (MF) 00142 MCOptions = MF->getTarget().Options.MCOptions; 00143 std::unique_ptr<MCTargetAsmParser> TAP( 00144 TM.getTarget().createMCAsmParser(*STI, *Parser, *MII, MCOptions)); 00145 if (!TAP) 00146 report_fatal_error("Inline asm not supported by this streamer because" 00147 " we don't have an asm parser for this target\n"); 00148 Parser->setAssemblerDialect(Dialect); 00149 Parser->setTargetParser(*TAP.get()); 00150 if (MF) { 00151 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); 00152 TAP->SetFrameRegister(TRI->getFrameRegister(*MF)); 00153 } 00154 00155 // Don't implicitly switch to the text section before the asm. 00156 int Res = Parser->Run(/*NoInitialTextSection*/ true, 00157 /*NoFinalize*/ true); 00158 emitInlineAsmEnd(STIOrig, STI.get()); 00159 if (Res && !HasDiagHandler) 00160 report_fatal_error("Error parsing inline asm\n"); 00161 } 00162 00163 static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, 00164 MachineModuleInfo *MMI, int InlineAsmVariant, 00165 AsmPrinter *AP, unsigned LocCookie, 00166 raw_ostream &OS) { 00167 // Switch to the inline assembly variant. 00168 OS << "\t.intel_syntax\n\t"; 00169 00170 const char *LastEmitted = AsmStr; // One past the last character emitted. 00171 unsigned NumOperands = MI->getNumOperands(); 00172 00173 while (*LastEmitted) { 00174 switch (*LastEmitted) { 00175 default: { 00176 // Not a special case, emit the string section literally. 00177 const char *LiteralEnd = LastEmitted+1; 00178 while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' && 00179 *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n') 00180 ++LiteralEnd; 00181 00182 OS.write(LastEmitted, LiteralEnd-LastEmitted); 00183 LastEmitted = LiteralEnd; 00184 break; 00185 } 00186 case '\n': 00187 ++LastEmitted; // Consume newline character. 00188 OS << '\n'; // Indent code with newline. 00189 break; 00190 case '$': { 00191 ++LastEmitted; // Consume '$' character. 00192 bool Done = true; 00193 00194 // Handle escapes. 00195 switch (*LastEmitted) { 00196 default: Done = false; break; 00197 case '$': 00198 ++LastEmitted; // Consume second '$' character. 00199 break; 00200 } 00201 if (Done) break; 00202 00203 const char *IDStart = LastEmitted; 00204 const char *IDEnd = IDStart; 00205 while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; 00206 00207 unsigned Val; 00208 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) 00209 report_fatal_error("Bad $ operand number in inline asm string: '" + 00210 Twine(AsmStr) + "'"); 00211 LastEmitted = IDEnd; 00212 00213 if (Val >= NumOperands-1) 00214 report_fatal_error("Invalid $ operand number in inline asm string: '" + 00215 Twine(AsmStr) + "'"); 00216 00217 // Okay, we finally have a value number. Ask the target to print this 00218 // operand! 00219 unsigned OpNo = InlineAsm::MIOp_FirstOperand; 00220 00221 bool Error = false; 00222 00223 // Scan to find the machine operand number for the operand. 00224 for (; Val; --Val) { 00225 if (OpNo >= MI->getNumOperands()) break; 00226 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 00227 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; 00228 } 00229 00230 // We may have a location metadata attached to the end of the 00231 // instruction, and at no point should see metadata at any 00232 // other point while processing. It's an error if so. 00233 if (OpNo >= MI->getNumOperands() || 00234 MI->getOperand(OpNo).isMetadata()) { 00235 Error = true; 00236 } else { 00237 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 00238 ++OpNo; // Skip over the ID number. 00239 00240 if (InlineAsm::isMemKind(OpFlags)) { 00241 Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant, 00242 /*Modifier*/ nullptr, OS); 00243 } else { 00244 Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, 00245 /*Modifier*/ nullptr, OS); 00246 } 00247 } 00248 if (Error) { 00249 std::string msg; 00250 raw_string_ostream Msg(msg); 00251 Msg << "invalid operand in inline asm: '" << AsmStr << "'"; 00252 MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); 00253 } 00254 break; 00255 } 00256 } 00257 } 00258 OS << "\n\t.att_syntax\n" << (char)0; // null terminate string. 00259 } 00260 00261 static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, 00262 MachineModuleInfo *MMI, int InlineAsmVariant, 00263 int AsmPrinterVariant, AsmPrinter *AP, 00264 unsigned LocCookie, raw_ostream &OS) { 00265 int CurVariant = -1; // The number of the {.|.|.} region we are in. 00266 const char *LastEmitted = AsmStr; // One past the last character emitted. 00267 unsigned NumOperands = MI->getNumOperands(); 00268 00269 OS << '\t'; 00270 00271 while (*LastEmitted) { 00272 switch (*LastEmitted) { 00273 default: { 00274 // Not a special case, emit the string section literally. 00275 const char *LiteralEnd = LastEmitted+1; 00276 while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' && 00277 *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n') 00278 ++LiteralEnd; 00279 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) 00280 OS.write(LastEmitted, LiteralEnd-LastEmitted); 00281 LastEmitted = LiteralEnd; 00282 break; 00283 } 00284 case '\n': 00285 ++LastEmitted; // Consume newline character. 00286 OS << '\n'; // Indent code with newline. 00287 break; 00288 case '$': { 00289 ++LastEmitted; // Consume '$' character. 00290 bool Done = true; 00291 00292 // Handle escapes. 00293 switch (*LastEmitted) { 00294 default: Done = false; break; 00295 case '$': // $$ -> $ 00296 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) 00297 OS << '$'; 00298 ++LastEmitted; // Consume second '$' character. 00299 break; 00300 case '(': // $( -> same as GCC's { character. 00301 ++LastEmitted; // Consume '(' character. 00302 if (CurVariant != -1) 00303 report_fatal_error("Nested variants found in inline asm string: '" + 00304 Twine(AsmStr) + "'"); 00305 CurVariant = 0; // We're in the first variant now. 00306 break; 00307 case '|': 00308 ++LastEmitted; // consume '|' character. 00309 if (CurVariant == -1) 00310 OS << '|'; // this is gcc's behavior for | outside a variant 00311 else 00312 ++CurVariant; // We're in the next variant. 00313 break; 00314 case ')': // $) -> same as GCC's } char. 00315 ++LastEmitted; // consume ')' character. 00316 if (CurVariant == -1) 00317 OS << '}'; // this is gcc's behavior for } outside a variant 00318 else 00319 CurVariant = -1; 00320 break; 00321 } 00322 if (Done) break; 00323 00324 bool HasCurlyBraces = false; 00325 if (*LastEmitted == '{') { // ${variable} 00326 ++LastEmitted; // Consume '{' character. 00327 HasCurlyBraces = true; 00328 } 00329 00330 // If we have ${:foo}, then this is not a real operand reference, it is a 00331 // "magic" string reference, just like in .td files. Arrange to call 00332 // PrintSpecial. 00333 if (HasCurlyBraces && *LastEmitted == ':') { 00334 ++LastEmitted; 00335 const char *StrStart = LastEmitted; 00336 const char *StrEnd = strchr(StrStart, '}'); 00337 if (!StrEnd) 00338 report_fatal_error("Unterminated ${:foo} operand in inline asm" 00339 " string: '" + Twine(AsmStr) + "'"); 00340 00341 std::string Val(StrStart, StrEnd); 00342 AP->PrintSpecial(MI, OS, Val.c_str()); 00343 LastEmitted = StrEnd+1; 00344 break; 00345 } 00346 00347 const char *IDStart = LastEmitted; 00348 const char *IDEnd = IDStart; 00349 while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; 00350 00351 unsigned Val; 00352 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) 00353 report_fatal_error("Bad $ operand number in inline asm string: '" + 00354 Twine(AsmStr) + "'"); 00355 LastEmitted = IDEnd; 00356 00357 char Modifier[2] = { 0, 0 }; 00358 00359 if (HasCurlyBraces) { 00360 // If we have curly braces, check for a modifier character. This 00361 // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm. 00362 if (*LastEmitted == ':') { 00363 ++LastEmitted; // Consume ':' character. 00364 if (*LastEmitted == 0) 00365 report_fatal_error("Bad ${:} expression in inline asm string: '" + 00366 Twine(AsmStr) + "'"); 00367 00368 Modifier[0] = *LastEmitted; 00369 ++LastEmitted; // Consume modifier character. 00370 } 00371 00372 if (*LastEmitted != '}') 00373 report_fatal_error("Bad ${} expression in inline asm string: '" + 00374 Twine(AsmStr) + "'"); 00375 ++LastEmitted; // Consume '}' character. 00376 } 00377 00378 if (Val >= NumOperands-1) 00379 report_fatal_error("Invalid $ operand number in inline asm string: '" + 00380 Twine(AsmStr) + "'"); 00381 00382 // Okay, we finally have a value number. Ask the target to print this 00383 // operand! 00384 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) { 00385 unsigned OpNo = InlineAsm::MIOp_FirstOperand; 00386 00387 bool Error = false; 00388 00389 // Scan to find the machine operand number for the operand. 00390 for (; Val; --Val) { 00391 if (OpNo >= MI->getNumOperands()) break; 00392 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 00393 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; 00394 } 00395 00396 // We may have a location metadata attached to the end of the 00397 // instruction, and at no point should see metadata at any 00398 // other point while processing. It's an error if so. 00399 if (OpNo >= MI->getNumOperands() || 00400 MI->getOperand(OpNo).isMetadata()) { 00401 Error = true; 00402 } else { 00403 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 00404 ++OpNo; // Skip over the ID number. 00405 00406 if (Modifier[0] == 'l') // labels are target independent 00407 // FIXME: What if the operand isn't an MBB, report error? 00408 OS << *MI->getOperand(OpNo).getMBB()->getSymbol(); 00409 else { 00410 if (InlineAsm::isMemKind(OpFlags)) { 00411 Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant, 00412 Modifier[0] ? Modifier : nullptr, 00413 OS); 00414 } else { 00415 Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, 00416 Modifier[0] ? Modifier : nullptr, OS); 00417 } 00418 } 00419 } 00420 if (Error) { 00421 std::string msg; 00422 raw_string_ostream Msg(msg); 00423 Msg << "invalid operand in inline asm: '" << AsmStr << "'"; 00424 MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); 00425 } 00426 } 00427 break; 00428 } 00429 } 00430 } 00431 OS << '\n' << (char)0; // null terminate string. 00432 } 00433 00434 /// EmitInlineAsm - This method formats and emits the specified machine 00435 /// instruction that is an inline asm. 00436 void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { 00437 assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); 00438 00439 // Count the number of register definitions to find the asm string. 00440 unsigned NumDefs = 0; 00441 for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); 00442 ++NumDefs) 00443 assert(NumDefs != MI->getNumOperands()-2 && "No asm string?"); 00444 00445 assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?"); 00446 00447 // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. 00448 const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); 00449 00450 // If this asmstr is empty, just print the #APP/#NOAPP markers. 00451 // These are useful to see where empty asm's wound up. 00452 if (AsmStr[0] == 0) { 00453 OutStreamer.emitRawComment(MAI->getInlineAsmStart()); 00454 OutStreamer.emitRawComment(MAI->getInlineAsmEnd()); 00455 return; 00456 } 00457 00458 // Emit the #APP start marker. This has to happen even if verbose-asm isn't 00459 // enabled, so we use emitRawComment. 00460 OutStreamer.emitRawComment(MAI->getInlineAsmStart()); 00461 00462 // Get the !srcloc metadata node if we have it, and decode the loc cookie from 00463 // it. 00464 unsigned LocCookie = 0; 00465 const MDNode *LocMD = nullptr; 00466 for (unsigned i = MI->getNumOperands(); i != 0; --i) { 00467 if (MI->getOperand(i-1).isMetadata() && 00468 (LocMD = MI->getOperand(i-1).getMetadata()) && 00469 LocMD->getNumOperands() != 0) { 00470 if (const ConstantInt *CI = dyn_cast<ConstantInt>(LocMD->getOperand(0))) { 00471 LocCookie = CI->getZExtValue(); 00472 break; 00473 } 00474 } 00475 } 00476 00477 // Emit the inline asm to a temporary string so we can emit it through 00478 // EmitInlineAsm. 00479 SmallString<256> StringData; 00480 raw_svector_ostream OS(StringData); 00481 00482 // The variant of the current asmprinter. 00483 int AsmPrinterVariant = MAI->getAssemblerDialect(); 00484 InlineAsm::AsmDialect InlineAsmVariant = MI->getInlineAsmDialect(); 00485 AsmPrinter *AP = const_cast<AsmPrinter*>(this); 00486 if (InlineAsmVariant == InlineAsm::AD_ATT) 00487 EmitGCCInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AsmPrinterVariant, 00488 AP, LocCookie, OS); 00489 else 00490 EmitMSInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AP, LocCookie, OS); 00491 00492 EmitInlineAsm(OS.str(), LocMD, MI->getInlineAsmDialect()); 00493 00494 // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't 00495 // enabled, so we use emitRawComment. 00496 OutStreamer.emitRawComment(MAI->getInlineAsmEnd()); 00497 } 00498 00499 00500 /// PrintSpecial - Print information related to the specified machine instr 00501 /// that is independent of the operand, and may be independent of the instr 00502 /// itself. This can be useful for portably encoding the comment character 00503 /// or other bits of target-specific knowledge into the asmstrings. The 00504 /// syntax used is ${:comment}. Targets can override this to add support 00505 /// for their own strange codes. 00506 void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, 00507 const char *Code) const { 00508 const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); 00509 if (!strcmp(Code, "private")) { 00510 OS << DL->getPrivateGlobalPrefix(); 00511 } else if (!strcmp(Code, "comment")) { 00512 OS << MAI->getCommentString(); 00513 } else if (!strcmp(Code, "uid")) { 00514 // Comparing the address of MI isn't sufficient, because machineinstrs may 00515 // be allocated to the same address across functions. 00516 00517 // If this is a new LastFn instruction, bump the counter. 00518 if (LastMI != MI || LastFn != getFunctionNumber()) { 00519 ++Counter; 00520 LastMI = MI; 00521 LastFn = getFunctionNumber(); 00522 } 00523 OS << Counter; 00524 } else { 00525 std::string msg; 00526 raw_string_ostream Msg(msg); 00527 Msg << "Unknown special formatter '" << Code 00528 << "' for machine instr: " << *MI; 00529 report_fatal_error(Msg.str()); 00530 } 00531 } 00532 00533 /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM 00534 /// instruction, using the specified assembler variant. Targets should 00535 /// override this to format as appropriate. 00536 bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 00537 unsigned AsmVariant, const char *ExtraCode, 00538 raw_ostream &O) { 00539 // Does this asm operand have a single letter operand modifier? 00540 if (ExtraCode && ExtraCode[0]) { 00541 if (ExtraCode[1] != 0) return true; // Unknown modifier. 00542 00543 const MachineOperand &MO = MI->getOperand(OpNo); 00544 switch (ExtraCode[0]) { 00545 default: 00546 return true; // Unknown modifier. 00547 case 'c': // Substitute immediate value without immediate syntax 00548 if (MO.getType() != MachineOperand::MO_Immediate) 00549 return true; 00550 O << MO.getImm(); 00551 return false; 00552 case 'n': // Negate the immediate constant. 00553 if (MO.getType() != MachineOperand::MO_Immediate) 00554 return true; 00555 O << -MO.getImm(); 00556 return false; 00557 } 00558 } 00559 return true; 00560 } 00561 00562 bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 00563 unsigned AsmVariant, 00564 const char *ExtraCode, raw_ostream &O) { 00565 // Target doesn't support this yet! 00566 return true; 00567 } 00568 00569 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, 00570 const MCSubtargetInfo *EndInfo) const {}