text: //===-- 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/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_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);
  
    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:
      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_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_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 = 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
  
  