[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / CodeGen / AsmPrinter / AsmPrinterInlineAsm.cpp
blob4a93181f5439d36ddf539678c92da76d200c5e73
1 //===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the inline assembler pieces of the AsmPrinter class.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/ADT/Twine.h"
16 #include "llvm/CodeGen/AsmPrinter.h"
17 #include "llvm/CodeGen/MachineBasicBlock.h"
18 #include "llvm/CodeGen/MachineFunction.h"
19 #include "llvm/CodeGen/MachineModuleInfo.h"
20 #include "llvm/CodeGen/TargetInstrInfo.h"
21 #include "llvm/CodeGen/TargetRegisterInfo.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/DataLayout.h"
24 #include "llvm/IR/DiagnosticInfo.h"
25 #include "llvm/IR/InlineAsm.h"
26 #include "llvm/IR/LLVMContext.h"
27 #include "llvm/IR/Module.h"
28 #include "llvm/MC/MCAsmInfo.h"
29 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
30 #include "llvm/MC/MCStreamer.h"
31 #include "llvm/MC/MCSubtargetInfo.h"
32 #include "llvm/MC/MCSymbol.h"
33 #include "llvm/Support/ErrorHandling.h"
34 #include "llvm/Support/MemoryBuffer.h"
35 #include "llvm/Support/SourceMgr.h"
36 #include "llvm/Support/TargetRegistry.h"
37 #include "llvm/Support/raw_ostream.h"
38 #include "llvm/Target/TargetMachine.h"
39 using namespace llvm;
41 #define DEBUG_TYPE "asm-printer"
43 unsigned AsmPrinter::addInlineAsmDiagBuffer(StringRef AsmStr,
44 const MDNode *LocMDNode) const {
45 MCContext &Context = MMI->getContext();
46 Context.initInlineSourceManager();
47 SourceMgr &SrcMgr = *Context.getInlineSourceManager();
48 std::vector<const MDNode *> &LocInfos = Context.getLocInfos();
50 std::unique_ptr<MemoryBuffer> Buffer;
51 // The inline asm source manager will outlive AsmStr, so make a copy of the
52 // string for SourceMgr to own.
53 Buffer = MemoryBuffer::getMemBufferCopy(AsmStr, "<inline asm>");
55 // Tell SrcMgr about this buffer, it takes ownership of the buffer.
56 unsigned BufNum = SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
58 // Store LocMDNode in DiagInfo, using BufNum as an identifier.
59 if (LocMDNode) {
60 LocInfos.resize(BufNum);
61 LocInfos[BufNum - 1] = LocMDNode;
64 return BufNum;
68 /// EmitInlineAsm - Emit a blob of inline asm to the output streamer.
69 void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
70 const MCTargetOptions &MCOptions,
71 const MDNode *LocMDNode,
72 InlineAsm::AsmDialect Dialect) const {
73 assert(!Str.empty() && "Can't emit empty inline asm block");
75 // Remember if the buffer is nul terminated or not so we can avoid a copy.
76 bool isNullTerminated = Str.back() == 0;
77 if (isNullTerminated)
78 Str = Str.substr(0, Str.size()-1);
80 // If the output streamer does not have mature MC support or the integrated
81 // assembler has been disabled or not required, just emit the blob textually.
82 // Otherwise parse the asm and emit it via MC support.
83 // This is useful in case the asm parser doesn't handle something but the
84 // system assembler does.
85 const MCAsmInfo *MCAI = TM.getMCAsmInfo();
86 assert(MCAI && "No MCAsmInfo");
87 if (!MCAI->useIntegratedAssembler() &&
88 !MCAI->parseInlineAsmUsingAsmParser() &&
89 !OutStreamer->isIntegratedAssemblerRequired()) {
90 emitInlineAsmStart();
91 OutStreamer->emitRawText(Str);
92 emitInlineAsmEnd(STI, nullptr);
93 return;
96 unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode);
97 SourceMgr &SrcMgr = *MMI->getContext().getInlineSourceManager();
98 SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
100 std::unique_ptr<MCAsmParser> Parser(
101 createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
103 // Do not use assembler-level information for parsing inline assembly.
104 OutStreamer->setUseAssemblerInfoForParsing(false);
106 // We create a new MCInstrInfo here since we might be at the module level
107 // and not have a MachineFunction to initialize the TargetInstrInfo from and
108 // we only need MCInstrInfo for asm parsing. We create one unconditionally
109 // because it's not subtarget dependent.
110 std::unique_ptr<MCInstrInfo> MII(TM.getTarget().createMCInstrInfo());
111 assert(MII && "Failed to create instruction info");
112 std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser(
113 STI, *Parser, *MII, MCOptions));
114 if (!TAP)
115 report_fatal_error("Inline asm not supported by this streamer because"
116 " we don't have an asm parser for this target\n");
117 Parser->setAssemblerDialect(Dialect);
118 Parser->setTargetParser(*TAP.get());
119 // Enable lexing Masm binary and hex integer literals in intel inline
120 // assembly.
121 if (Dialect == InlineAsm::AD_Intel)
122 Parser->getLexer().setLexMasmIntegers(true);
124 emitInlineAsmStart();
125 // Don't implicitly switch to the text section before the asm.
126 (void)Parser->Run(/*NoInitialTextSection*/ true,
127 /*NoFinalize*/ true);
128 emitInlineAsmEnd(STI, &TAP->getSTI());
131 static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
132 MachineModuleInfo *MMI, AsmPrinter *AP,
133 uint64_t LocCookie, raw_ostream &OS) {
134 // Switch to the inline assembly variant.
135 OS << "\t.intel_syntax\n\t";
137 const char *LastEmitted = AsmStr; // One past the last character emitted.
138 unsigned NumOperands = MI->getNumOperands();
140 while (*LastEmitted) {
141 switch (*LastEmitted) {
142 default: {
143 // Not a special case, emit the string section literally.
144 const char *LiteralEnd = LastEmitted+1;
145 while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
146 *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
147 ++LiteralEnd;
149 OS.write(LastEmitted, LiteralEnd-LastEmitted);
150 LastEmitted = LiteralEnd;
151 break;
153 case '\n':
154 ++LastEmitted; // Consume newline character.
155 OS << '\n'; // Indent code with newline.
156 break;
157 case '$': {
158 ++LastEmitted; // Consume '$' character.
159 bool Done = true;
161 // Handle escapes.
162 switch (*LastEmitted) {
163 default: Done = false; break;
164 case '$':
165 ++LastEmitted; // Consume second '$' character.
166 break;
168 if (Done) break;
170 bool HasCurlyBraces = false;
171 if (*LastEmitted == '{') { // ${variable}
172 ++LastEmitted; // Consume '{' character.
173 HasCurlyBraces = true;
176 // If we have ${:foo}, then this is not a real operand reference, it is a
177 // "magic" string reference, just like in .td files. Arrange to call
178 // PrintSpecial.
179 if (HasCurlyBraces && LastEmitted[0] == ':') {
180 ++LastEmitted;
181 const char *StrStart = LastEmitted;
182 const char *StrEnd = strchr(StrStart, '}');
183 if (!StrEnd)
184 report_fatal_error("Unterminated ${:foo} operand in inline asm"
185 " string: '" + Twine(AsmStr) + "'");
187 std::string Val(StrStart, StrEnd);
188 AP->PrintSpecial(MI, OS, Val.c_str());
189 LastEmitted = StrEnd+1;
190 break;
193 const char *IDStart = LastEmitted;
194 const char *IDEnd = IDStart;
195 while (isDigit(*IDEnd))
196 ++IDEnd;
198 unsigned Val;
199 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
200 report_fatal_error("Bad $ operand number in inline asm string: '" +
201 Twine(AsmStr) + "'");
202 LastEmitted = IDEnd;
204 if (Val >= NumOperands-1)
205 report_fatal_error("Invalid $ operand number in inline asm string: '" +
206 Twine(AsmStr) + "'");
208 char Modifier[2] = { 0, 0 };
210 if (HasCurlyBraces) {
211 // If we have curly braces, check for a modifier character. This
212 // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
213 if (*LastEmitted == ':') {
214 ++LastEmitted; // Consume ':' character.
215 if (*LastEmitted == 0)
216 report_fatal_error("Bad ${:} expression in inline asm string: '" +
217 Twine(AsmStr) + "'");
219 Modifier[0] = *LastEmitted;
220 ++LastEmitted; // Consume modifier character.
223 if (*LastEmitted != '}')
224 report_fatal_error("Bad ${} expression in inline asm string: '" +
225 Twine(AsmStr) + "'");
226 ++LastEmitted; // Consume '}' character.
229 // Okay, we finally have a value number. Ask the target to print this
230 // operand!
231 unsigned OpNo = InlineAsm::MIOp_FirstOperand;
233 bool Error = false;
235 // Scan to find the machine operand number for the operand.
236 for (; Val; --Val) {
237 if (OpNo >= MI->getNumOperands()) break;
238 unsigned OpFlags = MI->getOperand(OpNo).getImm();
239 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
242 // We may have a location metadata attached to the end of the
243 // instruction, and at no point should see metadata at any
244 // other point while processing. It's an error if so.
245 if (OpNo >= MI->getNumOperands() ||
246 MI->getOperand(OpNo).isMetadata()) {
247 Error = true;
248 } else {
249 unsigned OpFlags = MI->getOperand(OpNo).getImm();
250 ++OpNo; // Skip over the ID number.
252 if (InlineAsm::isMemKind(OpFlags)) {
253 Error = AP->PrintAsmMemoryOperand(
254 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
255 } else {
256 Error = AP->PrintAsmOperand(MI, OpNo,
257 Modifier[0] ? Modifier : nullptr, OS);
260 if (Error) {
261 std::string msg;
262 raw_string_ostream Msg(msg);
263 Msg << "invalid operand in inline asm: '" << AsmStr << "'";
264 MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
266 break;
270 OS << "\n\t.att_syntax\n" << (char)0; // null terminate string.
273 static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
274 MachineModuleInfo *MMI, const MCAsmInfo *MAI,
275 AsmPrinter *AP, uint64_t LocCookie,
276 raw_ostream &OS) {
277 int CurVariant = -1; // The number of the {.|.|.} region we are in.
278 const char *LastEmitted = AsmStr; // One past the last character emitted.
279 unsigned NumOperands = MI->getNumOperands();
280 int AsmPrinterVariant = MAI->getAssemblerDialect();
282 if (MAI->getEmitGNUAsmStartIndentationMarker())
283 OS << '\t';
285 while (*LastEmitted) {
286 switch (*LastEmitted) {
287 default: {
288 // Not a special case, emit the string section literally.
289 const char *LiteralEnd = LastEmitted+1;
290 while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
291 *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
292 ++LiteralEnd;
293 if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
294 OS.write(LastEmitted, LiteralEnd-LastEmitted);
295 LastEmitted = LiteralEnd;
296 break;
298 case '\n':
299 ++LastEmitted; // Consume newline character.
300 OS << '\n'; // Indent code with newline.
301 break;
302 case '$': {
303 ++LastEmitted; // Consume '$' character.
304 bool Done = true;
306 // Handle escapes.
307 switch (*LastEmitted) {
308 default: Done = false; break;
309 case '$': // $$ -> $
310 if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
311 OS << '$';
312 ++LastEmitted; // Consume second '$' character.
313 break;
314 case '(': // $( -> same as GCC's { character.
315 ++LastEmitted; // Consume '(' character.
316 if (CurVariant != -1)
317 report_fatal_error("Nested variants found in inline asm string: '" +
318 Twine(AsmStr) + "'");
319 CurVariant = 0; // We're in the first variant now.
320 break;
321 case '|':
322 ++LastEmitted; // consume '|' character.
323 if (CurVariant == -1)
324 OS << '|'; // this is gcc's behavior for | outside a variant
325 else
326 ++CurVariant; // We're in the next variant.
327 break;
328 case ')': // $) -> same as GCC's } char.
329 ++LastEmitted; // consume ')' character.
330 if (CurVariant == -1)
331 OS << '}'; // this is gcc's behavior for } outside a variant
332 else
333 CurVariant = -1;
334 break;
336 if (Done) break;
338 bool HasCurlyBraces = false;
339 if (*LastEmitted == '{') { // ${variable}
340 ++LastEmitted; // Consume '{' character.
341 HasCurlyBraces = true;
344 // If we have ${:foo}, then this is not a real operand reference, it is a
345 // "magic" string reference, just like in .td files. Arrange to call
346 // PrintSpecial.
347 if (HasCurlyBraces && *LastEmitted == ':') {
348 ++LastEmitted;
349 const char *StrStart = LastEmitted;
350 const char *StrEnd = strchr(StrStart, '}');
351 if (!StrEnd)
352 report_fatal_error("Unterminated ${:foo} operand in inline asm"
353 " string: '" + Twine(AsmStr) + "'");
355 std::string Val(StrStart, StrEnd);
356 AP->PrintSpecial(MI, OS, Val.c_str());
357 LastEmitted = StrEnd+1;
358 break;
361 const char *IDStart = LastEmitted;
362 const char *IDEnd = IDStart;
363 while (isDigit(*IDEnd))
364 ++IDEnd;
366 unsigned Val;
367 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
368 report_fatal_error("Bad $ operand number in inline asm string: '" +
369 Twine(AsmStr) + "'");
370 LastEmitted = IDEnd;
372 char Modifier[2] = { 0, 0 };
374 if (HasCurlyBraces) {
375 // If we have curly braces, check for a modifier character. This
376 // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
377 if (*LastEmitted == ':') {
378 ++LastEmitted; // Consume ':' character.
379 if (*LastEmitted == 0)
380 report_fatal_error("Bad ${:} expression in inline asm string: '" +
381 Twine(AsmStr) + "'");
383 Modifier[0] = *LastEmitted;
384 ++LastEmitted; // Consume modifier character.
387 if (*LastEmitted != '}')
388 report_fatal_error("Bad ${} expression in inline asm string: '" +
389 Twine(AsmStr) + "'");
390 ++LastEmitted; // Consume '}' character.
393 if (Val >= NumOperands-1)
394 report_fatal_error("Invalid $ operand number in inline asm string: '" +
395 Twine(AsmStr) + "'");
397 // Okay, we finally have a value number. Ask the target to print this
398 // operand!
399 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
400 unsigned OpNo = InlineAsm::MIOp_FirstOperand;
402 bool Error = false;
404 // Scan to find the machine operand number for the operand.
405 for (; Val; --Val) {
406 if (OpNo >= MI->getNumOperands()) break;
407 unsigned OpFlags = MI->getOperand(OpNo).getImm();
408 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
411 // We may have a location metadata attached to the end of the
412 // instruction, and at no point should see metadata at any
413 // other point while processing. It's an error if so.
414 if (OpNo >= MI->getNumOperands() ||
415 MI->getOperand(OpNo).isMetadata()) {
416 Error = true;
417 } else {
418 unsigned OpFlags = MI->getOperand(OpNo).getImm();
419 ++OpNo; // Skip over the ID number.
421 // FIXME: Shouldn't arch-independent output template handling go into
422 // PrintAsmOperand?
423 // Labels are target independent.
424 if (MI->getOperand(OpNo).isBlockAddress()) {
425 const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress();
426 MCSymbol *Sym = AP->GetBlockAddressSymbol(BA);
427 Sym->print(OS, AP->MAI);
428 MMI->getContext().registerInlineAsmLabel(Sym);
429 } else if (MI->getOperand(OpNo).isMBB()) {
430 const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol();
431 Sym->print(OS, AP->MAI);
432 } else if (Modifier[0] == 'l') {
433 Error = true;
434 } else if (InlineAsm::isMemKind(OpFlags)) {
435 Error = AP->PrintAsmMemoryOperand(
436 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
437 } else {
438 Error = AP->PrintAsmOperand(MI, OpNo,
439 Modifier[0] ? Modifier : nullptr, OS);
442 if (Error) {
443 std::string msg;
444 raw_string_ostream Msg(msg);
445 Msg << "invalid operand in inline asm: '" << AsmStr << "'";
446 MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
449 break;
453 OS << '\n' << (char)0; // null terminate string.
456 /// This method formats and emits the specified machine instruction that is an
457 /// inline asm.
458 void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const {
459 assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms");
461 // Count the number of register definitions to find the asm string.
462 unsigned NumDefs = 0;
463 for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef();
464 ++NumDefs)
465 assert(NumDefs != MI->getNumOperands()-2 && "No asm string?");
467 assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?");
469 // Disassemble the AsmStr, printing out the literal pieces, the operands, etc.
470 const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
472 // If this asmstr is empty, just print the #APP/#NOAPP markers.
473 // These are useful to see where empty asm's wound up.
474 if (AsmStr[0] == 0) {
475 OutStreamer->emitRawComment(MAI->getInlineAsmStart());
476 OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
477 return;
480 // Emit the #APP start marker. This has to happen even if verbose-asm isn't
481 // enabled, so we use emitRawComment.
482 OutStreamer->emitRawComment(MAI->getInlineAsmStart());
484 // Get the !srcloc metadata node if we have it, and decode the loc cookie from
485 // it.
486 uint64_t LocCookie = 0;
487 const MDNode *LocMD = nullptr;
488 for (unsigned i = MI->getNumOperands(); i != 0; --i) {
489 if (MI->getOperand(i-1).isMetadata() &&
490 (LocMD = MI->getOperand(i-1).getMetadata()) &&
491 LocMD->getNumOperands() != 0) {
492 if (const ConstantInt *CI =
493 mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) {
494 LocCookie = CI->getZExtValue();
495 break;
500 // Emit the inline asm to a temporary string so we can emit it through
501 // EmitInlineAsm.
502 SmallString<256> StringData;
503 raw_svector_ostream OS(StringData);
505 AsmPrinter *AP = const_cast<AsmPrinter*>(this);
506 if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT)
507 EmitGCCInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS);
508 else
509 EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS);
511 // Emit warnings if we use reserved registers on the clobber list, as
512 // that might lead to undefined behaviour.
513 SmallVector<Register, 8> RestrRegs;
514 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
515 // Start with the first operand descriptor, and iterate over them.
516 for (unsigned I = InlineAsm::MIOp_FirstOperand, NumOps = MI->getNumOperands();
517 I < NumOps; ++I) {
518 const MachineOperand &MO = MI->getOperand(I);
519 if (!MO.isImm())
520 continue;
521 unsigned Flags = MO.getImm();
522 if (InlineAsm::getKind(Flags) == InlineAsm::Kind_Clobber) {
523 Register Reg = MI->getOperand(I + 1).getReg();
524 if (!TRI->isAsmClobberable(*MF, Reg))
525 RestrRegs.push_back(Reg);
527 // Skip to one before the next operand descriptor, if it exists.
528 I += InlineAsm::getNumOperandRegisters(Flags);
531 if (!RestrRegs.empty()) {
532 std::string Msg = "inline asm clobber list contains reserved registers: ";
533 ListSeparator LS;
534 for (const Register &RR : RestrRegs) {
535 Msg += LS;
536 Msg += TRI->getName(RR);
538 const char *Note =
539 "Reserved registers on the clobber list may not be "
540 "preserved across the asm statement, and clobbering them may "
541 "lead to undefined behaviour.";
542 MMI->getModule()->getContext().diagnose(DiagnosticInfoInlineAsm(
543 LocCookie, Msg.c_str(), DiagnosticSeverity::DS_Warning));
544 MMI->getModule()->getContext().diagnose(
545 DiagnosticInfoInlineAsm(LocCookie, Note, DiagnosticSeverity::DS_Note));
548 emitInlineAsm(OS.str(), getSubtargetInfo(), TM.Options.MCOptions, LocMD,
549 MI->getInlineAsmDialect());
551 // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't
552 // enabled, so we use emitRawComment.
553 OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
556 /// PrintSpecial - Print information related to the specified machine instr
557 /// that is independent of the operand, and may be independent of the instr
558 /// itself. This can be useful for portably encoding the comment character
559 /// or other bits of target-specific knowledge into the asmstrings. The
560 /// syntax used is ${:comment}. Targets can override this to add support
561 /// for their own strange codes.
562 void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
563 const char *Code) const {
564 if (!strcmp(Code, "private")) {
565 const DataLayout &DL = MF->getDataLayout();
566 OS << DL.getPrivateGlobalPrefix();
567 } else if (!strcmp(Code, "comment")) {
568 OS << MAI->getCommentString();
569 } else if (!strcmp(Code, "uid")) {
570 // Comparing the address of MI isn't sufficient, because machineinstrs may
571 // be allocated to the same address across functions.
573 // If this is a new LastFn instruction, bump the counter.
574 if (LastMI != MI || LastFn != getFunctionNumber()) {
575 ++Counter;
576 LastMI = MI;
577 LastFn = getFunctionNumber();
579 OS << Counter;
580 } else {
581 std::string msg;
582 raw_string_ostream Msg(msg);
583 Msg << "Unknown special formatter '" << Code
584 << "' for machine instr: " << *MI;
585 report_fatal_error(Msg.str());
589 void AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS) {
590 assert(MO.isGlobal() && "caller should check MO.isGlobal");
591 getSymbolPreferLocal(*MO.getGlobal())->print(OS, MAI);
592 printOffset(MO.getOffset(), OS);
595 /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
596 /// instruction, using the specified assembler variant. Targets should
597 /// override this to format as appropriate for machine specific ExtraCodes
598 /// or when the arch-independent handling would be too complex otherwise.
599 bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
600 const char *ExtraCode, raw_ostream &O) {
601 // Does this asm operand have a single letter operand modifier?
602 if (ExtraCode && ExtraCode[0]) {
603 if (ExtraCode[1] != 0) return true; // Unknown modifier.
605 // https://gcc.gnu.org/onlinedocs/gccint/Output-Template.html
606 const MachineOperand &MO = MI->getOperand(OpNo);
607 switch (ExtraCode[0]) {
608 default:
609 return true; // Unknown modifier.
610 case 'a': // Print as memory address.
611 if (MO.isReg()) {
612 PrintAsmMemoryOperand(MI, OpNo, nullptr, O);
613 return false;
615 LLVM_FALLTHROUGH; // GCC allows '%a' to behave like '%c' with immediates.
616 case 'c': // Substitute immediate value without immediate syntax
617 if (MO.isImm()) {
618 O << MO.getImm();
619 return false;
621 if (MO.isGlobal()) {
622 PrintSymbolOperand(MO, O);
623 return false;
625 return true;
626 case 'n': // Negate the immediate constant.
627 if (!MO.isImm())
628 return true;
629 O << -MO.getImm();
630 return false;
631 case 's': // The GCC deprecated s modifier
632 if (!MO.isImm())
633 return true;
634 O << ((32 - MO.getImm()) & 31);
635 return false;
638 return true;
641 bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
642 const char *ExtraCode, raw_ostream &O) {
643 // Target doesn't support this yet!
644 return true;
647 void AsmPrinter::emitInlineAsmStart() const {}
649 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
650 const MCSubtargetInfo *EndInfo) const {}