LCOV - code coverage report
Current view: top level - lib/Target/AVR/MCTargetDesc - AVRAsmBackend.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 157 180 87.2 %
Date: 2018-10-20 13:21:21 Functions: 23 24 95.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13