1 //===-- AArch64AsmBackend.cpp - AArch64 Assembler Backend -----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "MCTargetDesc/AArch64FixupKinds.h"
10 #include "MCTargetDesc/AArch64MCExpr.h"
11 #include "MCTargetDesc/AArch64MCTargetDesc.h"
12 #include "Utils/AArch64BaseInfo.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/MCRegisterInfo.h"
23 #include "llvm/MC/MCSectionELF.h"
24 #include "llvm/MC/MCSectionMachO.h"
25 #include "llvm/MC/MCSubtargetInfo.h"
26 #include "llvm/MC/MCTargetOptions.h"
27 #include "llvm/MC/MCValue.h"
28 #include "llvm/MC/TargetRegistry.h"
29 #include "llvm/Support/EndianStream.h"
30 #include "llvm/Support/ErrorHandling.h"
35 class AArch64AsmBackend
: public MCAsmBackend
{
36 static const unsigned PCRelFlagVal
=
37 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits
| MCFixupKindInfo::FKF_IsPCRel
;
42 AArch64AsmBackend(const Target
&T
, const Triple
&TT
, bool IsLittleEndian
)
43 : MCAsmBackend(IsLittleEndian
? support::little
: support::big
),
46 unsigned getNumFixupKinds() const override
{
47 return AArch64::NumTargetFixupKinds
;
50 Optional
<MCFixupKind
> getFixupKind(StringRef Name
) const override
;
52 const MCFixupKindInfo
&getFixupKindInfo(MCFixupKind Kind
) const override
{
53 const static MCFixupKindInfo Infos
[AArch64::NumTargetFixupKinds
] = {
54 // This table *must* be in the order that the fixup_* kinds are defined
55 // in AArch64FixupKinds.h.
57 // Name Offset (bits) Size (bits) Flags
58 {"fixup_aarch64_pcrel_adr_imm21", 0, 32, PCRelFlagVal
},
59 {"fixup_aarch64_pcrel_adrp_imm21", 0, 32, PCRelFlagVal
},
60 {"fixup_aarch64_add_imm12", 10, 12, 0},
61 {"fixup_aarch64_ldst_imm12_scale1", 10, 12, 0},
62 {"fixup_aarch64_ldst_imm12_scale2", 10, 12, 0},
63 {"fixup_aarch64_ldst_imm12_scale4", 10, 12, 0},
64 {"fixup_aarch64_ldst_imm12_scale8", 10, 12, 0},
65 {"fixup_aarch64_ldst_imm12_scale16", 10, 12, 0},
66 {"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal
},
67 {"fixup_aarch64_movw", 5, 16, 0},
68 {"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal
},
69 {"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal
},
70 {"fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal
},
71 {"fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal
}};
73 // Fixup kinds from .reloc directive are like R_AARCH64_NONE. They do not
74 // require any extra processing.
75 if (Kind
>= FirstLiteralRelocationKind
)
76 return MCAsmBackend::getFixupKindInfo(FK_NONE
);
78 if (Kind
< FirstTargetFixupKind
)
79 return MCAsmBackend::getFixupKindInfo(Kind
);
81 assert(unsigned(Kind
- FirstTargetFixupKind
) < getNumFixupKinds() &&
83 return Infos
[Kind
- FirstTargetFixupKind
];
86 void applyFixup(const MCAssembler
&Asm
, const MCFixup
&Fixup
,
87 const MCValue
&Target
, MutableArrayRef
<char> Data
,
88 uint64_t Value
, bool IsResolved
,
89 const MCSubtargetInfo
*STI
) const override
;
91 bool fixupNeedsRelaxation(const MCFixup
&Fixup
, uint64_t Value
,
92 const MCRelaxableFragment
*DF
,
93 const MCAsmLayout
&Layout
) const override
;
94 void relaxInstruction(MCInst
&Inst
,
95 const MCSubtargetInfo
&STI
) const override
;
96 bool writeNopData(raw_ostream
&OS
, uint64_t Count
,
97 const MCSubtargetInfo
*STI
) const override
;
99 unsigned getFixupKindContainereSizeInBytes(unsigned Kind
) const;
101 bool shouldForceRelocation(const MCAssembler
&Asm
, const MCFixup
&Fixup
,
102 const MCValue
&Target
) override
;
105 } // end anonymous namespace
107 /// The number of bytes the fixup may change.
108 static unsigned getFixupKindNumBytes(unsigned Kind
) {
111 llvm_unreachable("Unknown fixup kind!");
120 case AArch64::fixup_aarch64_movw
:
121 case AArch64::fixup_aarch64_pcrel_branch14
:
122 case AArch64::fixup_aarch64_add_imm12
:
123 case AArch64::fixup_aarch64_ldst_imm12_scale1
:
124 case AArch64::fixup_aarch64_ldst_imm12_scale2
:
125 case AArch64::fixup_aarch64_ldst_imm12_scale4
:
126 case AArch64::fixup_aarch64_ldst_imm12_scale8
:
127 case AArch64::fixup_aarch64_ldst_imm12_scale16
:
128 case AArch64::fixup_aarch64_ldr_pcrel_imm19
:
129 case AArch64::fixup_aarch64_pcrel_branch19
:
132 case AArch64::fixup_aarch64_pcrel_adr_imm21
:
133 case AArch64::fixup_aarch64_pcrel_adrp_imm21
:
134 case AArch64::fixup_aarch64_pcrel_branch26
:
135 case AArch64::fixup_aarch64_pcrel_call26
:
145 static unsigned AdrImmBits(unsigned Value
) {
146 unsigned lo2
= Value
& 0x3;
147 unsigned hi19
= (Value
& 0x1ffffc) >> 2;
148 return (hi19
<< 5) | (lo2
<< 29);
151 static uint64_t adjustFixupValue(const MCFixup
&Fixup
, const MCValue
&Target
,
152 uint64_t Value
, MCContext
&Ctx
,
153 const Triple
&TheTriple
, bool IsResolved
) {
154 int64_t SignedValue
= static_cast<int64_t>(Value
);
155 switch (Fixup
.getTargetKind()) {
157 llvm_unreachable("Unknown fixup kind!");
158 case AArch64::fixup_aarch64_pcrel_adr_imm21
:
159 if (SignedValue
> 2097151 || SignedValue
< -2097152)
160 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
161 return AdrImmBits(Value
& 0x1fffffULL
);
162 case AArch64::fixup_aarch64_pcrel_adrp_imm21
:
164 if (TheTriple
.isOSBinFormatCOFF()) {
165 if (!isInt
<21>(SignedValue
))
166 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
167 return AdrImmBits(Value
& 0x1fffffULL
);
169 return AdrImmBits((Value
& 0x1fffff000ULL
) >> 12);
170 case AArch64::fixup_aarch64_ldr_pcrel_imm19
:
171 case AArch64::fixup_aarch64_pcrel_branch19
:
172 // Signed 21-bit immediate
173 if (SignedValue
> 2097151 || SignedValue
< -2097152)
174 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
176 Ctx
.reportError(Fixup
.getLoc(), "fixup not sufficiently aligned");
177 // Low two bits are not encoded.
178 return (Value
>> 2) & 0x7ffff;
179 case AArch64::fixup_aarch64_add_imm12
:
180 case AArch64::fixup_aarch64_ldst_imm12_scale1
:
181 if (TheTriple
.isOSBinFormatCOFF() && !IsResolved
)
183 // Unsigned 12-bit immediate
185 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
187 case AArch64::fixup_aarch64_ldst_imm12_scale2
:
188 if (TheTriple
.isOSBinFormatCOFF() && !IsResolved
)
190 // Unsigned 12-bit immediate which gets multiplied by 2
192 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
194 Ctx
.reportError(Fixup
.getLoc(), "fixup must be 2-byte aligned");
196 case AArch64::fixup_aarch64_ldst_imm12_scale4
:
197 if (TheTriple
.isOSBinFormatCOFF() && !IsResolved
)
199 // Unsigned 12-bit immediate which gets multiplied by 4
201 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
203 Ctx
.reportError(Fixup
.getLoc(), "fixup must be 4-byte aligned");
205 case AArch64::fixup_aarch64_ldst_imm12_scale8
:
206 if (TheTriple
.isOSBinFormatCOFF() && !IsResolved
)
208 // Unsigned 12-bit immediate which gets multiplied by 8
210 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
212 Ctx
.reportError(Fixup
.getLoc(), "fixup must be 8-byte aligned");
214 case AArch64::fixup_aarch64_ldst_imm12_scale16
:
215 if (TheTriple
.isOSBinFormatCOFF() && !IsResolved
)
217 // Unsigned 12-bit immediate which gets multiplied by 16
218 if (Value
>= 0x10000)
219 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
221 Ctx
.reportError(Fixup
.getLoc(), "fixup must be 16-byte aligned");
223 case AArch64::fixup_aarch64_movw
: {
224 AArch64MCExpr::VariantKind RefKind
=
225 static_cast<AArch64MCExpr::VariantKind
>(Target
.getRefKind());
226 if (AArch64MCExpr::getSymbolLoc(RefKind
) != AArch64MCExpr::VK_ABS
&&
227 AArch64MCExpr::getSymbolLoc(RefKind
) != AArch64MCExpr::VK_SABS
) {
229 // The fixup is an expression
230 if (SignedValue
> 0xFFFF || SignedValue
< -0xFFFF)
231 Ctx
.reportError(Fixup
.getLoc(),
232 "fixup value out of range [-0xFFFF, 0xFFFF]");
234 // Invert the negative immediate because it will feed into a MOVN.
236 SignedValue
= ~SignedValue
;
237 Value
= static_cast<uint64_t>(SignedValue
);
239 // VK_GOTTPREL, VK_TPREL, VK_DTPREL are movw fixups, but they can't
240 // ever be resolved in the assembler.
241 Ctx
.reportError(Fixup
.getLoc(),
242 "relocation for a thread-local variable points to an "
248 // FIXME: Figure out when this can actually happen, and verify our
250 Ctx
.reportError(Fixup
.getLoc(), "unresolved movw fixup not yet "
255 if (AArch64MCExpr::getSymbolLoc(RefKind
) == AArch64MCExpr::VK_SABS
) {
256 switch (AArch64MCExpr::getAddressFrag(RefKind
)) {
257 case AArch64MCExpr::VK_G0
:
259 case AArch64MCExpr::VK_G1
:
260 SignedValue
= SignedValue
>> 16;
262 case AArch64MCExpr::VK_G2
:
263 SignedValue
= SignedValue
>> 32;
265 case AArch64MCExpr::VK_G3
:
266 SignedValue
= SignedValue
>> 48;
269 llvm_unreachable("Variant kind doesn't correspond to fixup");
273 switch (AArch64MCExpr::getAddressFrag(RefKind
)) {
274 case AArch64MCExpr::VK_G0
:
276 case AArch64MCExpr::VK_G1
:
279 case AArch64MCExpr::VK_G2
:
282 case AArch64MCExpr::VK_G3
:
286 llvm_unreachable("Variant kind doesn't correspond to fixup");
290 if (RefKind
& AArch64MCExpr::VK_NC
) {
293 else if (AArch64MCExpr::getSymbolLoc(RefKind
) == AArch64MCExpr::VK_SABS
) {
294 if (SignedValue
> 0xFFFF || SignedValue
< -0xFFFF)
295 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
297 // Invert the negative immediate because it will feed into a MOVN.
299 SignedValue
= ~SignedValue
;
300 Value
= static_cast<uint64_t>(SignedValue
);
302 else if (Value
> 0xFFFF) {
303 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
307 case AArch64::fixup_aarch64_pcrel_branch14
:
308 // Signed 16-bit immediate
309 if (SignedValue
> 32767 || SignedValue
< -32768)
310 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
311 // Low two bits are not encoded (4-byte alignment assumed).
313 Ctx
.reportError(Fixup
.getLoc(), "fixup not sufficiently aligned");
314 return (Value
>> 2) & 0x3fff;
315 case AArch64::fixup_aarch64_pcrel_branch26
:
316 case AArch64::fixup_aarch64_pcrel_call26
:
317 // Signed 28-bit immediate
318 if (SignedValue
> 134217727 || SignedValue
< -134217728)
319 Ctx
.reportError(Fixup
.getLoc(), "fixup value out of range");
320 // Low two bits are not encoded (4-byte alignment assumed).
322 Ctx
.reportError(Fixup
.getLoc(), "fixup not sufficiently aligned");
323 return (Value
>> 2) & 0x3ffffff;
334 Optional
<MCFixupKind
> AArch64AsmBackend::getFixupKind(StringRef Name
) const {
335 if (!TheTriple
.isOSBinFormatELF())
338 unsigned Type
= llvm::StringSwitch
<unsigned>(Name
)
339 #define ELF_RELOC(X, Y) .Case(#X, Y)
340 #include "llvm/BinaryFormat/ELFRelocs/AArch64.def"
342 .Case("BFD_RELOC_NONE", ELF::R_AARCH64_NONE
)
343 .Case("BFD_RELOC_16", ELF::R_AARCH64_ABS16
)
344 .Case("BFD_RELOC_32", ELF::R_AARCH64_ABS32
)
345 .Case("BFD_RELOC_64", ELF::R_AARCH64_ABS64
)
349 return static_cast<MCFixupKind
>(FirstLiteralRelocationKind
+ Type
);
352 /// getFixupKindContainereSizeInBytes - The number of bytes of the
353 /// container involved in big endian or 0 if the item is little endian
354 unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind
) const {
355 if (Endian
== support::little
)
360 llvm_unreachable("Unknown fixup kind!");
371 case AArch64::fixup_aarch64_movw
:
372 case AArch64::fixup_aarch64_pcrel_branch14
:
373 case AArch64::fixup_aarch64_add_imm12
:
374 case AArch64::fixup_aarch64_ldst_imm12_scale1
:
375 case AArch64::fixup_aarch64_ldst_imm12_scale2
:
376 case AArch64::fixup_aarch64_ldst_imm12_scale4
:
377 case AArch64::fixup_aarch64_ldst_imm12_scale8
:
378 case AArch64::fixup_aarch64_ldst_imm12_scale16
:
379 case AArch64::fixup_aarch64_ldr_pcrel_imm19
:
380 case AArch64::fixup_aarch64_pcrel_branch19
:
381 case AArch64::fixup_aarch64_pcrel_adr_imm21
:
382 case AArch64::fixup_aarch64_pcrel_adrp_imm21
:
383 case AArch64::fixup_aarch64_pcrel_branch26
:
384 case AArch64::fixup_aarch64_pcrel_call26
:
385 // Instructions are always little endian
390 void AArch64AsmBackend::applyFixup(const MCAssembler
&Asm
, const MCFixup
&Fixup
,
391 const MCValue
&Target
,
392 MutableArrayRef
<char> Data
, uint64_t Value
,
394 const MCSubtargetInfo
*STI
) const {
396 return; // Doesn't change encoding.
397 unsigned Kind
= Fixup
.getKind();
398 if (Kind
>= FirstLiteralRelocationKind
)
400 unsigned NumBytes
= getFixupKindNumBytes(Kind
);
401 MCFixupKindInfo Info
= getFixupKindInfo(Fixup
.getKind());
402 MCContext
&Ctx
= Asm
.getContext();
403 int64_t SignedValue
= static_cast<int64_t>(Value
);
404 // Apply any target-specific value adjustments.
405 Value
= adjustFixupValue(Fixup
, Target
, Value
, Ctx
, TheTriple
, IsResolved
);
407 // Shift the value into position.
408 Value
<<= Info
.TargetOffset
;
410 unsigned Offset
= Fixup
.getOffset();
411 assert(Offset
+ NumBytes
<= Data
.size() && "Invalid fixup offset!");
413 // Used to point to big endian bytes.
414 unsigned FulleSizeInBytes
= getFixupKindContainereSizeInBytes(Fixup
.getKind());
416 // For each byte of the fragment that the fixup touches, mask in the
417 // bits from the fixup value.
418 if (FulleSizeInBytes
== 0) {
419 // Handle as little-endian
420 for (unsigned i
= 0; i
!= NumBytes
; ++i
) {
421 Data
[Offset
+ i
] |= uint8_t((Value
>> (i
* 8)) & 0xff);
424 // Handle as big-endian
425 assert((Offset
+ FulleSizeInBytes
) <= Data
.size() && "Invalid fixup size!");
426 assert(NumBytes
<= FulleSizeInBytes
&& "Invalid fixup size!");
427 for (unsigned i
= 0; i
!= NumBytes
; ++i
) {
428 unsigned Idx
= FulleSizeInBytes
- 1 - i
;
429 Data
[Offset
+ Idx
] |= uint8_t((Value
>> (i
* 8)) & 0xff);
433 // FIXME: getFixupKindInfo() and getFixupKindNumBytes() could be fixed to
434 // handle this more cleanly. This may affect the output of -show-mc-encoding.
435 AArch64MCExpr::VariantKind RefKind
=
436 static_cast<AArch64MCExpr::VariantKind
>(Target
.getRefKind());
437 if (AArch64MCExpr::getSymbolLoc(RefKind
) == AArch64MCExpr::VK_SABS
||
438 (!RefKind
&& Fixup
.getTargetKind() == AArch64::fixup_aarch64_movw
)) {
439 // If the immediate is negative, generate MOVN else MOVZ.
440 // (Bit 30 = 0) ==> MOVN, (Bit 30 = 1) ==> MOVZ.
442 Data
[Offset
+ 3] &= ~(1 << 6);
444 Data
[Offset
+ 3] |= (1 << 6);
448 bool AArch64AsmBackend::fixupNeedsRelaxation(const MCFixup
&Fixup
,
450 const MCRelaxableFragment
*DF
,
451 const MCAsmLayout
&Layout
) const {
452 // FIXME: This isn't correct for AArch64. Just moving the "generic" logic
453 // into the targets for now.
455 // Relax if the value is too big for a (signed) i8.
456 return int64_t(Value
) != int64_t(int8_t(Value
));
459 void AArch64AsmBackend::relaxInstruction(MCInst
&Inst
,
460 const MCSubtargetInfo
&STI
) const {
461 llvm_unreachable("AArch64AsmBackend::relaxInstruction() unimplemented");
464 bool AArch64AsmBackend::writeNopData(raw_ostream
&OS
, uint64_t Count
,
465 const MCSubtargetInfo
*STI
) const {
466 // If the count is not 4-byte aligned, we must be writing data into the text
467 // section (otherwise we have unaligned instructions, and thus have far
468 // bigger problems), so just write zeros instead.
469 OS
.write_zeros(Count
% 4);
471 // We are properly aligned, so write NOPs as requested.
473 for (uint64_t i
= 0; i
!= Count
; ++i
)
474 support::endian::write
<uint32_t>(OS
, 0xd503201f, Endian
);
478 bool AArch64AsmBackend::shouldForceRelocation(const MCAssembler
&Asm
,
479 const MCFixup
&Fixup
,
480 const MCValue
&Target
) {
481 unsigned Kind
= Fixup
.getKind();
482 if (Kind
>= FirstLiteralRelocationKind
)
485 // The ADRP instruction adds some multiple of 0x1000 to the current PC &
486 // ~0xfff. This means that the required offset to reach a symbol can vary by
487 // up to one step depending on where the ADRP is in memory. For example:
492 // If the ADRP occurs at address 0xffc then "there" will be at 0x1000 and
493 // we'll need that as an offset. At any other address "there" will be in the
494 // same page as the ADRP and the instruction should encode 0x0. Assuming the
495 // section isn't 0x1000-aligned, we therefore need to delegate this decision
496 // to the linker -- a relocation!
497 if (Kind
== AArch64::fixup_aarch64_pcrel_adrp_imm21
)
507 /// Compact unwind encoding values.
508 enum CompactUnwindEncodings
{
509 /// A "frameless" leaf function, where no non-volatile registers are
510 /// saved. The return remains in LR throughout the function.
511 UNWIND_ARM64_MODE_FRAMELESS
= 0x02000000,
513 /// No compact unwind encoding available. Instead the low 23-bits of
514 /// the compact unwind encoding is the offset of the DWARF FDE in the
515 /// __eh_frame section. This mode is never used in object files. It is only
516 /// generated by the linker in final linked images, which have only DWARF info
518 UNWIND_ARM64_MODE_DWARF
= 0x03000000,
520 /// This is a standard arm64 prologue where FP/LR are immediately
521 /// pushed on the stack, then SP is copied to FP. If there are any
522 /// non-volatile register saved, they are copied into the stack fame in pairs
523 /// in a contiguous ranger right below the saved FP/LR pair. Any subset of the
524 /// five X pairs and four D pairs can be saved, but the memory layout must be
525 /// in register number order.
526 UNWIND_ARM64_MODE_FRAME
= 0x04000000,
528 /// Frame register pair encodings.
529 UNWIND_ARM64_FRAME_X19_X20_PAIR
= 0x00000001,
530 UNWIND_ARM64_FRAME_X21_X22_PAIR
= 0x00000002,
531 UNWIND_ARM64_FRAME_X23_X24_PAIR
= 0x00000004,
532 UNWIND_ARM64_FRAME_X25_X26_PAIR
= 0x00000008,
533 UNWIND_ARM64_FRAME_X27_X28_PAIR
= 0x00000010,
534 UNWIND_ARM64_FRAME_D8_D9_PAIR
= 0x00000100,
535 UNWIND_ARM64_FRAME_D10_D11_PAIR
= 0x00000200,
536 UNWIND_ARM64_FRAME_D12_D13_PAIR
= 0x00000400,
537 UNWIND_ARM64_FRAME_D14_D15_PAIR
= 0x00000800
540 } // end CU namespace
542 // FIXME: This should be in a separate file.
543 class DarwinAArch64AsmBackend
: public AArch64AsmBackend
{
544 const MCRegisterInfo
&MRI
;
546 /// Encode compact unwind stack adjustment for frameless functions.
547 /// See UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK in compact_unwind_encoding.h.
548 /// The stack size always needs to be 16 byte aligned.
549 uint32_t encodeStackAdjustment(uint32_t StackSize
) const {
550 return (StackSize
/ 16) << 12;
554 DarwinAArch64AsmBackend(const Target
&T
, const Triple
&TT
,
555 const MCRegisterInfo
&MRI
)
556 : AArch64AsmBackend(T
, TT
, /*IsLittleEndian*/ true), MRI(MRI
) {}
558 std::unique_ptr
<MCObjectTargetWriter
>
559 createObjectTargetWriter() const override
{
560 uint32_t CPUType
= cantFail(MachO::getCPUType(TheTriple
));
561 uint32_t CPUSubType
= cantFail(MachO::getCPUSubType(TheTriple
));
562 return createAArch64MachObjectWriter(CPUType
, CPUSubType
,
563 TheTriple
.isArch32Bit());
566 /// Generate the compact unwind encoding from the CFI directives.
567 uint32_t generateCompactUnwindEncoding(
568 ArrayRef
<MCCFIInstruction
> Instrs
) const override
{
570 return CU::UNWIND_ARM64_MODE_FRAMELESS
;
573 unsigned StackSize
= 0;
575 uint32_t CompactUnwindEncoding
= 0;
577 for (size_t i
= 0, e
= Instrs
.size(); i
!= e
; ++i
) {
578 const MCCFIInstruction
&Inst
= Instrs
[i
];
580 switch (Inst
.getOperation()) {
582 // Cannot handle this directive: bail out.
583 return CU::UNWIND_ARM64_MODE_DWARF
;
584 case MCCFIInstruction::OpDefCfa
: {
585 // Defines a frame pointer.
587 getXRegFromWReg(*MRI
.getLLVMRegNum(Inst
.getRegister(), true));
589 // Other CFA registers than FP are not supported by compact unwind.
590 // Fallback on DWARF.
591 // FIXME: When opt-remarks are supported in MC, add a remark to notify
593 if (XReg
!= AArch64::FP
)
594 return CU::UNWIND_ARM64_MODE_DWARF
;
596 assert(XReg
== AArch64::FP
&& "Invalid frame pointer!");
597 assert(i
+ 2 < e
&& "Insufficient CFI instructions to define a frame!");
599 const MCCFIInstruction
&LRPush
= Instrs
[++i
];
600 assert(LRPush
.getOperation() == MCCFIInstruction::OpOffset
&&
601 "Link register not pushed!");
602 const MCCFIInstruction
&FPPush
= Instrs
[++i
];
603 assert(FPPush
.getOperation() == MCCFIInstruction::OpOffset
&&
604 "Frame pointer not pushed!");
606 assert(FPPush
.getOffset() + 8 == LRPush
.getOffset());
607 CurOffset
= FPPush
.getOffset();
609 unsigned LRReg
= *MRI
.getLLVMRegNum(LRPush
.getRegister(), true);
610 unsigned FPReg
= *MRI
.getLLVMRegNum(FPPush
.getRegister(), true);
612 LRReg
= getXRegFromWReg(LRReg
);
613 FPReg
= getXRegFromWReg(FPReg
);
615 assert(LRReg
== AArch64::LR
&& FPReg
== AArch64::FP
&&
616 "Pushing invalid registers for frame!");
618 // Indicate that the function has a frame.
619 CompactUnwindEncoding
|= CU::UNWIND_ARM64_MODE_FRAME
;
623 case MCCFIInstruction::OpDefCfaOffset
: {
625 return CU::UNWIND_ARM64_MODE_DWARF
;
626 StackSize
= std::abs(Inst
.getOffset());
629 case MCCFIInstruction::OpOffset
: {
630 // Registers are saved in pairs. We expect there to be two consecutive
631 // `.cfi_offset' instructions with the appropriate registers specified.
632 unsigned Reg1
= *MRI
.getLLVMRegNum(Inst
.getRegister(), true);
634 return CU::UNWIND_ARM64_MODE_DWARF
;
636 if (CurOffset
!= 0 && Inst
.getOffset() != CurOffset
- 8)
637 return CU::UNWIND_ARM64_MODE_DWARF
;
638 CurOffset
= Inst
.getOffset();
640 const MCCFIInstruction
&Inst2
= Instrs
[++i
];
641 if (Inst2
.getOperation() != MCCFIInstruction::OpOffset
)
642 return CU::UNWIND_ARM64_MODE_DWARF
;
643 unsigned Reg2
= *MRI
.getLLVMRegNum(Inst2
.getRegister(), true);
645 if (Inst2
.getOffset() != CurOffset
- 8)
646 return CU::UNWIND_ARM64_MODE_DWARF
;
647 CurOffset
= Inst2
.getOffset();
649 // N.B. The encodings must be in register number order, and the X
650 // registers before the D registers.
652 // X19/X20 pair = 0x00000001,
653 // X21/X22 pair = 0x00000002,
654 // X23/X24 pair = 0x00000004,
655 // X25/X26 pair = 0x00000008,
656 // X27/X28 pair = 0x00000010
657 Reg1
= getXRegFromWReg(Reg1
);
658 Reg2
= getXRegFromWReg(Reg2
);
660 if (Reg1
== AArch64::X19
&& Reg2
== AArch64::X20
&&
661 (CompactUnwindEncoding
& 0xF1E) == 0)
662 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_X19_X20_PAIR
;
663 else if (Reg1
== AArch64::X21
&& Reg2
== AArch64::X22
&&
664 (CompactUnwindEncoding
& 0xF1C) == 0)
665 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_X21_X22_PAIR
;
666 else if (Reg1
== AArch64::X23
&& Reg2
== AArch64::X24
&&
667 (CompactUnwindEncoding
& 0xF18) == 0)
668 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_X23_X24_PAIR
;
669 else if (Reg1
== AArch64::X25
&& Reg2
== AArch64::X26
&&
670 (CompactUnwindEncoding
& 0xF10) == 0)
671 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_X25_X26_PAIR
;
672 else if (Reg1
== AArch64::X27
&& Reg2
== AArch64::X28
&&
673 (CompactUnwindEncoding
& 0xF00) == 0)
674 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_X27_X28_PAIR
;
676 Reg1
= getDRegFromBReg(Reg1
);
677 Reg2
= getDRegFromBReg(Reg2
);
679 // D8/D9 pair = 0x00000100,
680 // D10/D11 pair = 0x00000200,
681 // D12/D13 pair = 0x00000400,
682 // D14/D15 pair = 0x00000800
683 if (Reg1
== AArch64::D8
&& Reg2
== AArch64::D9
&&
684 (CompactUnwindEncoding
& 0xE00) == 0)
685 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_D8_D9_PAIR
;
686 else if (Reg1
== AArch64::D10
&& Reg2
== AArch64::D11
&&
687 (CompactUnwindEncoding
& 0xC00) == 0)
688 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_D10_D11_PAIR
;
689 else if (Reg1
== AArch64::D12
&& Reg2
== AArch64::D13
&&
690 (CompactUnwindEncoding
& 0x800) == 0)
691 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_D12_D13_PAIR
;
692 else if (Reg1
== AArch64::D14
&& Reg2
== AArch64::D15
)
693 CompactUnwindEncoding
|= CU::UNWIND_ARM64_FRAME_D14_D15_PAIR
;
695 // A pair was pushed which we cannot handle.
696 return CU::UNWIND_ARM64_MODE_DWARF
;
705 // With compact unwind info we can only represent stack adjustments of up
707 if (StackSize
> 65520)
708 return CU::UNWIND_ARM64_MODE_DWARF
;
710 CompactUnwindEncoding
|= CU::UNWIND_ARM64_MODE_FRAMELESS
;
711 CompactUnwindEncoding
|= encodeStackAdjustment(StackSize
);
714 return CompactUnwindEncoding
;
718 } // end anonymous namespace
722 class ELFAArch64AsmBackend
: public AArch64AsmBackend
{
727 ELFAArch64AsmBackend(const Target
&T
, const Triple
&TT
, uint8_t OSABI
,
728 bool IsLittleEndian
, bool IsILP32
)
729 : AArch64AsmBackend(T
, TT
, IsLittleEndian
), OSABI(OSABI
),
732 std::unique_ptr
<MCObjectTargetWriter
>
733 createObjectTargetWriter() const override
{
734 return createAArch64ELFObjectWriter(OSABI
, IsILP32
);
741 class COFFAArch64AsmBackend
: public AArch64AsmBackend
{
743 COFFAArch64AsmBackend(const Target
&T
, const Triple
&TheTriple
)
744 : AArch64AsmBackend(T
, TheTriple
, /*IsLittleEndian*/ true) {}
746 std::unique_ptr
<MCObjectTargetWriter
>
747 createObjectTargetWriter() const override
{
748 return createAArch64WinCOFFObjectWriter();
753 MCAsmBackend
*llvm::createAArch64leAsmBackend(const Target
&T
,
754 const MCSubtargetInfo
&STI
,
755 const MCRegisterInfo
&MRI
,
756 const MCTargetOptions
&Options
) {
757 const Triple
&TheTriple
= STI
.getTargetTriple();
758 if (TheTriple
.isOSBinFormatMachO()) {
759 return new DarwinAArch64AsmBackend(T
, TheTriple
, MRI
);
762 if (TheTriple
.isOSBinFormatCOFF())
763 return new COFFAArch64AsmBackend(T
, TheTriple
);
765 assert(TheTriple
.isOSBinFormatELF() && "Invalid target");
767 uint8_t OSABI
= MCELFObjectTargetWriter::getOSABI(TheTriple
.getOS());
768 bool IsILP32
= STI
.getTargetTriple().getEnvironment() == Triple::GNUILP32
;
769 return new ELFAArch64AsmBackend(T
, TheTriple
, OSABI
, /*IsLittleEndian=*/true,
773 MCAsmBackend
*llvm::createAArch64beAsmBackend(const Target
&T
,
774 const MCSubtargetInfo
&STI
,
775 const MCRegisterInfo
&MRI
,
776 const MCTargetOptions
&Options
) {
777 const Triple
&TheTriple
= STI
.getTargetTriple();
778 assert(TheTriple
.isOSBinFormatELF() &&
779 "Big endian is only supported for ELF targets!");
780 uint8_t OSABI
= MCELFObjectTargetWriter::getOSABI(TheTriple
.getOS());
781 bool IsILP32
= STI
.getTargetTriple().getEnvironment() == Triple::GNUILP32
;
782 return new ELFAArch64AsmBackend(T
, TheTriple
, OSABI
, /*IsLittleEndian=*/false,