215 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- 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_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
 | 
						|
 |