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