xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp (revision d686ce931cab72612a9e1ada9fe99d65e11a32a3)
10b57cec5SDimitry Andric //===-- AVRAsmBackend.cpp - AVR Asm 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 // This file implements the AVRAsmBackend class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "MCTargetDesc/AVRAsmBackend.h"
140b57cec5SDimitry Andric #include "MCTargetDesc/AVRFixupKinds.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/AVRMCTargetDesc.h"
160fca6ea1SDimitry Andric #include "llvm/ADT/StringSwitch.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCDirectives.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h"
22e8d8bef9SDimitry Andric #include "llvm/MC/MCExpr.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
260b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
270b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
280b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
290b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric // FIXME: we should be doing checks to make sure asm operands
320b57cec5SDimitry Andric // are not out of bounds.
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric namespace adjust {
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric using namespace llvm;
370b57cec5SDimitry Andric 
385ffd83dbSDimitry Andric static void signed_width(unsigned Width, uint64_t Value,
395ffd83dbSDimitry Andric                          std::string Description, const MCFixup &Fixup,
405ffd83dbSDimitry Andric                          MCContext *Ctx = nullptr) {
410b57cec5SDimitry Andric   if (!isIntN(Width, Value)) {
420b57cec5SDimitry Andric     std::string Diagnostic = "out of range " + Description;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric     int64_t Min = minIntN(Width);
450b57cec5SDimitry Andric     int64_t Max = maxIntN(Width);
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric     Diagnostic += " (expected an integer in the range " + std::to_string(Min) +
480b57cec5SDimitry Andric                   " to " + std::to_string(Max) + ")";
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric     if (Ctx) {
5104eeddc0SDimitry Andric       Ctx->reportError(Fixup.getLoc(), Diagnostic);
520b57cec5SDimitry Andric     } else {
530b57cec5SDimitry Andric       llvm_unreachable(Diagnostic.c_str());
540b57cec5SDimitry Andric     }
550b57cec5SDimitry Andric   }
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
585ffd83dbSDimitry Andric static void unsigned_width(unsigned Width, uint64_t Value,
595ffd83dbSDimitry Andric                            std::string Description, const MCFixup &Fixup,
605ffd83dbSDimitry Andric                            MCContext *Ctx = nullptr) {
610b57cec5SDimitry Andric   if (!isUIntN(Width, Value)) {
620b57cec5SDimitry Andric     std::string Diagnostic = "out of range " + Description;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric     int64_t Max = maxUIntN(Width);
650b57cec5SDimitry Andric 
66349cc55cSDimitry Andric     Diagnostic +=
67349cc55cSDimitry Andric         " (expected an integer in the range 0 to " + std::to_string(Max) + ")";
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric     if (Ctx) {
7004eeddc0SDimitry Andric       Ctx->reportError(Fixup.getLoc(), Diagnostic);
710b57cec5SDimitry Andric     } else {
720b57cec5SDimitry Andric       llvm_unreachable(Diagnostic.c_str());
730b57cec5SDimitry Andric     }
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric /// Adjusts the value of a branch target before fixup application.
785ffd83dbSDimitry Andric static void adjustBranch(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
790b57cec5SDimitry Andric                          MCContext *Ctx = nullptr) {
800b57cec5SDimitry Andric   // We have one extra bit of precision because the value is rightshifted by
810b57cec5SDimitry Andric   // one.
820b57cec5SDimitry Andric   unsigned_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   // Rightshifts the value by one.
850b57cec5SDimitry Andric   AVR::fixups::adjustBranchTarget(Value);
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric /// Adjusts the value of a relative branch target before fixup application.
895ffd83dbSDimitry Andric static void adjustRelativeBranch(unsigned Size, const MCFixup &Fixup,
905ffd83dbSDimitry Andric                                  uint64_t &Value, MCContext *Ctx = nullptr) {
91*d686ce93SDimitry Andric   // Jumps are relative to the current instruction.
92*d686ce93SDimitry Andric   Value -= 2;
93*d686ce93SDimitry Andric 
940b57cec5SDimitry Andric   // We have one extra bit of precision because the value is rightshifted by
950b57cec5SDimitry Andric   // one.
960b57cec5SDimitry Andric   signed_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   // Rightshifts the value by one.
990b57cec5SDimitry Andric   AVR::fixups::adjustBranchTarget(Value);
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric /// 22-bit absolute fixup.
1030b57cec5SDimitry Andric ///
1040b57cec5SDimitry Andric /// Resolves to:
1050b57cec5SDimitry Andric /// 1001 kkkk 010k kkkk kkkk kkkk 111k kkkk
1060b57cec5SDimitry Andric ///
1070b57cec5SDimitry Andric /// Offset of 0 (so the result is left shifted by 3 bits before application).
1085ffd83dbSDimitry Andric static void fixup_call(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
1090b57cec5SDimitry Andric                        MCContext *Ctx = nullptr) {
1100b57cec5SDimitry Andric   adjustBranch(Size, Fixup, Value, Ctx);
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   auto top = Value & (0xf00000 << 6);   // the top four bits
1130b57cec5SDimitry Andric   auto middle = Value & (0x1ffff << 5); // the middle 13 bits
1140b57cec5SDimitry Andric   auto bottom = Value & 0x1f;           // end bottom 5 bits
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   Value = (top << 6) | (middle << 3) | (bottom << 0);
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric /// 7-bit PC-relative fixup.
1200b57cec5SDimitry Andric ///
1210b57cec5SDimitry Andric /// Resolves to:
1220b57cec5SDimitry Andric /// 0000 00kk kkkk k000
1230b57cec5SDimitry Andric /// Offset of 0 (so the result is left shifted by 3 bits before application).
1245ffd83dbSDimitry Andric static void fixup_7_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
1250b57cec5SDimitry Andric                           MCContext *Ctx = nullptr) {
1260b57cec5SDimitry Andric   adjustRelativeBranch(Size, Fixup, Value, Ctx);
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   // Because the value may be negative, we must mask out the sign bits
1290b57cec5SDimitry Andric   Value &= 0x7f;
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric /// 12-bit PC-relative fixup.
1330b57cec5SDimitry Andric /// Yes, the fixup is 12 bits even though the name says otherwise.
1340b57cec5SDimitry Andric ///
1350b57cec5SDimitry Andric /// Resolves to:
1360b57cec5SDimitry Andric /// 0000 kkkk kkkk kkkk
1370b57cec5SDimitry Andric /// Offset of 0 (so the result isn't left-shifted before application).
1385ffd83dbSDimitry Andric static void fixup_13_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
1390b57cec5SDimitry Andric                            MCContext *Ctx = nullptr) {
1400b57cec5SDimitry Andric   adjustRelativeBranch(Size, Fixup, Value, Ctx);
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   // Because the value may be negative, we must mask out the sign bits
1430b57cec5SDimitry Andric   Value &= 0xfff;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
1465ffd83dbSDimitry Andric /// 6-bit fixup for the immediate operand of the STD/LDD family of
1475ffd83dbSDimitry Andric /// instructions.
1485ffd83dbSDimitry Andric ///
1495ffd83dbSDimitry Andric /// Resolves to:
1505ffd83dbSDimitry Andric /// 10q0 qq10 0000 1qqq
1515ffd83dbSDimitry Andric static void fixup_6(const MCFixup &Fixup, uint64_t &Value,
1525ffd83dbSDimitry Andric                     MCContext *Ctx = nullptr) {
1535ffd83dbSDimitry Andric   unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
1545ffd83dbSDimitry Andric 
1555ffd83dbSDimitry Andric   Value = ((Value & 0x20) << 8) | ((Value & 0x18) << 7) | (Value & 0x07);
1565ffd83dbSDimitry Andric }
1575ffd83dbSDimitry Andric 
1580b57cec5SDimitry Andric /// 6-bit fixup for the immediate operand of the ADIW family of
1590b57cec5SDimitry Andric /// instructions.
1600b57cec5SDimitry Andric ///
1610b57cec5SDimitry Andric /// Resolves to:
1620b57cec5SDimitry Andric /// 0000 0000 kk00 kkkk
1635ffd83dbSDimitry Andric static void fixup_6_adiw(const MCFixup &Fixup, uint64_t &Value,
1640b57cec5SDimitry Andric                          MCContext *Ctx = nullptr) {
1650b57cec5SDimitry Andric   unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   Value = ((Value & 0x30) << 2) | (Value & 0x0f);
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric /// 5-bit port number fixup on the SBIC family of instructions.
1710b57cec5SDimitry Andric ///
1720b57cec5SDimitry Andric /// Resolves to:
1730b57cec5SDimitry Andric /// 0000 0000 AAAA A000
1745ffd83dbSDimitry Andric static void fixup_port5(const MCFixup &Fixup, uint64_t &Value,
1750b57cec5SDimitry Andric                         MCContext *Ctx = nullptr) {
1760b57cec5SDimitry Andric   unsigned_width(5, Value, std::string("port number"), Fixup, Ctx);
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   Value &= 0x1f;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   Value <<= 3;
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric /// 6-bit port number fixup on the `IN` family of instructions.
1840b57cec5SDimitry Andric ///
1850b57cec5SDimitry Andric /// Resolves to:
1860b57cec5SDimitry Andric /// 1011 0AAd dddd AAAA
1875ffd83dbSDimitry Andric static void fixup_port6(const MCFixup &Fixup, uint64_t &Value,
1880b57cec5SDimitry Andric                         MCContext *Ctx = nullptr) {
1890b57cec5SDimitry Andric   unsigned_width(6, Value, std::string("port number"), Fixup, Ctx);
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   Value = ((Value & 0x30) << 5) | (Value & 0x0f);
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric 
194bdd1243dSDimitry Andric /// 7-bit data space address fixup for the LDS/STS instructions on AVRTiny.
195bdd1243dSDimitry Andric ///
196bdd1243dSDimitry Andric /// Resolves to:
197bdd1243dSDimitry Andric /// 1010 ikkk dddd kkkk
198bdd1243dSDimitry Andric static void fixup_lds_sts_16(const MCFixup &Fixup, uint64_t &Value,
199bdd1243dSDimitry Andric                              MCContext *Ctx = nullptr) {
200bdd1243dSDimitry Andric   unsigned_width(7, Value, std::string("immediate"), Fixup, Ctx);
201bdd1243dSDimitry Andric   Value = ((Value & 0x70) << 8) | (Value & 0x0f);
202bdd1243dSDimitry Andric }
203bdd1243dSDimitry Andric 
2040b57cec5SDimitry Andric /// Adjusts a program memory address.
2050b57cec5SDimitry Andric /// This is a simple right-shift.
2065ffd83dbSDimitry Andric static void pm(uint64_t &Value) { Value >>= 1; }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric /// Fixups relating to the LDI instruction.
2090b57cec5SDimitry Andric namespace ldi {
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric /// Adjusts a value to fix up the immediate of an `LDI Rd, K` instruction.
2120b57cec5SDimitry Andric ///
2130b57cec5SDimitry Andric /// Resolves to:
2140b57cec5SDimitry Andric /// 0000 KKKK 0000 KKKK
2150b57cec5SDimitry Andric /// Offset of 0 (so the result isn't left-shifted before application).
2165ffd83dbSDimitry Andric static void fixup(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
2170b57cec5SDimitry Andric                   MCContext *Ctx = nullptr) {
2180b57cec5SDimitry Andric   uint64_t upper = Value & 0xf0;
2190b57cec5SDimitry Andric   uint64_t lower = Value & 0x0f;
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   Value = (upper << 4) | lower;
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
2245ffd83dbSDimitry Andric static void neg(uint64_t &Value) { Value *= -1; }
2250b57cec5SDimitry Andric 
2265ffd83dbSDimitry Andric static void lo8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
2270b57cec5SDimitry Andric                 MCContext *Ctx = nullptr) {
2280b57cec5SDimitry Andric   Value &= 0xff;
2290b57cec5SDimitry Andric   ldi::fixup(Size, Fixup, Value, Ctx);
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric 
2325ffd83dbSDimitry Andric static void hi8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
2330b57cec5SDimitry Andric                 MCContext *Ctx = nullptr) {
2340b57cec5SDimitry Andric   Value = (Value & 0xff00) >> 8;
2350b57cec5SDimitry Andric   ldi::fixup(Size, Fixup, Value, Ctx);
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric 
2385ffd83dbSDimitry Andric static void hh8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
2390b57cec5SDimitry Andric                 MCContext *Ctx = nullptr) {
2400b57cec5SDimitry Andric   Value = (Value & 0xff0000) >> 16;
2410b57cec5SDimitry Andric   ldi::fixup(Size, Fixup, Value, Ctx);
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric 
2445ffd83dbSDimitry Andric static void ms8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
2450b57cec5SDimitry Andric                 MCContext *Ctx = nullptr) {
2460b57cec5SDimitry Andric   Value = (Value & 0xff000000) >> 24;
2470b57cec5SDimitry Andric   ldi::fixup(Size, Fixup, Value, Ctx);
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric 
250349cc55cSDimitry Andric } // namespace ldi
251349cc55cSDimitry Andric } // namespace adjust
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric namespace llvm {
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric // Prepare value for the target space for it
2560b57cec5SDimitry Andric void AVRAsmBackend::adjustFixupValue(const MCFixup &Fixup,
257349cc55cSDimitry Andric                                      const MCValue &Target, uint64_t &Value,
2580b57cec5SDimitry Andric                                      MCContext *Ctx) const {
2590b57cec5SDimitry Andric   // The size of the fixup in bits.
2600b57cec5SDimitry Andric   uint64_t Size = AVRAsmBackend::getFixupKindInfo(Fixup.getKind()).TargetSize;
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   unsigned Kind = Fixup.getKind();
2630b57cec5SDimitry Andric   switch (Kind) {
2640b57cec5SDimitry Andric   default:
2650b57cec5SDimitry Andric     llvm_unreachable("unhandled fixup");
2660b57cec5SDimitry Andric   case AVR::fixup_7_pcrel:
2670b57cec5SDimitry Andric     adjust::fixup_7_pcrel(Size, Fixup, Value, Ctx);
2680b57cec5SDimitry Andric     break;
2690b57cec5SDimitry Andric   case AVR::fixup_13_pcrel:
2700b57cec5SDimitry Andric     adjust::fixup_13_pcrel(Size, Fixup, Value, Ctx);
2710b57cec5SDimitry Andric     break;
2720b57cec5SDimitry Andric   case AVR::fixup_call:
2730b57cec5SDimitry Andric     adjust::fixup_call(Size, Fixup, Value, Ctx);
2740b57cec5SDimitry Andric     break;
2750b57cec5SDimitry Andric   case AVR::fixup_ldi:
2760b57cec5SDimitry Andric     adjust::ldi::fixup(Size, Fixup, Value, Ctx);
2770b57cec5SDimitry Andric     break;
2780b57cec5SDimitry Andric   case AVR::fixup_lo8_ldi:
2790b57cec5SDimitry Andric     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
2800b57cec5SDimitry Andric     break;
2810b57cec5SDimitry Andric   case AVR::fixup_lo8_ldi_pm:
2820b57cec5SDimitry Andric   case AVR::fixup_lo8_ldi_gs:
2830b57cec5SDimitry Andric     adjust::pm(Value);
2840b57cec5SDimitry Andric     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
2850b57cec5SDimitry Andric     break;
2860b57cec5SDimitry Andric   case AVR::fixup_hi8_ldi:
2870b57cec5SDimitry Andric     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
2880b57cec5SDimitry Andric     break;
2890b57cec5SDimitry Andric   case AVR::fixup_hi8_ldi_pm:
2900b57cec5SDimitry Andric   case AVR::fixup_hi8_ldi_gs:
2910b57cec5SDimitry Andric     adjust::pm(Value);
2920b57cec5SDimitry Andric     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
2930b57cec5SDimitry Andric     break;
2940b57cec5SDimitry Andric   case AVR::fixup_hh8_ldi:
2950b57cec5SDimitry Andric   case AVR::fixup_hh8_ldi_pm:
296349cc55cSDimitry Andric     if (Kind == AVR::fixup_hh8_ldi_pm)
297349cc55cSDimitry Andric       adjust::pm(Value);
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric     adjust::ldi::hh8(Size, Fixup, Value, Ctx);
3000b57cec5SDimitry Andric     break;
3010b57cec5SDimitry Andric   case AVR::fixup_ms8_ldi:
3020b57cec5SDimitry Andric     adjust::ldi::ms8(Size, Fixup, Value, Ctx);
3030b57cec5SDimitry Andric     break;
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   case AVR::fixup_lo8_ldi_neg:
3060b57cec5SDimitry Andric   case AVR::fixup_lo8_ldi_pm_neg:
307349cc55cSDimitry Andric     if (Kind == AVR::fixup_lo8_ldi_pm_neg)
308349cc55cSDimitry Andric       adjust::pm(Value);
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric     adjust::ldi::neg(Value);
3110b57cec5SDimitry Andric     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
3120b57cec5SDimitry Andric     break;
3130b57cec5SDimitry Andric   case AVR::fixup_hi8_ldi_neg:
3140b57cec5SDimitry Andric   case AVR::fixup_hi8_ldi_pm_neg:
315349cc55cSDimitry Andric     if (Kind == AVR::fixup_hi8_ldi_pm_neg)
316349cc55cSDimitry Andric       adjust::pm(Value);
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric     adjust::ldi::neg(Value);
3190b57cec5SDimitry Andric     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
3200b57cec5SDimitry Andric     break;
3210b57cec5SDimitry Andric   case AVR::fixup_hh8_ldi_neg:
3220b57cec5SDimitry Andric   case AVR::fixup_hh8_ldi_pm_neg:
323349cc55cSDimitry Andric     if (Kind == AVR::fixup_hh8_ldi_pm_neg)
324349cc55cSDimitry Andric       adjust::pm(Value);
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric     adjust::ldi::neg(Value);
3270b57cec5SDimitry Andric     adjust::ldi::hh8(Size, Fixup, Value, Ctx);
3280b57cec5SDimitry Andric     break;
3290b57cec5SDimitry Andric   case AVR::fixup_ms8_ldi_neg:
3300b57cec5SDimitry Andric     adjust::ldi::neg(Value);
3310b57cec5SDimitry Andric     adjust::ldi::ms8(Size, Fixup, Value, Ctx);
3320b57cec5SDimitry Andric     break;
3330b57cec5SDimitry Andric   case AVR::fixup_16:
3340b57cec5SDimitry Andric     adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric     Value &= 0xffff;
3370b57cec5SDimitry Andric     break;
3380b57cec5SDimitry Andric   case AVR::fixup_16_pm:
3390b57cec5SDimitry Andric     Value >>= 1; // Flash addresses are always shifted.
3400b57cec5SDimitry Andric     adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric     Value &= 0xffff;
3430b57cec5SDimitry Andric     break;
3440b57cec5SDimitry Andric 
3455ffd83dbSDimitry Andric   case AVR::fixup_6:
3465ffd83dbSDimitry Andric     adjust::fixup_6(Fixup, Value, Ctx);
3475ffd83dbSDimitry Andric     break;
3480b57cec5SDimitry Andric   case AVR::fixup_6_adiw:
3490b57cec5SDimitry Andric     adjust::fixup_6_adiw(Fixup, Value, Ctx);
3500b57cec5SDimitry Andric     break;
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric   case AVR::fixup_port5:
3530b57cec5SDimitry Andric     adjust::fixup_port5(Fixup, Value, Ctx);
3540b57cec5SDimitry Andric     break;
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric   case AVR::fixup_port6:
3570b57cec5SDimitry Andric     adjust::fixup_port6(Fixup, Value, Ctx);
3580b57cec5SDimitry Andric     break;
3590b57cec5SDimitry Andric 
360bdd1243dSDimitry Andric   case AVR::fixup_lds_sts_16:
361bdd1243dSDimitry Andric     adjust::fixup_lds_sts_16(Fixup, Value, Ctx);
362bdd1243dSDimitry Andric     break;
363bdd1243dSDimitry Andric 
3640b57cec5SDimitry Andric   // Fixups which do not require adjustments.
3650b57cec5SDimitry Andric   case FK_Data_1:
3660b57cec5SDimitry Andric   case FK_Data_2:
3670b57cec5SDimitry Andric   case FK_Data_4:
3680b57cec5SDimitry Andric   case FK_Data_8:
3690b57cec5SDimitry Andric     break;
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric   case FK_GPRel_4:
3720b57cec5SDimitry Andric     llvm_unreachable("don't know how to adjust this fixup");
3730b57cec5SDimitry Andric     break;
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
3780b57cec5SDimitry Andric AVRAsmBackend::createObjectTargetWriter() const {
3790b57cec5SDimitry Andric   return createAVRELFObjectWriter(MCELFObjectTargetWriter::getOSABI(OSType));
3800b57cec5SDimitry Andric }
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric void AVRAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
3830b57cec5SDimitry Andric                                const MCValue &Target,
3840b57cec5SDimitry Andric                                MutableArrayRef<char> Data, uint64_t Value,
3850b57cec5SDimitry Andric                                bool IsResolved,
3860b57cec5SDimitry Andric                                const MCSubtargetInfo *STI) const {
387bdd1243dSDimitry Andric   if (Fixup.getKind() >= FirstLiteralRelocationKind)
388bdd1243dSDimitry Andric     return;
3890b57cec5SDimitry Andric   adjustFixupValue(Fixup, Target, Value, &Asm.getContext());
3900b57cec5SDimitry Andric   if (Value == 0)
3910b57cec5SDimitry Andric     return; // Doesn't change encoding.
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric   MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   // The number of bits in the fixup mask
3960b57cec5SDimitry Andric   auto NumBits = Info.TargetSize + Info.TargetOffset;
3970b57cec5SDimitry Andric   auto NumBytes = (NumBits / 8) + ((NumBits % 8) == 0 ? 0 : 1);
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric   // Shift the value into position.
4000b57cec5SDimitry Andric   Value <<= Info.TargetOffset;
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric   unsigned Offset = Fixup.getOffset();
4030b57cec5SDimitry Andric   assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric   // For each byte of the fragment that the fixup touches, mask in the
4060b57cec5SDimitry Andric   // bits from the fixup value.
4070b57cec5SDimitry Andric   for (unsigned i = 0; i < NumBytes; ++i) {
4080b57cec5SDimitry Andric     uint8_t mask = (((Value >> (i * 8)) & 0xff));
4090b57cec5SDimitry Andric     Data[Offset + i] |= mask;
4100b57cec5SDimitry Andric   }
4110b57cec5SDimitry Andric }
4120b57cec5SDimitry Andric 
413bdd1243dSDimitry Andric std::optional<MCFixupKind> AVRAsmBackend::getFixupKind(StringRef Name) const {
414bdd1243dSDimitry Andric   unsigned Type;
415bdd1243dSDimitry Andric   Type = llvm::StringSwitch<unsigned>(Name)
416bdd1243dSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y)
417bdd1243dSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/AVR.def"
418bdd1243dSDimitry Andric #undef ELF_RELOC
419bdd1243dSDimitry Andric              .Case("BFD_RELOC_NONE", ELF::R_AVR_NONE)
420bdd1243dSDimitry Andric              .Case("BFD_RELOC_16", ELF::R_AVR_16)
421bdd1243dSDimitry Andric              .Case("BFD_RELOC_32", ELF::R_AVR_32)
422bdd1243dSDimitry Andric              .Default(-1u);
423bdd1243dSDimitry Andric   if (Type != -1u)
424bdd1243dSDimitry Andric     return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
425bdd1243dSDimitry Andric   return std::nullopt;
426bdd1243dSDimitry Andric }
427bdd1243dSDimitry Andric 
4280b57cec5SDimitry Andric MCFixupKindInfo const &AVRAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
4290b57cec5SDimitry Andric   // NOTE: Many AVR fixups work on sets of non-contignous bits. We work around
4300b57cec5SDimitry Andric   // this by saying that the fixup is the size of the entire instruction.
4310b57cec5SDimitry Andric   const static MCFixupKindInfo Infos[AVR::NumTargetFixupKinds] = {
4320b57cec5SDimitry Andric       // This table *must* be in same the order of fixup_* kinds in
4330b57cec5SDimitry Andric       // AVRFixupKinds.h.
4340b57cec5SDimitry Andric       //
4350b57cec5SDimitry Andric       // name                    offset  bits  flags
4360b57cec5SDimitry Andric       {"fixup_32", 0, 32, 0},
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric       {"fixup_7_pcrel", 3, 7, MCFixupKindInfo::FKF_IsPCRel},
4390b57cec5SDimitry Andric       {"fixup_13_pcrel", 0, 12, MCFixupKindInfo::FKF_IsPCRel},
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric       {"fixup_16", 0, 16, 0},
4420b57cec5SDimitry Andric       {"fixup_16_pm", 0, 16, 0},
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric       {"fixup_ldi", 0, 8, 0},
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric       {"fixup_lo8_ldi", 0, 8, 0},
4470b57cec5SDimitry Andric       {"fixup_hi8_ldi", 0, 8, 0},
4480b57cec5SDimitry Andric       {"fixup_hh8_ldi", 0, 8, 0},
4490b57cec5SDimitry Andric       {"fixup_ms8_ldi", 0, 8, 0},
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric       {"fixup_lo8_ldi_neg", 0, 8, 0},
4520b57cec5SDimitry Andric       {"fixup_hi8_ldi_neg", 0, 8, 0},
4530b57cec5SDimitry Andric       {"fixup_hh8_ldi_neg", 0, 8, 0},
4540b57cec5SDimitry Andric       {"fixup_ms8_ldi_neg", 0, 8, 0},
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric       {"fixup_lo8_ldi_pm", 0, 8, 0},
4570b57cec5SDimitry Andric       {"fixup_hi8_ldi_pm", 0, 8, 0},
4580b57cec5SDimitry Andric       {"fixup_hh8_ldi_pm", 0, 8, 0},
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric       {"fixup_lo8_ldi_pm_neg", 0, 8, 0},
4610b57cec5SDimitry Andric       {"fixup_hi8_ldi_pm_neg", 0, 8, 0},
4620b57cec5SDimitry Andric       {"fixup_hh8_ldi_pm_neg", 0, 8, 0},
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric       {"fixup_call", 0, 22, 0},
4650b57cec5SDimitry Andric 
4660b57cec5SDimitry Andric       {"fixup_6", 0, 16, 0}, // non-contiguous
4670b57cec5SDimitry Andric       {"fixup_6_adiw", 0, 6, 0},
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric       {"fixup_lo8_ldi_gs", 0, 8, 0},
4700b57cec5SDimitry Andric       {"fixup_hi8_ldi_gs", 0, 8, 0},
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric       {"fixup_8", 0, 8, 0},
4730b57cec5SDimitry Andric       {"fixup_8_lo8", 0, 8, 0},
4740b57cec5SDimitry Andric       {"fixup_8_hi8", 0, 8, 0},
4750b57cec5SDimitry Andric       {"fixup_8_hlo8", 0, 8, 0},
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric       {"fixup_diff8", 0, 8, 0},
4780b57cec5SDimitry Andric       {"fixup_diff16", 0, 16, 0},
4790b57cec5SDimitry Andric       {"fixup_diff32", 0, 32, 0},
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric       {"fixup_lds_sts_16", 0, 16, 0},
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric       {"fixup_port6", 0, 16, 0}, // non-contiguous
4840b57cec5SDimitry Andric       {"fixup_port5", 3, 5, 0},
4850b57cec5SDimitry Andric   };
4860b57cec5SDimitry Andric 
487bdd1243dSDimitry Andric   // Fixup kinds from .reloc directive are like R_AVR_NONE. They do not require
488bdd1243dSDimitry Andric   // any extra processing.
489bdd1243dSDimitry Andric   if (Kind >= FirstLiteralRelocationKind)
490bdd1243dSDimitry Andric     return MCAsmBackend::getFixupKindInfo(FK_NONE);
491bdd1243dSDimitry Andric 
4920b57cec5SDimitry Andric   if (Kind < FirstTargetFixupKind)
4930b57cec5SDimitry Andric     return MCAsmBackend::getFixupKindInfo(Kind);
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric   assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
4960b57cec5SDimitry Andric          "Invalid kind!");
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric   return Infos[Kind - FirstTargetFixupKind];
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric 
501349cc55cSDimitry Andric bool AVRAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
502349cc55cSDimitry Andric                                  const MCSubtargetInfo *STI) const {
5030b57cec5SDimitry Andric   // If the count is not 2-byte aligned, we must be writing data into the text
5040b57cec5SDimitry Andric   // section (otherwise we have unaligned instructions, and thus have far
5050b57cec5SDimitry Andric   // bigger problems), so just write zeros instead.
5060b57cec5SDimitry Andric   assert((Count % 2) == 0 && "NOP instructions must be 2 bytes");
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric   OS.write_zeros(Count);
5090b57cec5SDimitry Andric   return true;
5100b57cec5SDimitry Andric }
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric bool AVRAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
5130b57cec5SDimitry Andric                                           const MCFixup &Fixup,
5145f757f3fSDimitry Andric                                           const MCValue &Target,
5155f757f3fSDimitry Andric                                           const MCSubtargetInfo *STI) {
5160b57cec5SDimitry Andric   switch ((unsigned)Fixup.getKind()) {
517349cc55cSDimitry Andric   default:
518bdd1243dSDimitry Andric     return Fixup.getKind() >= FirstLiteralRelocationKind;
5190b57cec5SDimitry Andric   case AVR::fixup_7_pcrel:
5200b57cec5SDimitry Andric   case AVR::fixup_13_pcrel:
5216c4b055cSDimitry Andric     // Always resolve relocations for PC-relative branches
52206c3fb27SDimitry Andric     return false;
5230b57cec5SDimitry Andric   case AVR::fixup_call:
5240b57cec5SDimitry Andric     return true;
5250b57cec5SDimitry Andric   }
5260b57cec5SDimitry Andric }
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric MCAsmBackend *createAVRAsmBackend(const Target &T, const MCSubtargetInfo &STI,
5290b57cec5SDimitry Andric                                   const MCRegisterInfo &MRI,
5300b57cec5SDimitry Andric                                   const llvm::MCTargetOptions &TO) {
5310b57cec5SDimitry Andric   return new AVRAsmBackend(STI.getTargetTriple().getOS());
5320b57cec5SDimitry Andric }
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric } // end of namespace llvm
535