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