/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // This file implements the inline assembler pieces of the AsmPrinter class. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "llvm/ADT/SmallString.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/IR/Constants.h" |
21 | | #include "llvm/IR/DataLayout.h" |
22 | | #include "llvm/IR/InlineAsm.h" |
23 | | #include "llvm/IR/LLVMContext.h" |
24 | | #include "llvm/IR/Module.h" |
25 | | #include "llvm/MC/MCAsmInfo.h" |
26 | | #include "llvm/MC/MCParser/MCTargetAsmParser.h" |
27 | | #include "llvm/MC/MCStreamer.h" |
28 | | #include "llvm/MC/MCSubtargetInfo.h" |
29 | | #include "llvm/MC/MCSymbol.h" |
30 | | #include "llvm/Support/ErrorHandling.h" |
31 | | #include "llvm/Support/MemoryBuffer.h" |
32 | | #include "llvm/Support/SourceMgr.h" |
33 | | #include "llvm/Support/TargetRegistry.h" |
34 | | #include "llvm/Support/raw_ostream.h" |
35 | | #include "llvm/Target/TargetInstrInfo.h" |
36 | | #include "llvm/Target/TargetMachine.h" |
37 | | #include "llvm/Target/TargetRegisterInfo.h" |
38 | | #include "llvm/Target/TargetSubtargetInfo.h" |
39 | | using namespace llvm; |
40 | | |
41 | | #define DEBUG_TYPE "asm-printer" |
42 | | |
43 | | /// srcMgrDiagHandler - This callback is invoked when the SourceMgr for an |
44 | | /// inline asm has an error in it. diagInfo is a pointer to the SrcMgrDiagInfo |
45 | | /// struct above. |
46 | 158 | static void srcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) { |
47 | 158 | AsmPrinter::SrcMgrDiagInfo *DiagInfo = |
48 | 158 | static_cast<AsmPrinter::SrcMgrDiagInfo *>(diagInfo); |
49 | 158 | assert(DiagInfo && "Diagnostic context not passed down?"); |
50 | 158 | |
51 | 158 | // Look up a LocInfo for the buffer this diagnostic is coming from. |
52 | 158 | unsigned BufNum = DiagInfo->SrcMgr.FindBufferContainingLoc(Diag.getLoc()); |
53 | 158 | const MDNode *LocInfo = nullptr; |
54 | 158 | if (BufNum > 0 && 158 BufNum <= DiagInfo->LocInfos.size()158 ) |
55 | 9 | LocInfo = DiagInfo->LocInfos[BufNum-1]; |
56 | 158 | |
57 | 158 | // If the inline asm had metadata associated with it, pull out a location |
58 | 158 | // cookie corresponding to which line the error occurred on. |
59 | 158 | unsigned LocCookie = 0; |
60 | 158 | if (LocInfo158 ) { |
61 | 9 | unsigned ErrorLine = Diag.getLineNo()-1; |
62 | 9 | if (ErrorLine >= LocInfo->getNumOperands()) |
63 | 0 | ErrorLine = 0; |
64 | 9 | |
65 | 9 | if (LocInfo->getNumOperands() != 0) |
66 | 9 | if (const ConstantInt *9 CI9 = |
67 | 9 | mdconst::dyn_extract<ConstantInt>(LocInfo->getOperand(ErrorLine))) |
68 | 9 | LocCookie = CI->getZExtValue(); |
69 | 9 | } |
70 | 158 | |
71 | 158 | DiagInfo->DiagHandler(Diag, DiagInfo->DiagContext, LocCookie); |
72 | 158 | } |
73 | | |
74 | | /// EmitInlineAsm - Emit a blob of inline asm to the output streamer. |
75 | | void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, |
76 | | const MCTargetOptions &MCOptions, |
77 | | const MDNode *LocMDNode, |
78 | 5.68k | InlineAsm::AsmDialect Dialect) const { |
79 | 5.68k | assert(!Str.empty() && "Can't emit empty inline asm block"); |
80 | 5.68k | |
81 | 5.68k | // Remember if the buffer is nul terminated or not so we can avoid a copy. |
82 | 5.68k | bool isNullTerminated = Str.back() == 0; |
83 | 5.68k | if (isNullTerminated) |
84 | 5.33k | Str = Str.substr(0, Str.size()-1); |
85 | 5.68k | |
86 | 5.68k | // If the output streamer does not have mature MC support or the integrated |
87 | 5.68k | // assembler has been disabled, just emit the blob textually. |
88 | 5.68k | // Otherwise parse the asm and emit it via MC support. |
89 | 5.68k | // This is useful in case the asm parser doesn't handle something but the |
90 | 5.68k | // system assembler does. |
91 | 5.68k | const MCAsmInfo *MCAI = TM.getMCAsmInfo(); |
92 | 5.68k | assert(MCAI && "No MCAsmInfo"); |
93 | 5.68k | if (!MCAI->useIntegratedAssembler() && |
94 | 5.68k | !OutStreamer->isIntegratedAssemblerRequired()1.71k ) { |
95 | 1.70k | emitInlineAsmStart(); |
96 | 1.70k | OutStreamer->EmitRawText(Str); |
97 | 1.70k | emitInlineAsmEnd(STI, nullptr); |
98 | 1.70k | return; |
99 | 1.70k | } |
100 | 3.98k | |
101 | 3.98k | if (3.98k !DiagInfo3.98k ) { |
102 | 767 | DiagInfo = make_unique<SrcMgrDiagInfo>(); |
103 | 767 | |
104 | 767 | MCContext &Context = MMI->getContext(); |
105 | 767 | Context.setInlineSourceManager(&DiagInfo->SrcMgr); |
106 | 767 | |
107 | 767 | LLVMContext &LLVMCtx = MMI->getModule()->getContext(); |
108 | 767 | if (LLVMCtx.getInlineAsmDiagnosticHandler()767 ) { |
109 | 745 | DiagInfo->DiagHandler = LLVMCtx.getInlineAsmDiagnosticHandler(); |
110 | 745 | DiagInfo->DiagContext = LLVMCtx.getInlineAsmDiagnosticContext(); |
111 | 745 | DiagInfo->SrcMgr.setDiagHandler(srcMgrDiagHandler, DiagInfo.get()); |
112 | 745 | } |
113 | 767 | } |
114 | 3.98k | |
115 | 3.98k | SourceMgr &SrcMgr = DiagInfo->SrcMgr; |
116 | 3.98k | SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths); |
117 | 3.98k | |
118 | 3.98k | std::unique_ptr<MemoryBuffer> Buffer; |
119 | 3.98k | // The inline asm source manager will outlive Str, so make a copy of the |
120 | 3.98k | // string for SourceMgr to own. |
121 | 3.98k | Buffer = MemoryBuffer::getMemBufferCopy(Str, "<inline asm>"); |
122 | 3.98k | |
123 | 3.98k | // Tell SrcMgr about this buffer, it takes ownership of the buffer. |
124 | 3.98k | unsigned BufNum = SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc()); |
125 | 3.98k | |
126 | 3.98k | // Store LocMDNode in DiagInfo, using BufNum as an identifier. |
127 | 3.98k | if (LocMDNode3.98k ) { |
128 | 1.02k | DiagInfo->LocInfos.resize(BufNum); |
129 | 1.02k | DiagInfo->LocInfos[BufNum-1] = LocMDNode; |
130 | 1.02k | } |
131 | 3.98k | |
132 | 3.98k | std::unique_ptr<MCAsmParser> Parser( |
133 | 3.98k | createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum)); |
134 | 3.98k | |
135 | 3.98k | // We create a new MCInstrInfo here since we might be at the module level |
136 | 3.98k | // and not have a MachineFunction to initialize the TargetInstrInfo from and |
137 | 3.98k | // we only need MCInstrInfo for asm parsing. We create one unconditionally |
138 | 3.98k | // because it's not subtarget dependent. |
139 | 3.98k | std::unique_ptr<MCInstrInfo> MII(TM.getTarget().createMCInstrInfo()); |
140 | 3.98k | std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser( |
141 | 3.98k | STI, *Parser, *MII, MCOptions)); |
142 | 3.98k | if (!TAP) |
143 | 0 | report_fatal_error("Inline asm not supported by this streamer because" |
144 | 0 | " we don't have an asm parser for this target\n"); |
145 | 3.98k | Parser->setAssemblerDialect(Dialect); |
146 | 3.98k | Parser->setTargetParser(*TAP.get()); |
147 | 3.98k | if (Dialect == InlineAsm::AD_Intel) |
148 | 3.98k | // We need this flag to be able to parse numbers like "0bH" |
149 | 17 | Parser->setParsingInlineAsm(true); |
150 | 3.98k | if (MF3.98k ) { |
151 | 3.63k | const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); |
152 | 3.63k | TAP->SetFrameRegister(TRI->getFrameRegister(*MF)); |
153 | 3.63k | } |
154 | 3.98k | |
155 | 3.98k | emitInlineAsmStart(); |
156 | 3.98k | // Don't implicitly switch to the text section before the asm. |
157 | 3.98k | int Res = Parser->Run(/*NoInitialTextSection*/ true, |
158 | 3.98k | /*NoFinalize*/ true); |
159 | 3.98k | emitInlineAsmEnd(STI, &TAP->getSTI()); |
160 | 3.98k | |
161 | 3.98k | if (Res && 3.98k !DiagInfo->DiagHandler32 ) |
162 | 0 | report_fatal_error("Error parsing inline asm\n"); |
163 | 3.98k | } |
164 | | |
165 | | static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, |
166 | | MachineModuleInfo *MMI, int InlineAsmVariant, |
167 | | AsmPrinter *AP, unsigned LocCookie, |
168 | 27 | raw_ostream &OS) { |
169 | 27 | // Switch to the inline assembly variant. |
170 | 27 | OS << "\t.intel_syntax\n\t"; |
171 | 27 | |
172 | 27 | const char *LastEmitted = AsmStr; // One past the last character emitted. |
173 | 27 | unsigned NumOperands = MI->getNumOperands(); |
174 | 27 | |
175 | 180 | while (*LastEmitted180 ) { |
176 | 153 | switch (*LastEmitted) { |
177 | 83 | default: { |
178 | 83 | // Not a special case, emit the string section literally. |
179 | 83 | const char *LiteralEnd = LastEmitted+1; |
180 | 866 | while (*LiteralEnd && 866 *LiteralEnd != '{'845 && *LiteralEnd != '|'845 && |
181 | 866 | *LiteralEnd != '}'845 && *LiteralEnd != '$'844 && *LiteralEnd != '\n'811 ) |
182 | 783 | ++LiteralEnd; |
183 | 83 | |
184 | 83 | OS.write(LastEmitted, LiteralEnd-LastEmitted); |
185 | 83 | LastEmitted = LiteralEnd; |
186 | 83 | break; |
187 | 153 | } |
188 | 37 | case '\n': |
189 | 37 | ++LastEmitted; // Consume newline character. |
190 | 37 | OS << '\n'; // Indent code with newline. |
191 | 37 | break; |
192 | 33 | case '$': { |
193 | 33 | ++LastEmitted; // Consume '$' character. |
194 | 33 | bool Done = true; |
195 | 33 | |
196 | 33 | // Handle escapes. |
197 | 33 | switch (*LastEmitted) { |
198 | 30 | default: Done = false; break; |
199 | 3 | case '$': |
200 | 3 | ++LastEmitted; // Consume second '$' character. |
201 | 3 | break; |
202 | 33 | } |
203 | 33 | if (33 Done33 ) break3 ; |
204 | 30 | |
205 | 30 | // If we have ${:foo}, then this is not a real operand reference, it is a |
206 | 30 | // "magic" string reference, just like in .td files. Arrange to call |
207 | 30 | // PrintSpecial. |
208 | 30 | if (30 LastEmitted[0] == '{' && 30 LastEmitted[1] == ':'2 ) { |
209 | 2 | LastEmitted += 2; |
210 | 2 | const char *StrStart = LastEmitted; |
211 | 2 | const char *StrEnd = strchr(StrStart, '}'); |
212 | 2 | if (!StrEnd) |
213 | 0 | report_fatal_error("Unterminated ${:foo} operand in inline asm" |
214 | 0 | " string: '" + Twine(AsmStr) + "'"); |
215 | 2 | |
216 | 2 | std::string Val(StrStart, StrEnd); |
217 | 2 | AP->PrintSpecial(MI, OS, Val.c_str()); |
218 | 2 | LastEmitted = StrEnd+1; |
219 | 2 | break; |
220 | 2 | } |
221 | 28 | |
222 | 28 | const char *IDStart = LastEmitted; |
223 | 28 | const char *IDEnd = IDStart; |
224 | 56 | while (*IDEnd >= '0' && 56 *IDEnd <= '9'30 ) ++IDEnd28 ; |
225 | 28 | |
226 | 28 | unsigned Val; |
227 | 28 | if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) |
228 | 0 | report_fatal_error("Bad $ operand number in inline asm string: '" + |
229 | 0 | Twine(AsmStr) + "'"); |
230 | 28 | LastEmitted = IDEnd; |
231 | 28 | |
232 | 28 | if (Val >= NumOperands-1) |
233 | 0 | report_fatal_error("Invalid $ operand number in inline asm string: '" + |
234 | 0 | Twine(AsmStr) + "'"); |
235 | 28 | |
236 | 28 | // Okay, we finally have a value number. Ask the target to print this |
237 | 28 | // operand! |
238 | 28 | unsigned OpNo = InlineAsm::MIOp_FirstOperand; |
239 | 28 | |
240 | 28 | bool Error = false; |
241 | 28 | |
242 | 28 | // Scan to find the machine operand number for the operand. |
243 | 59 | for (; Val59 ; --Val31 ) { |
244 | 31 | if (OpNo >= MI->getNumOperands()31 ) break0 ; |
245 | 31 | unsigned OpFlags = MI->getOperand(OpNo).getImm(); |
246 | 31 | OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; |
247 | 31 | } |
248 | 28 | |
249 | 28 | // We may have a location metadata attached to the end of the |
250 | 28 | // instruction, and at no point should see metadata at any |
251 | 28 | // other point while processing. It's an error if so. |
252 | 28 | if (OpNo >= MI->getNumOperands() || |
253 | 28 | MI->getOperand(OpNo).isMetadata()28 ) { |
254 | 0 | Error = true; |
255 | 28 | } else { |
256 | 28 | unsigned OpFlags = MI->getOperand(OpNo).getImm(); |
257 | 28 | ++OpNo; // Skip over the ID number. |
258 | 28 | |
259 | 28 | if (InlineAsm::isMemKind(OpFlags)28 ) { |
260 | 25 | Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant, |
261 | 25 | /*Modifier*/ nullptr, OS); |
262 | 28 | } else { |
263 | 3 | Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, |
264 | 3 | /*Modifier*/ nullptr, OS); |
265 | 3 | } |
266 | 28 | } |
267 | 28 | if (Error28 ) { |
268 | 0 | std::string msg; |
269 | 0 | raw_string_ostream Msg(msg); |
270 | 0 | Msg << "invalid operand in inline asm: '" << AsmStr << "'"; |
271 | 0 | MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); |
272 | 0 | } |
273 | 33 | break; |
274 | 33 | } |
275 | 153 | } |
276 | 153 | } |
277 | 27 | OS << "\n\t.att_syntax\n" << (char)0; // null terminate string. |
278 | 27 | } |
279 | | |
280 | | static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, |
281 | | MachineModuleInfo *MMI, int InlineAsmVariant, |
282 | | int AsmPrinterVariant, AsmPrinter *AP, |
283 | 5.30k | unsigned LocCookie, raw_ostream &OS) { |
284 | 5.30k | int CurVariant = -1; // The number of the {.|.|.} region we are in. |
285 | 5.30k | const char *LastEmitted = AsmStr; // One past the last character emitted. |
286 | 5.30k | unsigned NumOperands = MI->getNumOperands(); |
287 | 5.30k | |
288 | 5.30k | OS << '\t'; |
289 | 5.30k | |
290 | 21.1k | while (*LastEmitted21.1k ) { |
291 | 15.8k | switch (*LastEmitted) { |
292 | 9.61k | default: { |
293 | 9.61k | // Not a special case, emit the string section literally. |
294 | 9.61k | const char *LiteralEnd = LastEmitted+1; |
295 | 55.5k | while (*LiteralEnd && 55.5k *LiteralEnd != '{'51.9k && *LiteralEnd != '|'51.8k && |
296 | 55.5k | *LiteralEnd != '}'51.8k && *LiteralEnd != '$'51.8k && *LiteralEnd != '\n'47.3k ) |
297 | 45.9k | ++LiteralEnd; |
298 | 9.61k | if (CurVariant == -1 || 9.61k CurVariant == AsmPrinterVariant10 ) |
299 | 9.60k | OS.write(LastEmitted, LiteralEnd-LastEmitted); |
300 | 9.61k | LastEmitted = LiteralEnd; |
301 | 9.61k | break; |
302 | 15.8k | } |
303 | 1.57k | case '\n': |
304 | 1.57k | ++LastEmitted; // Consume newline character. |
305 | 1.57k | OS << '\n'; // Indent code with newline. |
306 | 1.57k | break; |
307 | 4.62k | case '$': { |
308 | 4.62k | ++LastEmitted; // Consume '$' character. |
309 | 4.62k | bool Done = true; |
310 | 4.62k | |
311 | 4.62k | // Handle escapes. |
312 | 4.62k | switch (*LastEmitted) { |
313 | 3.87k | default: Done = false; break; |
314 | 716 | case '$': // $$ -> $ |
315 | 716 | if (CurVariant == -1 || 716 CurVariant == AsmPrinterVariant0 ) |
316 | 716 | OS << '$'; |
317 | 716 | ++LastEmitted; // Consume second '$' character. |
318 | 716 | break; |
319 | 5 | case '(': // $( -> same as GCC's { character. |
320 | 5 | ++LastEmitted; // Consume '(' character. |
321 | 5 | if (CurVariant != -1) |
322 | 0 | report_fatal_error("Nested variants found in inline asm string: '" + |
323 | 0 | Twine(AsmStr) + "'"); |
324 | 5 | CurVariant = 0; // We're in the first variant now. |
325 | 5 | break; |
326 | 21 | case '|': |
327 | 21 | ++LastEmitted; // consume '|' character. |
328 | 21 | if (CurVariant == -1) |
329 | 16 | OS << '|'; // this is gcc's behavior for | outside a variant |
330 | 21 | else |
331 | 5 | ++CurVariant; // We're in the next variant. |
332 | 21 | break; |
333 | 5 | case ')': // $) -> same as GCC's } char. |
334 | 5 | ++LastEmitted; // consume ')' character. |
335 | 5 | if (CurVariant == -1) |
336 | 0 | OS << '}'; // this is gcc's behavior for } outside a variant |
337 | 5 | else |
338 | 5 | CurVariant = -1; |
339 | 5 | break; |
340 | 4.62k | } |
341 | 4.62k | if (4.62k Done4.62k ) break747 ; |
342 | 3.87k | |
343 | 3.87k | bool HasCurlyBraces = false; |
344 | 3.87k | if (*LastEmitted == '{'3.87k ) { // ${variable} |
345 | 287 | ++LastEmitted; // Consume '{' character. |
346 | 287 | HasCurlyBraces = true; |
347 | 287 | } |
348 | 3.87k | |
349 | 3.87k | // If we have ${:foo}, then this is not a real operand reference, it is a |
350 | 3.87k | // "magic" string reference, just like in .td files. Arrange to call |
351 | 3.87k | // PrintSpecial. |
352 | 3.87k | if (HasCurlyBraces && 3.87k *LastEmitted == ':'287 ) { |
353 | 4 | ++LastEmitted; |
354 | 4 | const char *StrStart = LastEmitted; |
355 | 4 | const char *StrEnd = strchr(StrStart, '}'); |
356 | 4 | if (!StrEnd) |
357 | 0 | report_fatal_error("Unterminated ${:foo} operand in inline asm" |
358 | 0 | " string: '" + Twine(AsmStr) + "'"); |
359 | 4 | |
360 | 4 | std::string Val(StrStart, StrEnd); |
361 | 4 | AP->PrintSpecial(MI, OS, Val.c_str()); |
362 | 4 | LastEmitted = StrEnd+1; |
363 | 4 | break; |
364 | 4 | } |
365 | 3.87k | |
366 | 3.87k | const char *IDStart = LastEmitted; |
367 | 3.87k | const char *IDEnd = IDStart; |
368 | 7.74k | while (*IDEnd >= '0' && 7.74k *IDEnd <= '9'4.26k ) ++IDEnd3.87k ; |
369 | 3.87k | |
370 | 3.87k | unsigned Val; |
371 | 3.87k | if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) |
372 | 0 | report_fatal_error("Bad $ operand number in inline asm string: '" + |
373 | 0 | Twine(AsmStr) + "'"); |
374 | 3.87k | LastEmitted = IDEnd; |
375 | 3.87k | |
376 | 3.87k | char Modifier[2] = { 0, 0 }; |
377 | 3.87k | |
378 | 3.87k | if (HasCurlyBraces3.87k ) { |
379 | 283 | // If we have curly braces, check for a modifier character. This |
380 | 283 | // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm. |
381 | 283 | if (*LastEmitted == ':'283 ) { |
382 | 276 | ++LastEmitted; // Consume ':' character. |
383 | 276 | if (*LastEmitted == 0) |
384 | 0 | report_fatal_error("Bad ${:} expression in inline asm string: '" + |
385 | 0 | Twine(AsmStr) + "'"); |
386 | 276 | |
387 | 276 | Modifier[0] = *LastEmitted; |
388 | 276 | ++LastEmitted; // Consume modifier character. |
389 | 276 | } |
390 | 283 | |
391 | 283 | if (283 *LastEmitted != '}'283 ) |
392 | 0 | report_fatal_error("Bad ${} expression in inline asm string: '" + |
393 | 0 | Twine(AsmStr) + "'"); |
394 | 283 | ++LastEmitted; // Consume '}' character. |
395 | 283 | } |
396 | 3.87k | |
397 | 3.87k | if (3.87k Val >= NumOperands-13.87k ) |
398 | 0 | report_fatal_error("Invalid $ operand number in inline asm string: '" + |
399 | 0 | Twine(AsmStr) + "'"); |
400 | 3.87k | |
401 | 3.87k | // Okay, we finally have a value number. Ask the target to print this |
402 | 3.87k | // operand! |
403 | 3.87k | if (3.87k CurVariant == -1 || 3.87k CurVariant == AsmPrinterVariant0 ) { |
404 | 3.87k | unsigned OpNo = InlineAsm::MIOp_FirstOperand; |
405 | 3.87k | |
406 | 3.87k | bool Error = false; |
407 | 3.87k | |
408 | 3.87k | // Scan to find the machine operand number for the operand. |
409 | 6.74k | for (; Val6.74k ; --Val2.87k ) { |
410 | 2.87k | if (OpNo >= MI->getNumOperands()2.87k ) break0 ; |
411 | 2.87k | unsigned OpFlags = MI->getOperand(OpNo).getImm(); |
412 | 2.87k | OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; |
413 | 2.87k | } |
414 | 3.87k | |
415 | 3.87k | // We may have a location metadata attached to the end of the |
416 | 3.87k | // instruction, and at no point should see metadata at any |
417 | 3.87k | // other point while processing. It's an error if so. |
418 | 3.87k | if (OpNo >= MI->getNumOperands() || |
419 | 3.87k | MI->getOperand(OpNo).isMetadata()3.87k ) { |
420 | 0 | Error = true; |
421 | 3.87k | } else { |
422 | 3.87k | unsigned OpFlags = MI->getOperand(OpNo).getImm(); |
423 | 3.87k | ++OpNo; // Skip over the ID number. |
424 | 3.87k | |
425 | 3.87k | if (Modifier[0] == 'l'3.87k ) { // Labels are target independent. |
426 | 2 | // FIXME: What if the operand isn't an MBB, report error? |
427 | 2 | const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol(); |
428 | 2 | Sym->print(OS, AP->MAI); |
429 | 3.87k | } else { |
430 | 3.87k | if (InlineAsm::isMemKind(OpFlags)3.87k ) { |
431 | 326 | Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant, |
432 | 326 | Modifier[0] ? Modifier10 : nullptr316 , |
433 | 326 | OS); |
434 | 3.87k | } else { |
435 | 3.54k | Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, |
436 | 3.54k | Modifier[0] ? Modifier264 : nullptr3.28k , OS); |
437 | 3.54k | } |
438 | 3.87k | } |
439 | 3.87k | } |
440 | 3.87k | if (Error3.87k ) { |
441 | 0 | std::string msg; |
442 | 0 | raw_string_ostream Msg(msg); |
443 | 0 | Msg << "invalid operand in inline asm: '" << AsmStr << "'"; |
444 | 0 | MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); |
445 | 0 | } |
446 | 3.87k | } |
447 | 4.62k | break; |
448 | 4.62k | } |
449 | 15.8k | } |
450 | 15.8k | } |
451 | 5.30k | OS << '\n' << (char)0; // null terminate string. |
452 | 5.30k | } |
453 | | |
454 | | /// EmitInlineAsm - This method formats and emits the specified machine |
455 | | /// instruction that is an inline asm. |
456 | 11.2k | void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { |
457 | 11.2k | assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); |
458 | 11.2k | |
459 | 11.2k | // Count the number of register definitions to find the asm string. |
460 | 11.2k | unsigned NumDefs = 0; |
461 | 11.2k | for (; MI->getOperand(NumDefs).isReg() && 11.2k MI->getOperand(NumDefs).isDef()0 ; |
462 | 0 | ++NumDefs) |
463 | 11.2k | assert(NumDefs != MI->getNumOperands()-2 && "No asm string?"); |
464 | 11.2k | |
465 | 11.2k | assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?"); |
466 | 11.2k | |
467 | 11.2k | // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. |
468 | 11.2k | const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); |
469 | 11.2k | |
470 | 11.2k | // If this asmstr is empty, just print the #APP/#NOAPP markers. |
471 | 11.2k | // These are useful to see where empty asm's wound up. |
472 | 11.2k | if (AsmStr[0] == 011.2k ) { |
473 | 5.87k | OutStreamer->emitRawComment(MAI->getInlineAsmStart()); |
474 | 5.87k | OutStreamer->emitRawComment(MAI->getInlineAsmEnd()); |
475 | 5.87k | return; |
476 | 5.87k | } |
477 | 5.33k | |
478 | 5.33k | // Emit the #APP start marker. This has to happen even if verbose-asm isn't |
479 | 5.33k | // enabled, so we use emitRawComment. |
480 | 5.33k | OutStreamer->emitRawComment(MAI->getInlineAsmStart()); |
481 | 5.33k | |
482 | 5.33k | // Get the !srcloc metadata node if we have it, and decode the loc cookie from |
483 | 5.33k | // it. |
484 | 5.33k | unsigned LocCookie = 0; |
485 | 5.33k | const MDNode *LocMD = nullptr; |
486 | 102k | for (unsigned i = MI->getNumOperands(); i != 0102k ; --i97.1k ) { |
487 | 98.2k | if (MI->getOperand(i-1).isMetadata() && |
488 | 1.04k | (LocMD = MI->getOperand(i-1).getMetadata()) && |
489 | 98.2k | LocMD->getNumOperands() != 01.04k ) { |
490 | 1.04k | if (const ConstantInt *CI = |
491 | 1.04k | mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) { |
492 | 1.04k | LocCookie = CI->getZExtValue(); |
493 | 1.04k | break; |
494 | 1.04k | } |
495 | 1.04k | } |
496 | 98.2k | } |
497 | 5.33k | |
498 | 5.33k | // Emit the inline asm to a temporary string so we can emit it through |
499 | 5.33k | // EmitInlineAsm. |
500 | 5.33k | SmallString<256> StringData; |
501 | 5.33k | raw_svector_ostream OS(StringData); |
502 | 5.33k | |
503 | 5.33k | // The variant of the current asmprinter. |
504 | 5.33k | int AsmPrinterVariant = MAI->getAssemblerDialect(); |
505 | 5.33k | InlineAsm::AsmDialect InlineAsmVariant = MI->getInlineAsmDialect(); |
506 | 5.33k | AsmPrinter *AP = const_cast<AsmPrinter*>(this); |
507 | 5.33k | if (InlineAsmVariant == InlineAsm::AD_ATT) |
508 | 5.30k | EmitGCCInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AsmPrinterVariant, |
509 | 5.30k | AP, LocCookie, OS); |
510 | 5.33k | else |
511 | 27 | EmitMSInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AP, LocCookie, OS); |
512 | 11.2k | |
513 | 11.2k | // Reset SanitizeAddress based on the function's attribute. |
514 | 11.2k | MCTargetOptions MCOptions = TM.Options.MCOptions; |
515 | 11.2k | MCOptions.SanitizeAddress = |
516 | 11.2k | MF->getFunction()->hasFnAttribute(Attribute::SanitizeAddress); |
517 | 11.2k | |
518 | 11.2k | EmitInlineAsm(OS.str(), getSubtargetInfo(), MCOptions, LocMD, |
519 | 11.2k | MI->getInlineAsmDialect()); |
520 | 11.2k | |
521 | 11.2k | // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't |
522 | 11.2k | // enabled, so we use emitRawComment. |
523 | 11.2k | OutStreamer->emitRawComment(MAI->getInlineAsmEnd()); |
524 | 11.2k | } |
525 | | |
526 | | |
527 | | /// PrintSpecial - Print information related to the specified machine instr |
528 | | /// that is independent of the operand, and may be independent of the instr |
529 | | /// itself. This can be useful for portably encoding the comment character |
530 | | /// or other bits of target-specific knowledge into the asmstrings. The |
531 | | /// syntax used is ${:comment}. Targets can override this to add support |
532 | | /// for their own strange codes. |
533 | | void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, |
534 | 6 | const char *Code) const { |
535 | 6 | if (!strcmp(Code, "private")6 ) { |
536 | 0 | const DataLayout &DL = MF->getDataLayout(); |
537 | 0 | OS << DL.getPrivateGlobalPrefix(); |
538 | 6 | } else if (6 !strcmp(Code, "comment")6 ) { |
539 | 0 | OS << MAI->getCommentString(); |
540 | 6 | } else if (6 !strcmp(Code, "uid")6 ) { |
541 | 6 | // Comparing the address of MI isn't sufficient, because machineinstrs may |
542 | 6 | // be allocated to the same address across functions. |
543 | 6 | |
544 | 6 | // If this is a new LastFn instruction, bump the counter. |
545 | 6 | if (LastMI != MI || 6 LastFn != getFunctionNumber()3 ) { |
546 | 3 | ++Counter; |
547 | 3 | LastMI = MI; |
548 | 3 | LastFn = getFunctionNumber(); |
549 | 3 | } |
550 | 6 | OS << Counter; |
551 | 0 | } else { |
552 | 0 | std::string msg; |
553 | 0 | raw_string_ostream Msg(msg); |
554 | 0 | Msg << "Unknown special formatter '" << Code |
555 | 0 | << "' for machine instr: " << *MI; |
556 | 0 | report_fatal_error(Msg.str()); |
557 | 0 | } |
558 | 6 | } |
559 | | |
560 | | /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM |
561 | | /// instruction, using the specified assembler variant. Targets should |
562 | | /// override this to format as appropriate. |
563 | | bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
564 | | unsigned AsmVariant, const char *ExtraCode, |
565 | 694 | raw_ostream &O) { |
566 | 694 | // Does this asm operand have a single letter operand modifier? |
567 | 694 | if (ExtraCode && 694 ExtraCode[0]53 ) { |
568 | 53 | if (ExtraCode[1] != 053 ) return true0 ; // Unknown modifier. |
569 | 53 | |
570 | 53 | const MachineOperand &MO = MI->getOperand(OpNo); |
571 | 53 | switch (ExtraCode[0]) { |
572 | 37 | default: |
573 | 37 | return true; // Unknown modifier. |
574 | 5 | case 'c': // Substitute immediate value without immediate syntax |
575 | 5 | if (MO.getType() != MachineOperand::MO_Immediate) |
576 | 0 | return true; |
577 | 5 | O << MO.getImm(); |
578 | 5 | return false; |
579 | 5 | case 'n': // Negate the immediate constant. |
580 | 5 | if (MO.getType() != MachineOperand::MO_Immediate) |
581 | 0 | return true; |
582 | 5 | O << -MO.getImm(); |
583 | 5 | return false; |
584 | 6 | case 's': // The GCC deprecated s modifier |
585 | 6 | if (MO.getType() != MachineOperand::MO_Immediate) |
586 | 5 | return true; |
587 | 1 | O << ((32 - MO.getImm()) & 31); |
588 | 1 | return false; |
589 | 53 | } |
590 | 53 | } |
591 | 641 | return true; |
592 | 641 | } |
593 | | |
594 | | bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, |
595 | | unsigned AsmVariant, |
596 | 0 | const char *ExtraCode, raw_ostream &O) { |
597 | 0 | // Target doesn't support this yet! |
598 | 0 | return true; |
599 | 0 | } |
600 | | |
601 | 5.27k | void AsmPrinter::emitInlineAsmStart() const {} |
602 | | |
603 | | void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, |
604 | 4.84k | const MCSubtargetInfo *EndInfo) const {} |