1//===-- AVRMCExpr.cpp - AVR specific MC expression classes ----------------===//
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#include "AVRMCExpr.h"
10
11#include "llvm/MC/MCAssembler.h"
12#include "llvm/MC/MCContext.h"
13#include "llvm/MC/MCStreamer.h"
14#include "llvm/MC/MCValue.h"
15
16namespace llvm {
17
18namespace {
19
20const struct ModifierEntry {
21 const char *const Spelling;
22 AVRMCExpr::VariantKind VariantKind;
23} ModifierNames[] = {
24 {.Spelling: "lo8", .VariantKind: AVRMCExpr::VK_AVR_LO8}, {.Spelling: "hi8", .VariantKind: AVRMCExpr::VK_AVR_HI8},
25 {.Spelling: "hh8", .VariantKind: AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8
26 {.Spelling: "hlo8", .VariantKind: AVRMCExpr::VK_AVR_HH8}, {.Spelling: "hhi8", .VariantKind: AVRMCExpr::VK_AVR_HHI8},
27
28 {.Spelling: "pm", .VariantKind: AVRMCExpr::VK_AVR_PM}, {.Spelling: "pm_lo8", .VariantKind: AVRMCExpr::VK_AVR_PM_LO8},
29 {.Spelling: "pm_hi8", .VariantKind: AVRMCExpr::VK_AVR_PM_HI8}, {.Spelling: "pm_hh8", .VariantKind: AVRMCExpr::VK_AVR_PM_HH8},
30
31 {.Spelling: "lo8_gs", .VariantKind: AVRMCExpr::VK_AVR_LO8_GS}, {.Spelling: "hi8_gs", .VariantKind: AVRMCExpr::VK_AVR_HI8_GS},
32 {.Spelling: "gs", .VariantKind: AVRMCExpr::VK_AVR_GS},
33};
34
35} // end of anonymous namespace
36
37const AVRMCExpr *AVRMCExpr::create(VariantKind Kind, const MCExpr *Expr,
38 bool Negated, MCContext &Ctx) {
39 return new (Ctx) AVRMCExpr(Kind, Expr, Negated);
40}
41
42void AVRMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
43 assert(Kind != VK_AVR_None);
44 OS << getName() << '(';
45 if (isNegated())
46 OS << '-' << '(';
47 getSubExpr()->print(OS, MAI);
48 if (isNegated())
49 OS << ')';
50 OS << ')';
51}
52
53bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const {
54 MCValue Value;
55
56 bool isRelocatable =
57 getSubExpr()->evaluateAsRelocatable(Res&: Value, Asm: nullptr, Fixup: nullptr);
58
59 if (!isRelocatable)
60 return false;
61
62 if (Value.isAbsolute()) {
63 Result = evaluateAsInt64(Value: Value.getConstant());
64 return true;
65 }
66
67 return false;
68}
69
70bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result,
71 const MCAssembler *Asm,
72 const MCFixup *Fixup) const {
73 MCValue Value;
74 bool isRelocatable = SubExpr->evaluateAsRelocatable(Res&: Value, Asm, Fixup);
75
76 if (!isRelocatable)
77 return false;
78
79 if (Value.isAbsolute()) {
80 Result = MCValue::get(Val: evaluateAsInt64(Value: Value.getConstant()));
81 } else {
82 if (!Asm || !Asm->hasLayout())
83 return false;
84
85 MCContext &Context = Asm->getContext();
86 const MCSymbolRefExpr *Sym = Value.getSymA();
87 MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
88 if (Modifier != MCSymbolRefExpr::VK_None)
89 return false;
90 if (Kind == VK_AVR_PM) {
91 Modifier = MCSymbolRefExpr::VK_AVR_PM;
92 }
93
94 Sym = MCSymbolRefExpr::create(Symbol: &Sym->getSymbol(), Kind: Modifier, Ctx&: Context);
95 Result = MCValue::get(SymA: Sym, SymB: Value.getSymB(), Val: Value.getConstant());
96 }
97
98 return true;
99}
100
101int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const {
102 if (Negated)
103 Value *= -1;
104
105 switch (Kind) {
106 case AVRMCExpr::VK_AVR_LO8:
107 Value &= 0xff;
108 break;
109 case AVRMCExpr::VK_AVR_HI8:
110 Value &= 0xff00;
111 Value >>= 8;
112 break;
113 case AVRMCExpr::VK_AVR_HH8:
114 Value &= 0xff0000;
115 Value >>= 16;
116 break;
117 case AVRMCExpr::VK_AVR_HHI8:
118 Value &= 0xff000000;
119 Value >>= 24;
120 break;
121 case AVRMCExpr::VK_AVR_PM_LO8:
122 case AVRMCExpr::VK_AVR_LO8_GS:
123 Value >>= 1; // Program memory addresses must always be shifted by one.
124 Value &= 0xff;
125 break;
126 case AVRMCExpr::VK_AVR_PM_HI8:
127 case AVRMCExpr::VK_AVR_HI8_GS:
128 Value >>= 1; // Program memory addresses must always be shifted by one.
129 Value &= 0xff00;
130 Value >>= 8;
131 break;
132 case AVRMCExpr::VK_AVR_PM_HH8:
133 Value >>= 1; // Program memory addresses must always be shifted by one.
134 Value &= 0xff0000;
135 Value >>= 16;
136 break;
137 case AVRMCExpr::VK_AVR_PM:
138 case AVRMCExpr::VK_AVR_GS:
139 Value >>= 1; // Program memory addresses must always be shifted by one.
140 break;
141
142 case AVRMCExpr::VK_AVR_None:
143 llvm_unreachable("Uninitialized expression.");
144 }
145 return static_cast<uint64_t>(Value) & 0xff;
146}
147
148AVR::Fixups AVRMCExpr::getFixupKind() const {
149 AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind;
150
151 switch (getKind()) {
152 case VK_AVR_LO8:
153 Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi;
154 break;
155 case VK_AVR_HI8:
156 Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi;
157 break;
158 case VK_AVR_HH8:
159 Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi;
160 break;
161 case VK_AVR_HHI8:
162 Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi;
163 break;
164
165 case VK_AVR_PM_LO8:
166 Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm;
167 break;
168 case VK_AVR_PM_HI8:
169 Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm;
170 break;
171 case VK_AVR_PM_HH8:
172 Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm;
173 break;
174 case VK_AVR_PM:
175 case VK_AVR_GS:
176 Kind = AVR::fixup_16_pm;
177 break;
178 case VK_AVR_LO8_GS:
179 Kind = AVR::fixup_lo8_ldi_gs;
180 break;
181 case VK_AVR_HI8_GS:
182 Kind = AVR::fixup_hi8_ldi_gs;
183 break;
184
185 case VK_AVR_None:
186 llvm_unreachable("Uninitialized expression");
187 }
188
189 return Kind;
190}
191
192void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
193 Streamer.visitUsedExpr(Expr: *getSubExpr());
194}
195
196const char *AVRMCExpr::getName() const {
197 const auto &Modifier =
198 llvm::find_if(Range: ModifierNames, P: [this](ModifierEntry const &Mod) {
199 return Mod.VariantKind == Kind;
200 });
201
202 if (Modifier != std::end(arr: ModifierNames)) {
203 return Modifier->Spelling;
204 }
205 return nullptr;
206}
207
208AVRMCExpr::VariantKind AVRMCExpr::getKindByName(StringRef Name) {
209 const auto &Modifier =
210 llvm::find_if(Range: ModifierNames, P: [&Name](ModifierEntry const &Mod) {
211 return Mod.Spelling == Name;
212 });
213
214 if (Modifier != std::end(arr: ModifierNames)) {
215 return Modifier->VariantKind;
216 }
217 return VK_AVR_None;
218}
219
220} // end of namespace llvm
221