10b57cec5SDimitry Andric //===-- AArch64AsmBackend.cpp - AArch64 Assembler Backend -----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "MCTargetDesc/AArch64FixupKinds.h"
100b57cec5SDimitry Andric #include "MCTargetDesc/AArch64MCExpr.h"
110b57cec5SDimitry Andric #include "MCTargetDesc/AArch64MCTargetDesc.h"
120b57cec5SDimitry Andric #include "Utils/AArch64BaseInfo.h"
130b57cec5SDimitry Andric #include "llvm/BinaryFormat/MachO.h"
140b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
150b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCDirectives.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCSectionMachO.h"
2481ad6265SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCTargetOptions.h"
260b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
27349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
280b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2906c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h"
3006c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
310b57cec5SDimitry Andric using namespace llvm;
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric namespace {
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric class AArch64AsmBackend : public MCAsmBackend {
360b57cec5SDimitry Andric static const unsigned PCRelFlagVal =
370b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits | MCFixupKindInfo::FKF_IsPCRel;
385ffd83dbSDimitry Andric protected:
390b57cec5SDimitry Andric Triple TheTriple;
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric public:
AArch64AsmBackend(const Target & T,const Triple & TT,bool IsLittleEndian)420b57cec5SDimitry Andric AArch64AsmBackend(const Target &T, const Triple &TT, bool IsLittleEndian)
435f757f3fSDimitry Andric : MCAsmBackend(IsLittleEndian ? llvm::endianness::little
445f757f3fSDimitry Andric : llvm::endianness::big),
450b57cec5SDimitry Andric TheTriple(TT) {}
460b57cec5SDimitry Andric
getNumFixupKinds() const470b57cec5SDimitry Andric unsigned getNumFixupKinds() const override {
480b57cec5SDimitry Andric return AArch64::NumTargetFixupKinds;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
51bdd1243dSDimitry Andric std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
520b57cec5SDimitry Andric
getFixupKindInfo(MCFixupKind Kind) const530b57cec5SDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
540b57cec5SDimitry Andric const static MCFixupKindInfo Infos[AArch64::NumTargetFixupKinds] = {
550b57cec5SDimitry Andric // This table *must* be in the order that the fixup_* kinds are defined
560b57cec5SDimitry Andric // in AArch64FixupKinds.h.
570b57cec5SDimitry Andric //
580b57cec5SDimitry Andric // Name Offset (bits) Size (bits) Flags
590b57cec5SDimitry Andric {"fixup_aarch64_pcrel_adr_imm21", 0, 32, PCRelFlagVal},
600b57cec5SDimitry Andric {"fixup_aarch64_pcrel_adrp_imm21", 0, 32, PCRelFlagVal},
610b57cec5SDimitry Andric {"fixup_aarch64_add_imm12", 10, 12, 0},
620b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale1", 10, 12, 0},
630b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale2", 10, 12, 0},
640b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale4", 10, 12, 0},
650b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale8", 10, 12, 0},
660b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale16", 10, 12, 0},
670b57cec5SDimitry Andric {"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal},
680b57cec5SDimitry Andric {"fixup_aarch64_movw", 5, 16, 0},
690b57cec5SDimitry Andric {"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal},
70cb14a3feSDimitry Andric {"fixup_aarch64_pcrel_branch16", 5, 16, PCRelFlagVal},
710b57cec5SDimitry Andric {"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal},
720b57cec5SDimitry Andric {"fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal},
73fe6060f1SDimitry Andric {"fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal}};
740b57cec5SDimitry Andric
755ffd83dbSDimitry Andric // Fixup kinds from .reloc directive are like R_AARCH64_NONE. They do not
765ffd83dbSDimitry Andric // require any extra processing.
775ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind)
785ffd83dbSDimitry Andric return MCAsmBackend::getFixupKindInfo(FK_NONE);
795ffd83dbSDimitry Andric
800b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind)
810b57cec5SDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind);
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
840b57cec5SDimitry Andric "Invalid kind!");
850b57cec5SDimitry Andric return Infos[Kind - FirstTargetFixupKind];
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
890b57cec5SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data,
900b57cec5SDimitry Andric uint64_t Value, bool IsResolved,
910b57cec5SDimitry Andric const MCSubtargetInfo *STI) const override;
920b57cec5SDimitry Andric
930fca6ea1SDimitry Andric bool fixupNeedsRelaxation(const MCFixup &Fixup,
940fca6ea1SDimitry Andric uint64_t Value) const override;
955ffd83dbSDimitry Andric void relaxInstruction(MCInst &Inst,
965ffd83dbSDimitry Andric const MCSubtargetInfo &STI) const override;
97349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count,
98349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override;
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric unsigned getFixupKindContainereSizeInBytes(unsigned Kind) const;
1010b57cec5SDimitry Andric
1020b57cec5SDimitry Andric bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
1035f757f3fSDimitry Andric const MCValue &Target,
1045f757f3fSDimitry Andric const MCSubtargetInfo *STI) override;
1050b57cec5SDimitry Andric };
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric } // end anonymous namespace
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric /// The number of bytes the fixup may change.
getFixupKindNumBytes(unsigned Kind)1100b57cec5SDimitry Andric static unsigned getFixupKindNumBytes(unsigned Kind) {
1110b57cec5SDimitry Andric switch (Kind) {
1120b57cec5SDimitry Andric default:
1130b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!");
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric case FK_Data_1:
1160b57cec5SDimitry Andric return 1;
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric case FK_Data_2:
1190b57cec5SDimitry Andric case FK_SecRel_2:
1200b57cec5SDimitry Andric return 2;
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric case AArch64::fixup_aarch64_movw:
1230b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch14:
124cb14a3feSDimitry Andric case AArch64::fixup_aarch64_pcrel_branch16:
1250b57cec5SDimitry Andric case AArch64::fixup_aarch64_add_imm12:
1260b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale1:
1270b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale2:
1280b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale4:
1290b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale8:
1300b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale16:
1310b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldr_pcrel_imm19:
1320b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch19:
1330b57cec5SDimitry Andric return 3;
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adr_imm21:
1360b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adrp_imm21:
1370b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch26:
1380b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_call26:
1390b57cec5SDimitry Andric case FK_Data_4:
1400b57cec5SDimitry Andric case FK_SecRel_4:
1410b57cec5SDimitry Andric return 4;
1420b57cec5SDimitry Andric
1430b57cec5SDimitry Andric case FK_Data_8:
1440b57cec5SDimitry Andric return 8;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric
AdrImmBits(unsigned Value)1480b57cec5SDimitry Andric static unsigned AdrImmBits(unsigned Value) {
1490b57cec5SDimitry Andric unsigned lo2 = Value & 0x3;
1500b57cec5SDimitry Andric unsigned hi19 = (Value & 0x1ffffc) >> 2;
1510b57cec5SDimitry Andric return (hi19 << 5) | (lo2 << 29);
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
adjustFixupValue(const MCFixup & Fixup,const MCValue & Target,uint64_t Value,MCContext & Ctx,const Triple & TheTriple,bool IsResolved)1540b57cec5SDimitry Andric static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target,
1550b57cec5SDimitry Andric uint64_t Value, MCContext &Ctx,
1560b57cec5SDimitry Andric const Triple &TheTriple, bool IsResolved) {
1570b57cec5SDimitry Andric int64_t SignedValue = static_cast<int64_t>(Value);
1588bcb0991SDimitry Andric switch (Fixup.getTargetKind()) {
1590b57cec5SDimitry Andric default:
1600b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!");
1610b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adr_imm21:
16206c3fb27SDimitry Andric if (!isInt<21>(SignedValue))
1630b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
1640b57cec5SDimitry Andric return AdrImmBits(Value & 0x1fffffULL);
1650b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adrp_imm21:
1660b57cec5SDimitry Andric assert(!IsResolved);
167349cc55cSDimitry Andric if (TheTriple.isOSBinFormatCOFF()) {
168349cc55cSDimitry Andric if (!isInt<21>(SignedValue))
169349cc55cSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
1700b57cec5SDimitry Andric return AdrImmBits(Value & 0x1fffffULL);
171349cc55cSDimitry Andric }
1720b57cec5SDimitry Andric return AdrImmBits((Value & 0x1fffff000ULL) >> 12);
1730b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldr_pcrel_imm19:
1740b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch19:
17506c3fb27SDimitry Andric // Signed 19-bit immediate which gets multiplied by 4
17606c3fb27SDimitry Andric if (!isInt<21>(SignedValue))
1770b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
1780b57cec5SDimitry Andric if (Value & 0x3)
1790b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
1800b57cec5SDimitry Andric // Low two bits are not encoded.
1810b57cec5SDimitry Andric return (Value >> 2) & 0x7ffff;
1820b57cec5SDimitry Andric case AArch64::fixup_aarch64_add_imm12:
1830b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale1:
1840b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
1850b57cec5SDimitry Andric Value &= 0xfff;
1860b57cec5SDimitry Andric // Unsigned 12-bit immediate
1875f757f3fSDimitry Andric if (!isUInt<12>(Value))
1880b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
1890b57cec5SDimitry Andric return Value;
1900b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale2:
1910b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
1920b57cec5SDimitry Andric Value &= 0xfff;
1930b57cec5SDimitry Andric // Unsigned 12-bit immediate which gets multiplied by 2
1945f757f3fSDimitry Andric if (!isUInt<13>(Value))
1950b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
1960b57cec5SDimitry Andric if (Value & 0x1)
1970b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup must be 2-byte aligned");
1980b57cec5SDimitry Andric return Value >> 1;
1990b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale4:
2000b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
2010b57cec5SDimitry Andric Value &= 0xfff;
2020b57cec5SDimitry Andric // Unsigned 12-bit immediate which gets multiplied by 4
2035f757f3fSDimitry Andric if (!isUInt<14>(Value))
2040b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
2050b57cec5SDimitry Andric if (Value & 0x3)
2060b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup must be 4-byte aligned");
2070b57cec5SDimitry Andric return Value >> 2;
2080b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale8:
2090b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
2100b57cec5SDimitry Andric Value &= 0xfff;
2110b57cec5SDimitry Andric // Unsigned 12-bit immediate which gets multiplied by 8
2125f757f3fSDimitry Andric if (!isUInt<15>(Value))
2130b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
2140b57cec5SDimitry Andric if (Value & 0x7)
2150b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup must be 8-byte aligned");
2160b57cec5SDimitry Andric return Value >> 3;
2170b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale16:
2180b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
2190b57cec5SDimitry Andric Value &= 0xfff;
2200b57cec5SDimitry Andric // Unsigned 12-bit immediate which gets multiplied by 16
2215f757f3fSDimitry Andric if (!isUInt<16>(Value))
2220b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
2230b57cec5SDimitry Andric if (Value & 0xf)
2240b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup must be 16-byte aligned");
2250b57cec5SDimitry Andric return Value >> 4;
2260b57cec5SDimitry Andric case AArch64::fixup_aarch64_movw: {
2270b57cec5SDimitry Andric AArch64MCExpr::VariantKind RefKind =
2280b57cec5SDimitry Andric static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind());
2290b57cec5SDimitry Andric if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS &&
2300b57cec5SDimitry Andric AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) {
2315ffd83dbSDimitry Andric if (!RefKind) {
2325ffd83dbSDimitry Andric // The fixup is an expression
2335ffd83dbSDimitry Andric if (SignedValue > 0xFFFF || SignedValue < -0xFFFF)
2345ffd83dbSDimitry Andric Ctx.reportError(Fixup.getLoc(),
2355ffd83dbSDimitry Andric "fixup value out of range [-0xFFFF, 0xFFFF]");
2365ffd83dbSDimitry Andric
2375ffd83dbSDimitry Andric // Invert the negative immediate because it will feed into a MOVN.
2385ffd83dbSDimitry Andric if (SignedValue < 0)
2395ffd83dbSDimitry Andric SignedValue = ~SignedValue;
2405ffd83dbSDimitry Andric Value = static_cast<uint64_t>(SignedValue);
2415ffd83dbSDimitry Andric } else
2420b57cec5SDimitry Andric // VK_GOTTPREL, VK_TPREL, VK_DTPREL are movw fixups, but they can't
2430b57cec5SDimitry Andric // ever be resolved in the assembler.
2440b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(),
2450b57cec5SDimitry Andric "relocation for a thread-local variable points to an "
2460b57cec5SDimitry Andric "absolute symbol");
2470b57cec5SDimitry Andric return Value;
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric
2500b57cec5SDimitry Andric if (!IsResolved) {
2510b57cec5SDimitry Andric // FIXME: Figure out when this can actually happen, and verify our
2520b57cec5SDimitry Andric // behavior.
2530b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "unresolved movw fixup not yet "
2540b57cec5SDimitry Andric "implemented");
2550b57cec5SDimitry Andric return Value;
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric
2580b57cec5SDimitry Andric if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS) {
2590b57cec5SDimitry Andric switch (AArch64MCExpr::getAddressFrag(RefKind)) {
2600b57cec5SDimitry Andric case AArch64MCExpr::VK_G0:
2610b57cec5SDimitry Andric break;
2620b57cec5SDimitry Andric case AArch64MCExpr::VK_G1:
2630b57cec5SDimitry Andric SignedValue = SignedValue >> 16;
2640b57cec5SDimitry Andric break;
2650b57cec5SDimitry Andric case AArch64MCExpr::VK_G2:
2660b57cec5SDimitry Andric SignedValue = SignedValue >> 32;
2670b57cec5SDimitry Andric break;
2680b57cec5SDimitry Andric case AArch64MCExpr::VK_G3:
2690b57cec5SDimitry Andric SignedValue = SignedValue >> 48;
2700b57cec5SDimitry Andric break;
2710b57cec5SDimitry Andric default:
2720b57cec5SDimitry Andric llvm_unreachable("Variant kind doesn't correspond to fixup");
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric
2750b57cec5SDimitry Andric } else {
2760b57cec5SDimitry Andric switch (AArch64MCExpr::getAddressFrag(RefKind)) {
2770b57cec5SDimitry Andric case AArch64MCExpr::VK_G0:
2780b57cec5SDimitry Andric break;
2790b57cec5SDimitry Andric case AArch64MCExpr::VK_G1:
2800b57cec5SDimitry Andric Value = Value >> 16;
2810b57cec5SDimitry Andric break;
2820b57cec5SDimitry Andric case AArch64MCExpr::VK_G2:
2830b57cec5SDimitry Andric Value = Value >> 32;
2840b57cec5SDimitry Andric break;
2850b57cec5SDimitry Andric case AArch64MCExpr::VK_G3:
2860b57cec5SDimitry Andric Value = Value >> 48;
2870b57cec5SDimitry Andric break;
2880b57cec5SDimitry Andric default:
2890b57cec5SDimitry Andric llvm_unreachable("Variant kind doesn't correspond to fixup");
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric }
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric if (RefKind & AArch64MCExpr::VK_NC) {
2940b57cec5SDimitry Andric Value &= 0xFFFF;
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric else if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS) {
2970b57cec5SDimitry Andric if (SignedValue > 0xFFFF || SignedValue < -0xFFFF)
2980b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
2990b57cec5SDimitry Andric
3000b57cec5SDimitry Andric // Invert the negative immediate because it will feed into a MOVN.
3010b57cec5SDimitry Andric if (SignedValue < 0)
3020b57cec5SDimitry Andric SignedValue = ~SignedValue;
3030b57cec5SDimitry Andric Value = static_cast<uint64_t>(SignedValue);
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric else if (Value > 0xFFFF) {
3060b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
3070b57cec5SDimitry Andric }
3080b57cec5SDimitry Andric return Value;
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch14:
3110b57cec5SDimitry Andric // Signed 16-bit immediate
3125f757f3fSDimitry Andric if (!isInt<16>(SignedValue))
3130b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
3140b57cec5SDimitry Andric // Low two bits are not encoded (4-byte alignment assumed).
3150b57cec5SDimitry Andric if (Value & 0x3)
3160b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
3170b57cec5SDimitry Andric return (Value >> 2) & 0x3fff;
318cb14a3feSDimitry Andric case AArch64::fixup_aarch64_pcrel_branch16:
319cb14a3feSDimitry Andric // Unsigned PC-relative offset, so invert the negative immediate.
320cb14a3feSDimitry Andric SignedValue = -SignedValue;
321cb14a3feSDimitry Andric Value = static_cast<uint64_t>(SignedValue);
322cb14a3feSDimitry Andric // Check valid 18-bit unsigned range.
323cb14a3feSDimitry Andric if (SignedValue < 0 || SignedValue > ((1 << 18) - 1))
324cb14a3feSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
325cb14a3feSDimitry Andric // Low two bits are not encoded (4-byte alignment assumed).
326cb14a3feSDimitry Andric if (Value & 0b11)
327cb14a3feSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
328cb14a3feSDimitry Andric return (Value >> 2) & 0xffff;
3290b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch26:
3300b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_call26:
3315f757f3fSDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved && SignedValue != 0) {
3325f757f3fSDimitry Andric // MSVC link.exe and lld do not support this relocation type
3335f757f3fSDimitry Andric // with a non-zero offset
3345f757f3fSDimitry Andric Ctx.reportError(Fixup.getLoc(),
3355f757f3fSDimitry Andric "cannot perform a PC-relative fixup with a non-zero "
3365f757f3fSDimitry Andric "symbol offset");
3375f757f3fSDimitry Andric }
3380b57cec5SDimitry Andric // Signed 28-bit immediate
3395f757f3fSDimitry Andric if (!isInt<28>(SignedValue))
3400b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
3410b57cec5SDimitry Andric // Low two bits are not encoded (4-byte alignment assumed).
3420b57cec5SDimitry Andric if (Value & 0x3)
3430b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
3440b57cec5SDimitry Andric return (Value >> 2) & 0x3ffffff;
3450b57cec5SDimitry Andric case FK_Data_1:
3460b57cec5SDimitry Andric case FK_Data_2:
3470b57cec5SDimitry Andric case FK_Data_4:
3480b57cec5SDimitry Andric case FK_Data_8:
3490b57cec5SDimitry Andric case FK_SecRel_2:
3500b57cec5SDimitry Andric case FK_SecRel_4:
3510b57cec5SDimitry Andric return Value;
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric }
3540b57cec5SDimitry Andric
355bdd1243dSDimitry Andric std::optional<MCFixupKind>
getFixupKind(StringRef Name) const356bdd1243dSDimitry Andric AArch64AsmBackend::getFixupKind(StringRef Name) const {
3575ffd83dbSDimitry Andric if (!TheTriple.isOSBinFormatELF())
358bdd1243dSDimitry Andric return std::nullopt;
3595ffd83dbSDimitry Andric
3605ffd83dbSDimitry Andric unsigned Type = llvm::StringSwitch<unsigned>(Name)
3615ffd83dbSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y)
3625ffd83dbSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/AArch64.def"
3635ffd83dbSDimitry Andric #undef ELF_RELOC
364fe6060f1SDimitry Andric .Case("BFD_RELOC_NONE", ELF::R_AARCH64_NONE)
365fe6060f1SDimitry Andric .Case("BFD_RELOC_16", ELF::R_AARCH64_ABS16)
366fe6060f1SDimitry Andric .Case("BFD_RELOC_32", ELF::R_AARCH64_ABS32)
367fe6060f1SDimitry Andric .Case("BFD_RELOC_64", ELF::R_AARCH64_ABS64)
3685ffd83dbSDimitry Andric .Default(-1u);
3695ffd83dbSDimitry Andric if (Type == -1u)
370bdd1243dSDimitry Andric return std::nullopt;
3715ffd83dbSDimitry Andric return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric
3740b57cec5SDimitry Andric /// getFixupKindContainereSizeInBytes - The number of bytes of the
3750b57cec5SDimitry Andric /// container involved in big endian or 0 if the item is little endian
getFixupKindContainereSizeInBytes(unsigned Kind) const3760b57cec5SDimitry Andric unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) const {
3775f757f3fSDimitry Andric if (Endian == llvm::endianness::little)
3780b57cec5SDimitry Andric return 0;
3790b57cec5SDimitry Andric
3800b57cec5SDimitry Andric switch (Kind) {
3810b57cec5SDimitry Andric default:
3820b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!");
3830b57cec5SDimitry Andric
3840b57cec5SDimitry Andric case FK_Data_1:
3850b57cec5SDimitry Andric return 1;
3860b57cec5SDimitry Andric case FK_Data_2:
3870b57cec5SDimitry Andric return 2;
3880b57cec5SDimitry Andric case FK_Data_4:
3890b57cec5SDimitry Andric return 4;
3900b57cec5SDimitry Andric case FK_Data_8:
3910b57cec5SDimitry Andric return 8;
3920b57cec5SDimitry Andric
3930b57cec5SDimitry Andric case AArch64::fixup_aarch64_movw:
3940b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch14:
395cb14a3feSDimitry Andric case AArch64::fixup_aarch64_pcrel_branch16:
3960b57cec5SDimitry Andric case AArch64::fixup_aarch64_add_imm12:
3970b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale1:
3980b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale2:
3990b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale4:
4000b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale8:
4010b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale16:
4020b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldr_pcrel_imm19:
4030b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch19:
4040b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adr_imm21:
4050b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adrp_imm21:
4060b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch26:
4070b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_call26:
4080b57cec5SDimitry Andric // Instructions are always little endian
4090b57cec5SDimitry Andric return 0;
4100b57cec5SDimitry Andric }
4110b57cec5SDimitry Andric }
4120b57cec5SDimitry Andric
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const4130b57cec5SDimitry Andric void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
4140b57cec5SDimitry Andric const MCValue &Target,
4150b57cec5SDimitry Andric MutableArrayRef<char> Data, uint64_t Value,
4160b57cec5SDimitry Andric bool IsResolved,
4170b57cec5SDimitry Andric const MCSubtargetInfo *STI) const {
4185f757f3fSDimitry Andric if (Fixup.getTargetKind() == FK_Data_8 && TheTriple.isOSBinFormatELF()) {
4195f757f3fSDimitry Andric auto RefKind = static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind());
4205f757f3fSDimitry Andric AArch64MCExpr::VariantKind SymLoc = AArch64MCExpr::getSymbolLoc(RefKind);
4215f757f3fSDimitry Andric if (SymLoc == AArch64AuthMCExpr::VK_AUTH ||
4225f757f3fSDimitry Andric SymLoc == AArch64AuthMCExpr::VK_AUTHADDR) {
4235f757f3fSDimitry Andric assert(Value == 0);
4245f757f3fSDimitry Andric const auto *Expr = cast<AArch64AuthMCExpr>(Fixup.getValue());
4255f757f3fSDimitry Andric Value = (uint64_t(Expr->getDiscriminator()) << 32) |
4265f757f3fSDimitry Andric (uint64_t(Expr->getKey()) << 60) |
4275f757f3fSDimitry Andric (uint64_t(Expr->hasAddressDiversity()) << 63);
4285f757f3fSDimitry Andric }
4295f757f3fSDimitry Andric }
4305f757f3fSDimitry Andric
4310b57cec5SDimitry Andric if (!Value)
4320b57cec5SDimitry Andric return; // Doesn't change encoding.
4335ffd83dbSDimitry Andric unsigned Kind = Fixup.getKind();
4345ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind)
4355ffd83dbSDimitry Andric return;
4365ffd83dbSDimitry Andric unsigned NumBytes = getFixupKindNumBytes(Kind);
4370b57cec5SDimitry Andric MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
4380b57cec5SDimitry Andric MCContext &Ctx = Asm.getContext();
4390b57cec5SDimitry Andric int64_t SignedValue = static_cast<int64_t>(Value);
4400b57cec5SDimitry Andric // Apply any target-specific value adjustments.
4410b57cec5SDimitry Andric Value = adjustFixupValue(Fixup, Target, Value, Ctx, TheTriple, IsResolved);
4420b57cec5SDimitry Andric
4430b57cec5SDimitry Andric // Shift the value into position.
4440b57cec5SDimitry Andric Value <<= Info.TargetOffset;
4450b57cec5SDimitry Andric
4460b57cec5SDimitry Andric unsigned Offset = Fixup.getOffset();
4470b57cec5SDimitry Andric assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
4480b57cec5SDimitry Andric
4490b57cec5SDimitry Andric // Used to point to big endian bytes.
4500b57cec5SDimitry Andric unsigned FulleSizeInBytes = getFixupKindContainereSizeInBytes(Fixup.getKind());
4510b57cec5SDimitry Andric
4520b57cec5SDimitry Andric // For each byte of the fragment that the fixup touches, mask in the
4530b57cec5SDimitry Andric // bits from the fixup value.
4540b57cec5SDimitry Andric if (FulleSizeInBytes == 0) {
4550b57cec5SDimitry Andric // Handle as little-endian
4560b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) {
4570b57cec5SDimitry Andric Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric } else {
4600b57cec5SDimitry Andric // Handle as big-endian
4610b57cec5SDimitry Andric assert((Offset + FulleSizeInBytes) <= Data.size() && "Invalid fixup size!");
4620b57cec5SDimitry Andric assert(NumBytes <= FulleSizeInBytes && "Invalid fixup size!");
4630b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) {
4640b57cec5SDimitry Andric unsigned Idx = FulleSizeInBytes - 1 - i;
4650b57cec5SDimitry Andric Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
4660b57cec5SDimitry Andric }
4670b57cec5SDimitry Andric }
4680b57cec5SDimitry Andric
4690b57cec5SDimitry Andric // FIXME: getFixupKindInfo() and getFixupKindNumBytes() could be fixed to
4700b57cec5SDimitry Andric // handle this more cleanly. This may affect the output of -show-mc-encoding.
4710b57cec5SDimitry Andric AArch64MCExpr::VariantKind RefKind =
4720b57cec5SDimitry Andric static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind());
4735ffd83dbSDimitry Andric if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS ||
4745ffd83dbSDimitry Andric (!RefKind && Fixup.getTargetKind() == AArch64::fixup_aarch64_movw)) {
4750b57cec5SDimitry Andric // If the immediate is negative, generate MOVN else MOVZ.
4760b57cec5SDimitry Andric // (Bit 30 = 0) ==> MOVN, (Bit 30 = 1) ==> MOVZ.
4770b57cec5SDimitry Andric if (SignedValue < 0)
4780b57cec5SDimitry Andric Data[Offset + 3] &= ~(1 << 6);
4790b57cec5SDimitry Andric else
4800b57cec5SDimitry Andric Data[Offset + 3] |= (1 << 6);
4810b57cec5SDimitry Andric }
4820b57cec5SDimitry Andric }
4830b57cec5SDimitry Andric
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value) const4840b57cec5SDimitry Andric bool AArch64AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
4850fca6ea1SDimitry Andric uint64_t Value) const {
4860b57cec5SDimitry Andric // FIXME: This isn't correct for AArch64. Just moving the "generic" logic
4870b57cec5SDimitry Andric // into the targets for now.
4880b57cec5SDimitry Andric //
4890b57cec5SDimitry Andric // Relax if the value is too big for a (signed) i8.
4900b57cec5SDimitry Andric return int64_t(Value) != int64_t(int8_t(Value));
4910b57cec5SDimitry Andric }
4920b57cec5SDimitry Andric
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const4935ffd83dbSDimitry Andric void AArch64AsmBackend::relaxInstruction(MCInst &Inst,
4945ffd83dbSDimitry Andric const MCSubtargetInfo &STI) const {
4950b57cec5SDimitry Andric llvm_unreachable("AArch64AsmBackend::relaxInstruction() unimplemented");
4960b57cec5SDimitry Andric }
4970b57cec5SDimitry Andric
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const498349cc55cSDimitry Andric bool AArch64AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
499349cc55cSDimitry Andric const MCSubtargetInfo *STI) const {
5000b57cec5SDimitry Andric // If the count is not 4-byte aligned, we must be writing data into the text
5010b57cec5SDimitry Andric // section (otherwise we have unaligned instructions, and thus have far
5020b57cec5SDimitry Andric // bigger problems), so just write zeros instead.
5030b57cec5SDimitry Andric OS.write_zeros(Count % 4);
5040b57cec5SDimitry Andric
5050b57cec5SDimitry Andric // We are properly aligned, so write NOPs as requested.
5060b57cec5SDimitry Andric Count /= 4;
5070b57cec5SDimitry Andric for (uint64_t i = 0; i != Count; ++i)
50881ad6265SDimitry Andric OS.write("\x1f\x20\x03\xd5", 4);
5090b57cec5SDimitry Andric return true;
5100b57cec5SDimitry Andric }
5110b57cec5SDimitry Andric
shouldForceRelocation(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,const MCSubtargetInfo * STI)5120b57cec5SDimitry Andric bool AArch64AsmBackend::shouldForceRelocation(const MCAssembler &Asm,
5130b57cec5SDimitry Andric const MCFixup &Fixup,
5145f757f3fSDimitry Andric const MCValue &Target,
5155f757f3fSDimitry Andric const MCSubtargetInfo *STI) {
5160b57cec5SDimitry Andric unsigned Kind = Fixup.getKind();
5175ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind)
5180b57cec5SDimitry Andric return true;
5190b57cec5SDimitry Andric
5200b57cec5SDimitry Andric // The ADRP instruction adds some multiple of 0x1000 to the current PC &
5210b57cec5SDimitry Andric // ~0xfff. This means that the required offset to reach a symbol can vary by
5220b57cec5SDimitry Andric // up to one step depending on where the ADRP is in memory. For example:
5230b57cec5SDimitry Andric //
5240b57cec5SDimitry Andric // ADRP x0, there
5250b57cec5SDimitry Andric // there:
5260b57cec5SDimitry Andric //
5270b57cec5SDimitry Andric // If the ADRP occurs at address 0xffc then "there" will be at 0x1000 and
5280b57cec5SDimitry Andric // we'll need that as an offset. At any other address "there" will be in the
5290b57cec5SDimitry Andric // same page as the ADRP and the instruction should encode 0x0. Assuming the
5300b57cec5SDimitry Andric // section isn't 0x1000-aligned, we therefore need to delegate this decision
5310b57cec5SDimitry Andric // to the linker -- a relocation!
5320b57cec5SDimitry Andric if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21)
5330b57cec5SDimitry Andric return true;
5340b57cec5SDimitry Andric
5350b57cec5SDimitry Andric return false;
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric
5380b57cec5SDimitry Andric namespace {
5390b57cec5SDimitry Andric
5400b57cec5SDimitry Andric namespace CU {
5410b57cec5SDimitry Andric
5420b57cec5SDimitry Andric /// Compact unwind encoding values.
5430b57cec5SDimitry Andric enum CompactUnwindEncodings {
5440b57cec5SDimitry Andric /// A "frameless" leaf function, where no non-volatile registers are
5450b57cec5SDimitry Andric /// saved. The return remains in LR throughout the function.
5460b57cec5SDimitry Andric UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
5470b57cec5SDimitry Andric
5480b57cec5SDimitry Andric /// No compact unwind encoding available. Instead the low 23-bits of
5490b57cec5SDimitry Andric /// the compact unwind encoding is the offset of the DWARF FDE in the
5500b57cec5SDimitry Andric /// __eh_frame section. This mode is never used in object files. It is only
5510b57cec5SDimitry Andric /// generated by the linker in final linked images, which have only DWARF info
5520b57cec5SDimitry Andric /// for a function.
5530b57cec5SDimitry Andric UNWIND_ARM64_MODE_DWARF = 0x03000000,
5540b57cec5SDimitry Andric
5550b57cec5SDimitry Andric /// This is a standard arm64 prologue where FP/LR are immediately
5560b57cec5SDimitry Andric /// pushed on the stack, then SP is copied to FP. If there are any
5570b57cec5SDimitry Andric /// non-volatile register saved, they are copied into the stack fame in pairs
5580b57cec5SDimitry Andric /// in a contiguous ranger right below the saved FP/LR pair. Any subset of the
5590b57cec5SDimitry Andric /// five X pairs and four D pairs can be saved, but the memory layout must be
5600b57cec5SDimitry Andric /// in register number order.
5610b57cec5SDimitry Andric UNWIND_ARM64_MODE_FRAME = 0x04000000,
5620b57cec5SDimitry Andric
5630b57cec5SDimitry Andric /// Frame register pair encodings.
5640b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
5650b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
5660b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
5670b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
5680b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
5690b57cec5SDimitry Andric UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
5700b57cec5SDimitry Andric UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
5710b57cec5SDimitry Andric UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
5720b57cec5SDimitry Andric UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800
5730b57cec5SDimitry Andric };
5740b57cec5SDimitry Andric
5750b57cec5SDimitry Andric } // end CU namespace
5760b57cec5SDimitry Andric
5770b57cec5SDimitry Andric // FIXME: This should be in a separate file.
5780b57cec5SDimitry Andric class DarwinAArch64AsmBackend : public AArch64AsmBackend {
5790b57cec5SDimitry Andric const MCRegisterInfo &MRI;
5800b57cec5SDimitry Andric
5810b57cec5SDimitry Andric /// Encode compact unwind stack adjustment for frameless functions.
5820b57cec5SDimitry Andric /// See UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK in compact_unwind_encoding.h.
5830b57cec5SDimitry Andric /// The stack size always needs to be 16 byte aligned.
encodeStackAdjustment(uint32_t StackSize) const5840b57cec5SDimitry Andric uint32_t encodeStackAdjustment(uint32_t StackSize) const {
5850b57cec5SDimitry Andric return (StackSize / 16) << 12;
5860b57cec5SDimitry Andric }
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric public:
DarwinAArch64AsmBackend(const Target & T,const Triple & TT,const MCRegisterInfo & MRI)5890b57cec5SDimitry Andric DarwinAArch64AsmBackend(const Target &T, const Triple &TT,
5905ffd83dbSDimitry Andric const MCRegisterInfo &MRI)
5915ffd83dbSDimitry Andric : AArch64AsmBackend(T, TT, /*IsLittleEndian*/ true), MRI(MRI) {}
5920b57cec5SDimitry Andric
5930b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const5940b57cec5SDimitry Andric createObjectTargetWriter() const override {
5955ffd83dbSDimitry Andric uint32_t CPUType = cantFail(MachO::getCPUType(TheTriple));
5965ffd83dbSDimitry Andric uint32_t CPUSubType = cantFail(MachO::getCPUSubType(TheTriple));
5975ffd83dbSDimitry Andric return createAArch64MachObjectWriter(CPUType, CPUSubType,
5985ffd83dbSDimitry Andric TheTriple.isArch32Bit());
5990b57cec5SDimitry Andric }
6000b57cec5SDimitry Andric
6010b57cec5SDimitry Andric /// Generate the compact unwind encoding from the CFI directives.
generateCompactUnwindEncoding(const MCDwarfFrameInfo * FI,const MCContext * Ctxt) const602*36b606aeSDimitry Andric uint64_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI,
60306c3fb27SDimitry Andric const MCContext *Ctxt) const override {
60406c3fb27SDimitry Andric ArrayRef<MCCFIInstruction> Instrs = FI->Instructions;
6050b57cec5SDimitry Andric if (Instrs.empty())
6060b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_FRAMELESS;
60706c3fb27SDimitry Andric if (!isDarwinCanonicalPersonality(FI->Personality) &&
60806c3fb27SDimitry Andric !Ctxt->emitCompactUnwindNonCanonical())
60906c3fb27SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6100b57cec5SDimitry Andric
6110b57cec5SDimitry Andric bool HasFP = false;
612*36b606aeSDimitry Andric uint64_t StackSize = 0;
6130b57cec5SDimitry Andric
614*36b606aeSDimitry Andric uint64_t CompactUnwindEncoding = 0;
615*36b606aeSDimitry Andric int64_t CurOffset = 0;
6160b57cec5SDimitry Andric for (size_t i = 0, e = Instrs.size(); i != e; ++i) {
6170b57cec5SDimitry Andric const MCCFIInstruction &Inst = Instrs[i];
6180b57cec5SDimitry Andric
6190b57cec5SDimitry Andric switch (Inst.getOperation()) {
6200b57cec5SDimitry Andric default:
6210b57cec5SDimitry Andric // Cannot handle this directive: bail out.
6220b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6230b57cec5SDimitry Andric case MCCFIInstruction::OpDefCfa: {
6240b57cec5SDimitry Andric // Defines a frame pointer.
6250b57cec5SDimitry Andric unsigned XReg =
6268bcb0991SDimitry Andric getXRegFromWReg(*MRI.getLLVMRegNum(Inst.getRegister(), true));
6270b57cec5SDimitry Andric
6280b57cec5SDimitry Andric // Other CFA registers than FP are not supported by compact unwind.
6290b57cec5SDimitry Andric // Fallback on DWARF.
6300b57cec5SDimitry Andric // FIXME: When opt-remarks are supported in MC, add a remark to notify
6310b57cec5SDimitry Andric // the user.
6320b57cec5SDimitry Andric if (XReg != AArch64::FP)
6330b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6340b57cec5SDimitry Andric
63581ad6265SDimitry Andric if (i + 2 >= e)
63681ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6370b57cec5SDimitry Andric
6380b57cec5SDimitry Andric const MCCFIInstruction &LRPush = Instrs[++i];
63981ad6265SDimitry Andric if (LRPush.getOperation() != MCCFIInstruction::OpOffset)
64081ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6410b57cec5SDimitry Andric const MCCFIInstruction &FPPush = Instrs[++i];
64281ad6265SDimitry Andric if (FPPush.getOperation() != MCCFIInstruction::OpOffset)
64381ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6440b57cec5SDimitry Andric
64581ad6265SDimitry Andric if (FPPush.getOffset() + 8 != LRPush.getOffset())
64681ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
647fe6060f1SDimitry Andric CurOffset = FPPush.getOffset();
648fe6060f1SDimitry Andric
6498bcb0991SDimitry Andric unsigned LRReg = *MRI.getLLVMRegNum(LRPush.getRegister(), true);
6508bcb0991SDimitry Andric unsigned FPReg = *MRI.getLLVMRegNum(FPPush.getRegister(), true);
6510b57cec5SDimitry Andric
6520b57cec5SDimitry Andric LRReg = getXRegFromWReg(LRReg);
6530b57cec5SDimitry Andric FPReg = getXRegFromWReg(FPReg);
6540b57cec5SDimitry Andric
65581ad6265SDimitry Andric if (LRReg != AArch64::LR || FPReg != AArch64::FP)
65681ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6570b57cec5SDimitry Andric
6580b57cec5SDimitry Andric // Indicate that the function has a frame.
6590b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAME;
6600b57cec5SDimitry Andric HasFP = true;
6610b57cec5SDimitry Andric break;
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric case MCCFIInstruction::OpDefCfaOffset: {
66481ad6265SDimitry Andric if (StackSize != 0)
66581ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6660b57cec5SDimitry Andric StackSize = std::abs(Inst.getOffset());
6670b57cec5SDimitry Andric break;
6680b57cec5SDimitry Andric }
6690b57cec5SDimitry Andric case MCCFIInstruction::OpOffset: {
6700b57cec5SDimitry Andric // Registers are saved in pairs. We expect there to be two consecutive
6710b57cec5SDimitry Andric // `.cfi_offset' instructions with the appropriate registers specified.
6728bcb0991SDimitry Andric unsigned Reg1 = *MRI.getLLVMRegNum(Inst.getRegister(), true);
6730b57cec5SDimitry Andric if (i + 1 == e)
6740b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6750b57cec5SDimitry Andric
676fe6060f1SDimitry Andric if (CurOffset != 0 && Inst.getOffset() != CurOffset - 8)
677fe6060f1SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
678fe6060f1SDimitry Andric CurOffset = Inst.getOffset();
679fe6060f1SDimitry Andric
6800b57cec5SDimitry Andric const MCCFIInstruction &Inst2 = Instrs[++i];
6810b57cec5SDimitry Andric if (Inst2.getOperation() != MCCFIInstruction::OpOffset)
6820b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
6838bcb0991SDimitry Andric unsigned Reg2 = *MRI.getLLVMRegNum(Inst2.getRegister(), true);
6840b57cec5SDimitry Andric
685fe6060f1SDimitry Andric if (Inst2.getOffset() != CurOffset - 8)
686fe6060f1SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
687fe6060f1SDimitry Andric CurOffset = Inst2.getOffset();
688fe6060f1SDimitry Andric
6890b57cec5SDimitry Andric // N.B. The encodings must be in register number order, and the X
6900b57cec5SDimitry Andric // registers before the D registers.
6910b57cec5SDimitry Andric
6920b57cec5SDimitry Andric // X19/X20 pair = 0x00000001,
6930b57cec5SDimitry Andric // X21/X22 pair = 0x00000002,
6940b57cec5SDimitry Andric // X23/X24 pair = 0x00000004,
6950b57cec5SDimitry Andric // X25/X26 pair = 0x00000008,
6960b57cec5SDimitry Andric // X27/X28 pair = 0x00000010
6970b57cec5SDimitry Andric Reg1 = getXRegFromWReg(Reg1);
6980b57cec5SDimitry Andric Reg2 = getXRegFromWReg(Reg2);
6990b57cec5SDimitry Andric
7000b57cec5SDimitry Andric if (Reg1 == AArch64::X19 && Reg2 == AArch64::X20 &&
7010b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF1E) == 0)
7020b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X19_X20_PAIR;
7030b57cec5SDimitry Andric else if (Reg1 == AArch64::X21 && Reg2 == AArch64::X22 &&
7040b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF1C) == 0)
7050b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X21_X22_PAIR;
7060b57cec5SDimitry Andric else if (Reg1 == AArch64::X23 && Reg2 == AArch64::X24 &&
7070b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF18) == 0)
7080b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X23_X24_PAIR;
7090b57cec5SDimitry Andric else if (Reg1 == AArch64::X25 && Reg2 == AArch64::X26 &&
7100b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF10) == 0)
7110b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X25_X26_PAIR;
7120b57cec5SDimitry Andric else if (Reg1 == AArch64::X27 && Reg2 == AArch64::X28 &&
7130b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF00) == 0)
7140b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X27_X28_PAIR;
7150b57cec5SDimitry Andric else {
7160b57cec5SDimitry Andric Reg1 = getDRegFromBReg(Reg1);
7170b57cec5SDimitry Andric Reg2 = getDRegFromBReg(Reg2);
7180b57cec5SDimitry Andric
7190b57cec5SDimitry Andric // D8/D9 pair = 0x00000100,
7200b57cec5SDimitry Andric // D10/D11 pair = 0x00000200,
7210b57cec5SDimitry Andric // D12/D13 pair = 0x00000400,
7220b57cec5SDimitry Andric // D14/D15 pair = 0x00000800
7230b57cec5SDimitry Andric if (Reg1 == AArch64::D8 && Reg2 == AArch64::D9 &&
7240b57cec5SDimitry Andric (CompactUnwindEncoding & 0xE00) == 0)
7250b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D8_D9_PAIR;
7260b57cec5SDimitry Andric else if (Reg1 == AArch64::D10 && Reg2 == AArch64::D11 &&
7270b57cec5SDimitry Andric (CompactUnwindEncoding & 0xC00) == 0)
7280b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D10_D11_PAIR;
7290b57cec5SDimitry Andric else if (Reg1 == AArch64::D12 && Reg2 == AArch64::D13 &&
7300b57cec5SDimitry Andric (CompactUnwindEncoding & 0x800) == 0)
7310b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D12_D13_PAIR;
7320b57cec5SDimitry Andric else if (Reg1 == AArch64::D14 && Reg2 == AArch64::D15)
7330b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D14_D15_PAIR;
7340b57cec5SDimitry Andric else
7350b57cec5SDimitry Andric // A pair was pushed which we cannot handle.
7360b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
7370b57cec5SDimitry Andric }
7380b57cec5SDimitry Andric
7390b57cec5SDimitry Andric break;
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric
7440b57cec5SDimitry Andric if (!HasFP) {
7450b57cec5SDimitry Andric // With compact unwind info we can only represent stack adjustments of up
7460b57cec5SDimitry Andric // to 65520 bytes.
7470b57cec5SDimitry Andric if (StackSize > 65520)
7480b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF;
7490b57cec5SDimitry Andric
7500b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAMELESS;
7510b57cec5SDimitry Andric CompactUnwindEncoding |= encodeStackAdjustment(StackSize);
7520b57cec5SDimitry Andric }
7530b57cec5SDimitry Andric
7540b57cec5SDimitry Andric return CompactUnwindEncoding;
7550b57cec5SDimitry Andric }
7560b57cec5SDimitry Andric };
7570b57cec5SDimitry Andric
7580b57cec5SDimitry Andric } // end anonymous namespace
7590b57cec5SDimitry Andric
7600b57cec5SDimitry Andric namespace {
7610b57cec5SDimitry Andric
7620b57cec5SDimitry Andric class ELFAArch64AsmBackend : public AArch64AsmBackend {
7630b57cec5SDimitry Andric public:
7640b57cec5SDimitry Andric uint8_t OSABI;
7650b57cec5SDimitry Andric bool IsILP32;
7660b57cec5SDimitry Andric
ELFAArch64AsmBackend(const Target & T,const Triple & TT,uint8_t OSABI,bool IsLittleEndian,bool IsILP32)7670b57cec5SDimitry Andric ELFAArch64AsmBackend(const Target &T, const Triple &TT, uint8_t OSABI,
7680b57cec5SDimitry Andric bool IsLittleEndian, bool IsILP32)
7690b57cec5SDimitry Andric : AArch64AsmBackend(T, TT, IsLittleEndian), OSABI(OSABI),
7700b57cec5SDimitry Andric IsILP32(IsILP32) {}
7710b57cec5SDimitry Andric
7720b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const7730b57cec5SDimitry Andric createObjectTargetWriter() const override {
7740b57cec5SDimitry Andric return createAArch64ELFObjectWriter(OSABI, IsILP32);
7750b57cec5SDimitry Andric }
7760b57cec5SDimitry Andric };
7770b57cec5SDimitry Andric
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric
7800b57cec5SDimitry Andric namespace {
7810b57cec5SDimitry Andric class COFFAArch64AsmBackend : public AArch64AsmBackend {
7820b57cec5SDimitry Andric public:
COFFAArch64AsmBackend(const Target & T,const Triple & TheTriple)7830b57cec5SDimitry Andric COFFAArch64AsmBackend(const Target &T, const Triple &TheTriple)
7840b57cec5SDimitry Andric : AArch64AsmBackend(T, TheTriple, /*IsLittleEndian*/ true) {}
7850b57cec5SDimitry Andric
7860b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const7870b57cec5SDimitry Andric createObjectTargetWriter() const override {
788bdd1243dSDimitry Andric return createAArch64WinCOFFObjectWriter(TheTriple);
7890b57cec5SDimitry Andric }
7900b57cec5SDimitry Andric };
7910b57cec5SDimitry Andric }
7920b57cec5SDimitry Andric
createAArch64leAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)7930b57cec5SDimitry Andric MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
7940b57cec5SDimitry Andric const MCSubtargetInfo &STI,
7950b57cec5SDimitry Andric const MCRegisterInfo &MRI,
7960b57cec5SDimitry Andric const MCTargetOptions &Options) {
7970b57cec5SDimitry Andric const Triple &TheTriple = STI.getTargetTriple();
7980b57cec5SDimitry Andric if (TheTriple.isOSBinFormatMachO()) {
7995ffd83dbSDimitry Andric return new DarwinAArch64AsmBackend(T, TheTriple, MRI);
8000b57cec5SDimitry Andric }
8010b57cec5SDimitry Andric
8020b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF())
8030b57cec5SDimitry Andric return new COFFAArch64AsmBackend(T, TheTriple);
8040b57cec5SDimitry Andric
8050b57cec5SDimitry Andric assert(TheTriple.isOSBinFormatELF() && "Invalid target");
8060b57cec5SDimitry Andric
8070b57cec5SDimitry Andric uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
808e8d8bef9SDimitry Andric bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
8090b57cec5SDimitry Andric return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/true,
8100b57cec5SDimitry Andric IsILP32);
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric
createAArch64beAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)8130b57cec5SDimitry Andric MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
8140b57cec5SDimitry Andric const MCSubtargetInfo &STI,
8150b57cec5SDimitry Andric const MCRegisterInfo &MRI,
8160b57cec5SDimitry Andric const MCTargetOptions &Options) {
8170b57cec5SDimitry Andric const Triple &TheTriple = STI.getTargetTriple();
8180b57cec5SDimitry Andric assert(TheTriple.isOSBinFormatELF() &&
8190b57cec5SDimitry Andric "Big endian is only supported for ELF targets!");
8200b57cec5SDimitry Andric uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
821e8d8bef9SDimitry Andric bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
8220b57cec5SDimitry Andric return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/false,
8230b57cec5SDimitry Andric IsILP32);
8240b57cec5SDimitry Andric }
825