190 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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<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_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
 | |
| 
 |