1 | //===-- AVRMCAsmInfo.cpp - AVR asm properties -----------------------------===// |
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 contains the declarations of the AVRMCAsmInfo properties. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "AVRMCAsmInfo.h" |
14 | #include "llvm/MC/MCAssembler.h" |
15 | #include "llvm/MC/MCContext.h" |
16 | #include "llvm/MC/MCExpr.h" |
17 | #include "llvm/MC/MCValue.h" |
18 | #include "llvm/TargetParser/Triple.h" |
19 | |
20 | using namespace llvm; |
21 | |
22 | AVRMCAsmInfo::AVRMCAsmInfo(const Triple &TT, const MCTargetOptions &Options) { |
23 | CodePointerSize = 2; |
24 | CalleeSaveStackSlotSize = 2; |
25 | CommentString = ";" ; |
26 | SeparatorString = "$" ; |
27 | PrivateGlobalPrefix = ".L" ; |
28 | PrivateLabelPrefix = ".L" ; |
29 | UsesELFSectionDirectiveForBSS = true; |
30 | SupportsDebugInformation = true; |
31 | } |
32 | |
33 | namespace { |
34 | const struct ModifierEntry { |
35 | const char *const Spelling; |
36 | AVRMCExpr::Specifier specifier; |
37 | } ModifierNames[] = { |
38 | {.Spelling: "lo8" , .specifier: AVR::S_LO8}, {.Spelling: "hi8" , .specifier: AVR::S_HI8}, |
39 | {.Spelling: "hh8" , .specifier: AVR::S_HH8}, // synonym with hlo8 |
40 | {.Spelling: "hlo8" , .specifier: AVR::S_HH8}, {.Spelling: "hhi8" , .specifier: AVR::S_HHI8}, |
41 | |
42 | {.Spelling: "pm" , .specifier: AVR::S_PM}, {.Spelling: "pm_lo8" , .specifier: AVR::S_PM_LO8}, |
43 | {.Spelling: "pm_hi8" , .specifier: AVR::S_PM_HI8}, {.Spelling: "pm_hh8" , .specifier: AVR::S_PM_HH8}, |
44 | |
45 | {.Spelling: "lo8_gs" , .specifier: AVR::S_LO8_GS}, {.Spelling: "hi8_gs" , .specifier: AVR::S_HI8_GS}, |
46 | {.Spelling: "gs" , .specifier: AVR::S_GS}, |
47 | }; |
48 | |
49 | } // end of anonymous namespace |
50 | |
51 | AVRMCExpr::Specifier AVRMCExpr::parseSpecifier(StringRef Name) { |
52 | const auto &Modifier = |
53 | llvm::find_if(Range: ModifierNames, P: [&Name](ModifierEntry const &Mod) { |
54 | return Mod.Spelling == Name; |
55 | }); |
56 | |
57 | if (Modifier != std::end(arr: ModifierNames)) { |
58 | return Modifier->specifier; |
59 | } |
60 | return AVR::S_AVR_NONE; |
61 | } |
62 | |
63 | const char *AVRMCExpr::getName() const { |
64 | const auto &Modifier = |
65 | llvm::find_if(Range: ModifierNames, P: [this](ModifierEntry const &Mod) { |
66 | return Mod.specifier == specifier; |
67 | }); |
68 | |
69 | if (Modifier != std::end(arr: ModifierNames)) { |
70 | return Modifier->Spelling; |
71 | } |
72 | return nullptr; |
73 | } |
74 | |
75 | AVR::Fixups AVRMCExpr::getFixupKind() const { |
76 | AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind; |
77 | |
78 | switch (specifier) { |
79 | case AVR::S_LO8: |
80 | Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi; |
81 | break; |
82 | case AVR::S_HI8: |
83 | Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi; |
84 | break; |
85 | case AVR::S_HH8: |
86 | Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi; |
87 | break; |
88 | case AVR::S_HHI8: |
89 | Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi; |
90 | break; |
91 | |
92 | case AVR::S_PM_LO8: |
93 | Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm; |
94 | break; |
95 | case AVR::S_PM_HI8: |
96 | Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm; |
97 | break; |
98 | case AVR::S_PM_HH8: |
99 | Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm; |
100 | break; |
101 | case AVR::S_PM: |
102 | case AVR::S_GS: |
103 | Kind = AVR::fixup_16_pm; |
104 | break; |
105 | case AVR::S_LO8_GS: |
106 | Kind = AVR::fixup_lo8_ldi_gs; |
107 | break; |
108 | case AVR::S_HI8_GS: |
109 | Kind = AVR::fixup_hi8_ldi_gs; |
110 | break; |
111 | |
112 | default: |
113 | llvm_unreachable("Uninitialized expression" ); |
114 | } |
115 | |
116 | return Kind; |
117 | } |
118 | |
119 | void AVRMCAsmInfo::printSpecifierExpr(raw_ostream &OS, |
120 | const MCSpecifierExpr &Expr) const { |
121 | auto &E = static_cast<const AVRMCExpr &>(Expr); |
122 | assert(E.getSpecifier() != AVR::S_AVR_NONE); |
123 | OS << E.getName() << '('; |
124 | if (E.isNegated()) |
125 | OS << '-' << '('; |
126 | printExpr(OS, *E.getSubExpr()); |
127 | if (E.isNegated()) |
128 | OS << ')'; |
129 | OS << ')'; |
130 | } |
131 | |
132 | int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const { |
133 | if (Negated) |
134 | Value *= -1; |
135 | |
136 | switch (specifier) { |
137 | case AVR::S_LO8: |
138 | Value &= 0xff; |
139 | break; |
140 | case AVR::S_HI8: |
141 | Value &= 0xff00; |
142 | Value >>= 8; |
143 | break; |
144 | case AVR::S_HH8: |
145 | Value &= 0xff0000; |
146 | Value >>= 16; |
147 | break; |
148 | case AVR::S_HHI8: |
149 | Value &= 0xff000000; |
150 | Value >>= 24; |
151 | break; |
152 | case AVR::S_PM_LO8: |
153 | case AVR::S_LO8_GS: |
154 | Value >>= 1; // Program memory addresses must always be shifted by one. |
155 | Value &= 0xff; |
156 | break; |
157 | case AVR::S_PM_HI8: |
158 | case AVR::S_HI8_GS: |
159 | Value >>= 1; // Program memory addresses must always be shifted by one. |
160 | Value &= 0xff00; |
161 | Value >>= 8; |
162 | break; |
163 | case AVR::S_PM_HH8: |
164 | Value >>= 1; // Program memory addresses must always be shifted by one. |
165 | Value &= 0xff0000; |
166 | Value >>= 16; |
167 | break; |
168 | case AVR::S_PM: |
169 | case AVR::S_GS: |
170 | Value >>= 1; // Program memory addresses must always be shifted by one. |
171 | break; |
172 | |
173 | case AVR::S_AVR_NONE: |
174 | default: |
175 | llvm_unreachable("Uninitialized expression." ); |
176 | } |
177 | return static_cast<uint64_t>(Value) & 0xff; |
178 | } |
179 | |
180 | // bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result, |
181 | // const MCAssembler *Asm) const { |
182 | bool AVRMCAsmInfo::evaluateAsRelocatableImpl(const MCSpecifierExpr &Expr, |
183 | MCValue &Result, |
184 | const MCAssembler *Asm) const { |
185 | auto &E = static_cast<const AVRMCExpr &>(Expr); |
186 | MCValue Value; |
187 | bool isRelocatable = E.getSubExpr()->evaluateAsRelocatable(Res&: Value, Asm); |
188 | if (!isRelocatable) |
189 | return false; |
190 | |
191 | if (Value.isAbsolute()) { |
192 | Result = MCValue::get(Val: E.evaluateAsInt64(Value: Value.getConstant())); |
193 | } else { |
194 | if (!Asm || !Asm->hasLayout()) |
195 | return false; |
196 | |
197 | auto Spec = AVR::S_None; |
198 | if (Value.getSpecifier()) |
199 | return false; |
200 | assert(!Value.getSubSym()); |
201 | if (E.getSpecifier() == AVR::S_PM) |
202 | Spec = AVR::S_PM; |
203 | |
204 | // TODO: don't attach specifier to MCSymbolRefExpr. |
205 | Result = |
206 | MCValue::get(SymA: Value.getAddSym(), SymB: nullptr, Val: Value.getConstant(), Specifier: Spec); |
207 | } |
208 | |
209 | return true; |
210 | } |
211 | |
212 | bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const { |
213 | MCValue Value; |
214 | bool isRelocatable = getSubExpr()->evaluateAsRelocatable(Res&: Value, Asm: nullptr); |
215 | if (!isRelocatable) |
216 | return false; |
217 | |
218 | if (Value.isAbsolute()) { |
219 | Result = evaluateAsInt64(Value: Value.getConstant()); |
220 | return true; |
221 | } |
222 | |
223 | return false; |
224 | } |
225 | |