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
33namespace adjust {
34
35using namespace llvm;
36
37static 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->reportError(Fixup.getLoc(), Diagnostic);
51    } else {
52      llvm_unreachable(Diagnostic.c_str());
53    }
54  }
55}
56
57static 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 +=
66        " (expected an integer in the range 0 to " + std::to_string(Max) + ")";
67
68    if (Ctx) {
69      Ctx->reportError(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.
77static 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.
88static 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).
104static 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).
120static 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).
134static 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
147static 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
159static 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
170static 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
183static 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/// 7-bit data space address fixup for the LDS/STS instructions on AVRTiny.
191///
192/// Resolves to:
193/// 1010 ikkk dddd kkkk
194static void fixup_lds_sts_16(const MCFixup &Fixup, uint64_t &Value,
195                             MCContext *Ctx = nullptr) {
196  unsigned_width(7, Value, std::string("immediate"), Fixup, Ctx);
197  Value = ((Value & 0x70) << 8) | (Value & 0x0f);
198}
199
200/// Adjusts a program memory address.
201/// This is a simple right-shift.
202static void pm(uint64_t &Value) { Value >>= 1; }
203
204/// Fixups relating to the LDI instruction.
205namespace ldi {
206
207/// Adjusts a value to fix up the immediate of an `LDI Rd, K` instruction.
208///
209/// Resolves to:
210/// 0000 KKKK 0000 KKKK
211/// Offset of 0 (so the result isn't left-shifted before application).
212static void fixup(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
213                  MCContext *Ctx = nullptr) {
214  uint64_t upper = Value & 0xf0;
215  uint64_t lower = Value & 0x0f;
216
217  Value = (upper << 4) | lower;
218}
219
220static void neg(uint64_t &Value) { Value *= -1; }
221
222static void lo8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
223                MCContext *Ctx = nullptr) {
224  Value &= 0xff;
225  ldi::fixup(Size, Fixup, Value, Ctx);
226}
227
228static void hi8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
229                MCContext *Ctx = nullptr) {
230  Value = (Value & 0xff00) >> 8;
231  ldi::fixup(Size, Fixup, Value, Ctx);
232}
233
234static void hh8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
235                MCContext *Ctx = nullptr) {
236  Value = (Value & 0xff0000) >> 16;
237  ldi::fixup(Size, Fixup, Value, Ctx);
238}
239
240static void ms8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
241                MCContext *Ctx = nullptr) {
242  Value = (Value & 0xff000000) >> 24;
243  ldi::fixup(Size, Fixup, Value, Ctx);
244}
245
246} // namespace ldi
247} // namespace adjust
248
249namespace llvm {
250
251// Prepare value for the target space for it
252void AVRAsmBackend::adjustFixupValue(const MCFixup &Fixup,
253                                     const MCValue &Target, uint64_t &Value,
254                                     MCContext *Ctx) const {
255  // The size of the fixup in bits.
256  uint64_t Size = AVRAsmBackend::getFixupKindInfo(Fixup.getKind()).TargetSize;
257
258  unsigned Kind = Fixup.getKind();
259  switch (Kind) {
260  default:
261    llvm_unreachable("unhandled fixup");
262  case AVR::fixup_7_pcrel:
263    adjust::fixup_7_pcrel(Size, Fixup, Value, Ctx);
264    break;
265  case AVR::fixup_13_pcrel:
266    adjust::fixup_13_pcrel(Size, Fixup, Value, Ctx);
267    break;
268  case AVR::fixup_call:
269    adjust::fixup_call(Size, Fixup, Value, Ctx);
270    break;
271  case AVR::fixup_ldi:
272    adjust::ldi::fixup(Size, Fixup, Value, Ctx);
273    break;
274  case AVR::fixup_lo8_ldi:
275    adjust::ldi::lo8(Size, Fixup, Value, Ctx);
276    break;
277  case AVR::fixup_lo8_ldi_pm:
278  case AVR::fixup_lo8_ldi_gs:
279    adjust::pm(Value);
280    adjust::ldi::lo8(Size, Fixup, Value, Ctx);
281    break;
282  case AVR::fixup_hi8_ldi:
283    adjust::ldi::hi8(Size, Fixup, Value, Ctx);
284    break;
285  case AVR::fixup_hi8_ldi_pm:
286  case AVR::fixup_hi8_ldi_gs:
287    adjust::pm(Value);
288    adjust::ldi::hi8(Size, Fixup, Value, Ctx);
289    break;
290  case AVR::fixup_hh8_ldi:
291  case AVR::fixup_hh8_ldi_pm:
292    if (Kind == AVR::fixup_hh8_ldi_pm)
293      adjust::pm(Value);
294
295    adjust::ldi::hh8(Size, Fixup, Value, Ctx);
296    break;
297  case AVR::fixup_ms8_ldi:
298    adjust::ldi::ms8(Size, Fixup, Value, Ctx);
299    break;
300
301  case AVR::fixup_lo8_ldi_neg:
302  case AVR::fixup_lo8_ldi_pm_neg:
303    if (Kind == AVR::fixup_lo8_ldi_pm_neg)
304      adjust::pm(Value);
305
306    adjust::ldi::neg(Value);
307    adjust::ldi::lo8(Size, Fixup, Value, Ctx);
308    break;
309  case AVR::fixup_hi8_ldi_neg:
310  case AVR::fixup_hi8_ldi_pm_neg:
311    if (Kind == AVR::fixup_hi8_ldi_pm_neg)
312      adjust::pm(Value);
313
314    adjust::ldi::neg(Value);
315    adjust::ldi::hi8(Size, Fixup, Value, Ctx);
316    break;
317  case AVR::fixup_hh8_ldi_neg:
318  case AVR::fixup_hh8_ldi_pm_neg:
319    if (Kind == AVR::fixup_hh8_ldi_pm_neg)
320      adjust::pm(Value);
321
322    adjust::ldi::neg(Value);
323    adjust::ldi::hh8(Size, Fixup, Value, Ctx);
324    break;
325  case AVR::fixup_ms8_ldi_neg:
326    adjust::ldi::neg(Value);
327    adjust::ldi::ms8(Size, Fixup, Value, Ctx);
328    break;
329  case AVR::fixup_16:
330    adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
331
332    Value &= 0xffff;
333    break;
334  case AVR::fixup_16_pm:
335    Value >>= 1; // Flash addresses are always shifted.
336    adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
337
338    Value &= 0xffff;
339    break;
340
341  case AVR::fixup_6:
342    adjust::fixup_6(Fixup, Value, Ctx);
343    break;
344  case AVR::fixup_6_adiw:
345    adjust::fixup_6_adiw(Fixup, Value, Ctx);
346    break;
347
348  case AVR::fixup_port5:
349    adjust::fixup_port5(Fixup, Value, Ctx);
350    break;
351
352  case AVR::fixup_port6:
353    adjust::fixup_port6(Fixup, Value, Ctx);
354    break;
355
356  case AVR::fixup_lds_sts_16:
357    adjust::fixup_lds_sts_16(Fixup, Value, Ctx);
358    break;
359
360  // Fixups which do not require adjustments.
361  case FK_Data_1:
362  case FK_Data_2:
363  case FK_Data_4:
364  case FK_Data_8:
365    break;
366
367  case FK_GPRel_4:
368    llvm_unreachable("don't know how to adjust this fixup");
369    break;
370  }
371}
372
373std::unique_ptr<MCObjectTargetWriter>
374AVRAsmBackend::createObjectTargetWriter() const {
375  return createAVRELFObjectWriter(MCELFObjectTargetWriter::getOSABI(OSType));
376}
377
378void AVRAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
379                               const MCValue &Target,
380                               MutableArrayRef<char> Data, uint64_t Value,
381                               bool IsResolved,
382                               const MCSubtargetInfo *STI) const {
383  if (Fixup.getKind() >= FirstLiteralRelocationKind)
384    return;
385  adjustFixupValue(Fixup, Target, Value, &Asm.getContext());
386  if (Value == 0)
387    return; // Doesn't change encoding.
388
389  MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
390
391  // The number of bits in the fixup mask
392  auto NumBits = Info.TargetSize + Info.TargetOffset;
393  auto NumBytes = (NumBits / 8) + ((NumBits % 8) == 0 ? 0 : 1);
394
395  // Shift the value into position.
396  Value <<= Info.TargetOffset;
397
398  unsigned Offset = Fixup.getOffset();
399  assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
400
401  // For each byte of the fragment that the fixup touches, mask in the
402  // bits from the fixup value.
403  for (unsigned i = 0; i < NumBytes; ++i) {
404    uint8_t mask = (((Value >> (i * 8)) & 0xff));
405    Data[Offset + i] |= mask;
406  }
407}
408
409std::optional<MCFixupKind> AVRAsmBackend::getFixupKind(StringRef Name) const {
410  unsigned Type;
411  Type = llvm::StringSwitch<unsigned>(Name)
412#define ELF_RELOC(X, Y) .Case(#X, Y)
413#include "llvm/BinaryFormat/ELFRelocs/AVR.def"
414#undef ELF_RELOC
415             .Case("BFD_RELOC_NONE", ELF::R_AVR_NONE)
416             .Case("BFD_RELOC_16", ELF::R_AVR_16)
417             .Case("BFD_RELOC_32", ELF::R_AVR_32)
418             .Default(-1u);
419  if (Type != -1u)
420    return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
421  return std::nullopt;
422}
423
424MCFixupKindInfo const &AVRAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
425  // NOTE: Many AVR fixups work on sets of non-contignous bits. We work around
426  // this by saying that the fixup is the size of the entire instruction.
427  const static MCFixupKindInfo Infos[AVR::NumTargetFixupKinds] = {
428      // This table *must* be in same the order of fixup_* kinds in
429      // AVRFixupKinds.h.
430      //
431      // name                    offset  bits  flags
432      {"fixup_32", 0, 32, 0},
433
434      {"fixup_7_pcrel", 3, 7, MCFixupKindInfo::FKF_IsPCRel},
435      {"fixup_13_pcrel", 0, 12, MCFixupKindInfo::FKF_IsPCRel},
436
437      {"fixup_16", 0, 16, 0},
438      {"fixup_16_pm", 0, 16, 0},
439
440      {"fixup_ldi", 0, 8, 0},
441
442      {"fixup_lo8_ldi", 0, 8, 0},
443      {"fixup_hi8_ldi", 0, 8, 0},
444      {"fixup_hh8_ldi", 0, 8, 0},
445      {"fixup_ms8_ldi", 0, 8, 0},
446
447      {"fixup_lo8_ldi_neg", 0, 8, 0},
448      {"fixup_hi8_ldi_neg", 0, 8, 0},
449      {"fixup_hh8_ldi_neg", 0, 8, 0},
450      {"fixup_ms8_ldi_neg", 0, 8, 0},
451
452      {"fixup_lo8_ldi_pm", 0, 8, 0},
453      {"fixup_hi8_ldi_pm", 0, 8, 0},
454      {"fixup_hh8_ldi_pm", 0, 8, 0},
455
456      {"fixup_lo8_ldi_pm_neg", 0, 8, 0},
457      {"fixup_hi8_ldi_pm_neg", 0, 8, 0},
458      {"fixup_hh8_ldi_pm_neg", 0, 8, 0},
459
460      {"fixup_call", 0, 22, 0},
461
462      {"fixup_6", 0, 16, 0}, // non-contiguous
463      {"fixup_6_adiw", 0, 6, 0},
464
465      {"fixup_lo8_ldi_gs", 0, 8, 0},
466      {"fixup_hi8_ldi_gs", 0, 8, 0},
467
468      {"fixup_8", 0, 8, 0},
469      {"fixup_8_lo8", 0, 8, 0},
470      {"fixup_8_hi8", 0, 8, 0},
471      {"fixup_8_hlo8", 0, 8, 0},
472
473      {"fixup_diff8", 0, 8, 0},
474      {"fixup_diff16", 0, 16, 0},
475      {"fixup_diff32", 0, 32, 0},
476
477      {"fixup_lds_sts_16", 0, 16, 0},
478
479      {"fixup_port6", 0, 16, 0}, // non-contiguous
480      {"fixup_port5", 3, 5, 0},
481  };
482
483  // Fixup kinds from .reloc directive are like R_AVR_NONE. They do not require
484  // any extra processing.
485  if (Kind >= FirstLiteralRelocationKind)
486    return MCAsmBackend::getFixupKindInfo(FK_NONE);
487
488  if (Kind < FirstTargetFixupKind)
489    return MCAsmBackend::getFixupKindInfo(Kind);
490
491  assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
492         "Invalid kind!");
493
494  return Infos[Kind - FirstTargetFixupKind];
495}
496
497bool AVRAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
498                                 const MCSubtargetInfo *STI) const {
499  // If the count is not 2-byte aligned, we must be writing data into the text
500  // section (otherwise we have unaligned instructions, and thus have far
501  // bigger problems), so just write zeros instead.
502  assert((Count % 2) == 0 && "NOP instructions must be 2 bytes");
503
504  OS.write_zeros(Count);
505  return true;
506}
507
508bool AVRAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
509                                          const MCFixup &Fixup,
510                                          const MCValue &Target,
511                                          const MCSubtargetInfo *STI) {
512  switch ((unsigned)Fixup.getKind()) {
513  default:
514    return Fixup.getKind() >= FirstLiteralRelocationKind;
515  // Fixups which should always be recorded as relocations.
516  case AVR::fixup_7_pcrel:
517  case AVR::fixup_13_pcrel:
518    // Do not force relocation for PC relative branch like 'rjmp .',
519    // 'rcall . - off' and 'breq . + off'.
520    if (const auto *SymA = Target.getSymA())
521      if (SymA->getSymbol().getName().size() == 0)
522        return false;
523    [[fallthrough]];
524  case AVR::fixup_call:
525    return true;
526  }
527}
528
529MCAsmBackend *createAVRAsmBackend(const Target &T, const MCSubtargetInfo &STI,
530                                  const MCRegisterInfo &MRI,
531                                  const llvm::MCTargetOptions &TO) {
532  return new AVRAsmBackend(STI.getTargetTriple().getOS());
533}
534
535} // end of namespace llvm
536