//===-- AVRMCExpr.cpp - AVR specific MC expression classes ----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "AVRMCExpr.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/MCAsmLayout.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_lo8", AVRMCExpr::VK_AVR_PM_LO8}, {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8}, {"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8}, }; } // 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); if (isNegated()) OS << '-'; OS << getName() << '('; getSubExpr()->print(OS, MAI); 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; 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: break; case AVRMCExpr::VK_AVR_HI8: Value >>= 8; break; case AVRMCExpr::VK_AVR_HH8: Value >>= 16; break; case AVRMCExpr::VK_AVR_HHI8: Value >>= 24; break; case AVRMCExpr::VK_AVR_PM_LO8: Value >>= 1; break; case AVRMCExpr::VK_AVR_PM_HI8: Value >>= 9; break; case AVRMCExpr::VK_AVR_PM_HH8: Value >>= 17; break; case AVRMCExpr::VK_AVR_None: llvm_unreachable("Uninitialized expression."); } return static_cast(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_None: llvm_unreachable("Uninitialized expression"); } return Kind; } void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const { Streamer.visitUsedExpr(*getSubExpr()); } const char *AVRMCExpr::getName() const { const auto &Modifier = std::find_if( std::begin(ModifierNames), std::end(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 = std::find_if( std::begin(ModifierNames), std::end(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