Home | History | Annotate | Line # | Download | only in MCTargetDesc
      1 //===-- AVRAsmBackend.cpp - AVR Asm Backend  ------------------------------===//
      2 //
      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
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file implements the AVRAsmBackend class.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include "MCTargetDesc/AVRAsmBackend.h"
     14 #include "MCTargetDesc/AVRFixupKinds.h"
     15 #include "MCTargetDesc/AVRMCTargetDesc.h"
     16 #include "llvm/MC/MCAsmBackend.h"
     17 #include "llvm/MC/MCAssembler.h"
     18 #include "llvm/MC/MCContext.h"
     19 #include "llvm/MC/MCDirectives.h"
     20 #include "llvm/MC/MCELFObjectWriter.h"
     21 #include "llvm/MC/MCExpr.h"
     22 #include "llvm/MC/MCFixupKindInfo.h"
     23 #include "llvm/MC/MCObjectWriter.h"
     24 #include "llvm/MC/MCSubtargetInfo.h"
     25 #include "llvm/MC/MCValue.h"
     26 #include "llvm/Support/ErrorHandling.h"
     27 #include "llvm/Support/MathExtras.h"
     28 #include "llvm/Support/raw_ostream.h"
     29 
     30 // FIXME: we should be doing checks to make sure asm operands
     31 // are not out of bounds.
     32 
     33 namespace adjust {
     34 
     35 using namespace llvm;
     36 
     37 static void signed_width(unsigned Width, uint64_t Value,
     38                          std::string Description, const MCFixup &Fixup,
     39                          MCContext *Ctx = nullptr) {
     40   if (!isIntN(Width, Value)) {
     41     std::string Diagnostic = "out of range " + Description;
     42 
     43     int64_t Min = minIntN(Width);
     44     int64_t Max = maxIntN(Width);
     45 
     46     Diagnostic += " (expected an integer in the range " + std::to_string(Min) +
     47       " to " + std::to_string(Max) + ")";
     48 
     49     if (Ctx) {
     50       Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
     51     } else {
     52       llvm_unreachable(Diagnostic.c_str());
     53     }
     54   }
     55 }
     56 
     57 static void unsigned_width(unsigned Width, uint64_t Value,
     58                            std::string Description, const MCFixup &Fixup,
     59                            MCContext *Ctx = nullptr) {
     60   if (!isUIntN(Width, Value)) {
     61     std::string Diagnostic = "out of range " + Description;
     62 
     63     int64_t Max = maxUIntN(Width);
     64 
     65     Diagnostic += " (expected an integer in the range 0 to " +
     66       std::to_string(Max) + ")";
     67 
     68     if (Ctx) {
     69       Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
     70     } else {
     71       llvm_unreachable(Diagnostic.c_str());
     72     }
     73   }
     74 }
     75 
     76 /// Adjusts the value of a branch target before fixup application.
     77 static void adjustBranch(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
     78                          MCContext *Ctx = nullptr) {
     79   // We have one extra bit of precision because the value is rightshifted by
     80   // one.
     81   unsigned_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
     82 
     83   // Rightshifts the value by one.
     84   AVR::fixups::adjustBranchTarget(Value);
     85 }
     86 
     87 /// Adjusts the value of a relative branch target before fixup application.
     88 static void adjustRelativeBranch(unsigned Size, const MCFixup &Fixup,
     89                                  uint64_t &Value, MCContext *Ctx = nullptr) {
     90   // We have one extra bit of precision because the value is rightshifted by
     91   // one.
     92   signed_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
     93 
     94   // Rightshifts the value by one.
     95   AVR::fixups::adjustBranchTarget(Value);
     96 }
     97 
     98 /// 22-bit absolute fixup.
     99 ///
    100 /// Resolves to:
    101 /// 1001 kkkk 010k kkkk kkkk kkkk 111k kkkk
    102 ///
    103 /// Offset of 0 (so the result is left shifted by 3 bits before application).
    104 static void fixup_call(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
    105                        MCContext *Ctx = nullptr) {
    106   adjustBranch(Size, Fixup, Value, Ctx);
    107 
    108   auto top = Value & (0xf00000 << 6);   // the top four bits
    109   auto middle = Value & (0x1ffff << 5); // the middle 13 bits
    110   auto bottom = Value & 0x1f;           // end bottom 5 bits
    111 
    112   Value = (top << 6) | (middle << 3) | (bottom << 0);
    113 }
    114 
    115 /// 7-bit PC-relative fixup.
    116 ///
    117 /// Resolves to:
    118 /// 0000 00kk kkkk k000
    119 /// Offset of 0 (so the result is left shifted by 3 bits before application).
    120 static void fixup_7_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
    121                           MCContext *Ctx = nullptr) {
    122   adjustRelativeBranch(Size, Fixup, Value, Ctx);
    123 
    124   // Because the value may be negative, we must mask out the sign bits
    125   Value &= 0x7f;
    126 }
    127 
    128 /// 12-bit PC-relative fixup.
    129 /// Yes, the fixup is 12 bits even though the name says otherwise.
    130 ///
    131 /// Resolves to:
    132 /// 0000 kkkk kkkk kkkk
    133 /// Offset of 0 (so the result isn't left-shifted before application).
    134 static void fixup_13_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
    135                            MCContext *Ctx = nullptr) {
    136   adjustRelativeBranch(Size, Fixup, Value, Ctx);
    137 
    138   // Because the value may be negative, we must mask out the sign bits
    139   Value &= 0xfff;
    140 }
    141 
    142 /// 6-bit fixup for the immediate operand of the STD/LDD family of
    143 /// instructions.
    144 ///
    145 /// Resolves to:
    146 /// 10q0 qq10 0000 1qqq
    147 static void fixup_6(const MCFixup &Fixup, uint64_t &Value,
    148                     MCContext *Ctx = nullptr) {
    149   unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
    150 
    151   Value = ((Value & 0x20) << 8) | ((Value & 0x18) << 7) | (Value & 0x07);
    152 }
    153 
    154 /// 6-bit fixup for the immediate operand of the ADIW family of
    155 /// instructions.
    156 ///
    157 /// Resolves to:
    158 /// 0000 0000 kk00 kkkk
    159 static void fixup_6_adiw(const MCFixup &Fixup, uint64_t &Value,
    160                          MCContext *Ctx = nullptr) {
    161   unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
    162 
    163   Value = ((Value & 0x30) << 2) | (Value & 0x0f);
    164 }
    165 
    166 /// 5-bit port number fixup on the SBIC family of instructions.
    167 ///
    168 /// Resolves to:
    169 /// 0000 0000 AAAA A000
    170 static void fixup_port5(const MCFixup &Fixup, uint64_t &Value,
    171                         MCContext *Ctx = nullptr) {
    172   unsigned_width(5, Value, std::string("port number"), Fixup, Ctx);
    173 
    174   Value &= 0x1f;
    175 
    176   Value <<= 3;
    177 }
    178 
    179 /// 6-bit port number fixup on the `IN` family of instructions.
    180 ///
    181 /// Resolves to:
    182 /// 1011 0AAd dddd AAAA
    183 static void fixup_port6(const MCFixup &Fixup, uint64_t &Value,
    184                         MCContext *Ctx = nullptr) {
    185   unsigned_width(6, Value, std::string("port number"), Fixup, Ctx);
    186 
    187   Value = ((Value & 0x30) << 5) | (Value & 0x0f);
    188 }
    189 
    190 /// Adjusts a program memory address.
    191 /// This is a simple right-shift.
    192 static void pm(uint64_t &Value) { Value >>= 1; }
    193 
    194 /// Fixups relating to the LDI instruction.
    195 namespace ldi {
    196 
    197 /// Adjusts a value to fix up the immediate of an `LDI Rd, K` instruction.
    198 ///
    199 /// Resolves to:
    200 /// 0000 KKKK 0000 KKKK
    201 /// Offset of 0 (so the result isn't left-shifted before application).
    202 static void fixup(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
    203                   MCContext *Ctx = nullptr) {
    204   uint64_t upper = Value & 0xf0;
    205   uint64_t lower = Value & 0x0f;
    206 
    207   Value = (upper << 4) | lower;
    208 }
    209 
    210 static void neg(uint64_t &Value) { Value *= -1; }
    211 
    212 static void lo8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
    213                 MCContext *Ctx = nullptr) {
    214   Value &= 0xff;
    215   ldi::fixup(Size, Fixup, Value, Ctx);
    216 }
    217 
    218 static void hi8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
    219                 MCContext *Ctx = nullptr) {
    220   Value = (Value & 0xff00) >> 8;
    221   ldi::fixup(Size, Fixup, Value, Ctx);
    222 }
    223 
    224 static void hh8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
    225                 MCContext *Ctx = nullptr) {
    226   Value = (Value & 0xff0000) >> 16;
    227   ldi::fixup(Size, Fixup, Value, Ctx);
    228 }
    229 
    230 static void ms8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
    231                 MCContext *Ctx = nullptr) {
    232   Value = (Value & 0xff000000) >> 24;
    233   ldi::fixup(Size, Fixup, Value, Ctx);
    234 }
    235 
    236 } // end of ldi namespace
    237 } // end of adjust namespace
    238 
    239 namespace llvm {
    240 
    241 // Prepare value for the target space for it
    242 void AVRAsmBackend::adjustFixupValue(const MCFixup &Fixup,
    243                                      const MCValue &Target,
    244                                      uint64_t &Value,
    245                                      MCContext *Ctx) const {
    246   // The size of the fixup in bits.
    247   uint64_t Size = AVRAsmBackend::getFixupKindInfo(Fixup.getKind()).TargetSize;
    248 
    249   unsigned Kind = Fixup.getKind();
    250   switch (Kind) {
    251   default:
    252     llvm_unreachable("unhandled fixup");
    253   case AVR::fixup_7_pcrel:
    254     adjust::fixup_7_pcrel(Size, Fixup, Value, Ctx);
    255     break;
    256   case AVR::fixup_13_pcrel:
    257     adjust::fixup_13_pcrel(Size, Fixup, Value, Ctx);
    258     break;
    259   case AVR::fixup_call:
    260     adjust::fixup_call(Size, Fixup, Value, Ctx);
    261     break;
    262   case AVR::fixup_ldi:
    263     adjust::ldi::fixup(Size, Fixup, Value, Ctx);
    264     break;
    265   case AVR::fixup_lo8_ldi:
    266     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
    267     break;
    268   case AVR::fixup_lo8_ldi_pm:
    269   case AVR::fixup_lo8_ldi_gs:
    270     adjust::pm(Value);
    271     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
    272     break;
    273   case AVR::fixup_hi8_ldi:
    274     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
    275     break;
    276   case AVR::fixup_hi8_ldi_pm:
    277   case AVR::fixup_hi8_ldi_gs:
    278     adjust::pm(Value);
    279     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
    280     break;
    281   case AVR::fixup_hh8_ldi:
    282   case AVR::fixup_hh8_ldi_pm:
    283     if (Kind == AVR::fixup_hh8_ldi_pm) adjust::pm(Value);
    284 
    285     adjust::ldi::hh8(Size, Fixup, Value, Ctx);
    286     break;
    287   case AVR::fixup_ms8_ldi:
    288     adjust::ldi::ms8(Size, Fixup, Value, Ctx);
    289     break;
    290 
    291   case AVR::fixup_lo8_ldi_neg:
    292   case AVR::fixup_lo8_ldi_pm_neg:
    293     if (Kind == AVR::fixup_lo8_ldi_pm_neg) adjust::pm(Value);
    294 
    295     adjust::ldi::neg(Value);
    296     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
    297     break;
    298   case AVR::fixup_hi8_ldi_neg:
    299   case AVR::fixup_hi8_ldi_pm_neg:
    300     if (Kind == AVR::fixup_hi8_ldi_pm_neg) adjust::pm(Value);
    301 
    302     adjust::ldi::neg(Value);
    303     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
    304     break;
    305   case AVR::fixup_hh8_ldi_neg:
    306   case AVR::fixup_hh8_ldi_pm_neg:
    307     if (Kind == AVR::fixup_hh8_ldi_pm_neg) adjust::pm(Value);
    308 
    309     adjust::ldi::neg(Value);
    310     adjust::ldi::hh8(Size, Fixup, Value, Ctx);
    311     break;
    312   case AVR::fixup_ms8_ldi_neg:
    313     adjust::ldi::neg(Value);
    314     adjust::ldi::ms8(Size, Fixup, Value, Ctx);
    315     break;
    316   case AVR::fixup_16:
    317     adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
    318 
    319     Value &= 0xffff;
    320     break;
    321   case AVR::fixup_16_pm:
    322     Value >>= 1; // Flash addresses are always shifted.
    323     adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
    324 
    325     Value &= 0xffff;
    326     break;
    327 
    328   case AVR::fixup_6:
    329     adjust::fixup_6(Fixup, Value, Ctx);
    330     break;
    331   case AVR::fixup_6_adiw:
    332     adjust::fixup_6_adiw(Fixup, Value, Ctx);
    333     break;
    334 
    335   case AVR::fixup_port5:
    336     adjust::fixup_port5(Fixup, Value, Ctx);
    337     break;
    338 
    339   case AVR::fixup_port6:
    340     adjust::fixup_port6(Fixup, Value, Ctx);
    341     break;
    342 
    343   // Fixups which do not require adjustments.
    344   case FK_Data_1:
    345   case FK_Data_2:
    346   case FK_Data_4:
    347   case FK_Data_8:
    348     break;
    349 
    350   case FK_GPRel_4:
    351     llvm_unreachable("don't know how to adjust this fixup");
    352     break;
    353   }
    354 }
    355 
    356 std::unique_ptr<MCObjectTargetWriter>
    357 AVRAsmBackend::createObjectTargetWriter() const {
    358   return createAVRELFObjectWriter(MCELFObjectTargetWriter::getOSABI(OSType));
    359 }
    360 
    361 void AVRAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
    362                                const MCValue &Target,
    363                                MutableArrayRef<char> Data, uint64_t Value,
    364                                bool IsResolved,
    365                                const MCSubtargetInfo *STI) const {
    366   adjustFixupValue(Fixup, Target, Value, &Asm.getContext());
    367   if (Value == 0)
    368     return; // Doesn't change encoding.
    369 
    370   MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
    371 
    372   // The number of bits in the fixup mask
    373   auto NumBits = Info.TargetSize + Info.TargetOffset;
    374   auto NumBytes = (NumBits / 8) + ((NumBits % 8) == 0 ? 0 : 1);
    375 
    376   // Shift the value into position.
    377   Value <<= Info.TargetOffset;
    378 
    379   unsigned Offset = Fixup.getOffset();
    380   assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
    381 
    382   // For each byte of the fragment that the fixup touches, mask in the
    383   // bits from the fixup value.
    384   for (unsigned i = 0; i < NumBytes; ++i) {
    385     uint8_t mask = (((Value >> (i * 8)) & 0xff));
    386     Data[Offset + i] |= mask;
    387   }
    388 }
    389 
    390 MCFixupKindInfo const &AVRAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
    391   // NOTE: Many AVR fixups work on sets of non-contignous bits. We work around
    392   // this by saying that the fixup is the size of the entire instruction.
    393   const static MCFixupKindInfo Infos[AVR::NumTargetFixupKinds] = {
    394       // This table *must* be in same the order of fixup_* kinds in
    395       // AVRFixupKinds.h.
    396       //
    397       // name                    offset  bits  flags
    398       {"fixup_32", 0, 32, 0},
    399 
    400       {"fixup_7_pcrel", 3, 7, MCFixupKindInfo::FKF_IsPCRel},
    401       {"fixup_13_pcrel", 0, 12, MCFixupKindInfo::FKF_IsPCRel},
    402 
    403       {"fixup_16", 0, 16, 0},
    404       {"fixup_16_pm", 0, 16, 0},
    405 
    406       {"fixup_ldi", 0, 8, 0},
    407 
    408       {"fixup_lo8_ldi", 0, 8, 0},
    409       {"fixup_hi8_ldi", 0, 8, 0},
    410       {"fixup_hh8_ldi", 0, 8, 0},
    411       {"fixup_ms8_ldi", 0, 8, 0},
    412 
    413       {"fixup_lo8_ldi_neg", 0, 8, 0},
    414       {"fixup_hi8_ldi_neg", 0, 8, 0},
    415       {"fixup_hh8_ldi_neg", 0, 8, 0},
    416       {"fixup_ms8_ldi_neg", 0, 8, 0},
    417 
    418       {"fixup_lo8_ldi_pm", 0, 8, 0},
    419       {"fixup_hi8_ldi_pm", 0, 8, 0},
    420       {"fixup_hh8_ldi_pm", 0, 8, 0},
    421 
    422       {"fixup_lo8_ldi_pm_neg", 0, 8, 0},
    423       {"fixup_hi8_ldi_pm_neg", 0, 8, 0},
    424       {"fixup_hh8_ldi_pm_neg", 0, 8, 0},
    425 
    426       {"fixup_call", 0, 22, 0},
    427 
    428       {"fixup_6", 0, 16, 0}, // non-contiguous
    429       {"fixup_6_adiw", 0, 6, 0},
    430 
    431       {"fixup_lo8_ldi_gs", 0, 8, 0},
    432       {"fixup_hi8_ldi_gs", 0, 8, 0},
    433 
    434       {"fixup_8", 0, 8, 0},
    435       {"fixup_8_lo8", 0, 8, 0},
    436       {"fixup_8_hi8", 0, 8, 0},
    437       {"fixup_8_hlo8", 0, 8, 0},
    438 
    439       {"fixup_diff8", 0, 8, 0},
    440       {"fixup_diff16", 0, 16, 0},
    441       {"fixup_diff32", 0, 32, 0},
    442 
    443       {"fixup_lds_sts_16", 0, 16, 0},
    444 
    445       {"fixup_port6", 0, 16, 0}, // non-contiguous
    446       {"fixup_port5", 3, 5, 0},
    447   };
    448 
    449   if (Kind < FirstTargetFixupKind)
    450     return MCAsmBackend::getFixupKindInfo(Kind);
    451 
    452   assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
    453          "Invalid kind!");
    454 
    455   return Infos[Kind - FirstTargetFixupKind];
    456 }
    457 
    458 bool AVRAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
    459   // If the count is not 2-byte aligned, we must be writing data into the text
    460   // section (otherwise we have unaligned instructions, and thus have far
    461   // bigger problems), so just write zeros instead.
    462   assert((Count % 2) == 0 && "NOP instructions must be 2 bytes");
    463 
    464   OS.write_zeros(Count);
    465   return true;
    466 }
    467 
    468 bool AVRAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
    469                                           const MCFixup &Fixup,
    470                                           const MCValue &Target) {
    471   switch ((unsigned) Fixup.getKind()) {
    472   default: return false;
    473   // Fixups which should always be recorded as relocations.
    474   case AVR::fixup_7_pcrel:
    475   case AVR::fixup_13_pcrel:
    476   case AVR::fixup_call:
    477     return true;
    478   }
    479 }
    480 
    481 MCAsmBackend *createAVRAsmBackend(const Target &T, const MCSubtargetInfo &STI,
    482                                   const MCRegisterInfo &MRI,
    483                                   const llvm::MCTargetOptions &TO) {
    484   return new AVRAsmBackend(STI.getTargetTriple().getOS());
    485 }
    486 
    487 } // end of namespace llvm
    488 
    489