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