xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp (revision d5b0e70f7e04d971691517ce1304d86a1e367e2e)
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 
17 namespace llvm {
18 
19 namespace {
20 
21 const 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 
38 const AVRMCExpr *AVRMCExpr::create(VariantKind Kind, const MCExpr *Expr,
39                                    bool Negated, MCContext &Ctx) {
40   return new (Ctx) AVRMCExpr(Kind, Expr, Negated);
41 }
42 
43 void 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 
54 bool 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 
71 bool 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 
102 int64_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 
149 AVR::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 
193 void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
194   Streamer.visitUsedExpr(*getSubExpr());
195 }
196 
197 const 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 
209 AVRMCExpr::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