LCOV - code coverage report
Current view: top level - lib/Target/AArch64/MCTargetDesc - AArch64AsmBackend.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 188 214 87.9 %
Date: 2017-09-14 15:23:50 Functions: 17 23 73.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- AArch64AsmBackend.cpp - AArch64 Assembler Backend -----------------===//
       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             : #include "AArch64.h"
      11             : #include "AArch64RegisterInfo.h"
      12             : #include "MCTargetDesc/AArch64FixupKinds.h"
      13             : #include "llvm/ADT/Triple.h"
      14             : #include "llvm/BinaryFormat/MachO.h"
      15             : #include "llvm/MC/MCAsmBackend.h"
      16             : #include "llvm/MC/MCAssembler.h"
      17             : #include "llvm/MC/MCContext.h"
      18             : #include "llvm/MC/MCDirectives.h"
      19             : #include "llvm/MC/MCELFObjectWriter.h"
      20             : #include "llvm/MC/MCFixupKindInfo.h"
      21             : #include "llvm/MC/MCObjectWriter.h"
      22             : #include "llvm/MC/MCSectionELF.h"
      23             : #include "llvm/MC/MCSectionMachO.h"
      24             : #include "llvm/MC/MCValue.h"
      25             : #include "llvm/Support/ErrorHandling.h"
      26             : using namespace llvm;
      27             : 
      28             : namespace {
      29             : 
      30        2532 : class AArch64AsmBackend : public MCAsmBackend {
      31             :   static const unsigned PCRelFlagVal =
      32             :       MCFixupKindInfo::FKF_IsAlignedDownTo32Bits | MCFixupKindInfo::FKF_IsPCRel;
      33             :   Triple TheTriple;
      34             : 
      35             : public:
      36             :   bool IsLittleEndian;
      37             : 
      38             : public:
      39             :   AArch64AsmBackend(const Target &T, const Triple &TT, bool IsLittleEndian)
      40        1275 :       : MCAsmBackend(), TheTriple(TT), IsLittleEndian(IsLittleEndian) {}
      41             : 
      42           0 :   unsigned getNumFixupKinds() const override {
      43           0 :     return AArch64::NumTargetFixupKinds;
      44             :   }
      45             : 
      46        4623 :   const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
      47             :     const static MCFixupKindInfo Infos[AArch64::NumTargetFixupKinds] = {
      48             :         // This table *must* be in the order that the fixup_* kinds are defined
      49             :         // in AArch64FixupKinds.h.
      50             :         //
      51             :         // Name                           Offset (bits) Size (bits)     Flags
      52             :         {"fixup_aarch64_pcrel_adr_imm21", 0, 32, PCRelFlagVal},
      53             :         {"fixup_aarch64_pcrel_adrp_imm21", 0, 32, PCRelFlagVal},
      54             :         {"fixup_aarch64_add_imm12", 10, 12, 0},
      55             :         {"fixup_aarch64_ldst_imm12_scale1", 10, 12, 0},
      56             :         {"fixup_aarch64_ldst_imm12_scale2", 10, 12, 0},
      57             :         {"fixup_aarch64_ldst_imm12_scale4", 10, 12, 0},
      58             :         {"fixup_aarch64_ldst_imm12_scale8", 10, 12, 0},
      59             :         {"fixup_aarch64_ldst_imm12_scale16", 10, 12, 0},
      60             :         {"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal},
      61             :         {"fixup_aarch64_movw", 5, 16, 0},
      62             :         {"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal},
      63             :         {"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal},
      64             :         {"fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal},
      65             :         {"fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal},
      66             :         {"fixup_aarch64_tlsdesc_call", 0, 0, 0}};
      67             : 
      68        5011 :     if (Kind < FirstTargetFixupKind)
      69        1464 :       return MCAsmBackend::getFixupKindInfo(Kind);
      70             : 
      71             :     assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
      72             :            "Invalid kind!");
      73        3547 :     return Infos[Kind - FirstTargetFixupKind];
      74             :   }
      75             : 
      76             :   void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
      77             :                   const MCValue &Target, MutableArrayRef<char> Data,
      78             :                   uint64_t Value, bool IsResolved) const override;
      79             : 
      80             :   bool mayNeedRelaxation(const MCInst &Inst) const override;
      81             :   bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
      82             :                             const MCRelaxableFragment *DF,
      83             :                             const MCAsmLayout &Layout) const override;
      84             :   void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
      85             :                         MCInst &Res) const override;
      86             :   bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
      87             : 
      88             :   void HandleAssemblerFlag(MCAssemblerFlag Flag) {}
      89             : 
      90             :   unsigned getPointerSize() const { return 8; }
      91             : 
      92             :   unsigned getFixupKindContainereSizeInBytes(unsigned Kind) const;
      93             : 
      94             :   bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
      95             :                              const MCValue &Target) override;
      96             : };
      97             : 
      98             : } // end anonymous namespace
      99             : 
     100             : /// \brief The number of bytes the fixup may change.
     101        1393 : static unsigned getFixupKindNumBytes(unsigned Kind) {
     102        1393 :   switch (Kind) {
     103           0 :   default:
     104           0 :     llvm_unreachable("Unknown fixup kind!");
     105             : 
     106             :   case AArch64::fixup_aarch64_tlsdesc_call:
     107             :     return 0;
     108             : 
     109           3 :   case FK_Data_1:
     110           3 :     return 1;
     111             : 
     112         123 :   case AArch64::fixup_aarch64_movw:
     113             :   case FK_Data_2:
     114             :   case FK_SecRel_2:
     115         123 :     return 2;
     116             : 
     117         567 :   case AArch64::fixup_aarch64_pcrel_branch14:
     118             :   case AArch64::fixup_aarch64_add_imm12:
     119             :   case AArch64::fixup_aarch64_ldst_imm12_scale1:
     120             :   case AArch64::fixup_aarch64_ldst_imm12_scale2:
     121             :   case AArch64::fixup_aarch64_ldst_imm12_scale4:
     122             :   case AArch64::fixup_aarch64_ldst_imm12_scale8:
     123             :   case AArch64::fixup_aarch64_ldst_imm12_scale16:
     124             :   case AArch64::fixup_aarch64_ldr_pcrel_imm19:
     125             :   case AArch64::fixup_aarch64_pcrel_branch19:
     126         567 :     return 3;
     127             : 
     128         532 :   case AArch64::fixup_aarch64_pcrel_adr_imm21:
     129             :   case AArch64::fixup_aarch64_pcrel_adrp_imm21:
     130             :   case AArch64::fixup_aarch64_pcrel_branch26:
     131             :   case AArch64::fixup_aarch64_pcrel_call26:
     132             :   case FK_Data_4:
     133             :   case FK_SecRel_4:
     134         532 :     return 4;
     135             : 
     136         149 :   case FK_Data_8:
     137         149 :     return 8;
     138             :   }
     139             : }
     140             : 
     141             : static unsigned AdrImmBits(unsigned Value) {
     142           6 :   unsigned lo2 = Value & 0x3;
     143           6 :   unsigned hi19 = (Value & 0x1ffffc) >> 2;
     144           6 :   return (hi19 << 5) | (lo2 << 29);
     145             : }
     146             : 
     147         388 : static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
     148             :                                  MCContext &Ctx, const Triple &TheTriple,
     149             :                                  bool IsResolved) {
     150         388 :   unsigned Kind = Fixup.getKind();
     151         388 :   int64_t SignedValue = static_cast<int64_t>(Value);
     152         388 :   switch (Kind) {
     153           0 :   default:
     154           0 :     llvm_unreachable("Unknown fixup kind!");
     155           5 :   case AArch64::fixup_aarch64_pcrel_adr_imm21:
     156           5 :     if (SignedValue > 2097151 || SignedValue < -2097152)
     157           2 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     158          10 :     return AdrImmBits(Value & 0x1fffffULL);
     159           1 :   case AArch64::fixup_aarch64_pcrel_adrp_imm21:
     160             :     assert(!IsResolved);
     161           1 :     if (TheTriple.isOSBinFormatCOFF())
     162           2 :       return AdrImmBits(Value & 0x1fffffULL);
     163           0 :     return AdrImmBits((Value & 0x1fffff000ULL) >> 12);
     164          28 :   case AArch64::fixup_aarch64_ldr_pcrel_imm19:
     165             :   case AArch64::fixup_aarch64_pcrel_branch19:
     166             :     // Signed 21-bit immediate
     167          28 :     if (SignedValue > 2097151 || SignedValue < -2097152)
     168           5 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     169          28 :     if (Value & 0x3)
     170           4 :       Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
     171             :     // Low two bits are not encoded.
     172          28 :     return (Value >> 2) & 0x7ffff;
     173          96 :   case AArch64::fixup_aarch64_add_imm12:
     174             :   case AArch64::fixup_aarch64_ldst_imm12_scale1:
     175          96 :     if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
     176           2 :       Value &= 0xfff;
     177             :     // Unsigned 12-bit immediate
     178          96 :     if (Value >= 0x1000)
     179          20 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     180             :     return Value;
     181           4 :   case AArch64::fixup_aarch64_ldst_imm12_scale2:
     182           4 :     if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
     183           0 :       Value &= 0xfff;
     184             :     // Unsigned 12-bit immediate which gets multiplied by 2
     185           4 :     if (Value >= 0x2000)
     186           2 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     187           4 :     if (Value & 0x1)
     188           2 :       Ctx.reportError(Fixup.getLoc(), "fixup must be 2-byte aligned");
     189           4 :     return Value >> 1;
     190           4 :   case AArch64::fixup_aarch64_ldst_imm12_scale4:
     191           4 :     if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
     192           0 :       Value &= 0xfff;
     193             :     // Unsigned 12-bit immediate which gets multiplied by 4
     194           4 :     if (Value >= 0x4000)
     195           2 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     196           4 :     if (Value & 0x3)
     197           2 :       Ctx.reportError(Fixup.getLoc(), "fixup must be 4-byte aligned");
     198           4 :     return Value >> 2;
     199           5 :   case AArch64::fixup_aarch64_ldst_imm12_scale8:
     200           5 :     if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
     201           1 :       Value &= 0xfff;
     202             :     // Unsigned 12-bit immediate which gets multiplied by 8
     203           5 :     if (Value >= 0x8000)
     204           2 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     205           5 :     if (Value & 0x7)
     206           4 :       Ctx.reportError(Fixup.getLoc(), "fixup must be 8-byte aligned");
     207           5 :     return Value >> 3;
     208           4 :   case AArch64::fixup_aarch64_ldst_imm12_scale16:
     209           4 :     if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
     210           0 :       Value &= 0xfff;
     211             :     // Unsigned 12-bit immediate which gets multiplied by 16
     212           4 :     if (Value >= 0x10000)
     213           2 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     214           4 :     if (Value & 0xf)
     215           2 :       Ctx.reportError(Fixup.getLoc(), "fixup must be 16-byte aligned");
     216           4 :     return Value >> 4;
     217           0 :   case AArch64::fixup_aarch64_movw:
     218           0 :     Ctx.reportError(Fixup.getLoc(),
     219             :                     "no resolvable MOVZ/MOVK fixups supported yet");
     220           0 :     return Value;
     221           4 :   case AArch64::fixup_aarch64_pcrel_branch14:
     222             :     // Signed 16-bit immediate
     223           4 :     if (SignedValue > 32767 || SignedValue < -32768)
     224           2 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     225             :     // Low two bits are not encoded (4-byte alignment assumed).
     226           4 :     if (Value & 0x3)
     227           2 :       Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
     228           4 :     return (Value >> 2) & 0x3fff;
     229          10 :   case AArch64::fixup_aarch64_pcrel_branch26:
     230             :   case AArch64::fixup_aarch64_pcrel_call26:
     231             :     // Signed 28-bit immediate
     232          10 :     if (SignedValue > 134217727 || SignedValue < -134217728)
     233           2 :       Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
     234             :     // Low two bits are not encoded (4-byte alignment assumed).
     235          10 :     if (Value & 0x3)
     236           2 :       Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
     237          10 :     return (Value >> 2) & 0x3ffffff;
     238             :   case FK_Data_1:
     239             :   case FK_Data_2:
     240             :   case FK_Data_4:
     241             :   case FK_Data_8:
     242             :   case FK_SecRel_2:
     243             :   case FK_SecRel_4:
     244             :     return Value;
     245             :   }
     246             : }
     247             : 
     248             : /// getFixupKindContainereSizeInBytes - The number of bytes of the
     249             : /// container involved in big endian or 0 if the item is little endian
     250             : unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) const {
     251         388 :   if (IsLittleEndian)
     252             :     return 0;
     253             : 
     254          16 :   switch (Kind) {
     255           0 :   default:
     256           0 :     llvm_unreachable("Unknown fixup kind!");
     257             : 
     258             :   case FK_Data_1:
     259             :     return 1;
     260             :   case FK_Data_2:
     261             :     return 2;
     262             :   case FK_Data_4:
     263             :     return 4;
     264             :   case FK_Data_8:
     265             :     return 8;
     266             : 
     267             :   case AArch64::fixup_aarch64_tlsdesc_call:
     268             :   case AArch64::fixup_aarch64_movw:
     269             :   case AArch64::fixup_aarch64_pcrel_branch14:
     270             :   case AArch64::fixup_aarch64_add_imm12:
     271             :   case AArch64::fixup_aarch64_ldst_imm12_scale1:
     272             :   case AArch64::fixup_aarch64_ldst_imm12_scale2:
     273             :   case AArch64::fixup_aarch64_ldst_imm12_scale4:
     274             :   case AArch64::fixup_aarch64_ldst_imm12_scale8:
     275             :   case AArch64::fixup_aarch64_ldst_imm12_scale16:
     276             :   case AArch64::fixup_aarch64_ldr_pcrel_imm19:
     277             :   case AArch64::fixup_aarch64_pcrel_branch19:
     278             :   case AArch64::fixup_aarch64_pcrel_adr_imm21:
     279             :   case AArch64::fixup_aarch64_pcrel_adrp_imm21:
     280             :   case AArch64::fixup_aarch64_pcrel_branch26:
     281             :   case AArch64::fixup_aarch64_pcrel_call26:
     282             :     // Instructions are always little endian
     283             :     return 0;
     284             :   }
     285             : }
     286             : 
     287        1393 : void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
     288             :                                    const MCValue &Target,
     289             :                                    MutableArrayRef<char> Data, uint64_t Value,
     290             :                                    bool IsResolved) const {
     291        1393 :   unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
     292        1393 :   if (!Value)
     293             :     return; // Doesn't change encoding.
     294         776 :   MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
     295         388 :   MCContext &Ctx = Asm.getContext();
     296             :   // Apply any target-specific value adjustments.
     297         388 :   Value = adjustFixupValue(Fixup, Value, Ctx, TheTriple, IsResolved);
     298             : 
     299             :   // Shift the value into position.
     300         388 :   Value <<= Info.TargetOffset;
     301             : 
     302         388 :   unsigned Offset = Fixup.getOffset();
     303             :   assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
     304             : 
     305             :   // Used to point to big endian bytes.
     306         403 :   unsigned FulleSizeInBytes = getFixupKindContainereSizeInBytes(Fixup.getKind());
     307             : 
     308             :   // For each byte of the fragment that the fixup touches, mask in the
     309             :   // bits from the fixup value.
     310             :   if (FulleSizeInBytes == 0) {
     311             :     // Handle as little-endian
     312        3467 :     for (unsigned i = 0; i != NumBytes; ++i) {
     313        3094 :       Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
     314             :     }
     315             :   } else {
     316             :     // Handle as big-endian
     317             :     assert((Offset + FulleSizeInBytes) <= Data.size() && "Invalid fixup size!");
     318             :     assert(NumBytes <= FulleSizeInBytes && "Invalid fixup size!");
     319         135 :     for (unsigned i = 0; i != NumBytes; ++i) {
     320          60 :       unsigned Idx = FulleSizeInBytes - 1 - i;
     321         120 :       Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
     322             :     }
     323             :   }
     324             : }
     325             : 
     326        1607 : bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
     327        1607 :   return false;
     328             : }
     329             : 
     330           0 : bool AArch64AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
     331             :                                              uint64_t Value,
     332             :                                              const MCRelaxableFragment *DF,
     333             :                                              const MCAsmLayout &Layout) const {
     334             :   // FIXME:  This isn't correct for AArch64. Just moving the "generic" logic
     335             :   // into the targets for now.
     336             :   //
     337             :   // Relax if the value is too big for a (signed) i8.
     338           0 :   return int64_t(Value) != int64_t(int8_t(Value));
     339             : }
     340             : 
     341           0 : void AArch64AsmBackend::relaxInstruction(const MCInst &Inst,
     342             :                                          const MCSubtargetInfo &STI,
     343             :                                          MCInst &Res) const {
     344           0 :   llvm_unreachable("AArch64AsmBackend::relaxInstruction() unimplemented");
     345             : }
     346             : 
     347         237 : bool AArch64AsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
     348             :   // If the count is not 4-byte aligned, we must be writing data into the text
     349             :   // section (otherwise we have unaligned instructions, and thus have far
     350             :   // bigger problems), so just write zeros instead.
     351         237 :   OW->WriteZeros(Count % 4);
     352             : 
     353             :   // We are properly aligned, so write NOPs as requested.
     354         237 :   Count /= 4;
     355         256 :   for (uint64_t i = 0; i != Count; ++i)
     356          19 :     OW->write32(0xd503201f);
     357         237 :   return true;
     358             : }
     359             : 
     360         352 : bool AArch64AsmBackend::shouldForceRelocation(const MCAssembler &Asm,
     361             :                                               const MCFixup &Fixup,
     362             :                                               const MCValue &Target) {
     363             :   // The ADRP instruction adds some multiple of 0x1000 to the current PC &
     364             :   // ~0xfff. This means that the required offset to reach a symbol can vary by
     365             :   // up to one step depending on where the ADRP is in memory. For example:
     366             :   //
     367             :   //     ADRP x0, there
     368             :   //  there:
     369             :   //
     370             :   // If the ADRP occurs at address 0xffc then "there" will be at 0x1000 and
     371             :   // we'll need that as an offset. At any other address "there" will be in the
     372             :   // same page as the ADRP and the instruction should encode 0x0. Assuming the
     373             :   // section isn't 0x1000-aligned, we therefore need to delegate this decision
     374             :   // to the linker -- a relocation!
     375         352 :   if ((uint32_t)Fixup.getKind() == AArch64::fixup_aarch64_pcrel_adrp_imm21)
     376             :     return true;
     377         334 :   return false;
     378             : }
     379             : 
     380             : namespace {
     381             : 
     382             : namespace CU {
     383             : 
     384             : /// \brief Compact unwind encoding values.
     385             : enum CompactUnwindEncodings {
     386             :   /// \brief A "frameless" leaf function, where no non-volatile registers are
     387             :   /// saved. The return remains in LR throughout the function.
     388             :   UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
     389             : 
     390             :   /// \brief No compact unwind encoding available. Instead the low 23-bits of
     391             :   /// the compact unwind encoding is the offset of the DWARF FDE in the
     392             :   /// __eh_frame section. This mode is never used in object files. It is only
     393             :   /// generated by the linker in final linked images, which have only DWARF info
     394             :   /// for a function.
     395             :   UNWIND_ARM64_MODE_DWARF = 0x03000000,
     396             : 
     397             :   /// \brief This is a standard arm64 prologue where FP/LR are immediately
     398             :   /// pushed on the stack, then SP is copied to FP. If there are any
     399             :   /// non-volatile register saved, they are copied into the stack fame in pairs
     400             :   /// in a contiguous ranger right below the saved FP/LR pair. Any subset of the
     401             :   /// five X pairs and four D pairs can be saved, but the memory layout must be
     402             :   /// in register number order.
     403             :   UNWIND_ARM64_MODE_FRAME = 0x04000000,
     404             : 
     405             :   /// \brief Frame register pair encodings.
     406             :   UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
     407             :   UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
     408             :   UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
     409             :   UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
     410             :   UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
     411             :   UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
     412             :   UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
     413             :   UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
     414             :   UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800
     415             : };
     416             : 
     417             : } // end CU namespace
     418             : 
     419             : // FIXME: This should be in a separate file.
     420         328 : class DarwinAArch64AsmBackend : public AArch64AsmBackend {
     421             :   const MCRegisterInfo &MRI;
     422             : 
     423             :   /// \brief Encode compact unwind stack adjustment for frameless functions.
     424             :   /// See UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK in compact_unwind_encoding.h.
     425             :   /// The stack size always needs to be 16 byte aligned.
     426             :   uint32_t encodeStackAdjustment(uint32_t StackSize) const {
     427           3 :     return (StackSize / 16) << 12;
     428             :   }
     429             : 
     430             : public:
     431             :   DarwinAArch64AsmBackend(const Target &T, const Triple &TT,
     432             :                           const MCRegisterInfo &MRI)
     433         664 :       : AArch64AsmBackend(T, TT, /*IsLittleEndian*/ true), MRI(MRI) {}
     434             : 
     435          28 :   MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
     436             :     return createAArch64MachObjectWriter(OS, MachO::CPU_TYPE_ARM64,
     437          28 :                                          MachO::CPU_SUBTYPE_ARM64_ALL);
     438             :   }
     439             : 
     440             :   /// \brief Generate the compact unwind encoding from the CFI directives.
     441          16 :   uint32_t generateCompactUnwindEncoding(
     442             :                              ArrayRef<MCCFIInstruction> Instrs) const override {
     443          16 :     if (Instrs.empty())
     444             :       return CU::UNWIND_ARM64_MODE_FRAMELESS;
     445             : 
     446             :     bool HasFP = false;
     447             :     unsigned StackSize = 0;
     448             : 
     449             :     uint32_t CompactUnwindEncoding = 0;
     450          50 :     for (size_t i = 0, e = Instrs.size(); i != e; ++i) {
     451          42 :       const MCCFIInstruction &Inst = Instrs[i];
     452             : 
     453          21 :       switch (Inst.getOperation()) {
     454             :       default:
     455             :         // Cannot handle this directive:  bail out.
     456             :         return CU::UNWIND_ARM64_MODE_DWARF;
     457           7 :       case MCCFIInstruction::OpDefCfa: {
     458             :         // Defines a frame pointer.
     459             :         assert(getXRegFromWReg(MRI.getLLVMRegNum(Inst.getRegister(), true)) ==
     460             :                    AArch64::FP &&
     461             :                "Invalid frame pointer!");
     462             :         assert(i + 2 < e && "Insufficient CFI instructions to define a frame!");
     463             : 
     464          14 :         const MCCFIInstruction &LRPush = Instrs[++i];
     465             :         assert(LRPush.getOperation() == MCCFIInstruction::OpOffset &&
     466             :                "Link register not pushed!");
     467          14 :         const MCCFIInstruction &FPPush = Instrs[++i];
     468             :         assert(FPPush.getOperation() == MCCFIInstruction::OpOffset &&
     469             :                "Frame pointer not pushed!");
     470             : 
     471           7 :         unsigned LRReg = MRI.getLLVMRegNum(LRPush.getRegister(), true);
     472           7 :         unsigned FPReg = MRI.getLLVMRegNum(FPPush.getRegister(), true);
     473             : 
     474           7 :         LRReg = getXRegFromWReg(LRReg);
     475           7 :         FPReg = getXRegFromWReg(FPReg);
     476             : 
     477             :         assert(LRReg == AArch64::LR && FPReg == AArch64::FP &&
     478             :                "Pushing invalid registers for frame!");
     479             : 
     480             :         // Indicate that the function has a frame.
     481           7 :         CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAME;
     482           7 :         HasFP = true;
     483           7 :         break;
     484             :       }
     485           5 :       case MCCFIInstruction::OpDefCfaOffset: {
     486             :         assert(StackSize == 0 && "We already have the CFA offset!");
     487           5 :         StackSize = std::abs(Inst.getOffset());
     488           5 :         break;
     489             :       }
     490           9 :       case MCCFIInstruction::OpOffset: {
     491             :         // Registers are saved in pairs. We expect there to be two consecutive
     492             :         // `.cfi_offset' instructions with the appropriate registers specified.
     493           9 :         unsigned Reg1 = MRI.getLLVMRegNum(Inst.getRegister(), true);
     494           9 :         if (i + 1 == e)
     495             :           return CU::UNWIND_ARM64_MODE_DWARF;
     496             : 
     497          18 :         const MCCFIInstruction &Inst2 = Instrs[++i];
     498           9 :         if (Inst2.getOperation() != MCCFIInstruction::OpOffset)
     499             :           return CU::UNWIND_ARM64_MODE_DWARF;
     500           9 :         unsigned Reg2 = MRI.getLLVMRegNum(Inst2.getRegister(), true);
     501             : 
     502             :         // N.B. The encodings must be in register number order, and the X
     503             :         // registers before the D registers.
     504             : 
     505             :         // X19/X20 pair = 0x00000001,
     506             :         // X21/X22 pair = 0x00000002,
     507             :         // X23/X24 pair = 0x00000004,
     508             :         // X25/X26 pair = 0x00000008,
     509             :         // X27/X28 pair = 0x00000010
     510           9 :         Reg1 = getXRegFromWReg(Reg1);
     511           9 :         Reg2 = getXRegFromWReg(Reg2);
     512             : 
     513          11 :         if (Reg1 == AArch64::X19 && Reg2 == AArch64::X20 &&
     514           2 :             (CompactUnwindEncoding & 0xF1E) == 0)
     515           2 :           CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X19_X20_PAIR;
     516           8 :         else if (Reg1 == AArch64::X21 && Reg2 == AArch64::X22 &&
     517           1 :                  (CompactUnwindEncoding & 0xF1C) == 0)
     518           1 :           CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X21_X22_PAIR;
     519           7 :         else if (Reg1 == AArch64::X23 && Reg2 == AArch64::X24 &&
     520           1 :                  (CompactUnwindEncoding & 0xF18) == 0)
     521           1 :           CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X23_X24_PAIR;
     522           6 :         else if (Reg1 == AArch64::X25 && Reg2 == AArch64::X26 &&
     523           1 :                  (CompactUnwindEncoding & 0xF10) == 0)
     524           1 :           CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X25_X26_PAIR;
     525           6 :         else if (Reg1 == AArch64::X27 && Reg2 == AArch64::X28 &&
     526           2 :                  (CompactUnwindEncoding & 0xF00) == 0)
     527           2 :           CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X27_X28_PAIR;
     528             :         else {
     529           2 :           Reg1 = getDRegFromBReg(Reg1);
     530           2 :           Reg2 = getDRegFromBReg(Reg2);
     531             : 
     532             :           // D8/D9 pair   = 0x00000100,
     533             :           // D10/D11 pair = 0x00000200,
     534             :           // D12/D13 pair = 0x00000400,
     535             :           // D14/D15 pair = 0x00000800
     536           2 :           if (Reg1 == AArch64::D8 && Reg2 == AArch64::D9 &&
     537           0 :               (CompactUnwindEncoding & 0xE00) == 0)
     538           0 :             CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D8_D9_PAIR;
     539           2 :           else if (Reg1 == AArch64::D10 && Reg2 == AArch64::D11 &&
     540           0 :                    (CompactUnwindEncoding & 0xC00) == 0)
     541           0 :             CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D10_D11_PAIR;
     542           2 :           else if (Reg1 == AArch64::D12 && Reg2 == AArch64::D13 &&
     543           0 :                    (CompactUnwindEncoding & 0x800) == 0)
     544           0 :             CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D12_D13_PAIR;
     545           2 :           else if (Reg1 == AArch64::D14 && Reg2 == AArch64::D15)
     546           0 :             CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D14_D15_PAIR;
     547             :           else
     548             :             // A pair was pushed which we cannot handle.
     549             :             return CU::UNWIND_ARM64_MODE_DWARF;
     550             :         }
     551             : 
     552             :         break;
     553             :       }
     554             :       }
     555             :     }
     556             : 
     557          10 :     if (!HasFP) {
     558             :       // With compact unwind info we can only represent stack adjustments of up
     559             :       // to 65520 bytes.
     560           3 :       if (StackSize > 65520)
     561             :         return CU::UNWIND_ARM64_MODE_DWARF;
     562             : 
     563           3 :       CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAMELESS;
     564           6 :       CompactUnwindEncoding |= encodeStackAdjustment(StackSize);
     565             :     }
     566             : 
     567             :     return CompactUnwindEncoding;
     568             :   }
     569             : };
     570             : 
     571             : } // end anonymous namespace
     572             : 
     573             : namespace {
     574             : 
     575         928 : class ELFAArch64AsmBackend : public AArch64AsmBackend {
     576             : public:
     577             :   uint8_t OSABI;
     578             :   bool IsILP32;
     579             : 
     580             :   ELFAArch64AsmBackend(const Target &T, const Triple &TT, uint8_t OSABI,
     581             :                        bool IsLittleEndian, bool IsILP32)
     582         933 :       : AArch64AsmBackend(T, TT, IsLittleEndian), OSABI(OSABI),
     583        1866 :         IsILP32(IsILP32) {}
     584             : 
     585         156 :   MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
     586         156 :     return createAArch64ELFObjectWriter(OS, OSABI, IsLittleEndian, IsILP32);
     587             :   }
     588             : };
     589             : 
     590             : }
     591             : 
     592             : namespace {
     593          10 : class COFFAArch64AsmBackend : public AArch64AsmBackend {
     594             : public:
     595             :   COFFAArch64AsmBackend(const Target &T, const Triple &TheTriple)
     596          20 :       : AArch64AsmBackend(T, TheTriple, /*IsLittleEndian*/ true) {}
     597             : 
     598           5 :   MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
     599           5 :     return createAArch64WinCOFFObjectWriter(OS);
     600             :   }
     601             : };
     602             : }
     603             : 
     604        1249 : MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
     605             :                                               const MCRegisterInfo &MRI,
     606             :                                               const Triple &TheTriple,
     607             :                                               StringRef CPU,
     608             :                                               const MCTargetOptions &Options) {
     609        1249 :   if (TheTriple.isOSBinFormatMachO())
     610         664 :     return new DarwinAArch64AsmBackend(T, TheTriple, MRI);
     611             : 
     612         917 :   if (TheTriple.isOSBinFormatCOFF())
     613          20 :     return new COFFAArch64AsmBackend(T, TheTriple);
     614             : 
     615             :   assert(TheTriple.isOSBinFormatELF() && "Invalid target");
     616             : 
     617        1814 :   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
     618        1814 :   bool IsILP32 = Options.getABIName() == "ilp32";
     619             :   return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/true,
     620        1814 :                                   IsILP32);
     621             : }
     622             : 
     623          26 : MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
     624             :                                               const MCRegisterInfo &MRI,
     625             :                                               const Triple &TheTriple,
     626             :                                               StringRef CPU,
     627             :                                               const MCTargetOptions &Options) {
     628             :   assert(TheTriple.isOSBinFormatELF() &&
     629             :          "Big endian is only supported for ELF targets!");
     630          52 :   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
     631          52 :   bool IsILP32 = Options.getABIName() == "ilp32";
     632             :   return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/false,
     633          52 :                                   IsILP32);
     634             : }

Generated by: LCOV version 1.13