• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
signed_width(unsigned Width,uint64_t Value,std::string Description,const MCFixup & Fixup,MCContext * Ctx=nullptr)38 void signed_width(unsigned Width, uint64_t Value, std::string Description,
39                   const MCFixup &Fixup, 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 
unsigned_width(unsigned Width,uint64_t Value,std::string Description,const MCFixup & Fixup,MCContext * Ctx=nullptr)57 void unsigned_width(unsigned Width, uint64_t Value, std::string Description,
58                     const MCFixup &Fixup, MCContext *Ctx = nullptr) {
59   if (!isUIntN(Width, Value)) {
60     std::string Diagnostic = "out of range " + Description;
61 
62     int64_t Max = maxUIntN(Width);
63 
64     Diagnostic += " (expected an integer in the range 0 to " +
65       std::to_string(Max) + ")";
66 
67     if (Ctx) {
68       Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
69     } else {
70       llvm_unreachable(Diagnostic.c_str());
71     }
72   }
73 }
74 
75 /// Adjusts the value of a branch target before fixup application.
adjustBranch(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)76 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   unsigned_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
81 
82   // Rightshifts the value by one.
83   AVR::fixups::adjustBranchTarget(Value);
84 }
85 
86 /// Adjusts the value of a relative branch target before fixup application.
adjustRelativeBranch(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)87 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   signed_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
92 
93   Value -= 2;
94 
95   // Rightshifts the value by one.
96   AVR::fixups::adjustBranchTarget(Value);
97 }
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).
fixup_call(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)105 void fixup_call(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
106                 MCContext *Ctx = nullptr) {
107   adjustBranch(Size, Fixup, Value, Ctx);
108 
109   auto top = Value & (0xf00000 << 6);   // the top four bits
110   auto middle = Value & (0x1ffff << 5); // the middle 13 bits
111   auto bottom = Value & 0x1f;           // end bottom 5 bits
112 
113   Value = (top << 6) | (middle << 3) | (bottom << 0);
114 }
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).
fixup_7_pcrel(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)121 void fixup_7_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
122                    MCContext *Ctx = nullptr) {
123   adjustRelativeBranch(Size, Fixup, Value, Ctx);
124 
125   // Because the value may be negative, we must mask out the sign bits
126   Value &= 0x7f;
127 }
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).
fixup_13_pcrel(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)135 void fixup_13_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
136                     MCContext *Ctx = nullptr) {
137   adjustRelativeBranch(Size, Fixup, Value, Ctx);
138 
139   // Because the value may be negative, we must mask out the sign bits
140   Value &= 0xfff;
141 }
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
fixup_6_adiw(const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)148 void fixup_6_adiw(const MCFixup &Fixup, uint64_t &Value,
149                   MCContext *Ctx = nullptr) {
150   unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
151 
152   Value = ((Value & 0x30) << 2) | (Value & 0x0f);
153 }
154 
155 /// 5-bit port number fixup on the SBIC family of instructions.
156 ///
157 /// Resolves to:
158 /// 0000 0000 AAAA A000
fixup_port5(const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)159 void fixup_port5(const MCFixup &Fixup, uint64_t &Value,
160                  MCContext *Ctx = nullptr) {
161   unsigned_width(5, Value, std::string("port number"), Fixup, Ctx);
162 
163   Value &= 0x1f;
164 
165   Value <<= 3;
166 }
167 
168 /// 6-bit port number fixup on the `IN` family of instructions.
169 ///
170 /// Resolves to:
171 /// 1011 0AAd dddd AAAA
fixup_port6(const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)172 void fixup_port6(const MCFixup &Fixup, uint64_t &Value,
173                  MCContext *Ctx = nullptr) {
174   unsigned_width(6, Value, std::string("port number"), Fixup, Ctx);
175 
176   Value = ((Value & 0x30) << 5) | (Value & 0x0f);
177 }
178 
179 /// Adjusts a program memory address.
180 /// This is a simple right-shift.
pm(uint64_t & Value)181 void pm(uint64_t &Value) {
182   Value >>= 1;
183 }
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).
fixup(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)193 void fixup(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
194            MCContext *Ctx = nullptr) {
195   uint64_t upper = Value & 0xf0;
196   uint64_t lower = Value & 0x0f;
197 
198   Value = (upper << 4) | lower;
199 }
200 
neg(uint64_t & Value)201 void neg(uint64_t &Value) { Value *= -1; }
202 
lo8(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)203 void lo8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
204          MCContext *Ctx = nullptr) {
205   Value &= 0xff;
206   ldi::fixup(Size, Fixup, Value, Ctx);
207 }
208 
hi8(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)209 void hi8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
210          MCContext *Ctx = nullptr) {
211   Value = (Value & 0xff00) >> 8;
212   ldi::fixup(Size, Fixup, Value, Ctx);
213 }
214 
hh8(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)215 void hh8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
216          MCContext *Ctx = nullptr) {
217   Value = (Value & 0xff0000) >> 16;
218   ldi::fixup(Size, Fixup, Value, Ctx);
219 }
220 
ms8(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)221 void ms8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
222          MCContext *Ctx = nullptr) {
223   Value = (Value & 0xff000000) >> 24;
224   ldi::fixup(Size, Fixup, Value, Ctx);
225 }
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
adjustFixupValue(const MCFixup & Fixup,const MCValue & Target,uint64_t & Value,MCContext * Ctx) const233 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   uint64_t Size = AVRAsmBackend::getFixupKindInfo(Fixup.getKind()).TargetSize;
239 
240   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   if (const MCSymbolRefExpr *A = Target.getSymA()) {
248     if (A->getSymbol().isTemporary())
249       Value += 2;
250   }
251 
252   switch (Kind) {
253   default:
254     llvm_unreachable("unhandled fixup");
255   case AVR::fixup_7_pcrel:
256     adjust::fixup_7_pcrel(Size, Fixup, Value, Ctx);
257     break;
258   case AVR::fixup_13_pcrel:
259     adjust::fixup_13_pcrel(Size, Fixup, Value, Ctx);
260     break;
261   case AVR::fixup_call:
262     adjust::fixup_call(Size, Fixup, Value, Ctx);
263     break;
264   case AVR::fixup_ldi:
265     adjust::ldi::fixup(Size, Fixup, Value, Ctx);
266     break;
267   case AVR::fixup_lo8_ldi:
268     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
269     break;
270   case AVR::fixup_lo8_ldi_pm:
271   case AVR::fixup_lo8_ldi_gs:
272     adjust::pm(Value);
273     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
274     break;
275   case AVR::fixup_hi8_ldi:
276     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
277     break;
278   case AVR::fixup_hi8_ldi_pm:
279   case AVR::fixup_hi8_ldi_gs:
280     adjust::pm(Value);
281     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
282     break;
283   case AVR::fixup_hh8_ldi:
284   case AVR::fixup_hh8_ldi_pm:
285     if (Kind == AVR::fixup_hh8_ldi_pm) adjust::pm(Value);
286 
287     adjust::ldi::hh8(Size, Fixup, Value, Ctx);
288     break;
289   case AVR::fixup_ms8_ldi:
290     adjust::ldi::ms8(Size, Fixup, Value, Ctx);
291     break;
292 
293   case AVR::fixup_lo8_ldi_neg:
294   case AVR::fixup_lo8_ldi_pm_neg:
295     if (Kind == AVR::fixup_lo8_ldi_pm_neg) adjust::pm(Value);
296 
297     adjust::ldi::neg(Value);
298     adjust::ldi::lo8(Size, Fixup, Value, Ctx);
299     break;
300   case AVR::fixup_hi8_ldi_neg:
301   case AVR::fixup_hi8_ldi_pm_neg:
302     if (Kind == AVR::fixup_hi8_ldi_pm_neg) adjust::pm(Value);
303 
304     adjust::ldi::neg(Value);
305     adjust::ldi::hi8(Size, Fixup, Value, Ctx);
306     break;
307   case AVR::fixup_hh8_ldi_neg:
308   case AVR::fixup_hh8_ldi_pm_neg:
309     if (Kind == AVR::fixup_hh8_ldi_pm_neg) adjust::pm(Value);
310 
311     adjust::ldi::neg(Value);
312     adjust::ldi::hh8(Size, Fixup, Value, Ctx);
313     break;
314   case AVR::fixup_ms8_ldi_neg:
315     adjust::ldi::neg(Value);
316     adjust::ldi::ms8(Size, Fixup, Value, Ctx);
317     break;
318   case AVR::fixup_16:
319     adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
320 
321     Value &= 0xffff;
322     break;
323   case AVR::fixup_16_pm:
324     Value >>= 1; // Flash addresses are always shifted.
325     adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
326 
327     Value &= 0xffff;
328     break;
329 
330   case AVR::fixup_6_adiw:
331     adjust::fixup_6_adiw(Fixup, Value, Ctx);
332     break;
333 
334   case AVR::fixup_port5:
335     adjust::fixup_port5(Fixup, Value, Ctx);
336     break;
337 
338   case AVR::fixup_port6:
339     adjust::fixup_port6(Fixup, Value, Ctx);
340     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 }
354 
355 std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const356 AVRAsmBackend::createObjectTargetWriter() const {
357   return createAVRELFObjectWriter(MCELFObjectTargetWriter::getOSABI(OSType));
358 }
359 
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const360 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   adjustFixupValue(Fixup, Target, Value, &Asm.getContext());
366   if (Value == 0)
367     return; // Doesn't change encoding.
368 
369   MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
370 
371   // The number of bits in the fixup mask
372   auto NumBits = Info.TargetSize + Info.TargetOffset;
373   auto NumBytes = (NumBits / 8) + ((NumBits % 8) == 0 ? 0 : 1);
374 
375   // Shift the value into position.
376   Value <<= Info.TargetOffset;
377 
378   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   for (unsigned i = 0; i < NumBytes; ++i) {
384     uint8_t mask = (((Value >> (i * 8)) & 0xff));
385     Data[Offset + i] |= mask;
386   }
387 }
388 
getFixupKindInfo(MCFixupKind Kind) const389 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   if (Kind < FirstTargetFixupKind)
449     return MCAsmBackend::getFixupKindInfo(Kind);
450 
451   assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
452          "Invalid kind!");
453 
454   return Infos[Kind - FirstTargetFixupKind];
455 }
456 
writeNopData(raw_ostream & OS,uint64_t Count) const457 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   OS.write_zeros(Count);
464   return true;
465 }
466 
shouldForceRelocation(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target)467 bool AVRAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
468                                           const MCFixup &Fixup,
469                                           const MCValue &Target) {
470   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 
createAVRAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const llvm::MCTargetOptions & TO)480 MCAsmBackend *createAVRAsmBackend(const Target &T, const MCSubtargetInfo &STI,
481                                   const MCRegisterInfo &MRI,
482                                   const llvm::MCTargetOptions &TO) {
483   return new AVRAsmBackend(STI.getTargetTriple().getOS());
484 }
485 
486 } // end of namespace llvm
487 
488