blob: d0aa6af9c0c224b8a97273735eb69a793c3adb89 [file] [log] [blame]
Tim Northover00ed9962014-03-29 10:18:08 +00001//===-- ARM64AsmPrinter.cpp - ARM64 LLVM assembly writer ------------------===//
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 contains a printer that converts from our internal representation
11// of machine-dependent LLVM code to the ARM64 assembly language.
12//
13//===----------------------------------------------------------------------===//
14
15#define DEBUG_TYPE "asm-printer"
16#include "ARM64.h"
17#include "ARM64MachineFunctionInfo.h"
18#include "ARM64MCInstLower.h"
19#include "ARM64RegisterInfo.h"
20#include "InstPrinter/ARM64InstPrinter.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/StringSwitch.h"
23#include "llvm/ADT/Twine.h"
24#include "llvm/CodeGen/AsmPrinter.h"
25#include "llvm/CodeGen/MachineInstr.h"
26#include "llvm/CodeGen/StackMaps.h"
27#include "llvm/IR/DataLayout.h"
28#include "llvm/IR/DebugInfo.h"
29#include "llvm/MC/MCAsmInfo.h"
30#include "llvm/MC/MCContext.h"
31#include "llvm/MC/MCInst.h"
32#include "llvm/MC/MCInstBuilder.h"
33#include "llvm/MC/MCLinkerOptimizationHint.h"
34#include "llvm/MC/MCStreamer.h"
35#include "llvm/Support/Debug.h"
36#include "llvm/Support/TargetRegistry.h"
37using namespace llvm;
38
39namespace {
40
41class ARM64AsmPrinter : public AsmPrinter {
42 ARM64MCInstLower MCInstLowering;
43 StackMaps SM;
44
45public:
46 ARM64AsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
47 : AsmPrinter(TM, Streamer), MCInstLowering(OutContext, *Mang, *this),
48 SM(*this), ARM64FI(NULL), LOHLabelCounter(0) {}
49
50 virtual const char *getPassName() const { return "ARM64 Assembly Printer"; }
51
52 /// \brief Wrapper for MCInstLowering.lowerOperand() for the
53 /// tblgen'erated pseudo lowering.
54 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
55 return MCInstLowering.lowerOperand(MO, MCOp);
56 }
57
58 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
59 const MachineInstr &MI);
60 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
61 const MachineInstr &MI);
62 /// \brief tblgen'erated driver function for lowering simple MI->MC
63 /// pseudo instructions.
64 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
65 const MachineInstr *MI);
66
67 void EmitInstruction(const MachineInstr *MI);
68
69 void getAnalysisUsage(AnalysisUsage &AU) const {
70 AsmPrinter::getAnalysisUsage(AU);
71 AU.setPreservesAll();
72 }
73
74 bool runOnMachineFunction(MachineFunction &F) {
75 ARM64FI = F.getInfo<ARM64FunctionInfo>();
76 return AsmPrinter::runOnMachineFunction(F);
77 }
78
79private:
80 MachineLocation getDebugValueLocation(const MachineInstr *MI) const;
81 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
82 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
83 bool printAsmRegInClass(const MachineOperand &MO,
84 const TargetRegisterClass *RC, bool isVector,
85 raw_ostream &O);
86
87 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
88 unsigned AsmVariant, const char *ExtraCode,
89 raw_ostream &O);
90 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
91 unsigned AsmVariant, const char *ExtraCode,
92 raw_ostream &O);
93
94 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
95
96 void EmitFunctionBodyEnd();
97
98 MCSymbol *GetCPISymbol(unsigned CPID) const;
99 void EmitEndOfAsmFile(Module &M);
100 ARM64FunctionInfo *ARM64FI;
101
102 /// \brief Emit the LOHs contained in ARM64FI.
103 void EmitLOHs();
104
105 typedef std::map<const MachineInstr *, MCSymbol *> MInstToMCSymbol;
106 MInstToMCSymbol LOHInstToLabel;
107 unsigned LOHLabelCounter;
108};
109
110} // end of anonymous namespace
111
112//===----------------------------------------------------------------------===//
113
114void ARM64AsmPrinter::EmitEndOfAsmFile(Module &M) {
115 // Funny Darwin hack: This flag tells the linker that no global symbols
116 // contain code that falls through to other global symbols (e.g. the obvious
117 // implementation of multiple entry points). If this doesn't occur, the
118 // linker can safely perform dead code stripping. Since LLVM never
119 // generates code that does this, it is always safe to set.
120 OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
121 SM.serializeToStackMapSection();
122}
123
124MachineLocation
125ARM64AsmPrinter::getDebugValueLocation(const MachineInstr *MI) const {
126 MachineLocation Location;
127 assert(MI->getNumOperands() == 4 && "Invalid no. of machine operands!");
128 // Frame address. Currently handles register +- offset only.
129 if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm())
130 Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm());
131 else {
132 DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n");
133 }
134 return Location;
135}
136
137void ARM64AsmPrinter::EmitLOHs() {
Tim Northover00ed9962014-03-29 10:18:08 +0000138 SmallVector<MCSymbol *, 3> MCArgs;
139
Benjamin Kramer3ad660a2014-03-29 19:21:20 +0000140 for (const auto &D : ARM64FI->getLOHContainer()) {
141 for (const MachineInstr *MI : D.getArgs()) {
142 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
Tim Northover00ed9962014-03-29 10:18:08 +0000143 assert(LabelIt != LOHInstToLabel.end() &&
144 "Label hasn't been inserted for LOH related instruction");
145 MCArgs.push_back(LabelIt->second);
146 }
Benjamin Kramer3ad660a2014-03-29 19:21:20 +0000147 OutStreamer.EmitLOHDirective(D.getKind(), MCArgs);
Tim Northover00ed9962014-03-29 10:18:08 +0000148 MCArgs.clear();
149 }
150}
151
152void ARM64AsmPrinter::EmitFunctionBodyEnd() {
153 if (!ARM64FI->getLOHRelated().empty())
154 EmitLOHs();
155}
156
157/// GetCPISymbol - Return the symbol for the specified constant pool entry.
158MCSymbol *ARM64AsmPrinter::GetCPISymbol(unsigned CPID) const {
159 // Darwin uses a linker-private symbol name for constant-pools (to
160 // avoid addends on the relocation?), ELF has no such concept and
161 // uses a normal private symbol.
162 if (getDataLayout().getLinkerPrivateGlobalPrefix()[0])
163 return OutContext.GetOrCreateSymbol(
164 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
165 Twine(getFunctionNumber()) + "_" + Twine(CPID));
166
167 return OutContext.GetOrCreateSymbol(
168 Twine(getDataLayout().getPrivateGlobalPrefix()) + "CPI" +
169 Twine(getFunctionNumber()) + "_" + Twine(CPID));
170}
171
172void ARM64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
173 raw_ostream &O) {
174 const MachineOperand &MO = MI->getOperand(OpNum);
175 switch (MO.getType()) {
176 default:
177 assert(0 && "<unknown operand type>");
178 case MachineOperand::MO_Register: {
179 unsigned Reg = MO.getReg();
180 assert(TargetRegisterInfo::isPhysicalRegister(Reg));
181 assert(!MO.getSubReg() && "Subregs should be eliminated!");
182 O << ARM64InstPrinter::getRegisterName(Reg);
183 break;
184 }
185 case MachineOperand::MO_Immediate: {
186 int64_t Imm = MO.getImm();
187 O << '#' << Imm;
188 break;
189 }
190 }
191}
192
193bool ARM64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
194 raw_ostream &O) {
195 unsigned Reg = MO.getReg();
196 switch (Mode) {
197 default:
198 return true; // Unknown mode.
199 case 'w':
200 Reg = getWRegFromXReg(Reg);
201 break;
202 case 'x':
203 Reg = getXRegFromWReg(Reg);
204 break;
205 }
206
207 O << ARM64InstPrinter::getRegisterName(Reg);
208 return false;
209}
210
211// Prints the register in MO using class RC using the offset in the
212// new register class. This should not be used for cross class
213// printing.
214bool ARM64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
215 const TargetRegisterClass *RC,
216 bool isVector, raw_ostream &O) {
217 assert(MO.isReg() && "Should only get here with a register!");
218 const ARM64RegisterInfo *RI =
219 static_cast<const ARM64RegisterInfo *>(TM.getRegisterInfo());
220 unsigned Reg = MO.getReg();
221 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
222 assert(RI->regsOverlap(RegToPrint, Reg));
223 O << ARM64InstPrinter::getRegisterName(
224 RegToPrint, isVector ? ARM64::vreg : ARM64::NoRegAltName);
225 return false;
226}
227
228bool ARM64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
229 unsigned AsmVariant,
230 const char *ExtraCode, raw_ostream &O) {
231 const MachineOperand &MO = MI->getOperand(OpNum);
232 // Does this asm operand have a single letter operand modifier?
233 if (ExtraCode && ExtraCode[0]) {
234 if (ExtraCode[1] != 0)
235 return true; // Unknown modifier.
236
237 switch (ExtraCode[0]) {
238 default:
239 return true; // Unknown modifier.
240 case 'w': // Print W register
241 case 'x': // Print X register
242 if (MO.isReg())
243 return printAsmMRegister(MO, ExtraCode[0], O);
244 if (MO.isImm() && MO.getImm() == 0) {
245 unsigned Reg = ExtraCode[0] == 'w' ? ARM64::WZR : ARM64::XZR;
246 O << ARM64InstPrinter::getRegisterName(Reg);
247 return false;
248 }
249 printOperand(MI, OpNum, O);
250 return false;
251 case 'b': // Print B register.
252 case 'h': // Print H register.
253 case 's': // Print S register.
254 case 'd': // Print D register.
255 case 'q': // Print Q register.
256 if (MO.isReg()) {
257 const TargetRegisterClass *RC;
258 switch (ExtraCode[0]) {
259 case 'b':
260 RC = &ARM64::FPR8RegClass;
261 break;
262 case 'h':
263 RC = &ARM64::FPR16RegClass;
264 break;
265 case 's':
266 RC = &ARM64::FPR32RegClass;
267 break;
268 case 'd':
269 RC = &ARM64::FPR64RegClass;
270 break;
271 case 'q':
272 RC = &ARM64::FPR128RegClass;
273 break;
274 default:
275 return true;
276 }
277 return printAsmRegInClass(MO, RC, false /* vector */, O);
278 }
279 printOperand(MI, OpNum, O);
280 return false;
281 }
282 }
283
284 // According to ARM, we should emit x and v registers unless we have a
285 // modifier.
286 if (MO.isReg()) {
287 unsigned Reg = MO.getReg();
288
289 // If this is a w or x register, print an x register.
290 if (ARM64::GPR32allRegClass.contains(Reg) ||
291 ARM64::GPR64allRegClass.contains(Reg))
292 return printAsmMRegister(MO, 'x', O);
293
294 // If this is a b, h, s, d, or q register, print it as a v register.
295 return printAsmRegInClass(MO, &ARM64::FPR128RegClass, true /* vector */, O);
296 }
297
298 printOperand(MI, OpNum, O);
299 return false;
300}
301
302bool ARM64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
303 unsigned OpNum, unsigned AsmVariant,
304 const char *ExtraCode,
305 raw_ostream &O) {
306 if (ExtraCode && ExtraCode[0])
307 return true; // Unknown modifier.
308
309 const MachineOperand &MO = MI->getOperand(OpNum);
310 assert(MO.isReg() && "unexpected inline asm memory operand");
311 O << "[" << ARM64InstPrinter::getRegisterName(MO.getReg()) << "]";
312 return false;
313}
314
315void ARM64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
316 raw_ostream &OS) {
317 unsigned NOps = MI->getNumOperands();
318 assert(NOps == 4);
319 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
320 // cast away const; DIetc do not take const operands for some reason.
321 DIVariable V(const_cast<MDNode *>(MI->getOperand(NOps - 1).getMetadata()));
322 OS << V.getName();
323 OS << " <- ";
324 // Frame address. Currently handles register +- offset only.
325 assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
326 OS << '[';
327 printOperand(MI, 0, OS);
328 OS << '+';
329 printOperand(MI, 1, OS);
330 OS << ']';
331 OS << "+";
332 printOperand(MI, NOps - 2, OS);
333}
334
335void ARM64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
336 const MachineInstr &MI) {
337 unsigned NumNOPBytes = MI.getOperand(1).getImm();
338
339 SM.recordStackMap(MI);
340 // Emit padding.
341 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
342 for (unsigned i = 0; i < NumNOPBytes; i += 4)
343 EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::HINT).addImm(0));
344}
345
346// Lower a patchpoint of the form:
347// [<def>], <id>, <numBytes>, <target>, <numArgs>
348void ARM64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
349 const MachineInstr &MI) {
350 SM.recordPatchPoint(MI);
351
352 PatchPointOpers Opers(&MI);
353
354 int64_t CallTarget = Opers.getMetaOper(PatchPointOpers::TargetPos).getImm();
355 unsigned EncodedBytes = 0;
356 if (CallTarget) {
357 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
358 "High 16 bits of call target should be zero.");
359 unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
360 EncodedBytes = 16;
361 // Materialize the jump address:
362 EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::MOVZWi)
363 .addReg(ScratchReg)
364 .addImm((CallTarget >> 32) & 0xFFFF)
365 .addImm(32));
366 EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::MOVKWi)
367 .addReg(ScratchReg)
368 .addReg(ScratchReg)
369 .addImm((CallTarget >> 16) & 0xFFFF)
370 .addImm(16));
371 EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::MOVKWi)
372 .addReg(ScratchReg)
373 .addReg(ScratchReg)
374 .addImm(CallTarget & 0xFFFF)
375 .addImm(0));
376 EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::BLR).addReg(ScratchReg));
377 }
378 // Emit padding.
379 unsigned NumBytes = Opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
380 assert(NumBytes >= EncodedBytes &&
381 "Patchpoint can't request size less than the length of a call.");
382 assert((NumBytes - EncodedBytes) % 4 == 0 &&
383 "Invalid number of NOP bytes requested!");
384 for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
385 EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::HINT).addImm(0));
386}
387
388// Simple pseudo-instructions have their lowering (with expansion to real
389// instructions) auto-generated.
390#include "ARM64GenMCPseudoLowering.inc"
391
392static unsigned getRealIndexedOpcode(unsigned Opc) {
393 switch (Opc) {
394 case ARM64::LDRXpre_isel: return ARM64::LDRXpre;
395 case ARM64::LDRWpre_isel: return ARM64::LDRWpre;
396 case ARM64::LDRDpre_isel: return ARM64::LDRDpre;
397 case ARM64::LDRSpre_isel: return ARM64::LDRSpre;
398 case ARM64::LDRBBpre_isel: return ARM64::LDRBBpre;
399 case ARM64::LDRHHpre_isel: return ARM64::LDRHHpre;
400 case ARM64::LDRSBWpre_isel: return ARM64::LDRSBWpre;
401 case ARM64::LDRSBXpre_isel: return ARM64::LDRSBXpre;
402 case ARM64::LDRSHWpre_isel: return ARM64::LDRSHWpre;
403 case ARM64::LDRSHXpre_isel: return ARM64::LDRSHXpre;
404 case ARM64::LDRSWpre_isel: return ARM64::LDRSWpre;
405
406 case ARM64::LDRDpost_isel: return ARM64::LDRDpost;
407 case ARM64::LDRSpost_isel: return ARM64::LDRSpost;
408 case ARM64::LDRXpost_isel: return ARM64::LDRXpost;
409 case ARM64::LDRWpost_isel: return ARM64::LDRWpost;
410 case ARM64::LDRHHpost_isel: return ARM64::LDRHHpost;
411 case ARM64::LDRBBpost_isel: return ARM64::LDRBBpost;
412 case ARM64::LDRSWpost_isel: return ARM64::LDRSWpost;
413 case ARM64::LDRSHWpost_isel: return ARM64::LDRSHWpost;
414 case ARM64::LDRSHXpost_isel: return ARM64::LDRSHXpost;
415 case ARM64::LDRSBWpost_isel: return ARM64::LDRSBWpost;
416 case ARM64::LDRSBXpost_isel: return ARM64::LDRSBXpost;
417
418 case ARM64::STRXpre_isel: return ARM64::STRXpre;
419 case ARM64::STRWpre_isel: return ARM64::STRWpre;
420 case ARM64::STRHHpre_isel: return ARM64::STRHHpre;
421 case ARM64::STRBBpre_isel: return ARM64::STRBBpre;
422 case ARM64::STRDpre_isel: return ARM64::STRDpre;
423 case ARM64::STRSpre_isel: return ARM64::STRSpre;
424 }
425 llvm_unreachable("Unexpected pre-indexed opcode!");
426}
427
428void ARM64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
429 // Do any auto-generated pseudo lowerings.
430 if (emitPseudoExpansionLowering(OutStreamer, MI))
431 return;
432
433 if (ARM64FI->getLOHRelated().count(MI)) {
434 // Generate a label for LOH related instruction
435 MCSymbol *LOHLabel = GetTempSymbol("loh", LOHLabelCounter++);
436 // Associate the instruction with the label
437 LOHInstToLabel[MI] = LOHLabel;
438 OutStreamer.EmitLabel(LOHLabel);
439 }
440
441 // Do any manual lowerings.
442 switch (MI->getOpcode()) {
443 default:
444 break;
445 case ARM64::DBG_VALUE: {
446 if (isVerbose() && OutStreamer.hasRawTextSupport()) {
447 SmallString<128> TmpStr;
448 raw_svector_ostream OS(TmpStr);
449 PrintDebugValueComment(MI, OS);
450 OutStreamer.EmitRawText(StringRef(OS.str()));
451 }
452 return;
453 }
454 // Indexed loads and stores use a pseudo to handle complex operand
455 // tricks and writeback to the base register. We strip off the writeback
456 // operand and switch the opcode here. Post-indexed stores were handled by the
457 // tablegen'erated pseudos above. (The complex operand <--> simple
458 // operand isel is beyond tablegen's ability, so we do these manually).
459 case ARM64::LDRHHpre_isel:
460 case ARM64::LDRBBpre_isel:
461 case ARM64::LDRXpre_isel:
462 case ARM64::LDRWpre_isel:
463 case ARM64::LDRDpre_isel:
464 case ARM64::LDRSpre_isel:
465 case ARM64::LDRSBWpre_isel:
466 case ARM64::LDRSBXpre_isel:
467 case ARM64::LDRSHWpre_isel:
468 case ARM64::LDRSHXpre_isel:
469 case ARM64::LDRSWpre_isel:
470 case ARM64::LDRDpost_isel:
471 case ARM64::LDRSpost_isel:
472 case ARM64::LDRXpost_isel:
473 case ARM64::LDRWpost_isel:
474 case ARM64::LDRHHpost_isel:
475 case ARM64::LDRBBpost_isel:
476 case ARM64::LDRSWpost_isel:
477 case ARM64::LDRSHWpost_isel:
478 case ARM64::LDRSHXpost_isel:
479 case ARM64::LDRSBWpost_isel:
480 case ARM64::LDRSBXpost_isel: {
481 MCInst TmpInst;
482 // For loads, the writeback operand to be skipped is the second.
483 TmpInst.setOpcode(getRealIndexedOpcode(MI->getOpcode()));
484 TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
485 TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(2).getReg()));
486 TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm()));
487 EmitToStreamer(OutStreamer, TmpInst);
488 return;
489 }
490 case ARM64::STRXpre_isel:
491 case ARM64::STRWpre_isel:
492 case ARM64::STRHHpre_isel:
493 case ARM64::STRBBpre_isel:
494 case ARM64::STRDpre_isel:
495 case ARM64::STRSpre_isel: {
496 MCInst TmpInst;
497 // For loads, the writeback operand to be skipped is the first.
498 TmpInst.setOpcode(getRealIndexedOpcode(MI->getOpcode()));
499 TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg()));
500 TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(2).getReg()));
501 TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm()));
502 EmitToStreamer(OutStreamer, TmpInst);
503 return;
504 }
505
506 // Tail calls use pseudo instructions so they have the proper code-gen
507 // attributes (isCall, isReturn, etc.). We lower them to the real
508 // instruction here.
509 case ARM64::TCRETURNri: {
510 MCInst TmpInst;
511 TmpInst.setOpcode(ARM64::BR);
512 TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
513 EmitToStreamer(OutStreamer, TmpInst);
514 return;
515 }
516 case ARM64::TCRETURNdi: {
517 MCOperand Dest;
518 MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
519 MCInst TmpInst;
520 TmpInst.setOpcode(ARM64::B);
521 TmpInst.addOperand(Dest);
522 EmitToStreamer(OutStreamer, TmpInst);
523 return;
524 }
525 case ARM64::TLSDESC_BLR: {
526 MCOperand Callee, Sym;
527 MCInstLowering.lowerOperand(MI->getOperand(0), Callee);
528 MCInstLowering.lowerOperand(MI->getOperand(1), Sym);
529
530 // First emit a relocation-annotation. This expands to no code, but requests
531 // the following instruction gets an R_AARCH64_TLSDESC_CALL.
532 MCInst TLSDescCall;
533 TLSDescCall.setOpcode(ARM64::TLSDESCCALL);
534 TLSDescCall.addOperand(Sym);
535 EmitToStreamer(OutStreamer, TLSDescCall);
536
537 // Other than that it's just a normal indirect call to the function loaded
538 // from the descriptor.
539 MCInst BLR;
540 BLR.setOpcode(ARM64::BLR);
541 BLR.addOperand(Callee);
542 EmitToStreamer(OutStreamer, BLR);
543
544 return;
545 }
546
547 case TargetOpcode::STACKMAP:
548 return LowerSTACKMAP(OutStreamer, SM, *MI);
549
550 case TargetOpcode::PATCHPOINT:
551 return LowerPATCHPOINT(OutStreamer, SM, *MI);
552 }
553
554 // Finally, do the automated lowerings for everything else.
555 MCInst TmpInst;
556 MCInstLowering.Lower(MI, TmpInst);
557 EmitToStreamer(OutStreamer, TmpInst);
558}
559
560// Force static initialization.
561extern "C" void LLVMInitializeARM64AsmPrinter() {
562 RegisterAsmPrinter<ARM64AsmPrinter> X(TheARM64Target);
563}