ARM64: initial backend import
[oota-llvm.git] / lib / Target / ARM64 / ARM64AsmPrinter.cpp
1 //===-- 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"
37 using namespace llvm;
38
39 namespace {
40
41 class ARM64AsmPrinter : public AsmPrinter {
42   ARM64MCInstLower MCInstLowering;
43   StackMaps SM;
44
45 public:
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
79 private:
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
114 void 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
124 MachineLocation
125 ARM64AsmPrinter::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
137 void ARM64AsmPrinter::EmitLOHs() {
138   const ARM64FunctionInfo::MILOHDirectives &LOHs =
139       const_cast<const ARM64FunctionInfo *>(ARM64FI)
140           ->getLOHContainer()
141           .getDirectives();
142   SmallVector<MCSymbol *, 3> MCArgs;
143
144   for (ARM64FunctionInfo::MILOHDirectives::const_iterator It = LOHs.begin(),
145                                                           EndIt = LOHs.end();
146        It != EndIt; ++It) {
147     const ARM64FunctionInfo::MILOHArgs &MIArgs = It->getArgs();
148     for (ARM64FunctionInfo::MILOHArgs::const_iterator
149              MIArgsIt = MIArgs.begin(),
150              EndMIArgsIt = MIArgs.end();
151          MIArgsIt != EndMIArgsIt; ++MIArgsIt) {
152       MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(*MIArgsIt);
153       assert(LabelIt != LOHInstToLabel.end() &&
154              "Label hasn't been inserted for LOH related instruction");
155       MCArgs.push_back(LabelIt->second);
156     }
157     OutStreamer.EmitLOHDirective(It->getKind(), MCArgs);
158     MCArgs.clear();
159   }
160 }
161
162 void ARM64AsmPrinter::EmitFunctionBodyEnd() {
163   if (!ARM64FI->getLOHRelated().empty())
164     EmitLOHs();
165 }
166
167 /// GetCPISymbol - Return the symbol for the specified constant pool entry.
168 MCSymbol *ARM64AsmPrinter::GetCPISymbol(unsigned CPID) const {
169   // Darwin uses a linker-private symbol name for constant-pools (to
170   // avoid addends on the relocation?), ELF has no such concept and
171   // uses a normal private symbol.
172   if (getDataLayout().getLinkerPrivateGlobalPrefix()[0])
173     return OutContext.GetOrCreateSymbol(
174         Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
175         Twine(getFunctionNumber()) + "_" + Twine(CPID));
176
177   return OutContext.GetOrCreateSymbol(
178       Twine(getDataLayout().getPrivateGlobalPrefix()) + "CPI" +
179       Twine(getFunctionNumber()) + "_" + Twine(CPID));
180 }
181
182 void ARM64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
183                                    raw_ostream &O) {
184   const MachineOperand &MO = MI->getOperand(OpNum);
185   switch (MO.getType()) {
186   default:
187     assert(0 && "<unknown operand type>");
188   case MachineOperand::MO_Register: {
189     unsigned Reg = MO.getReg();
190     assert(TargetRegisterInfo::isPhysicalRegister(Reg));
191     assert(!MO.getSubReg() && "Subregs should be eliminated!");
192     O << ARM64InstPrinter::getRegisterName(Reg);
193     break;
194   }
195   case MachineOperand::MO_Immediate: {
196     int64_t Imm = MO.getImm();
197     O << '#' << Imm;
198     break;
199   }
200   }
201 }
202
203 bool ARM64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
204                                         raw_ostream &O) {
205   unsigned Reg = MO.getReg();
206   switch (Mode) {
207   default:
208     return true; // Unknown mode.
209   case 'w':
210     Reg = getWRegFromXReg(Reg);
211     break;
212   case 'x':
213     Reg = getXRegFromWReg(Reg);
214     break;
215   }
216
217   O << ARM64InstPrinter::getRegisterName(Reg);
218   return false;
219 }
220
221 // Prints the register in MO using class RC using the offset in the
222 // new register class. This should not be used for cross class
223 // printing.
224 bool ARM64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
225                                          const TargetRegisterClass *RC,
226                                          bool isVector, raw_ostream &O) {
227   assert(MO.isReg() && "Should only get here with a register!");
228   const ARM64RegisterInfo *RI =
229       static_cast<const ARM64RegisterInfo *>(TM.getRegisterInfo());
230   unsigned Reg = MO.getReg();
231   unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
232   assert(RI->regsOverlap(RegToPrint, Reg));
233   O << ARM64InstPrinter::getRegisterName(
234            RegToPrint, isVector ? ARM64::vreg : ARM64::NoRegAltName);
235   return false;
236 }
237
238 bool ARM64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
239                                       unsigned AsmVariant,
240                                       const char *ExtraCode, raw_ostream &O) {
241   const MachineOperand &MO = MI->getOperand(OpNum);
242   // Does this asm operand have a single letter operand modifier?
243   if (ExtraCode && ExtraCode[0]) {
244     if (ExtraCode[1] != 0)
245       return true; // Unknown modifier.
246
247     switch (ExtraCode[0]) {
248     default:
249       return true; // Unknown modifier.
250     case 'w':      // Print W register
251     case 'x':      // Print X register
252       if (MO.isReg())
253         return printAsmMRegister(MO, ExtraCode[0], O);
254       if (MO.isImm() && MO.getImm() == 0) {
255         unsigned Reg = ExtraCode[0] == 'w' ? ARM64::WZR : ARM64::XZR;
256         O << ARM64InstPrinter::getRegisterName(Reg);
257         return false;
258       }
259       printOperand(MI, OpNum, O);
260       return false;
261     case 'b': // Print B register.
262     case 'h': // Print H register.
263     case 's': // Print S register.
264     case 'd': // Print D register.
265     case 'q': // Print Q register.
266       if (MO.isReg()) {
267         const TargetRegisterClass *RC;
268         switch (ExtraCode[0]) {
269         case 'b':
270           RC = &ARM64::FPR8RegClass;
271           break;
272         case 'h':
273           RC = &ARM64::FPR16RegClass;
274           break;
275         case 's':
276           RC = &ARM64::FPR32RegClass;
277           break;
278         case 'd':
279           RC = &ARM64::FPR64RegClass;
280           break;
281         case 'q':
282           RC = &ARM64::FPR128RegClass;
283           break;
284         default:
285           return true;
286         }
287         return printAsmRegInClass(MO, RC, false /* vector */, O);
288       }
289       printOperand(MI, OpNum, O);
290       return false;
291     }
292   }
293
294   // According to ARM, we should emit x and v registers unless we have a
295   // modifier.
296   if (MO.isReg()) {
297     unsigned Reg = MO.getReg();
298
299     // If this is a w or x register, print an x register.
300     if (ARM64::GPR32allRegClass.contains(Reg) ||
301         ARM64::GPR64allRegClass.contains(Reg))
302       return printAsmMRegister(MO, 'x', O);
303
304     // If this is a b, h, s, d, or q register, print it as a v register.
305     return printAsmRegInClass(MO, &ARM64::FPR128RegClass, true /* vector */, O);
306   }
307
308   printOperand(MI, OpNum, O);
309   return false;
310 }
311
312 bool ARM64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
313                                             unsigned OpNum, unsigned AsmVariant,
314                                             const char *ExtraCode,
315                                             raw_ostream &O) {
316   if (ExtraCode && ExtraCode[0])
317     return true; // Unknown modifier.
318
319   const MachineOperand &MO = MI->getOperand(OpNum);
320   assert(MO.isReg() && "unexpected inline asm memory operand");
321   O << "[" << ARM64InstPrinter::getRegisterName(MO.getReg()) << "]";
322   return false;
323 }
324
325 void ARM64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
326                                              raw_ostream &OS) {
327   unsigned NOps = MI->getNumOperands();
328   assert(NOps == 4);
329   OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
330   // cast away const; DIetc do not take const operands for some reason.
331   DIVariable V(const_cast<MDNode *>(MI->getOperand(NOps - 1).getMetadata()));
332   OS << V.getName();
333   OS << " <- ";
334   // Frame address.  Currently handles register +- offset only.
335   assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
336   OS << '[';
337   printOperand(MI, 0, OS);
338   OS << '+';
339   printOperand(MI, 1, OS);
340   OS << ']';
341   OS << "+";
342   printOperand(MI, NOps - 2, OS);
343 }
344
345 void ARM64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
346                                     const MachineInstr &MI) {
347   unsigned NumNOPBytes = MI.getOperand(1).getImm();
348
349   SM.recordStackMap(MI);
350   // Emit padding.
351   assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
352   for (unsigned i = 0; i < NumNOPBytes; i += 4)
353     EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::HINT).addImm(0));
354 }
355
356 // Lower a patchpoint of the form:
357 // [<def>], <id>, <numBytes>, <target>, <numArgs>
358 void ARM64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
359                                       const MachineInstr &MI) {
360   SM.recordPatchPoint(MI);
361
362   PatchPointOpers Opers(&MI);
363
364   int64_t CallTarget = Opers.getMetaOper(PatchPointOpers::TargetPos).getImm();
365   unsigned EncodedBytes = 0;
366   if (CallTarget) {
367     assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
368            "High 16 bits of call target should be zero.");
369     unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
370     EncodedBytes = 16;
371     // Materialize the jump address:
372     EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::MOVZWi)
373                                     .addReg(ScratchReg)
374                                     .addImm((CallTarget >> 32) & 0xFFFF)
375                                     .addImm(32));
376     EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::MOVKWi)
377                                     .addReg(ScratchReg)
378                                     .addReg(ScratchReg)
379                                     .addImm((CallTarget >> 16) & 0xFFFF)
380                                     .addImm(16));
381     EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::MOVKWi)
382                                     .addReg(ScratchReg)
383                                     .addReg(ScratchReg)
384                                     .addImm(CallTarget & 0xFFFF)
385                                     .addImm(0));
386     EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::BLR).addReg(ScratchReg));
387   }
388   // Emit padding.
389   unsigned NumBytes = Opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
390   assert(NumBytes >= EncodedBytes &&
391          "Patchpoint can't request size less than the length of a call.");
392   assert((NumBytes - EncodedBytes) % 4 == 0 &&
393          "Invalid number of NOP bytes requested!");
394   for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
395     EmitToStreamer(OutStreamer, MCInstBuilder(ARM64::HINT).addImm(0));
396 }
397
398 // Simple pseudo-instructions have their lowering (with expansion to real
399 // instructions) auto-generated.
400 #include "ARM64GenMCPseudoLowering.inc"
401
402 static unsigned getRealIndexedOpcode(unsigned Opc) {
403   switch (Opc) {
404   case ARM64::LDRXpre_isel:    return ARM64::LDRXpre;
405   case ARM64::LDRWpre_isel:    return ARM64::LDRWpre;
406   case ARM64::LDRDpre_isel:    return ARM64::LDRDpre;
407   case ARM64::LDRSpre_isel:    return ARM64::LDRSpre;
408   case ARM64::LDRBBpre_isel:   return ARM64::LDRBBpre;
409   case ARM64::LDRHHpre_isel:   return ARM64::LDRHHpre;
410   case ARM64::LDRSBWpre_isel:  return ARM64::LDRSBWpre;
411   case ARM64::LDRSBXpre_isel:  return ARM64::LDRSBXpre;
412   case ARM64::LDRSHWpre_isel:  return ARM64::LDRSHWpre;
413   case ARM64::LDRSHXpre_isel:  return ARM64::LDRSHXpre;
414   case ARM64::LDRSWpre_isel:   return ARM64::LDRSWpre;
415
416   case ARM64::LDRDpost_isel:   return ARM64::LDRDpost;
417   case ARM64::LDRSpost_isel:   return ARM64::LDRSpost;
418   case ARM64::LDRXpost_isel:   return ARM64::LDRXpost;
419   case ARM64::LDRWpost_isel:   return ARM64::LDRWpost;
420   case ARM64::LDRHHpost_isel:  return ARM64::LDRHHpost;
421   case ARM64::LDRBBpost_isel:  return ARM64::LDRBBpost;
422   case ARM64::LDRSWpost_isel:  return ARM64::LDRSWpost;
423   case ARM64::LDRSHWpost_isel: return ARM64::LDRSHWpost;
424   case ARM64::LDRSHXpost_isel: return ARM64::LDRSHXpost;
425   case ARM64::LDRSBWpost_isel: return ARM64::LDRSBWpost;
426   case ARM64::LDRSBXpost_isel: return ARM64::LDRSBXpost;
427
428   case ARM64::STRXpre_isel:    return ARM64::STRXpre;
429   case ARM64::STRWpre_isel:    return ARM64::STRWpre;
430   case ARM64::STRHHpre_isel:   return ARM64::STRHHpre;
431   case ARM64::STRBBpre_isel:   return ARM64::STRBBpre;
432   case ARM64::STRDpre_isel:    return ARM64::STRDpre;
433   case ARM64::STRSpre_isel:    return ARM64::STRSpre;
434   }
435   llvm_unreachable("Unexpected pre-indexed opcode!");
436 }
437
438 void ARM64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
439   // Do any auto-generated pseudo lowerings.
440   if (emitPseudoExpansionLowering(OutStreamer, MI))
441     return;
442
443   if (ARM64FI->getLOHRelated().count(MI)) {
444     // Generate a label for LOH related instruction
445     MCSymbol *LOHLabel = GetTempSymbol("loh", LOHLabelCounter++);
446     // Associate the instruction with the label
447     LOHInstToLabel[MI] = LOHLabel;
448     OutStreamer.EmitLabel(LOHLabel);
449   }
450
451   // Do any manual lowerings.
452   switch (MI->getOpcode()) {
453   default:
454     break;
455   case ARM64::DBG_VALUE: {
456     if (isVerbose() && OutStreamer.hasRawTextSupport()) {
457       SmallString<128> TmpStr;
458       raw_svector_ostream OS(TmpStr);
459       PrintDebugValueComment(MI, OS);
460       OutStreamer.EmitRawText(StringRef(OS.str()));
461     }
462     return;
463   }
464   // Indexed loads and stores use a pseudo to handle complex operand
465   // tricks and writeback to the base register. We strip off the writeback
466   // operand and switch the opcode here. Post-indexed stores were handled by the
467   // tablegen'erated pseudos above. (The complex operand <--> simple
468   // operand isel is beyond tablegen's ability, so we do these manually).
469   case ARM64::LDRHHpre_isel:
470   case ARM64::LDRBBpre_isel:
471   case ARM64::LDRXpre_isel:
472   case ARM64::LDRWpre_isel:
473   case ARM64::LDRDpre_isel:
474   case ARM64::LDRSpre_isel:
475   case ARM64::LDRSBWpre_isel:
476   case ARM64::LDRSBXpre_isel:
477   case ARM64::LDRSHWpre_isel:
478   case ARM64::LDRSHXpre_isel:
479   case ARM64::LDRSWpre_isel:
480   case ARM64::LDRDpost_isel:
481   case ARM64::LDRSpost_isel:
482   case ARM64::LDRXpost_isel:
483   case ARM64::LDRWpost_isel:
484   case ARM64::LDRHHpost_isel:
485   case ARM64::LDRBBpost_isel:
486   case ARM64::LDRSWpost_isel:
487   case ARM64::LDRSHWpost_isel:
488   case ARM64::LDRSHXpost_isel:
489   case ARM64::LDRSBWpost_isel:
490   case ARM64::LDRSBXpost_isel: {
491     MCInst TmpInst;
492     // For loads, the writeback operand to be skipped is the second.
493     TmpInst.setOpcode(getRealIndexedOpcode(MI->getOpcode()));
494     TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
495     TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(2).getReg()));
496     TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm()));
497     EmitToStreamer(OutStreamer, TmpInst);
498     return;
499   }
500   case ARM64::STRXpre_isel:
501   case ARM64::STRWpre_isel:
502   case ARM64::STRHHpre_isel:
503   case ARM64::STRBBpre_isel:
504   case ARM64::STRDpre_isel:
505   case ARM64::STRSpre_isel: {
506     MCInst TmpInst;
507     // For loads, the writeback operand to be skipped is the first.
508     TmpInst.setOpcode(getRealIndexedOpcode(MI->getOpcode()));
509     TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg()));
510     TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(2).getReg()));
511     TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm()));
512     EmitToStreamer(OutStreamer, TmpInst);
513     return;
514   }
515
516   // Tail calls use pseudo instructions so they have the proper code-gen
517   // attributes (isCall, isReturn, etc.). We lower them to the real
518   // instruction here.
519   case ARM64::TCRETURNri: {
520     MCInst TmpInst;
521     TmpInst.setOpcode(ARM64::BR);
522     TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
523     EmitToStreamer(OutStreamer, TmpInst);
524     return;
525   }
526   case ARM64::TCRETURNdi: {
527     MCOperand Dest;
528     MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
529     MCInst TmpInst;
530     TmpInst.setOpcode(ARM64::B);
531     TmpInst.addOperand(Dest);
532     EmitToStreamer(OutStreamer, TmpInst);
533     return;
534   }
535   case ARM64::TLSDESC_BLR: {
536     MCOperand Callee, Sym;
537     MCInstLowering.lowerOperand(MI->getOperand(0), Callee);
538     MCInstLowering.lowerOperand(MI->getOperand(1), Sym);
539
540     // First emit a relocation-annotation. This expands to no code, but requests
541     // the following instruction gets an R_AARCH64_TLSDESC_CALL.
542     MCInst TLSDescCall;
543     TLSDescCall.setOpcode(ARM64::TLSDESCCALL);
544     TLSDescCall.addOperand(Sym);
545     EmitToStreamer(OutStreamer, TLSDescCall);
546
547     // Other than that it's just a normal indirect call to the function loaded
548     // from the descriptor.
549     MCInst BLR;
550     BLR.setOpcode(ARM64::BLR);
551     BLR.addOperand(Callee);
552     EmitToStreamer(OutStreamer, BLR);
553
554     return;
555   }
556
557   case TargetOpcode::STACKMAP:
558     return LowerSTACKMAP(OutStreamer, SM, *MI);
559
560   case TargetOpcode::PATCHPOINT:
561     return LowerPATCHPOINT(OutStreamer, SM, *MI);
562   }
563
564   // Finally, do the automated lowerings for everything else.
565   MCInst TmpInst;
566   MCInstLowering.Lower(MI, TmpInst);
567   EmitToStreamer(OutStreamer, TmpInst);
568 }
569
570 // Force static initialization.
571 extern "C" void LLVMInitializeARM64AsmPrinter() {
572   RegisterAsmPrinter<ARM64AsmPrinter> X(TheARM64Target);
573 }