#include "MCTargetDesc/AArch64FixupKinds.h"
#include "MCTargetDesc/AArch64MCExpr.h"
#include "MCTargetDesc/AArch64MCTargetDesc.h"
#include "Utils/AArch64BaseInfo.h"
#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDirectives.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
namespace {
class AArch64AsmBackend : public MCAsmBackend {
static const unsigned PCRelFlagVal =
MCFixupKindInfo::FKF_IsAlignedDownTo32Bits | MCFixupKindInfo::FKF_IsPCRel;
protected:
Triple TheTriple;
public:
AArch64AsmBackend(const Target &T, const Triple &TT, bool IsLittleEndian)
: MCAsmBackend(IsLittleEndian ? support::little : support::big),
TheTriple(TT) {}
unsigned getNumFixupKinds() const override {
return AArch64::NumTargetFixupKinds;
}
Optional<MCFixupKind> getFixupKind(StringRef Name) const override;
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
const static MCFixupKindInfo Infos[AArch64::NumTargetFixupKinds] = {
{"fixup_aarch64_pcrel_adr_imm21", 0, 32, PCRelFlagVal},
{"fixup_aarch64_pcrel_adrp_imm21", 0, 32, PCRelFlagVal},
{"fixup_aarch64_add_imm12", 10, 12, 0},
{"fixup_aarch64_ldst_imm12_scale1", 10, 12, 0},
{"fixup_aarch64_ldst_imm12_scale2", 10, 12, 0},
{"fixup_aarch64_ldst_imm12_scale4", 10, 12, 0},
{"fixup_aarch64_ldst_imm12_scale8", 10, 12, 0},
{"fixup_aarch64_ldst_imm12_scale16", 10, 12, 0},
{"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal},
{"fixup_aarch64_movw", 5, 16, 0},
{"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal},
{"fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal}};
if (Kind >= FirstLiteralRelocationKind)
return MCAsmBackend::getFixupKindInfo(FK_NONE);
if (Kind < FirstTargetFixupKind)
return MCAsmBackend::getFixupKindInfo(Kind);
assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
"Invalid kind!");
return Infos[Kind - FirstTargetFixupKind];
}
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
uint64_t Value, bool IsResolved,
const MCSubtargetInfo *STI) const override;
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override;
void relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
unsigned getFixupKindContainereSizeInBytes(unsigned Kind) const;
bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target) override;
};
}
static unsigned getFixupKindNumBytes(unsigned Kind) {
switch (Kind) {
default:
llvm_unreachable("Unknown fixup kind!");
case FK_Data_1:
return 1;
case FK_Data_2:
case FK_SecRel_2:
return 2;
case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch14:
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
case AArch64::fixup_aarch64_ldst_imm12_scale2:
case AArch64::fixup_aarch64_ldst_imm12_scale4:
case AArch64::fixup_aarch64_ldst_imm12_scale8:
case AArch64::fixup_aarch64_ldst_imm12_scale16:
case AArch64::fixup_aarch64_ldr_pcrel_imm19:
case AArch64::fixup_aarch64_pcrel_branch19:
return 3;
case AArch64::fixup_aarch64_pcrel_adr_imm21:
case AArch64::fixup_aarch64_pcrel_adrp_imm21:
case AArch64::fixup_aarch64_pcrel_branch26:
case AArch64::fixup_aarch64_pcrel_call26:
case FK_Data_4:
case FK_SecRel_4:
return 4;
case FK_Data_8:
return 8;
}
}
static unsigned AdrImmBits(unsigned Value) {
unsigned lo2 = Value & 0x3;
unsigned hi19 = (Value & 0x1ffffc) >> 2;
return (hi19 << 5) | (lo2 << 29);
}
static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target,
uint64_t Value, MCContext &Ctx,
const Triple &TheTriple, bool IsResolved) {
int64_t SignedValue = static_cast<int64_t>(Value);
switch (Fixup.getTargetKind()) {
default:
llvm_unreachable("Unknown fixup kind!");
case AArch64::fixup_aarch64_pcrel_adr_imm21:
if (SignedValue > 2097151 || SignedValue < -2097152)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
return AdrImmBits(Value & 0x1fffffULL);
case AArch64::fixup_aarch64_pcrel_adrp_imm21:
assert(!IsResolved);
if (TheTriple.isOSBinFormatCOFF()) {
if (!isInt<21>(SignedValue))
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
return AdrImmBits(Value & 0x1fffffULL);
}
return AdrImmBits((Value & 0x1fffff000ULL) >> 12);
case AArch64::fixup_aarch64_ldr_pcrel_imm19:
case AArch64::fixup_aarch64_pcrel_branch19:
if (SignedValue > 2097151 || SignedValue < -2097152)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
if (Value & 0x3)
Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
return (Value >> 2) & 0x7ffff;
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
Value &= 0xfff;
if (Value >= 0x1000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
return Value;
case AArch64::fixup_aarch64_ldst_imm12_scale2:
if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
Value &= 0xfff;
if (Value >= 0x2000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
if (Value & 0x1)
Ctx.reportError(Fixup.getLoc(), "fixup must be 2-byte aligned");
return Value >> 1;
case AArch64::fixup_aarch64_ldst_imm12_scale4:
if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
Value &= 0xfff;
if (Value >= 0x4000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
if (Value & 0x3)
Ctx.reportError(Fixup.getLoc(), "fixup must be 4-byte aligned");
return Value >> 2;
case AArch64::fixup_aarch64_ldst_imm12_scale8:
if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
Value &= 0xfff;
if (Value >= 0x8000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
if (Value & 0x7)
Ctx.reportError(Fixup.getLoc(), "fixup must be 8-byte aligned");
return Value >> 3;
case AArch64::fixup_aarch64_ldst_imm12_scale16:
if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
Value &= 0xfff;
if (Value >= 0x10000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
if (Value & 0xf)
Ctx.reportError(Fixup.getLoc(), "fixup must be 16-byte aligned");
return Value >> 4;
case AArch64::fixup_aarch64_movw: {
AArch64MCExpr::VariantKind RefKind =
static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind());
if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS &&
AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) {
if (!RefKind) {
if (SignedValue > 0xFFFF || SignedValue < -0xFFFF)
Ctx.reportError(Fixup.getLoc(),
"fixup value out of range [-0xFFFF, 0xFFFF]");
if (SignedValue < 0)
SignedValue = ~SignedValue;
Value = static_cast<uint64_t>(SignedValue);
} else
Ctx.reportError(Fixup.getLoc(),
"relocation for a thread-local variable points to an "
"absolute symbol");
return Value;
}
if (!IsResolved) {
Ctx.reportError(Fixup.getLoc(), "unresolved movw fixup not yet "
"implemented");
return Value;
}
if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS) {
switch (AArch64MCExpr::getAddressFrag(RefKind)) {
case AArch64MCExpr::VK_G0:
break;
case AArch64MCExpr::VK_G1:
SignedValue = SignedValue >> 16;
break;
case AArch64MCExpr::VK_G2:
SignedValue = SignedValue >> 32;
break;
case AArch64MCExpr::VK_G3:
SignedValue = SignedValue >> 48;
break;
default:
llvm_unreachable("Variant kind doesn't correspond to fixup");
}
} else {
switch (AArch64MCExpr::getAddressFrag(RefKind)) {
case AArch64MCExpr::VK_G0:
break;
case AArch64MCExpr::VK_G1:
Value = Value >> 16;
break;
case AArch64MCExpr::VK_G2:
Value = Value >> 32;
break;
case AArch64MCExpr::VK_G3:
Value = Value >> 48;
break;
default:
llvm_unreachable("Variant kind doesn't correspond to fixup");
}
}
if (RefKind & AArch64MCExpr::VK_NC) {
Value &= 0xFFFF;
}
else if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS) {
if (SignedValue > 0xFFFF || SignedValue < -0xFFFF)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
if (SignedValue < 0)
SignedValue = ~SignedValue;
Value = static_cast<uint64_t>(SignedValue);
}
else if (Value > 0xFFFF) {
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
}
return Value;
}
case AArch64::fixup_aarch64_pcrel_branch14:
if (SignedValue > 32767 || SignedValue < -32768)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
if (Value & 0x3)
Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
return (Value >> 2) & 0x3fff;
case AArch64::fixup_aarch64_pcrel_branch26:
case AArch64::fixup_aarch64_pcrel_call26:
if (SignedValue > 134217727 || SignedValue < -134217728)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
if (Value & 0x3)
Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
return (Value >> 2) & 0x3ffffff;
case FK_Data_1:
case FK_Data_2:
case FK_Data_4:
case FK_Data_8:
case FK_SecRel_2:
case FK_SecRel_4:
return Value;
}
}
Optional<MCFixupKind> AArch64AsmBackend::getFixupKind(StringRef Name) const {
if (!TheTriple.isOSBinFormatELF())
return None;
unsigned Type = llvm::StringSwitch<unsigned>(Name)
#define ELF_RELOC(X, Y) .Case(#X, Y)
#include "llvm/BinaryFormat/ELFRelocs/AArch64.def"
#undef ELF_RELOC
.Case("BFD_RELOC_NONE", ELF::R_AARCH64_NONE)
.Case("BFD_RELOC_16", ELF::R_AARCH64_ABS16)
.Case("BFD_RELOC_32", ELF::R_AARCH64_ABS32)
.Case("BFD_RELOC_64", ELF::R_AARCH64_ABS64)
.Default(-1u);
if (Type == -1u)
return None;
return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
}
unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) const {
if (Endian == support::little)
return 0;
switch (Kind) {
default:
llvm_unreachable("Unknown fixup kind!");
case FK_Data_1:
return 1;
case FK_Data_2:
return 2;
case FK_Data_4:
return 4;
case FK_Data_8:
return 8;
case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch14:
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
case AArch64::fixup_aarch64_ldst_imm12_scale2:
case AArch64::fixup_aarch64_ldst_imm12_scale4:
case AArch64::fixup_aarch64_ldst_imm12_scale8:
case AArch64::fixup_aarch64_ldst_imm12_scale16:
case AArch64::fixup_aarch64_ldr_pcrel_imm19:
case AArch64::fixup_aarch64_pcrel_branch19:
case AArch64::fixup_aarch64_pcrel_adr_imm21:
case AArch64::fixup_aarch64_pcrel_adrp_imm21:
case AArch64::fixup_aarch64_pcrel_branch26:
case AArch64::fixup_aarch64_pcrel_call26:
return 0;
}
}
void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
bool IsResolved,
const MCSubtargetInfo *STI) const {
if (!Value)
return; unsigned Kind = Fixup.getKind();
if (Kind >= FirstLiteralRelocationKind)
return;
unsigned NumBytes = getFixupKindNumBytes(Kind);
MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
MCContext &Ctx = Asm.getContext();
int64_t SignedValue = static_cast<int64_t>(Value);
Value = adjustFixupValue(Fixup, Target, Value, Ctx, TheTriple, IsResolved);
Value <<= Info.TargetOffset;
unsigned Offset = Fixup.getOffset();
assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
unsigned FulleSizeInBytes = getFixupKindContainereSizeInBytes(Fixup.getKind());
if (FulleSizeInBytes == 0) {
for (unsigned i = 0; i != NumBytes; ++i) {
Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
}
} else {
assert((Offset + FulleSizeInBytes) <= Data.size() && "Invalid fixup size!");
assert(NumBytes <= FulleSizeInBytes && "Invalid fixup size!");
for (unsigned i = 0; i != NumBytes; ++i) {
unsigned Idx = FulleSizeInBytes - 1 - i;
Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
}
}
AArch64MCExpr::VariantKind RefKind =
static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind());
if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS ||
(!RefKind && Fixup.getTargetKind() == AArch64::fixup_aarch64_movw)) {
if (SignedValue < 0)
Data[Offset + 3] &= ~(1 << 6);
else
Data[Offset + 3] |= (1 << 6);
}
}
bool AArch64AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const {
return int64_t(Value) != int64_t(int8_t(Value));
}
void AArch64AsmBackend::relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const {
llvm_unreachable("AArch64AsmBackend::relaxInstruction() unimplemented");
}
bool AArch64AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
OS.write_zeros(Count % 4);
Count /= 4;
for (uint64_t i = 0; i != Count; ++i)
OS.write("\x1f\x20\x03\xd5", 4);
return true;
}
bool AArch64AsmBackend::shouldForceRelocation(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCValue &Target) {
unsigned Kind = Fixup.getKind();
if (Kind >= FirstLiteralRelocationKind)
return true;
if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21)
return true;
return false;
}
namespace {
namespace CU {
enum CompactUnwindEncodings {
UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
UNWIND_ARM64_MODE_DWARF = 0x03000000,
UNWIND_ARM64_MODE_FRAME = 0x04000000,
UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800
};
}
class DarwinAArch64AsmBackend : public AArch64AsmBackend {
const MCRegisterInfo &MRI;
uint32_t encodeStackAdjustment(uint32_t StackSize) const {
return (StackSize / 16) << 12;
}
public:
DarwinAArch64AsmBackend(const Target &T, const Triple &TT,
const MCRegisterInfo &MRI)
: AArch64AsmBackend(T, TT, true), MRI(MRI) {}
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override {
uint32_t CPUType = cantFail(MachO::getCPUType(TheTriple));
uint32_t CPUSubType = cantFail(MachO::getCPUSubType(TheTriple));
return createAArch64MachObjectWriter(CPUType, CPUSubType,
TheTriple.isArch32Bit());
}
uint32_t generateCompactUnwindEncoding(
ArrayRef<MCCFIInstruction> Instrs) const override {
if (Instrs.empty())
return CU::UNWIND_ARM64_MODE_FRAMELESS;
bool HasFP = false;
unsigned StackSize = 0;
uint32_t CompactUnwindEncoding = 0;
int CurOffset = 0;
for (size_t i = 0, e = Instrs.size(); i != e; ++i) {
const MCCFIInstruction &Inst = Instrs[i];
switch (Inst.getOperation()) {
default:
return CU::UNWIND_ARM64_MODE_DWARF;
case MCCFIInstruction::OpDefCfa: {
unsigned XReg =
getXRegFromWReg(*MRI.getLLVMRegNum(Inst.getRegister(), true));
if (XReg != AArch64::FP)
return CU::UNWIND_ARM64_MODE_DWARF;
if (i + 2 >= e)
return CU::UNWIND_ARM64_MODE_DWARF;
const MCCFIInstruction &LRPush = Instrs[++i];
if (LRPush.getOperation() != MCCFIInstruction::OpOffset)
return CU::UNWIND_ARM64_MODE_DWARF;
const MCCFIInstruction &FPPush = Instrs[++i];
if (FPPush.getOperation() != MCCFIInstruction::OpOffset)
return CU::UNWIND_ARM64_MODE_DWARF;
if (FPPush.getOffset() + 8 != LRPush.getOffset())
return CU::UNWIND_ARM64_MODE_DWARF;
CurOffset = FPPush.getOffset();
unsigned LRReg = *MRI.getLLVMRegNum(LRPush.getRegister(), true);
unsigned FPReg = *MRI.getLLVMRegNum(FPPush.getRegister(), true);
LRReg = getXRegFromWReg(LRReg);
FPReg = getXRegFromWReg(FPReg);
if (LRReg != AArch64::LR || FPReg != AArch64::FP)
return CU::UNWIND_ARM64_MODE_DWARF;
CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAME;
HasFP = true;
break;
}
case MCCFIInstruction::OpDefCfaOffset: {
if (StackSize != 0)
return CU::UNWIND_ARM64_MODE_DWARF;
StackSize = std::abs(Inst.getOffset());
break;
}
case MCCFIInstruction::OpOffset: {
unsigned Reg1 = *MRI.getLLVMRegNum(Inst.getRegister(), true);
if (i + 1 == e)
return CU::UNWIND_ARM64_MODE_DWARF;
if (CurOffset != 0 && Inst.getOffset() != CurOffset - 8)
return CU::UNWIND_ARM64_MODE_DWARF;
CurOffset = Inst.getOffset();
const MCCFIInstruction &Inst2 = Instrs[++i];
if (Inst2.getOperation() != MCCFIInstruction::OpOffset)
return CU::UNWIND_ARM64_MODE_DWARF;
unsigned Reg2 = *MRI.getLLVMRegNum(Inst2.getRegister(), true);
if (Inst2.getOffset() != CurOffset - 8)
return CU::UNWIND_ARM64_MODE_DWARF;
CurOffset = Inst2.getOffset();
Reg1 = getXRegFromWReg(Reg1);
Reg2 = getXRegFromWReg(Reg2);
if (Reg1 == AArch64::X19 && Reg2 == AArch64::X20 &&
(CompactUnwindEncoding & 0xF1E) == 0)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X19_X20_PAIR;
else if (Reg1 == AArch64::X21 && Reg2 == AArch64::X22 &&
(CompactUnwindEncoding & 0xF1C) == 0)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X21_X22_PAIR;
else if (Reg1 == AArch64::X23 && Reg2 == AArch64::X24 &&
(CompactUnwindEncoding & 0xF18) == 0)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X23_X24_PAIR;
else if (Reg1 == AArch64::X25 && Reg2 == AArch64::X26 &&
(CompactUnwindEncoding & 0xF10) == 0)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X25_X26_PAIR;
else if (Reg1 == AArch64::X27 && Reg2 == AArch64::X28 &&
(CompactUnwindEncoding & 0xF00) == 0)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X27_X28_PAIR;
else {
Reg1 = getDRegFromBReg(Reg1);
Reg2 = getDRegFromBReg(Reg2);
if (Reg1 == AArch64::D8 && Reg2 == AArch64::D9 &&
(CompactUnwindEncoding & 0xE00) == 0)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D8_D9_PAIR;
else if (Reg1 == AArch64::D10 && Reg2 == AArch64::D11 &&
(CompactUnwindEncoding & 0xC00) == 0)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D10_D11_PAIR;
else if (Reg1 == AArch64::D12 && Reg2 == AArch64::D13 &&
(CompactUnwindEncoding & 0x800) == 0)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D12_D13_PAIR;
else if (Reg1 == AArch64::D14 && Reg2 == AArch64::D15)
CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D14_D15_PAIR;
else
return CU::UNWIND_ARM64_MODE_DWARF;
}
break;
}
}
}
if (!HasFP) {
if (StackSize > 65520)
return CU::UNWIND_ARM64_MODE_DWARF;
CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAMELESS;
CompactUnwindEncoding |= encodeStackAdjustment(StackSize);
}
return CompactUnwindEncoding;
}
};
}
namespace {
class ELFAArch64AsmBackend : public AArch64AsmBackend {
public:
uint8_t OSABI;
bool IsILP32;
ELFAArch64AsmBackend(const Target &T, const Triple &TT, uint8_t OSABI,
bool IsLittleEndian, bool IsILP32)
: AArch64AsmBackend(T, TT, IsLittleEndian), OSABI(OSABI),
IsILP32(IsILP32) {}
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override {
return createAArch64ELFObjectWriter(OSABI, IsILP32);
}
};
}
namespace {
class COFFAArch64AsmBackend : public AArch64AsmBackend {
public:
COFFAArch64AsmBackend(const Target &T, const Triple &TheTriple)
: AArch64AsmBackend(T, TheTriple, true) {}
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override {
return createAArch64WinCOFFObjectWriter();
}
};
}
MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options) {
const Triple &TheTriple = STI.getTargetTriple();
if (TheTriple.isOSBinFormatMachO()) {
return new DarwinAArch64AsmBackend(T, TheTriple, MRI);
}
if (TheTriple.isOSBinFormatCOFF())
return new COFFAArch64AsmBackend(T, TheTriple);
assert(TheTriple.isOSBinFormatELF() && "Invalid target");
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
return new ELFAArch64AsmBackend(T, TheTriple, OSABI, true,
IsILP32);
}
MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options) {
const Triple &TheTriple = STI.getTargetTriple();
assert(TheTriple.isOSBinFormatELF() &&
"Big endian is only supported for ELF targets!");
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
return new ELFAArch64AsmBackend(T, TheTriple, OSABI, false,
IsILP32);
}