forked from OSchip/llvm-project
[AVR] Add AVRMCExpr
Summary: This adds the AVRMCExpr headers and implementation. Reviewers: arsenm, ruiu, grosbach, kparzysz Subscribers: wdng, beanz, mgorny, kparzysz, jtbandes, llvm-commits Differential Revision: https://reviews.llvm.org/D20503 llvm-svn: 282397
This commit is contained in:
parent
984461062f
commit
c4ec11f451
|
|
@ -0,0 +1,149 @@
|
||||||
|
//===-- AVRFixupKinds.h - AVR Specific Fixup Entries ------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_AVR_FIXUP_KINDS_H
|
||||||
|
#define LLVM_AVR_FIXUP_KINDS_H
|
||||||
|
|
||||||
|
#include "llvm/MC/MCFixup.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace AVR {
|
||||||
|
|
||||||
|
/// The set of supported fixups.
|
||||||
|
///
|
||||||
|
/// Although most of the current fixup types reflect a unique relocation
|
||||||
|
/// one can have multiple fixup types for a given relocation and thus need
|
||||||
|
/// to be uniquely named.
|
||||||
|
///
|
||||||
|
/// \note This table *must* be in the same order of
|
||||||
|
/// MCFixupKindInfo Infos[AVR::NumTargetFixupKinds]
|
||||||
|
/// in `AVRAsmBackend.cpp`.
|
||||||
|
enum Fixups {
|
||||||
|
/// A 32-bit AVR fixup.
|
||||||
|
fixup_32 = FirstTargetFixupKind,
|
||||||
|
|
||||||
|
/// A 7-bit PC-relative fixup for the family of conditional
|
||||||
|
/// branches which take 7-bit targets (BRNE,BRGT,etc).
|
||||||
|
fixup_7_pcrel,
|
||||||
|
/// A 12-bit PC-relative fixup for the family of branches
|
||||||
|
/// which take 12-bit targets (RJMP,RCALL,etc).
|
||||||
|
/// \note Although the fixup is labelled as 13 bits, it
|
||||||
|
/// is actually only encoded in 12. The reason for
|
||||||
|
/// The nonmenclature is that AVR branch targets are
|
||||||
|
/// rightshifted by 1, because instructions are always
|
||||||
|
/// aligned to 2 bytes, so the 0'th bit is always 0.
|
||||||
|
/// This way there is 13-bits of precision.
|
||||||
|
fixup_13_pcrel,
|
||||||
|
|
||||||
|
/// A 16-bit address.
|
||||||
|
fixup_16,
|
||||||
|
/// A 16-bit program memory address.
|
||||||
|
fixup_16_pm,
|
||||||
|
|
||||||
|
/// Replaces the 8-bit immediate with another value.
|
||||||
|
fixup_ldi,
|
||||||
|
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the lower 8 bits of a 16-bit value (bits 0-7).
|
||||||
|
fixup_lo8_ldi,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a 16-bit value (bits 8-15).
|
||||||
|
fixup_hi8_ldi,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a 24-bit value (bits 16-23).
|
||||||
|
fixup_hh8_ldi,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a 32-bit value (bits 24-31).
|
||||||
|
fixup_ms8_ldi,
|
||||||
|
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the lower 8 bits of a negated 16-bit value (bits 0-7).
|
||||||
|
fixup_lo8_ldi_neg,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a negated 16-bit value (bits 8-15).
|
||||||
|
fixup_hi8_ldi_neg,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a negated negated 24-bit value (bits 16-23).
|
||||||
|
fixup_hh8_ldi_neg,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a negated negated 32-bit value (bits 24-31).
|
||||||
|
fixup_ms8_ldi_neg,
|
||||||
|
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the lower 8 bits of a 16-bit program memory address value (bits 0-7).
|
||||||
|
fixup_lo8_ldi_pm,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a 16-bit program memory address value (bits
|
||||||
|
/// 8-15).
|
||||||
|
fixup_hi8_ldi_pm,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a 24-bit program memory address value (bits
|
||||||
|
/// 16-23).
|
||||||
|
fixup_hh8_ldi_pm,
|
||||||
|
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the lower 8 bits of a negated 16-bit program memory address value
|
||||||
|
/// (bits 0-7).
|
||||||
|
fixup_lo8_ldi_pm_neg,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a negated 16-bit program memory address value
|
||||||
|
/// (bits 8-15).
|
||||||
|
fixup_hi8_ldi_pm_neg,
|
||||||
|
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
|
||||||
|
/// with the upper 8 bits of a negated 24-bit program memory address value
|
||||||
|
/// (bits 16-23).
|
||||||
|
fixup_hh8_ldi_pm_neg,
|
||||||
|
|
||||||
|
/// A 22-bit fixup for the target of a `CALL k` or `JMP k` instruction.
|
||||||
|
fixup_call,
|
||||||
|
|
||||||
|
fixup_6,
|
||||||
|
/// A symbol+addr fixup for the `LDD <x>+<n>, <r>" family of instructions.
|
||||||
|
fixup_6_adiw,
|
||||||
|
|
||||||
|
fixup_lo8_ldi_gs,
|
||||||
|
fixup_hi8_ldi_gs,
|
||||||
|
|
||||||
|
fixup_8,
|
||||||
|
fixup_8_lo8,
|
||||||
|
fixup_8_hi8,
|
||||||
|
fixup_8_hlo8,
|
||||||
|
|
||||||
|
/// Fixup to calculate the difference between two symbols.
|
||||||
|
/// Is the only stateful fixup. We do not support it yet.
|
||||||
|
fixup_sym_diff,
|
||||||
|
fixup_16_ldst,
|
||||||
|
|
||||||
|
fixup_lds_sts_16,
|
||||||
|
|
||||||
|
/// A 6-bit port address.
|
||||||
|
fixup_port6,
|
||||||
|
/// A 5-bit port address.
|
||||||
|
fixup_port5,
|
||||||
|
|
||||||
|
// Marker
|
||||||
|
LastTargetFixupKind,
|
||||||
|
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace fixups {
|
||||||
|
|
||||||
|
/// Adjusts the value of a branch target.
|
||||||
|
/// All branch targets in AVR are rightshifted by 1 to take advantage
|
||||||
|
/// of the fact that all instructions are aligned to addresses of size
|
||||||
|
/// 2, so bit 0 of an address is always 0. This gives us another bit
|
||||||
|
/// of precision.
|
||||||
|
/// \param[in,out] The target to adjust.
|
||||||
|
template <typename T> inline void adjustBranchTarget(T &val) { val >>= 1; }
|
||||||
|
|
||||||
|
} // end of namespace fixups
|
||||||
|
}
|
||||||
|
} // end of namespace llvm::AVR
|
||||||
|
|
||||||
|
#endif // LLVM_AVR_FIXUP_KINDS_H
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
//===-- 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
|
||||||
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
//===-- AVRMCExpr.h - AVR specific MC expression classes --------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_AVR_MCEXPR_H
|
||||||
|
#define LLVM_AVR_MCEXPR_H
|
||||||
|
|
||||||
|
#include "llvm/MC/MCExpr.h"
|
||||||
|
|
||||||
|
#include "MCTargetDesc/AVRFixupKinds.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
/// A expression in AVR machine code.
|
||||||
|
class AVRMCExpr : public MCTargetExpr {
|
||||||
|
public:
|
||||||
|
/// Specifies the type of an expression.
|
||||||
|
enum VariantKind {
|
||||||
|
VK_AVR_None,
|
||||||
|
|
||||||
|
VK_AVR_HI8, ///< Corresponds to `hi8()`.
|
||||||
|
VK_AVR_LO8, ///< Corresponds to `lo8()`.
|
||||||
|
VK_AVR_HH8, ///< Corresponds to `hlo8() and hh8()`.
|
||||||
|
VK_AVR_HHI8, ///< Corresponds to `hhi8()`.
|
||||||
|
|
||||||
|
VK_AVR_PM_LO8, ///< Corresponds to `pm_lo8()`.
|
||||||
|
VK_AVR_PM_HI8, ///< Corresponds to `pm_hi8()`.
|
||||||
|
VK_AVR_PM_HH8 ///< Corresponds to `pm_hh8()`.
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Creates an AVR machine code expression.
|
||||||
|
static const AVRMCExpr *create(VariantKind Kind, const MCExpr *Expr,
|
||||||
|
bool isNegated, MCContext &Ctx);
|
||||||
|
|
||||||
|
/// Gets the type of the expression.
|
||||||
|
VariantKind getKind() const { return Kind; }
|
||||||
|
/// Gets the name of the expression.
|
||||||
|
const char *getName() const;
|
||||||
|
const MCExpr *getSubExpr() const { return SubExpr; }
|
||||||
|
/// Gets the fixup which corresponds to the expression.
|
||||||
|
AVR::Fixups getFixupKind() const;
|
||||||
|
/// Evaluates the fixup as a constant value.
|
||||||
|
bool evaluateAsConstant(int64_t &Result) const;
|
||||||
|
|
||||||
|
bool isNegated() const { return Negated; }
|
||||||
|
void setNegated(bool negated = true) { Negated = negated; }
|
||||||
|
|
||||||
|
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
|
||||||
|
bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
|
||||||
|
const MCFixup *Fixup) const override;
|
||||||
|
|
||||||
|
void visitUsedExpr(MCStreamer &streamer) const override;
|
||||||
|
|
||||||
|
MCFragment *findAssociatedFragment() const override {
|
||||||
|
return getSubExpr()->findAssociatedFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {}
|
||||||
|
|
||||||
|
static bool classof(const MCExpr *E) {
|
||||||
|
return E->getKind() == MCExpr::Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static VariantKind getKindByName(StringRef Name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int64_t evaluateAsInt64(int64_t Value) const;
|
||||||
|
|
||||||
|
const VariantKind Kind;
|
||||||
|
const MCExpr *SubExpr;
|
||||||
|
bool Negated;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit AVRMCExpr(VariantKind Kind, const MCExpr *Expr, bool Negated)
|
||||||
|
: Kind(Kind), SubExpr(Expr), Negated(Negated) {}
|
||||||
|
~AVRMCExpr() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace llvm
|
||||||
|
|
||||||
|
#endif // LLVM_AVR_MCEXPR_H
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
add_llvm_library(LLVMAVRDesc
|
add_llvm_library(LLVMAVRDesc
|
||||||
AVRELFStreamer.cpp
|
AVRELFStreamer.cpp
|
||||||
AVRMCAsmInfo.cpp
|
AVRMCAsmInfo.cpp
|
||||||
|
AVRMCExpr.cpp
|
||||||
AVRTargetStreamer.cpp
|
AVRTargetStreamer.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue