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.
10 //
11 //===----------------------------------------------------------------------===//
12
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;
40
41 #define DEBUG_TYPE "asm-printer"
42
addInlineAsmDiagBuffer(StringRef AsmStr,const MDNode * LocMDNode) const43 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();
49
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>");
54
55 // Tell SrcMgr about this buffer, it takes ownership of the buffer.
56 unsigned BufNum = SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
57
58 // Store LocMDNode in DiagInfo, using BufNum as an identifier.
59 if (LocMDNode) {
60 LocInfos.resize(BufNum);
61 LocInfos[BufNum - 1] = LocMDNode;
62 }
63
64 return BufNum;
65 }
66
67
68 /// EmitInlineAsm - Emit a blob of inline asm to the output streamer.
emitInlineAsm(StringRef Str,const MCSubtargetInfo & STI,const MCTargetOptions & MCOptions,const MDNode * LocMDNode,InlineAsm::AsmDialect Dialect) const69 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");
74
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);
79
80 // If the output streamer does not have mature MC support or the integrated
81 // assembler has been disabled, 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 !OutStreamer->isIntegratedAssemblerRequired()) {
89 emitInlineAsmStart();
90 OutStreamer->emitRawText(Str);
91 emitInlineAsmEnd(STI, nullptr);
92 return;
93 }
94
95 unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode);
96 SourceMgr &SrcMgr = *MMI->getContext().getInlineSourceManager();
97 SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
98
99 std::unique_ptr<MCAsmParser> Parser(
100 createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
101
102 // Do not use assembler-level information for parsing inline assembly.
103 OutStreamer->setUseAssemblerInfoForParsing(false);
104
105 // We create a new MCInstrInfo here since we might be at the module level
106 // and not have a MachineFunction to initialize the TargetInstrInfo from and
107 // we only need MCInstrInfo for asm parsing. We create one unconditionally
108 // because it's not subtarget dependent.
109 std::unique_ptr<MCInstrInfo> MII(TM.getTarget().createMCInstrInfo());
110 assert(MII && "Failed to create instruction info");
111 std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser(
112 STI, *Parser, *MII, MCOptions));
113 if (!TAP)
114 report_fatal_error("Inline asm not supported by this streamer because"
115 " we don't have an asm parser for this target\n");
116 Parser->setAssemblerDialect(Dialect);
117 Parser->setTargetParser(*TAP.get());
118 // Enable lexing Masm binary and hex integer literals in intel inline
119 // assembly.
120 if (Dialect == InlineAsm::AD_Intel)
121 Parser->getLexer().setLexMasmIntegers(true);
122
123 emitInlineAsmStart();
124 // Don't implicitly switch to the text section before the asm.
125 (void)Parser->Run(/*NoInitialTextSection*/ true,
126 /*NoFinalize*/ true);
127 emitInlineAsmEnd(STI, &TAP->getSTI());
128 }
129
EmitMSInlineAsmStr(const char * AsmStr,const MachineInstr * MI,MachineModuleInfo * MMI,AsmPrinter * AP,unsigned LocCookie,raw_ostream & OS)130 static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
131 MachineModuleInfo *MMI, AsmPrinter *AP,
132 unsigned LocCookie, raw_ostream &OS) {
133 // Switch to the inline assembly variant.
134 OS << "\t.intel_syntax\n\t";
135
136 const char *LastEmitted = AsmStr; // One past the last character emitted.
137 unsigned NumOperands = MI->getNumOperands();
138
139 while (*LastEmitted) {
140 switch (*LastEmitted) {
141 default: {
142 // Not a special case, emit the string section literally.
143 const char *LiteralEnd = LastEmitted+1;
144 while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
145 *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
146 ++LiteralEnd;
147
148 OS.write(LastEmitted, LiteralEnd-LastEmitted);
149 LastEmitted = LiteralEnd;
150 break;
151 }
152 case '\n':
153 ++LastEmitted; // Consume newline character.
154 OS << '\n'; // Indent code with newline.
155 break;
156 case '$': {
157 ++LastEmitted; // Consume '$' character.
158 bool Done = true;
159
160 // Handle escapes.
161 switch (*LastEmitted) {
162 default: Done = false; break;
163 case '$':
164 ++LastEmitted; // Consume second '$' character.
165 break;
166 }
167 if (Done) break;
168
169 bool HasCurlyBraces = false;
170 if (*LastEmitted == '{') { // ${variable}
171 ++LastEmitted; // Consume '{' character.
172 HasCurlyBraces = true;
173 }
174
175 // If we have ${:foo}, then this is not a real operand reference, it is a
176 // "magic" string reference, just like in .td files. Arrange to call
177 // PrintSpecial.
178 if (HasCurlyBraces && LastEmitted[0] == ':') {
179 ++LastEmitted;
180 const char *StrStart = LastEmitted;
181 const char *StrEnd = strchr(StrStart, '}');
182 if (!StrEnd)
183 report_fatal_error("Unterminated ${:foo} operand in inline asm"
184 " string: '" + Twine(AsmStr) + "'");
185
186 std::string Val(StrStart, StrEnd);
187 AP->PrintSpecial(MI, OS, Val.c_str());
188 LastEmitted = StrEnd+1;
189 break;
190 }
191
192 const char *IDStart = LastEmitted;
193 const char *IDEnd = IDStart;
194 while (isDigit(*IDEnd))
195 ++IDEnd;
196
197 unsigned Val;
198 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
199 report_fatal_error("Bad $ operand number in inline asm string: '" +
200 Twine(AsmStr) + "'");
201 LastEmitted = IDEnd;
202
203 if (Val >= NumOperands-1)
204 report_fatal_error("Invalid $ operand number in inline asm string: '" +
205 Twine(AsmStr) + "'");
206
207 char Modifier[2] = { 0, 0 };
208
209 if (HasCurlyBraces) {
210 // If we have curly braces, check for a modifier character. This
211 // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
212 if (*LastEmitted == ':') {
213 ++LastEmitted; // Consume ':' character.
214 if (*LastEmitted == 0)
215 report_fatal_error("Bad ${:} expression in inline asm string: '" +
216 Twine(AsmStr) + "'");
217
218 Modifier[0] = *LastEmitted;
219 ++LastEmitted; // Consume modifier character.
220 }
221
222 if (*LastEmitted != '}')
223 report_fatal_error("Bad ${} expression in inline asm string: '" +
224 Twine(AsmStr) + "'");
225 ++LastEmitted; // Consume '}' character.
226 }
227
228 // Okay, we finally have a value number. Ask the target to print this
229 // operand!
230 unsigned OpNo = InlineAsm::MIOp_FirstOperand;
231
232 bool Error = false;
233
234 // Scan to find the machine operand number for the operand.
235 for (; Val; --Val) {
236 if (OpNo >= MI->getNumOperands()) break;
237 unsigned OpFlags = MI->getOperand(OpNo).getImm();
238 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
239 }
240
241 // We may have a location metadata attached to the end of the
242 // instruction, and at no point should see metadata at any
243 // other point while processing. It's an error if so.
244 if (OpNo >= MI->getNumOperands() ||
245 MI->getOperand(OpNo).isMetadata()) {
246 Error = true;
247 } else {
248 unsigned OpFlags = MI->getOperand(OpNo).getImm();
249 ++OpNo; // Skip over the ID number.
250
251 if (InlineAsm::isMemKind(OpFlags)) {
252 Error = AP->PrintAsmMemoryOperand(
253 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
254 } else {
255 Error = AP->PrintAsmOperand(MI, OpNo,
256 Modifier[0] ? Modifier : nullptr, OS);
257 }
258 }
259 if (Error) {
260 std::string msg;
261 raw_string_ostream Msg(msg);
262 Msg << "invalid operand in inline asm: '" << AsmStr << "'";
263 MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
264 }
265 break;
266 }
267 }
268 }
269 OS << "\n\t.att_syntax\n" << (char)0; // null terminate string.
270 }
271
EmitGCCInlineAsmStr(const char * AsmStr,const MachineInstr * MI,MachineModuleInfo * MMI,const MCAsmInfo * MAI,AsmPrinter * AP,unsigned LocCookie,raw_ostream & OS)272 static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
273 MachineModuleInfo *MMI, const MCAsmInfo *MAI,
274 AsmPrinter *AP, unsigned LocCookie,
275 raw_ostream &OS) {
276 int CurVariant = -1; // The number of the {.|.|.} region we are in.
277 const char *LastEmitted = AsmStr; // One past the last character emitted.
278 unsigned NumOperands = MI->getNumOperands();
279 int AsmPrinterVariant = MAI->getAssemblerDialect();
280
281 if (MAI->getEmitGNUAsmStartIndentationMarker())
282 OS << '\t';
283
284 while (*LastEmitted) {
285 switch (*LastEmitted) {
286 default: {
287 // Not a special case, emit the string section literally.
288 const char *LiteralEnd = LastEmitted+1;
289 while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
290 *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
291 ++LiteralEnd;
292 if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
293 OS.write(LastEmitted, LiteralEnd-LastEmitted);
294 LastEmitted = LiteralEnd;
295 break;
296 }
297 case '\n':
298 ++LastEmitted; // Consume newline character.
299 OS << '\n'; // Indent code with newline.
300 break;
301 case '$': {
302 ++LastEmitted; // Consume '$' character.
303 bool Done = true;
304
305 // Handle escapes.
306 switch (*LastEmitted) {
307 default: Done = false; break;
308 case '$': // $$ -> $
309 if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
310 OS << '$';
311 ++LastEmitted; // Consume second '$' character.
312 break;
313 case '(': // $( -> same as GCC's { character.
314 ++LastEmitted; // Consume '(' character.
315 if (CurVariant != -1)
316 report_fatal_error("Nested variants found in inline asm string: '" +
317 Twine(AsmStr) + "'");
318 CurVariant = 0; // We're in the first variant now.
319 break;
320 case '|':
321 ++LastEmitted; // consume '|' character.
322 if (CurVariant == -1)
323 OS << '|'; // this is gcc's behavior for | outside a variant
324 else
325 ++CurVariant; // We're in the next variant.
326 break;
327 case ')': // $) -> same as GCC's } char.
328 ++LastEmitted; // consume ')' character.
329 if (CurVariant == -1)
330 OS << '}'; // this is gcc's behavior for } outside a variant
331 else
332 CurVariant = -1;
333 break;
334 }
335 if (Done) break;
336
337 bool HasCurlyBraces = false;
338 if (*LastEmitted == '{') { // ${variable}
339 ++LastEmitted; // Consume '{' character.
340 HasCurlyBraces = true;
341 }
342
343 // If we have ${:foo}, then this is not a real operand reference, it is a
344 // "magic" string reference, just like in .td files. Arrange to call
345 // PrintSpecial.
346 if (HasCurlyBraces && *LastEmitted == ':') {
347 ++LastEmitted;
348 const char *StrStart = LastEmitted;
349 const char *StrEnd = strchr(StrStart, '}');
350 if (!StrEnd)
351 report_fatal_error("Unterminated ${:foo} operand in inline asm"
352 " string: '" + Twine(AsmStr) + "'");
353
354 std::string Val(StrStart, StrEnd);
355 AP->PrintSpecial(MI, OS, Val.c_str());
356 LastEmitted = StrEnd+1;
357 break;
358 }
359
360 const char *IDStart = LastEmitted;
361 const char *IDEnd = IDStart;
362 while (isDigit(*IDEnd))
363 ++IDEnd;
364
365 unsigned Val;
366 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
367 report_fatal_error("Bad $ operand number in inline asm string: '" +
368 Twine(AsmStr) + "'");
369 LastEmitted = IDEnd;
370
371 char Modifier[2] = { 0, 0 };
372
373 if (HasCurlyBraces) {
374 // If we have curly braces, check for a modifier character. This
375 // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
376 if (*LastEmitted == ':') {
377 ++LastEmitted; // Consume ':' character.
378 if (*LastEmitted == 0)
379 report_fatal_error("Bad ${:} expression in inline asm string: '" +
380 Twine(AsmStr) + "'");
381
382 Modifier[0] = *LastEmitted;
383 ++LastEmitted; // Consume modifier character.
384 }
385
386 if (*LastEmitted != '}')
387 report_fatal_error("Bad ${} expression in inline asm string: '" +
388 Twine(AsmStr) + "'");
389 ++LastEmitted; // Consume '}' character.
390 }
391
392 if (Val >= NumOperands-1)
393 report_fatal_error("Invalid $ operand number in inline asm string: '" +
394 Twine(AsmStr) + "'");
395
396 // Okay, we finally have a value number. Ask the target to print this
397 // operand!
398 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
399 unsigned OpNo = InlineAsm::MIOp_FirstOperand;
400
401 bool Error = false;
402
403 // Scan to find the machine operand number for the operand.
404 for (; Val; --Val) {
405 if (OpNo >= MI->getNumOperands()) break;
406 unsigned OpFlags = MI->getOperand(OpNo).getImm();
407 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
408 }
409
410 // We may have a location metadata attached to the end of the
411 // instruction, and at no point should see metadata at any
412 // other point while processing. It's an error if so.
413 if (OpNo >= MI->getNumOperands() ||
414 MI->getOperand(OpNo).isMetadata()) {
415 Error = true;
416 } else {
417 unsigned OpFlags = MI->getOperand(OpNo).getImm();
418 ++OpNo; // Skip over the ID number.
419
420 // FIXME: Shouldn't arch-independent output template handling go into
421 // PrintAsmOperand?
422 // Labels are target independent.
423 if (MI->getOperand(OpNo).isBlockAddress()) {
424 const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress();
425 MCSymbol *Sym = AP->GetBlockAddressSymbol(BA);
426 Sym->print(OS, AP->MAI);
427 MMI->getContext().registerInlineAsmLabel(Sym);
428 } else if (MI->getOperand(OpNo).isMBB()) {
429 const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol();
430 Sym->print(OS, AP->MAI);
431 } else if (Modifier[0] == 'l') {
432 Error = true;
433 } else if (InlineAsm::isMemKind(OpFlags)) {
434 Error = AP->PrintAsmMemoryOperand(
435 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
436 } else {
437 Error = AP->PrintAsmOperand(MI, OpNo,
438 Modifier[0] ? Modifier : nullptr, OS);
439 }
440 }
441 if (Error) {
442 std::string msg;
443 raw_string_ostream Msg(msg);
444 Msg << "invalid operand in inline asm: '" << AsmStr << "'";
445 MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
446 }
447 }
448 break;
449 }
450 }
451 }
452 OS << '\n' << (char)0; // null terminate string.
453 }
454
455 /// This method formats and emits the specified machine instruction that is an
456 /// inline asm.
emitInlineAsm(const MachineInstr * MI) const457 void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const {
458 assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms");
459
460 // Count the number of register definitions to find the asm string.
461 unsigned NumDefs = 0;
462 for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef();
463 ++NumDefs)
464 assert(NumDefs != MI->getNumOperands()-2 && "No asm string?");
465
466 assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?");
467
468 // Disassemble the AsmStr, printing out the literal pieces, the operands, etc.
469 const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
470
471 // If this asmstr is empty, just print the #APP/#NOAPP markers.
472 // These are useful to see where empty asm's wound up.
473 if (AsmStr[0] == 0) {
474 OutStreamer->emitRawComment(MAI->getInlineAsmStart());
475 OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
476 return;
477 }
478
479 // Emit the #APP start marker. This has to happen even if verbose-asm isn't
480 // enabled, so we use emitRawComment.
481 OutStreamer->emitRawComment(MAI->getInlineAsmStart());
482
483 // Get the !srcloc metadata node if we have it, and decode the loc cookie from
484 // it.
485 unsigned LocCookie = 0;
486 const MDNode *LocMD = nullptr;
487 for (unsigned i = MI->getNumOperands(); i != 0; --i) {
488 if (MI->getOperand(i-1).isMetadata() &&
489 (LocMD = MI->getOperand(i-1).getMetadata()) &&
490 LocMD->getNumOperands() != 0) {
491 if (const ConstantInt *CI =
492 mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) {
493 LocCookie = CI->getZExtValue();
494 break;
495 }
496 }
497 }
498
499 // Emit the inline asm to a temporary string so we can emit it through
500 // EmitInlineAsm.
501 SmallString<256> StringData;
502 raw_svector_ostream OS(StringData);
503
504 AsmPrinter *AP = const_cast<AsmPrinter*>(this);
505 if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT)
506 EmitGCCInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS);
507 else
508 EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS);
509
510 // Emit warnings if we use reserved registers on the clobber list, as
511 // that might lead to undefined behaviour.
512 SmallVector<Register, 8> RestrRegs;
513 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
514 // Start with the first operand descriptor, and iterate over them.
515 for (unsigned I = InlineAsm::MIOp_FirstOperand, NumOps = MI->getNumOperands();
516 I < NumOps; ++I) {
517 const MachineOperand &MO = MI->getOperand(I);
518 if (!MO.isImm())
519 continue;
520 unsigned Flags = MO.getImm();
521 if (InlineAsm::getKind(Flags) == InlineAsm::Kind_Clobber) {
522 Register Reg = MI->getOperand(I + 1).getReg();
523 if (!TRI->isAsmClobberable(*MF, Reg))
524 RestrRegs.push_back(Reg);
525 }
526 // Skip to one before the next operand descriptor, if it exists.
527 I += InlineAsm::getNumOperandRegisters(Flags);
528 }
529
530 if (!RestrRegs.empty()) {
531 std::string Msg = "inline asm clobber list contains reserved registers: ";
532 ListSeparator LS;
533 for (const Register &RR : RestrRegs) {
534 Msg += LS;
535 Msg += TRI->getName(RR);
536 }
537 const char *Note =
538 "Reserved registers on the clobber list may not be "
539 "preserved across the asm statement, and clobbering them may "
540 "lead to undefined behaviour.";
541 MMI->getModule()->getContext().diagnose(DiagnosticInfoInlineAsm(
542 LocCookie, Msg.c_str(), DiagnosticSeverity::DS_Warning));
543 MMI->getModule()->getContext().diagnose(
544 DiagnosticInfoInlineAsm(LocCookie, Note, DiagnosticSeverity::DS_Note));
545 }
546
547 emitInlineAsm(OS.str(), getSubtargetInfo(), TM.Options.MCOptions, LocMD,
548 MI->getInlineAsmDialect());
549
550 // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't
551 // enabled, so we use emitRawComment.
552 OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
553 }
554
555 /// PrintSpecial - Print information related to the specified machine instr
556 /// that is independent of the operand, and may be independent of the instr
557 /// itself. This can be useful for portably encoding the comment character
558 /// or other bits of target-specific knowledge into the asmstrings. The
559 /// syntax used is ${:comment}. Targets can override this to add support
560 /// for their own strange codes.
PrintSpecial(const MachineInstr * MI,raw_ostream & OS,const char * Code) const561 void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
562 const char *Code) const {
563 if (!strcmp(Code, "private")) {
564 const DataLayout &DL = MF->getDataLayout();
565 OS << DL.getPrivateGlobalPrefix();
566 } else if (!strcmp(Code, "comment")) {
567 OS << MAI->getCommentString();
568 } else if (!strcmp(Code, "uid")) {
569 // Comparing the address of MI isn't sufficient, because machineinstrs may
570 // be allocated to the same address across functions.
571
572 // If this is a new LastFn instruction, bump the counter.
573 if (LastMI != MI || LastFn != getFunctionNumber()) {
574 ++Counter;
575 LastMI = MI;
576 LastFn = getFunctionNumber();
577 }
578 OS << Counter;
579 } else {
580 std::string msg;
581 raw_string_ostream Msg(msg);
582 Msg << "Unknown special formatter '" << Code
583 << "' for machine instr: " << *MI;
584 report_fatal_error(Msg.str());
585 }
586 }
587
PrintSymbolOperand(const MachineOperand & MO,raw_ostream & OS)588 void AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS) {
589 assert(MO.isGlobal() && "caller should check MO.isGlobal");
590 getSymbolPreferLocal(*MO.getGlobal())->print(OS, MAI);
591 printOffset(MO.getOffset(), OS);
592 }
593
594 /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
595 /// instruction, using the specified assembler variant. Targets should
596 /// override this to format as appropriate for machine specific ExtraCodes
597 /// or when the arch-independent handling would be too complex otherwise.
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)598 bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
599 const char *ExtraCode, raw_ostream &O) {
600 // Does this asm operand have a single letter operand modifier?
601 if (ExtraCode && ExtraCode[0]) {
602 if (ExtraCode[1] != 0) return true; // Unknown modifier.
603
604 // https://gcc.gnu.org/onlinedocs/gccint/Output-Template.html
605 const MachineOperand &MO = MI->getOperand(OpNo);
606 switch (ExtraCode[0]) {
607 default:
608 return true; // Unknown modifier.
609 case 'a': // Print as memory address.
610 if (MO.isReg()) {
611 PrintAsmMemoryOperand(MI, OpNo, nullptr, O);
612 return false;
613 }
614 LLVM_FALLTHROUGH; // GCC allows '%a' to behave like '%c' with immediates.
615 case 'c': // Substitute immediate value without immediate syntax
616 if (MO.isImm()) {
617 O << MO.getImm();
618 return false;
619 }
620 if (MO.isGlobal()) {
621 PrintSymbolOperand(MO, O);
622 return false;
623 }
624 return true;
625 case 'n': // Negate the immediate constant.
626 if (!MO.isImm())
627 return true;
628 O << -MO.getImm();
629 return false;
630 case 's': // The GCC deprecated s modifier
631 if (!MO.isImm())
632 return true;
633 O << ((32 - MO.getImm()) & 31);
634 return false;
635 }
636 }
637 return true;
638 }
639
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)640 bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
641 const char *ExtraCode, raw_ostream &O) {
642 // Target doesn't support this yet!
643 return true;
644 }
645
emitInlineAsmStart() const646 void AsmPrinter::emitInlineAsmStart() const {}
647
emitInlineAsmEnd(const MCSubtargetInfo & StartInfo,const MCSubtargetInfo * EndInfo) const648 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
649 const MCSubtargetInfo *EndInfo) const {}
650