| //===-- AVRMCExpr.cpp - AVR specific MC expression classes ----------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "AVRMCExpr.h" | |
| #include "llvm/MC/MCAsmLayout.h" | |
| #include "llvm/MC/MCAssembler.h" | |
| #include "llvm/MC/MCContext.h" | |
| #include "llvm/MC/MCStreamer.h" | |
| #include "llvm/MC/MCValue.h" | |
| namespace llvm { | |
| namespace { | |
| const struct ModifierEntry { | |
| const char *const Spelling; | |
| AVRMCExpr::VariantKind VariantKind; | |
| } ModifierNames[] = { | |
| {"lo8", AVRMCExpr::VK_AVR_LO8}, {"hi8", AVRMCExpr::VK_AVR_HI8}, | |
| {"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8 | |
| {"hlo8", AVRMCExpr::VK_AVR_HH8}, {"hhi8", AVRMCExpr::VK_AVR_HHI8}, | |
| {"pm", AVRMCExpr::VK_AVR_PM}, {"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, | |
| {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8}, {"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8}, | |
| {"lo8_gs", AVRMCExpr::VK_AVR_LO8_GS}, {"hi8_gs", AVRMCExpr::VK_AVR_HI8_GS}, | |
| {"gs", AVRMCExpr::VK_AVR_GS}, | |
| }; | |
| } // end of anonymous namespace | |
| const AVRMCExpr *AVRMCExpr::create(VariantKind Kind, const MCExpr *Expr, | |
| bool Negated, MCContext &Ctx) { | |
| return new (Ctx) AVRMCExpr(Kind, Expr, Negated); | |
| } | |
| void AVRMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { | |
| assert(Kind != VK_AVR_None); | |
| OS << getName() << '('; | |
| if (isNegated()) | |
| OS << '-' << '('; | |
| getSubExpr()->print(OS, MAI); | |
| if (isNegated()) | |
| OS << ')'; | |
| OS << ')'; | |
| } | |
| bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const { | |
| MCValue Value; | |
| bool isRelocatable = | |
| getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr); | |
| if (!isRelocatable) | |
| return false; | |
| if (Value.isAbsolute()) { | |
| Result = evaluateAsInt64(Value.getConstant()); | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result, | |
| const MCAsmLayout *Layout, | |
| const MCFixup *Fixup) const { | |
| MCValue Value; | |
| bool isRelocatable = SubExpr->evaluateAsRelocatable(Value, Layout, Fixup); | |
| if (!isRelocatable) | |
| return false; | |
| if (Value.isAbsolute()) { | |
| Result = MCValue::get(evaluateAsInt64(Value.getConstant())); | |
| } else { | |
| if (!Layout) | |
| return false; | |
| MCContext &Context = Layout->getAssembler().getContext(); | |
| const MCSymbolRefExpr *Sym = Value.getSymA(); | |
| MCSymbolRefExpr::VariantKind Modifier = Sym->getKind(); | |
| if (Modifier != MCSymbolRefExpr::VK_None) | |
| return false; | |
| if (Kind == VK_AVR_PM) { | |
| Modifier = MCSymbolRefExpr::VK_AVR_PM; | |
| } | |
| Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context); | |
| Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant()); | |
| } | |
| return true; | |
| } | |
| int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const { | |
| if (Negated) | |
| Value *= -1; | |
| switch (Kind) { | |
| case AVRMCExpr::VK_AVR_LO8: | |
| Value &= 0xff; | |
| break; | |
| case AVRMCExpr::VK_AVR_HI8: | |
| Value &= 0xff00; | |
| Value >>= 8; | |
| break; | |
| case AVRMCExpr::VK_AVR_HH8: | |
| Value &= 0xff0000; | |
| Value >>= 16; | |
| break; | |
| case AVRMCExpr::VK_AVR_HHI8: | |
| Value &= 0xff000000; | |
| Value >>= 24; | |
| break; | |
| case AVRMCExpr::VK_AVR_PM_LO8: | |
| case AVRMCExpr::VK_AVR_LO8_GS: | |
| Value >>= 1; // Program memory addresses must always be shifted by one. | |
| Value &= 0xff; | |
| break; | |
| case AVRMCExpr::VK_AVR_PM_HI8: | |
| case AVRMCExpr::VK_AVR_HI8_GS: | |
| Value >>= 1; // Program memory addresses must always be shifted by one. | |
| Value &= 0xff00; | |
| Value >>= 8; | |
| break; | |
| case AVRMCExpr::VK_AVR_PM_HH8: | |
| Value >>= 1; // Program memory addresses must always be shifted by one. | |
| Value &= 0xff0000; | |
| Value >>= 16; | |
| break; | |
| case AVRMCExpr::VK_AVR_PM: | |
| case AVRMCExpr::VK_AVR_GS: | |
| Value >>= 1; // Program memory addresses must always be shifted by one. | |
| break; | |
| case AVRMCExpr::VK_AVR_None: | |
| llvm_unreachable("Uninitialized expression."); | |
| } | |
| return static_cast<uint64_t>(Value) & 0xff; | |
| } | |
| AVR::Fixups AVRMCExpr::getFixupKind() const { | |
| AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind; | |
| switch (getKind()) { | |
| case VK_AVR_LO8: | |
| Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi; | |
| break; | |
| case VK_AVR_HI8: | |
| Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi; | |
| break; | |
| case VK_AVR_HH8: | |
| Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi; | |
| break; | |
| case VK_AVR_HHI8: | |
| Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi; | |
| break; | |
| case VK_AVR_PM_LO8: | |
| Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm; | |
| break; | |
| case VK_AVR_PM_HI8: | |
| Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm; | |
| break; | |
| case VK_AVR_PM_HH8: | |
| Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm; | |
| break; | |
| case VK_AVR_PM: | |
| case VK_AVR_GS: | |
| Kind = AVR::fixup_16_pm; | |
| break; | |
| case VK_AVR_LO8_GS: | |
| Kind = AVR::fixup_lo8_ldi_gs; | |
| break; | |
| case VK_AVR_HI8_GS: | |
| Kind = AVR::fixup_hi8_ldi_gs; | |
| break; | |
| case VK_AVR_None: | |
| llvm_unreachable("Uninitialized expression"); | |
| } | |
| return Kind; | |
| } | |
| void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const { | |
| Streamer.visitUsedExpr(*getSubExpr()); | |
| } | |
| const char *AVRMCExpr::getName() const { | |
| const auto &Modifier = | |
| llvm::find_if(ModifierNames, [this](ModifierEntry const &Mod) { | |
| return Mod.VariantKind == Kind; | |
| }); | |
| if (Modifier != std::end(ModifierNames)) { | |
| return Modifier->Spelling; | |
| } | |
| return nullptr; | |
| } | |
| AVRMCExpr::VariantKind AVRMCExpr::getKindByName(StringRef Name) { | |
| const auto &Modifier = | |
| llvm::find_if(ModifierNames, [&Name](ModifierEntry const &Mod) { | |
| return Mod.Spelling == Name; | |
| }); | |
| if (Modifier != std::end(ModifierNames)) { | |
| return Modifier->VariantKind; | |
| } | |
| return VK_AVR_None; | |
| } | |
| } // end of namespace llvm |