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", AVRMCExpr::VK_AVR_PM},         {"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8},
30    {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8}, {"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  OS << getName() << '(';
46  if (isNegated())
47    OS << '-' << '(';
48  getSubExpr()->print(OS, MAI);
49  if (isNegated())
50    OS << ')';
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)
84      return false;
85
86    MCContext &Context = Layout->getAssembler().getContext();
87    const MCSymbolRefExpr *Sym = Value.getSymA();
88    MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
89    if (Modifier != MCSymbolRefExpr::VK_None)
90      return false;
91    if (Kind == VK_AVR_PM) {
92      Modifier = MCSymbolRefExpr::VK_AVR_PM;
93    }
94
95    Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
96    Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
97  }
98
99  return true;
100}
101
102int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const {
103  if (Negated)
104    Value *= -1;
105
106  switch (Kind) {
107  case AVRMCExpr::VK_AVR_LO8:
108    Value &= 0xff;
109    break;
110  case AVRMCExpr::VK_AVR_HI8:
111    Value &= 0xff00;
112    Value >>= 8;
113    break;
114  case AVRMCExpr::VK_AVR_HH8:
115    Value &= 0xff0000;
116    Value >>= 16;
117    break;
118  case AVRMCExpr::VK_AVR_HHI8:
119    Value &= 0xff000000;
120    Value >>= 24;
121    break;
122  case AVRMCExpr::VK_AVR_PM_LO8:
123  case AVRMCExpr::VK_AVR_LO8_GS:
124    Value >>= 1; // Program memory addresses must always be shifted by one.
125    Value &= 0xff;
126    break;
127  case AVRMCExpr::VK_AVR_PM_HI8:
128  case AVRMCExpr::VK_AVR_HI8_GS:
129    Value >>= 1; // Program memory addresses must always be shifted by one.
130    Value &= 0xff00;
131    Value >>= 8;
132    break;
133  case AVRMCExpr::VK_AVR_PM_HH8:
134    Value >>= 1; // Program memory addresses must always be shifted by one.
135    Value &= 0xff0000;
136    Value >>= 16;
137    break;
138  case AVRMCExpr::VK_AVR_PM:
139  case AVRMCExpr::VK_AVR_GS:
140    Value >>= 1; // Program memory addresses must always be shifted by one.
141    break;
142
143  case AVRMCExpr::VK_AVR_None:
144    llvm_unreachable("Uninitialized expression.");
145  }
146  return static_cast<uint64_t>(Value) & 0xff;
147}
148
149AVR::Fixups AVRMCExpr::getFixupKind() const {
150  AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind;
151
152  switch (getKind()) {
153  case VK_AVR_LO8:
154    Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi;
155    break;
156  case VK_AVR_HI8:
157    Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi;
158    break;
159  case VK_AVR_HH8:
160    Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi;
161    break;
162  case VK_AVR_HHI8:
163    Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi;
164    break;
165
166  case VK_AVR_PM_LO8:
167    Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm;
168    break;
169  case VK_AVR_PM_HI8:
170    Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm;
171    break;
172  case VK_AVR_PM_HH8:
173    Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm;
174    break;
175  case VK_AVR_PM:
176  case VK_AVR_GS:
177    Kind = AVR::fixup_16_pm;
178    break;
179  case VK_AVR_LO8_GS:
180    Kind = AVR::fixup_lo8_ldi_gs;
181    break;
182  case VK_AVR_HI8_GS:
183    Kind = AVR::fixup_hi8_ldi_gs;
184    break;
185
186  case VK_AVR_None:
187    llvm_unreachable("Uninitialized expression");
188  }
189
190  return Kind;
191}
192
193void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
194  Streamer.visitUsedExpr(*getSubExpr());
195}
196
197const char *AVRMCExpr::getName() const {
198  const auto &Modifier =
199      llvm::find_if(ModifierNames, [this](ModifierEntry const &Mod) {
200        return Mod.VariantKind == Kind;
201      });
202
203  if (Modifier != std::end(ModifierNames)) {
204    return Modifier->Spelling;
205  }
206  return nullptr;
207}
208
209AVRMCExpr::VariantKind AVRMCExpr::getKindByName(StringRef Name) {
210  const auto &Modifier =
211      llvm::find_if(ModifierNames, [&Name](ModifierEntry const &Mod) {
212        return Mod.Spelling == Name;
213      });
214
215  if (Modifier != std::end(ModifierNames)) {
216    return Modifier->VariantKind;
217  }
218  return VK_AVR_None;
219}
220
221} // end of namespace llvm
222