xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- AVRMCExpr.cpp - AVR specific MC expression classes ----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "AVRMCExpr.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
120b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
130b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
140b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric namespace llvm {
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric namespace {
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric const struct ModifierEntry {
210b57cec5SDimitry Andric   const char *const Spelling;
220b57cec5SDimitry Andric   AVRMCExpr::VariantKind VariantKind;
230b57cec5SDimitry Andric } ModifierNames[] = {
240b57cec5SDimitry Andric     {"lo8", AVRMCExpr::VK_AVR_LO8},       {"hi8", AVRMCExpr::VK_AVR_HI8},
250b57cec5SDimitry Andric     {"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8
260b57cec5SDimitry Andric     {"hlo8", AVRMCExpr::VK_AVR_HH8},      {"hhi8", AVRMCExpr::VK_AVR_HHI8},
270b57cec5SDimitry Andric 
28349cc55cSDimitry Andric     {"pm", AVRMCExpr::VK_AVR_PM},         {"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8},
29349cc55cSDimitry Andric     {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8}, {"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8},
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric     {"lo8_gs", AVRMCExpr::VK_AVR_LO8_GS}, {"hi8_gs", AVRMCExpr::VK_AVR_HI8_GS},
320b57cec5SDimitry Andric     {"gs", AVRMCExpr::VK_AVR_GS},
330b57cec5SDimitry Andric };
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric } // end of anonymous namespace
360b57cec5SDimitry Andric 
create(VariantKind Kind,const MCExpr * Expr,bool Negated,MCContext & Ctx)370b57cec5SDimitry Andric const AVRMCExpr *AVRMCExpr::create(VariantKind Kind, const MCExpr *Expr,
380b57cec5SDimitry Andric                                    bool Negated, MCContext &Ctx) {
390b57cec5SDimitry Andric   return new (Ctx) AVRMCExpr(Kind, Expr, Negated);
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric 
printImpl(raw_ostream & OS,const MCAsmInfo * MAI) const420b57cec5SDimitry Andric void AVRMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
430b57cec5SDimitry Andric   assert(Kind != VK_AVR_None);
440b57cec5SDimitry Andric   OS << getName() << '(';
45bdd1243dSDimitry Andric   if (isNegated())
46bdd1243dSDimitry Andric     OS << '-' << '(';
470b57cec5SDimitry Andric   getSubExpr()->print(OS, MAI);
48bdd1243dSDimitry Andric   if (isNegated())
49bdd1243dSDimitry Andric     OS << ')';
500b57cec5SDimitry Andric   OS << ')';
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
evaluateAsConstant(int64_t & Result) const530b57cec5SDimitry Andric bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const {
540b57cec5SDimitry Andric   MCValue Value;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   bool isRelocatable =
570b57cec5SDimitry Andric       getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr);
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   if (!isRelocatable)
600b57cec5SDimitry Andric     return false;
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   if (Value.isAbsolute()) {
630b57cec5SDimitry Andric     Result = evaluateAsInt64(Value.getConstant());
640b57cec5SDimitry Andric     return true;
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   return false;
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
evaluateAsRelocatableImpl(MCValue & Result,const MCAssembler * Asm,const MCFixup * Fixup) const700b57cec5SDimitry Andric bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result,
71*0fca6ea1SDimitry Andric                                           const MCAssembler *Asm,
720b57cec5SDimitry Andric                                           const MCFixup *Fixup) const {
730b57cec5SDimitry Andric   MCValue Value;
74*0fca6ea1SDimitry Andric   bool isRelocatable = SubExpr->evaluateAsRelocatable(Value, Asm, Fixup);
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   if (!isRelocatable)
770b57cec5SDimitry Andric     return false;
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   if (Value.isAbsolute()) {
800b57cec5SDimitry Andric     Result = MCValue::get(evaluateAsInt64(Value.getConstant()));
810b57cec5SDimitry Andric   } else {
82*0fca6ea1SDimitry Andric     if (!Asm || !Asm->hasLayout())
83349cc55cSDimitry Andric       return false;
840b57cec5SDimitry Andric 
85*0fca6ea1SDimitry Andric     MCContext &Context = Asm->getContext();
860b57cec5SDimitry Andric     const MCSymbolRefExpr *Sym = Value.getSymA();
870b57cec5SDimitry Andric     MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
880b57cec5SDimitry Andric     if (Modifier != MCSymbolRefExpr::VK_None)
890b57cec5SDimitry Andric       return false;
90fe6060f1SDimitry Andric     if (Kind == VK_AVR_PM) {
91fe6060f1SDimitry Andric       Modifier = MCSymbolRefExpr::VK_AVR_PM;
92fe6060f1SDimitry Andric     }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric     Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
950b57cec5SDimitry Andric     Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   return true;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
evaluateAsInt64(int64_t Value) const1010b57cec5SDimitry Andric int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const {
1020b57cec5SDimitry Andric   if (Negated)
1030b57cec5SDimitry Andric     Value *= -1;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   switch (Kind) {
1060b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_LO8:
1070b57cec5SDimitry Andric     Value &= 0xff;
1080b57cec5SDimitry Andric     break;
1090b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_HI8:
1100b57cec5SDimitry Andric     Value &= 0xff00;
1110b57cec5SDimitry Andric     Value >>= 8;
1120b57cec5SDimitry Andric     break;
1130b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_HH8:
1140b57cec5SDimitry Andric     Value &= 0xff0000;
1150b57cec5SDimitry Andric     Value >>= 16;
1160b57cec5SDimitry Andric     break;
1170b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_HHI8:
1180b57cec5SDimitry Andric     Value &= 0xff000000;
1190b57cec5SDimitry Andric     Value >>= 24;
1200b57cec5SDimitry Andric     break;
1210b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_PM_LO8:
1220b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_LO8_GS:
1230b57cec5SDimitry Andric     Value >>= 1; // Program memory addresses must always be shifted by one.
1240b57cec5SDimitry Andric     Value &= 0xff;
1250b57cec5SDimitry Andric     break;
1260b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_PM_HI8:
1270b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_HI8_GS:
1280b57cec5SDimitry Andric     Value >>= 1; // Program memory addresses must always be shifted by one.
1290b57cec5SDimitry Andric     Value &= 0xff00;
1300b57cec5SDimitry Andric     Value >>= 8;
1310b57cec5SDimitry Andric     break;
1320b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_PM_HH8:
1330b57cec5SDimitry Andric     Value >>= 1; // Program memory addresses must always be shifted by one.
1340b57cec5SDimitry Andric     Value &= 0xff0000;
1350b57cec5SDimitry Andric     Value >>= 16;
1360b57cec5SDimitry Andric     break;
137fe6060f1SDimitry Andric   case AVRMCExpr::VK_AVR_PM:
1380b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_GS:
1390b57cec5SDimitry Andric     Value >>= 1; // Program memory addresses must always be shifted by one.
1400b57cec5SDimitry Andric     break;
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   case AVRMCExpr::VK_AVR_None:
1430b57cec5SDimitry Andric     llvm_unreachable("Uninitialized expression.");
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric   return static_cast<uint64_t>(Value) & 0xff;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
getFixupKind() const1480b57cec5SDimitry Andric AVR::Fixups AVRMCExpr::getFixupKind() const {
1490b57cec5SDimitry Andric   AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind;
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   switch (getKind()) {
1520b57cec5SDimitry Andric   case VK_AVR_LO8:
1530b57cec5SDimitry Andric     Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi;
1540b57cec5SDimitry Andric     break;
1550b57cec5SDimitry Andric   case VK_AVR_HI8:
1560b57cec5SDimitry Andric     Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi;
1570b57cec5SDimitry Andric     break;
1580b57cec5SDimitry Andric   case VK_AVR_HH8:
1590b57cec5SDimitry Andric     Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi;
1600b57cec5SDimitry Andric     break;
1610b57cec5SDimitry Andric   case VK_AVR_HHI8:
1620b57cec5SDimitry Andric     Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi;
1630b57cec5SDimitry Andric     break;
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   case VK_AVR_PM_LO8:
1660b57cec5SDimitry Andric     Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm;
1670b57cec5SDimitry Andric     break;
1680b57cec5SDimitry Andric   case VK_AVR_PM_HI8:
1690b57cec5SDimitry Andric     Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm;
1700b57cec5SDimitry Andric     break;
1710b57cec5SDimitry Andric   case VK_AVR_PM_HH8:
1720b57cec5SDimitry Andric     Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm;
1730b57cec5SDimitry Andric     break;
174fe6060f1SDimitry Andric   case VK_AVR_PM:
1750b57cec5SDimitry Andric   case VK_AVR_GS:
1760b57cec5SDimitry Andric     Kind = AVR::fixup_16_pm;
1770b57cec5SDimitry Andric     break;
1780b57cec5SDimitry Andric   case VK_AVR_LO8_GS:
1790b57cec5SDimitry Andric     Kind = AVR::fixup_lo8_ldi_gs;
1800b57cec5SDimitry Andric     break;
1810b57cec5SDimitry Andric   case VK_AVR_HI8_GS:
1820b57cec5SDimitry Andric     Kind = AVR::fixup_hi8_ldi_gs;
1830b57cec5SDimitry Andric     break;
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   case VK_AVR_None:
1860b57cec5SDimitry Andric     llvm_unreachable("Uninitialized expression");
1870b57cec5SDimitry Andric   }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric   return Kind;
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
visitUsedExpr(MCStreamer & Streamer) const1920b57cec5SDimitry Andric void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
1930b57cec5SDimitry Andric   Streamer.visitUsedExpr(*getSubExpr());
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
getName() const1960b57cec5SDimitry Andric const char *AVRMCExpr::getName() const {
197e8d8bef9SDimitry Andric   const auto &Modifier =
198e8d8bef9SDimitry Andric       llvm::find_if(ModifierNames, [this](ModifierEntry const &Mod) {
199e8d8bef9SDimitry Andric         return Mod.VariantKind == Kind;
200e8d8bef9SDimitry Andric       });
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   if (Modifier != std::end(ModifierNames)) {
2030b57cec5SDimitry Andric     return Modifier->Spelling;
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric   return nullptr;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
getKindByName(StringRef Name)2080b57cec5SDimitry Andric AVRMCExpr::VariantKind AVRMCExpr::getKindByName(StringRef Name) {
209e8d8bef9SDimitry Andric   const auto &Modifier =
210e8d8bef9SDimitry Andric       llvm::find_if(ModifierNames, [&Name](ModifierEntry const &Mod) {
211e8d8bef9SDimitry Andric         return Mod.Spelling == Name;
212e8d8bef9SDimitry Andric       });
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   if (Modifier != std::end(ModifierNames)) {
2150b57cec5SDimitry Andric     return Modifier->VariantKind;
2160b57cec5SDimitry Andric   }
2170b57cec5SDimitry Andric   return VK_AVR_None;
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric } // end of namespace llvm
221