1 //===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===//
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
7 //===----------------------------------------------------------------------===//
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"
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.
60 LocInfos
.resize(BufNum
);
61 LocInfos
[BufNum
- 1] = LocMDNode
;
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;
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()) {
91 OutStreamer
->emitRawText(Str
);
92 emitInlineAsmEnd(STI
, nullptr);
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
));
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
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
) {
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')
149 OS
.write(LastEmitted
, LiteralEnd
-LastEmitted
);
150 LastEmitted
= LiteralEnd
;
154 ++LastEmitted
; // Consume newline character.
155 OS
<< '\n'; // Indent code with newline.
158 ++LastEmitted
; // Consume '$' character.
162 switch (*LastEmitted
) {
163 default: Done
= false; break;
165 ++LastEmitted
; // Consume second '$' character.
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
179 if (HasCurlyBraces
&& LastEmitted
[0] == ':') {
181 const char *StrStart
= LastEmitted
;
182 const char *StrEnd
= strchr(StrStart
, '}');
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;
193 const char *IDStart
= LastEmitted
;
194 const char *IDEnd
= IDStart
;
195 while (isDigit(*IDEnd
))
199 if (StringRef(IDStart
, IDEnd
-IDStart
).getAsInteger(10, Val
))
200 report_fatal_error("Bad $ operand number in inline asm string: '" +
201 Twine(AsmStr
) + "'");
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
231 unsigned OpNo
= InlineAsm::MIOp_FirstOperand
;
235 // Scan to find the machine operand number for the operand.
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()) {
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
);
256 Error
= AP
->PrintAsmOperand(MI
, OpNo
,
257 Modifier
[0] ? Modifier
: nullptr, OS
);
262 raw_string_ostream
Msg(msg
);
263 Msg
<< "invalid operand in inline asm: '" << AsmStr
<< "'";
264 MMI
->getModule()->getContext().emitError(LocCookie
, Msg
.str());
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
,
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())
285 while (*LastEmitted
) {
286 switch (*LastEmitted
) {
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')
293 if (CurVariant
== -1 || CurVariant
== AsmPrinterVariant
)
294 OS
.write(LastEmitted
, LiteralEnd
-LastEmitted
);
295 LastEmitted
= LiteralEnd
;
299 ++LastEmitted
; // Consume newline character.
300 OS
<< '\n'; // Indent code with newline.
303 ++LastEmitted
; // Consume '$' character.
307 switch (*LastEmitted
) {
308 default: Done
= false; break;
310 if (CurVariant
== -1 || CurVariant
== AsmPrinterVariant
)
312 ++LastEmitted
; // Consume second '$' character.
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.
322 ++LastEmitted
; // consume '|' character.
323 if (CurVariant
== -1)
324 OS
<< '|'; // this is gcc's behavior for | outside a variant
326 ++CurVariant
; // We're in the next variant.
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
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
347 if (HasCurlyBraces
&& *LastEmitted
== ':') {
349 const char *StrStart
= LastEmitted
;
350 const char *StrEnd
= strchr(StrStart
, '}');
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;
361 const char *IDStart
= LastEmitted
;
362 const char *IDEnd
= IDStart
;
363 while (isDigit(*IDEnd
))
367 if (StringRef(IDStart
, IDEnd
-IDStart
).getAsInteger(10, Val
))
368 report_fatal_error("Bad $ operand number in inline asm string: '" +
369 Twine(AsmStr
) + "'");
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
399 if (CurVariant
== -1 || CurVariant
== AsmPrinterVariant
) {
400 unsigned OpNo
= InlineAsm::MIOp_FirstOperand
;
404 // Scan to find the machine operand number for the operand.
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()) {
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
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') {
434 } else if (InlineAsm::isMemKind(OpFlags
)) {
435 Error
= AP
->PrintAsmMemoryOperand(
436 MI
, OpNo
, Modifier
[0] ? Modifier
: nullptr, OS
);
438 Error
= AP
->PrintAsmOperand(MI
, OpNo
,
439 Modifier
[0] ? Modifier
: nullptr, OS
);
444 raw_string_ostream
Msg(msg
);
445 Msg
<< "invalid operand in inline asm: '" << AsmStr
<< "'";
446 MMI
->getModule()->getContext().emitError(LocCookie
, Msg
.str());
453 OS
<< '\n' << (char)0; // null terminate string.
456 /// This method formats and emits the specified machine instruction that is an
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();
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());
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
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();
500 // Emit the inline asm to a temporary string so we can emit it through
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
);
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();
518 const MachineOperand
&MO
= MI
->getOperand(I
);
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: ";
534 for (const Register
&RR
: RestrRegs
) {
536 Msg
+= TRI
->getName(RR
);
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()) {
577 LastFn
= getFunctionNumber();
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]) {
609 return true; // Unknown modifier.
610 case 'a': // Print as memory address.
612 PrintAsmMemoryOperand(MI
, OpNo
, nullptr, O
);
615 LLVM_FALLTHROUGH
; // GCC allows '%a' to behave like '%c' with immediates.
616 case 'c': // Substitute immediate value without immediate syntax
622 PrintSymbolOperand(MO
, O
);
626 case 'n': // Negate the immediate constant.
631 case 's': // The GCC deprecated s modifier
634 O
<< ((32 - MO
.getImm()) & 31);
641 bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
642 const char *ExtraCode
, raw_ostream
&O
) {
643 // Target doesn't support this yet!
647 void AsmPrinter::emitInlineAsmStart() const {}
649 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo
&StartInfo
,
650 const MCSubtargetInfo
*EndInfo
) const {}