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
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 static void signed_width(unsigned Width, uint64_t Value,
39 std::string Description, const MCFixup &Fixup,
40 MCContext *Ctx = nullptr) {
41 if (!isIntN(Width, Value)) {
42 std::string Diagnostic = "out of range " + Description;
43
44 int64_t Min = minIntN(Width);
45 int64_t Max = maxIntN(Width);
46
47 Diagnostic += " (expected an integer in the range " + std::to_string(Min) +
48 " to " + std::to_string(Max) + ")";
49
50 if (Ctx) {
51 Ctx->reportError(Fixup.getLoc(), Diagnostic);
52 } else {
53 llvm_unreachable(Diagnostic.c_str());
54 }
55 }
56 }
57
unsigned_width(unsigned Width,uint64_t Value,std::string Description,const MCFixup & Fixup,MCContext * Ctx=nullptr)58 static void unsigned_width(unsigned Width, uint64_t Value,
59 std::string Description, const MCFixup &Fixup,
60 MCContext *Ctx = nullptr) {
61 if (!isUIntN(Width, Value)) {
62 std::string Diagnostic = "out of range " + Description;
63
64 int64_t Max = maxUIntN(Width);
65
66 Diagnostic +=
67 " (expected an integer in the range 0 to " + std::to_string(Max) + ")";
68
69 if (Ctx) {
70 Ctx->reportError(Fixup.getLoc(), Diagnostic);
71 } else {
72 llvm_unreachable(Diagnostic.c_str());
73 }
74 }
75 }
76
77 /// Adjusts the value of a branch target before fixup application.
adjustBranch(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)78 static 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(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
83
84 // Rightshifts the value by one.
85 AVR::fixups::adjustBranchTarget(Value);
86 }
87
88 /// Adjusts the value of a relative branch target before fixup application.
adjustRelativeBranch(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)89 static void adjustRelativeBranch(unsigned Size, const MCFixup &Fixup,
90 uint64_t &Value, MCContext *Ctx = nullptr) {
91 // Jumps are relative to the current instruction.
92 Value -= 2;
93
94 // We have one extra bit of precision because the value is rightshifted by
95 // one.
96 signed_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
97
98 // Rightshifts the value by one.
99 AVR::fixups::adjustBranchTarget(Value);
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).
fixup_call(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)108 static 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).
fixup_7_pcrel(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)124 static 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).
fixup_13_pcrel(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)138 static 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
fixup_6(const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)151 static void fixup_6(const MCFixup &Fixup, uint64_t &Value,
152 MCContext *Ctx = nullptr) {
153 unsigned_width(6, Value, 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
fixup_6_adiw(const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)163 static void fixup_6_adiw(const MCFixup &Fixup, uint64_t &Value,
164 MCContext *Ctx = nullptr) {
165 unsigned_width(6, Value, 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
fixup_port5(const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)174 static void fixup_port5(const MCFixup &Fixup, uint64_t &Value,
175 MCContext *Ctx = nullptr) {
176 unsigned_width(5, Value, 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
fixup_port6(const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)187 static void fixup_port6(const MCFixup &Fixup, uint64_t &Value,
188 MCContext *Ctx = nullptr) {
189 unsigned_width(6, Value, 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
fixup_lds_sts_16(const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)198 static void fixup_lds_sts_16(const MCFixup &Fixup, uint64_t &Value,
199 MCContext *Ctx = nullptr) {
200 unsigned_width(7, Value, 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.
pm(uint64_t & Value)206 static void pm(uint64_t &Value) { Value >>= 1; }
207
208 /// Fixups relating to the LDI instruction.
209 namespace 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).
fixup(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)216 static 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
neg(uint64_t & Value)224 static void neg(uint64_t &Value) { Value *= -1; }
225
lo8(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)226 static 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
hi8(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)232 static 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
hh8(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)238 static 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
ms8(unsigned Size,const MCFixup & Fixup,uint64_t & Value,MCContext * Ctx=nullptr)244 static 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
253 namespace llvm {
254
255 // Prepare value for the target space for it
adjustFixupValue(const MCFixup & Fixup,const MCValue & Target,uint64_t & Value,MCContext * Ctx) const256 void 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(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(16, Value, 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(16, Value, 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
377 std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const378 AVRAsmBackend::createObjectTargetWriter() const {
379 return createAVRELFObjectWriter(MCELFObjectTargetWriter::getOSABI(OSType));
380 }
381
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const382 void 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, &Asm.getContext());
390 if (Value == 0)
391 return; // Doesn't change encoding.
392
393 MCFixupKindInfo Info = getFixupKindInfo(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
getFixupKind(StringRef Name) const413 std::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("BFD_RELOC_NONE", ELF::R_AVR_NONE)
420 .Case("BFD_RELOC_16", ELF::R_AVR_16)
421 .Case("BFD_RELOC_32", ELF::R_AVR_32)
422 .Default(-1u);
423 if (Type != -1u)
424 return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
425 return std::nullopt;
426 }
427
getFixupKindInfo(MCFixupKind Kind) const428 MCFixupKindInfo 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 {"fixup_32", 0, 32, 0},
437
438 {"fixup_7_pcrel", 3, 7, MCFixupKindInfo::FKF_IsPCRel},
439 {"fixup_13_pcrel", 0, 12, MCFixupKindInfo::FKF_IsPCRel},
440
441 {"fixup_16", 0, 16, 0},
442 {"fixup_16_pm", 0, 16, 0},
443
444 {"fixup_ldi", 0, 8, 0},
445
446 {"fixup_lo8_ldi", 0, 8, 0},
447 {"fixup_hi8_ldi", 0, 8, 0},
448 {"fixup_hh8_ldi", 0, 8, 0},
449 {"fixup_ms8_ldi", 0, 8, 0},
450
451 {"fixup_lo8_ldi_neg", 0, 8, 0},
452 {"fixup_hi8_ldi_neg", 0, 8, 0},
453 {"fixup_hh8_ldi_neg", 0, 8, 0},
454 {"fixup_ms8_ldi_neg", 0, 8, 0},
455
456 {"fixup_lo8_ldi_pm", 0, 8, 0},
457 {"fixup_hi8_ldi_pm", 0, 8, 0},
458 {"fixup_hh8_ldi_pm", 0, 8, 0},
459
460 {"fixup_lo8_ldi_pm_neg", 0, 8, 0},
461 {"fixup_hi8_ldi_pm_neg", 0, 8, 0},
462 {"fixup_hh8_ldi_pm_neg", 0, 8, 0},
463
464 {"fixup_call", 0, 22, 0},
465
466 {"fixup_6", 0, 16, 0}, // non-contiguous
467 {"fixup_6_adiw", 0, 6, 0},
468
469 {"fixup_lo8_ldi_gs", 0, 8, 0},
470 {"fixup_hi8_ldi_gs", 0, 8, 0},
471
472 {"fixup_8", 0, 8, 0},
473 {"fixup_8_lo8", 0, 8, 0},
474 {"fixup_8_hi8", 0, 8, 0},
475 {"fixup_8_hlo8", 0, 8, 0},
476
477 {"fixup_diff8", 0, 8, 0},
478 {"fixup_diff16", 0, 16, 0},
479 {"fixup_diff32", 0, 32, 0},
480
481 {"fixup_lds_sts_16", 0, 16, 0},
482
483 {"fixup_port6", 0, 16, 0}, // non-contiguous
484 {"fixup_port5", 3, 5, 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(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
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const501 bool 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(Count);
509 return true;
510 }
511
shouldForceRelocation(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,const MCSubtargetInfo * STI)512 bool 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
createAVRAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const llvm::MCTargetOptions & TO)528 MCAsmBackend *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