Home | History | Annotate | Download | only in AArch64
      1 //===-- AArch64AsmPrinter.cpp - AArch64 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 AArch64 assembly language.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "MCTargetDesc/AArch64AddressingModes.h"
     16 #include "AArch64.h"
     17 #include "AArch64MCInstLower.h"
     18 #include "AArch64MachineFunctionInfo.h"
     19 #include "AArch64RegisterInfo.h"
     20 #include "AArch64Subtarget.h"
     21 #include "InstPrinter/AArch64InstPrinter.h"
     22 #include "MCTargetDesc/AArch64MCExpr.h"
     23 #include "llvm/ADT/SmallString.h"
     24 #include "llvm/ADT/StringSwitch.h"
     25 #include "llvm/ADT/Twine.h"
     26 #include "llvm/CodeGen/AsmPrinter.h"
     27 #include "llvm/CodeGen/MachineInstr.h"
     28 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
     29 #include "llvm/CodeGen/StackMaps.h"
     30 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
     31 #include "llvm/IR/DataLayout.h"
     32 #include "llvm/IR/DebugInfo.h"
     33 #include "llvm/MC/MCAsmInfo.h"
     34 #include "llvm/MC/MCContext.h"
     35 #include "llvm/MC/MCInst.h"
     36 #include "llvm/MC/MCInstBuilder.h"
     37 #include "llvm/MC/MCLinkerOptimizationHint.h"
     38 #include "llvm/MC/MCStreamer.h"
     39 #include "llvm/MC/MCSymbol.h"
     40 #include "llvm/Support/Debug.h"
     41 #include "llvm/Support/TargetRegistry.h"
     42 #include "llvm/Support/raw_ostream.h"
     43 using namespace llvm;
     44 
     45 #define DEBUG_TYPE "asm-printer"
     46 
     47 namespace {
     48 
     49 class AArch64AsmPrinter : public AsmPrinter {
     50   AArch64MCInstLower MCInstLowering;
     51   StackMaps SM;
     52   const AArch64Subtarget *STI;
     53 
     54 public:
     55   AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
     56       : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this),
     57         SM(*this), AArch64FI(nullptr) {}
     58 
     59   const char *getPassName() const override {
     60     return "AArch64 Assembly Printer";
     61   }
     62 
     63   /// \brief Wrapper for MCInstLowering.lowerOperand() for the
     64   /// tblgen'erated pseudo lowering.
     65   bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
     66     return MCInstLowering.lowerOperand(MO, MCOp);
     67   }
     68 
     69   void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
     70                      const MachineInstr &MI);
     71   void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
     72                        const MachineInstr &MI);
     73   /// \brief tblgen'erated driver function for lowering simple MI->MC
     74   /// pseudo instructions.
     75   bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
     76                                    const MachineInstr *MI);
     77 
     78   void EmitInstruction(const MachineInstr *MI) override;
     79 
     80   void getAnalysisUsage(AnalysisUsage &AU) const override {
     81     AsmPrinter::getAnalysisUsage(AU);
     82     AU.setPreservesAll();
     83   }
     84 
     85   bool runOnMachineFunction(MachineFunction &F) override {
     86     AArch64FI = F.getInfo<AArch64FunctionInfo>();
     87     STI = static_cast<const AArch64Subtarget*>(&F.getSubtarget());
     88     return AsmPrinter::runOnMachineFunction(F);
     89   }
     90 
     91 private:
     92   void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
     93   bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
     94   bool printAsmRegInClass(const MachineOperand &MO,
     95                           const TargetRegisterClass *RC, bool isVector,
     96                           raw_ostream &O);
     97 
     98   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
     99                        unsigned AsmVariant, const char *ExtraCode,
    100                        raw_ostream &O) override;
    101   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
    102                              unsigned AsmVariant, const char *ExtraCode,
    103                              raw_ostream &O) override;
    104 
    105   void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
    106 
    107   void EmitFunctionBodyEnd() override;
    108 
    109   MCSymbol *GetCPISymbol(unsigned CPID) const override;
    110   void EmitEndOfAsmFile(Module &M) override;
    111   AArch64FunctionInfo *AArch64FI;
    112 
    113   /// \brief Emit the LOHs contained in AArch64FI.
    114   void EmitLOHs();
    115 
    116   /// Emit instruction to set float register to zero.
    117   void EmitFMov0(const MachineInstr &MI);
    118 
    119   typedef std::map<const MachineInstr *, MCSymbol *> MInstToMCSymbol;
    120   MInstToMCSymbol LOHInstToLabel;
    121 };
    122 
    123 } // end of anonymous namespace
    124 
    125 //===----------------------------------------------------------------------===//
    126 
    127 void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) {
    128   const Triple &TT = TM.getTargetTriple();
    129   if (TT.isOSBinFormatMachO()) {
    130     // Funny Darwin hack: This flag tells the linker that no global symbols
    131     // contain code that falls through to other global symbols (e.g. the obvious
    132     // implementation of multiple entry points).  If this doesn't occur, the
    133     // linker can safely perform dead code stripping.  Since LLVM never
    134     // generates code that does this, it is always safe to set.
    135     OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
    136     SM.serializeToStackMapSection();
    137   }
    138 }
    139 
    140 void AArch64AsmPrinter::EmitLOHs() {
    141   SmallVector<MCSymbol *, 3> MCArgs;
    142 
    143   for (const auto &D : AArch64FI->getLOHContainer()) {
    144     for (const MachineInstr *MI : D.getArgs()) {
    145       MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
    146       assert(LabelIt != LOHInstToLabel.end() &&
    147              "Label hasn't been inserted for LOH related instruction");
    148       MCArgs.push_back(LabelIt->second);
    149     }
    150     OutStreamer->EmitLOHDirective(D.getKind(), MCArgs);
    151     MCArgs.clear();
    152   }
    153 }
    154 
    155 void AArch64AsmPrinter::EmitFunctionBodyEnd() {
    156   if (!AArch64FI->getLOHRelated().empty())
    157     EmitLOHs();
    158 }
    159 
    160 /// GetCPISymbol - Return the symbol for the specified constant pool entry.
    161 MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
    162   // Darwin uses a linker-private symbol name for constant-pools (to
    163   // avoid addends on the relocation?), ELF has no such concept and
    164   // uses a normal private symbol.
    165   if (getDataLayout().getLinkerPrivateGlobalPrefix()[0])
    166     return OutContext.getOrCreateSymbol(
    167         Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
    168         Twine(getFunctionNumber()) + "_" + Twine(CPID));
    169 
    170   return OutContext.getOrCreateSymbol(
    171       Twine(getDataLayout().getPrivateGlobalPrefix()) + "CPI" +
    172       Twine(getFunctionNumber()) + "_" + Twine(CPID));
    173 }
    174 
    175 void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
    176                                      raw_ostream &O) {
    177   const MachineOperand &MO = MI->getOperand(OpNum);
    178   switch (MO.getType()) {
    179   default:
    180     llvm_unreachable("<unknown operand type>");
    181   case MachineOperand::MO_Register: {
    182     unsigned Reg = MO.getReg();
    183     assert(TargetRegisterInfo::isPhysicalRegister(Reg));
    184     assert(!MO.getSubReg() && "Subregs should be eliminated!");
    185     O << AArch64InstPrinter::getRegisterName(Reg);
    186     break;
    187   }
    188   case MachineOperand::MO_Immediate: {
    189     int64_t Imm = MO.getImm();
    190     O << '#' << Imm;
    191     break;
    192   }
    193   case MachineOperand::MO_GlobalAddress: {
    194     const GlobalValue *GV = MO.getGlobal();
    195     MCSymbol *Sym = getSymbol(GV);
    196 
    197     // FIXME: Can we get anything other than a plain symbol here?
    198     assert(!MO.getTargetFlags() && "Unknown operand target flag!");
    199 
    200     Sym->print(O, MAI);
    201     printOffset(MO.getOffset(), O);
    202     break;
    203   }
    204   }
    205 }
    206 
    207 bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
    208                                           raw_ostream &O) {
    209   unsigned Reg = MO.getReg();
    210   switch (Mode) {
    211   default:
    212     return true; // Unknown mode.
    213   case 'w':
    214     Reg = getWRegFromXReg(Reg);
    215     break;
    216   case 'x':
    217     Reg = getXRegFromWReg(Reg);
    218     break;
    219   }
    220 
    221   O << AArch64InstPrinter::getRegisterName(Reg);
    222   return false;
    223 }
    224 
    225 // Prints the register in MO using class RC using the offset in the
    226 // new register class. This should not be used for cross class
    227 // printing.
    228 bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
    229                                            const TargetRegisterClass *RC,
    230                                            bool isVector, raw_ostream &O) {
    231   assert(MO.isReg() && "Should only get here with a register!");
    232   const TargetRegisterInfo *RI = STI->getRegisterInfo();
    233   unsigned Reg = MO.getReg();
    234   unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
    235   assert(RI->regsOverlap(RegToPrint, Reg));
    236   O << AArch64InstPrinter::getRegisterName(
    237            RegToPrint, isVector ? AArch64::vreg : AArch64::NoRegAltName);
    238   return false;
    239 }
    240 
    241 bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
    242                                         unsigned AsmVariant,
    243                                         const char *ExtraCode, raw_ostream &O) {
    244   const MachineOperand &MO = MI->getOperand(OpNum);
    245 
    246   // First try the generic code, which knows about modifiers like 'c' and 'n'.
    247   if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O))
    248     return false;
    249 
    250   // Does this asm operand have a single letter operand modifier?
    251   if (ExtraCode && ExtraCode[0]) {
    252     if (ExtraCode[1] != 0)
    253       return true; // Unknown modifier.
    254 
    255     switch (ExtraCode[0]) {
    256     default:
    257       return true; // Unknown modifier.
    258     case 'w':      // Print W register
    259     case 'x':      // Print X register
    260       if (MO.isReg())
    261         return printAsmMRegister(MO, ExtraCode[0], O);
    262       if (MO.isImm() && MO.getImm() == 0) {
    263         unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
    264         O << AArch64InstPrinter::getRegisterName(Reg);
    265         return false;
    266       }
    267       printOperand(MI, OpNum, O);
    268       return false;
    269     case 'b': // Print B register.
    270     case 'h': // Print H register.
    271     case 's': // Print S register.
    272     case 'd': // Print D register.
    273     case 'q': // Print Q register.
    274       if (MO.isReg()) {
    275         const TargetRegisterClass *RC;
    276         switch (ExtraCode[0]) {
    277         case 'b':
    278           RC = &AArch64::FPR8RegClass;
    279           break;
    280         case 'h':
    281           RC = &AArch64::FPR16RegClass;
    282           break;
    283         case 's':
    284           RC = &AArch64::FPR32RegClass;
    285           break;
    286         case 'd':
    287           RC = &AArch64::FPR64RegClass;
    288           break;
    289         case 'q':
    290           RC = &AArch64::FPR128RegClass;
    291           break;
    292         default:
    293           return true;
    294         }
    295         return printAsmRegInClass(MO, RC, false /* vector */, O);
    296       }
    297       printOperand(MI, OpNum, O);
    298       return false;
    299     }
    300   }
    301 
    302   // According to ARM, we should emit x and v registers unless we have a
    303   // modifier.
    304   if (MO.isReg()) {
    305     unsigned Reg = MO.getReg();
    306 
    307     // If this is a w or x register, print an x register.
    308     if (AArch64::GPR32allRegClass.contains(Reg) ||
    309         AArch64::GPR64allRegClass.contains(Reg))
    310       return printAsmMRegister(MO, 'x', O);
    311 
    312     // If this is a b, h, s, d, or q register, print it as a v register.
    313     return printAsmRegInClass(MO, &AArch64::FPR128RegClass, true /* vector */,
    314                               O);
    315   }
    316 
    317   printOperand(MI, OpNum, O);
    318   return false;
    319 }
    320 
    321 bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
    322                                               unsigned OpNum,
    323                                               unsigned AsmVariant,
    324                                               const char *ExtraCode,
    325                                               raw_ostream &O) {
    326   if (ExtraCode && ExtraCode[0])
    327     return true; // Unknown modifier.
    328 
    329   const MachineOperand &MO = MI->getOperand(OpNum);
    330   assert(MO.isReg() && "unexpected inline asm memory operand");
    331   O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
    332   return false;
    333 }
    334 
    335 void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
    336                                                raw_ostream &OS) {
    337   unsigned NOps = MI->getNumOperands();
    338   assert(NOps == 4);
    339   OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
    340   // cast away const; DIetc do not take const operands for some reason.
    341   OS << cast<DILocalVariable>(MI->getOperand(NOps - 2).getMetadata())
    342             ->getName();
    343   OS << " <- ";
    344   // Frame address.  Currently handles register +- offset only.
    345   assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
    346   OS << '[';
    347   printOperand(MI, 0, OS);
    348   OS << '+';
    349   printOperand(MI, 1, OS);
    350   OS << ']';
    351   OS << "+";
    352   printOperand(MI, NOps - 2, OS);
    353 }
    354 
    355 void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
    356                                       const MachineInstr &MI) {
    357   unsigned NumNOPBytes = MI.getOperand(1).getImm();
    358 
    359   SM.recordStackMap(MI);
    360   assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
    361 
    362   // Scan ahead to trim the shadow.
    363   const MachineBasicBlock &MBB = *MI.getParent();
    364   MachineBasicBlock::const_iterator MII(MI);
    365   ++MII;
    366   while (NumNOPBytes > 0) {
    367     if (MII == MBB.end() || MII->isCall() ||
    368         MII->getOpcode() == AArch64::DBG_VALUE ||
    369         MII->getOpcode() == TargetOpcode::PATCHPOINT ||
    370         MII->getOpcode() == TargetOpcode::STACKMAP)
    371       break;
    372     ++MII;
    373     NumNOPBytes -= 4;
    374   }
    375 
    376   // Emit nops.
    377   for (unsigned i = 0; i < NumNOPBytes; i += 4)
    378     EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
    379 }
    380 
    381 // Lower a patchpoint of the form:
    382 // [<def>], <id>, <numBytes>, <target>, <numArgs>
    383 void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
    384                                         const MachineInstr &MI) {
    385   SM.recordPatchPoint(MI);
    386 
    387   PatchPointOpers Opers(&MI);
    388 
    389   int64_t CallTarget = Opers.getMetaOper(PatchPointOpers::TargetPos).getImm();
    390   unsigned EncodedBytes = 0;
    391   if (CallTarget) {
    392     assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
    393            "High 16 bits of call target should be zero.");
    394     unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
    395     EncodedBytes = 16;
    396     // Materialize the jump address:
    397     EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi)
    398                                     .addReg(ScratchReg)
    399                                     .addImm((CallTarget >> 32) & 0xFFFF)
    400                                     .addImm(32));
    401     EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
    402                                     .addReg(ScratchReg)
    403                                     .addReg(ScratchReg)
    404                                     .addImm((CallTarget >> 16) & 0xFFFF)
    405                                     .addImm(16));
    406     EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
    407                                     .addReg(ScratchReg)
    408                                     .addReg(ScratchReg)
    409                                     .addImm(CallTarget & 0xFFFF)
    410                                     .addImm(0));
    411     EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
    412   }
    413   // Emit padding.
    414   unsigned NumBytes = Opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
    415   assert(NumBytes >= EncodedBytes &&
    416          "Patchpoint can't request size less than the length of a call.");
    417   assert((NumBytes - EncodedBytes) % 4 == 0 &&
    418          "Invalid number of NOP bytes requested!");
    419   for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
    420     EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
    421 }
    422 
    423 void AArch64AsmPrinter::EmitFMov0(const MachineInstr &MI) {
    424   unsigned DestReg = MI.getOperand(0).getReg();
    425   if (STI->hasZeroCycleZeroing()) {
    426     // Convert S/D register to corresponding Q register
    427     if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31) {
    428       DestReg = AArch64::Q0 + (DestReg - AArch64::S0);
    429     } else {
    430       assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31);
    431       DestReg = AArch64::Q0 + (DestReg - AArch64::D0);
    432     }
    433     MCInst MOVI;
    434     MOVI.setOpcode(AArch64::MOVIv2d_ns);
    435     MOVI.addOperand(MCOperand::createReg(DestReg));
    436     MOVI.addOperand(MCOperand::createImm(0));
    437     EmitToStreamer(*OutStreamer, MOVI);
    438   } else {
    439     MCInst FMov;
    440     switch (MI.getOpcode()) {
    441     default: llvm_unreachable("Unexpected opcode");
    442     case AArch64::FMOVS0:
    443       FMov.setOpcode(AArch64::FMOVWSr);
    444       FMov.addOperand(MCOperand::createReg(DestReg));
    445       FMov.addOperand(MCOperand::createReg(AArch64::WZR));
    446       break;
    447     case AArch64::FMOVD0:
    448       FMov.setOpcode(AArch64::FMOVXDr);
    449       FMov.addOperand(MCOperand::createReg(DestReg));
    450       FMov.addOperand(MCOperand::createReg(AArch64::XZR));
    451       break;
    452     }
    453     EmitToStreamer(*OutStreamer, FMov);
    454   }
    455 }
    456 
    457 // Simple pseudo-instructions have their lowering (with expansion to real
    458 // instructions) auto-generated.
    459 #include "AArch64GenMCPseudoLowering.inc"
    460 
    461 void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
    462   // Do any auto-generated pseudo lowerings.
    463   if (emitPseudoExpansionLowering(*OutStreamer, MI))
    464     return;
    465 
    466   if (AArch64FI->getLOHRelated().count(MI)) {
    467     // Generate a label for LOH related instruction
    468     MCSymbol *LOHLabel = createTempSymbol("loh");
    469     // Associate the instruction with the label
    470     LOHInstToLabel[MI] = LOHLabel;
    471     OutStreamer->EmitLabel(LOHLabel);
    472   }
    473 
    474   // Do any manual lowerings.
    475   switch (MI->getOpcode()) {
    476   default:
    477     break;
    478   case AArch64::DBG_VALUE: {
    479     if (isVerbose() && OutStreamer->hasRawTextSupport()) {
    480       SmallString<128> TmpStr;
    481       raw_svector_ostream OS(TmpStr);
    482       PrintDebugValueComment(MI, OS);
    483       OutStreamer->EmitRawText(StringRef(OS.str()));
    484     }
    485     return;
    486   }
    487 
    488   // Tail calls use pseudo instructions so they have the proper code-gen
    489   // attributes (isCall, isReturn, etc.). We lower them to the real
    490   // instruction here.
    491   case AArch64::TCRETURNri: {
    492     MCInst TmpInst;
    493     TmpInst.setOpcode(AArch64::BR);
    494     TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
    495     EmitToStreamer(*OutStreamer, TmpInst);
    496     return;
    497   }
    498   case AArch64::TCRETURNdi: {
    499     MCOperand Dest;
    500     MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
    501     MCInst TmpInst;
    502     TmpInst.setOpcode(AArch64::B);
    503     TmpInst.addOperand(Dest);
    504     EmitToStreamer(*OutStreamer, TmpInst);
    505     return;
    506   }
    507   case AArch64::TLSDESC_CALLSEQ: {
    508     /// lower this to:
    509     ///    adrp  x0, :tlsdesc:var
    510     ///    ldr   x1, [x0, #:tlsdesc_lo12:var]
    511     ///    add   x0, x0, #:tlsdesc_lo12:var
    512     ///    .tlsdesccall var
    513     ///    blr   x1
    514     ///    (TPIDR_EL0 offset now in x0)
    515     const MachineOperand &MO_Sym = MI->getOperand(0);
    516     MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
    517     MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
    518     MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF |
    519                                    AArch64II::MO_NC);
    520     MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
    521     MCInstLowering.lowerOperand(MO_Sym, Sym);
    522     MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
    523     MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
    524 
    525     MCInst Adrp;
    526     Adrp.setOpcode(AArch64::ADRP);
    527     Adrp.addOperand(MCOperand::createReg(AArch64::X0));
    528     Adrp.addOperand(SymTLSDesc);
    529     EmitToStreamer(*OutStreamer, Adrp);
    530 
    531     MCInst Ldr;
    532     Ldr.setOpcode(AArch64::LDRXui);
    533     Ldr.addOperand(MCOperand::createReg(AArch64::X1));
    534     Ldr.addOperand(MCOperand::createReg(AArch64::X0));
    535     Ldr.addOperand(SymTLSDescLo12);
    536     Ldr.addOperand(MCOperand::createImm(0));
    537     EmitToStreamer(*OutStreamer, Ldr);
    538 
    539     MCInst Add;
    540     Add.setOpcode(AArch64::ADDXri);
    541     Add.addOperand(MCOperand::createReg(AArch64::X0));
    542     Add.addOperand(MCOperand::createReg(AArch64::X0));
    543     Add.addOperand(SymTLSDescLo12);
    544     Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
    545     EmitToStreamer(*OutStreamer, Add);
    546 
    547     // Emit a relocation-annotation. This expands to no code, but requests
    548     // the following instruction gets an R_AARCH64_TLSDESC_CALL.
    549     MCInst TLSDescCall;
    550     TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
    551     TLSDescCall.addOperand(Sym);
    552     EmitToStreamer(*OutStreamer, TLSDescCall);
    553 
    554     MCInst Blr;
    555     Blr.setOpcode(AArch64::BLR);
    556     Blr.addOperand(MCOperand::createReg(AArch64::X1));
    557     EmitToStreamer(*OutStreamer, Blr);
    558 
    559     return;
    560   }
    561 
    562   case AArch64::FMOVS0:
    563   case AArch64::FMOVD0:
    564     EmitFMov0(*MI);
    565     return;
    566 
    567   case TargetOpcode::STACKMAP:
    568     return LowerSTACKMAP(*OutStreamer, SM, *MI);
    569 
    570   case TargetOpcode::PATCHPOINT:
    571     return LowerPATCHPOINT(*OutStreamer, SM, *MI);
    572   }
    573 
    574   // Finally, do the automated lowerings for everything else.
    575   MCInst TmpInst;
    576   MCInstLowering.Lower(MI, TmpInst);
    577   EmitToStreamer(*OutStreamer, TmpInst);
    578 }
    579 
    580 // Force static initialization.
    581 extern "C" void LLVMInitializeAArch64AsmPrinter() {
    582   RegisterAsmPrinter<AArch64AsmPrinter> X(TheAArch64leTarget);
    583   RegisterAsmPrinter<AArch64AsmPrinter> Y(TheAArch64beTarget);
    584   RegisterAsmPrinter<AArch64AsmPrinter> Z(TheARM64Target);
    585 }
    586