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