LCOV - code coverage report
Current view: top level - lib/Target/AArch64 - AArch64AsmPrinter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 292 327 89.3 %
Date: 2017-09-14 15:23:50 Functions: 21 22 95.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13