Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 679be7e

Browse files
author
Dylan McKay
committed
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282397 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent ecba024 commit 679be7e

File tree

4 files changed

+427
-0
lines changed

4 files changed

+427
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
//===-- AVRFixupKinds.h - AVR Specific Fixup Entries ------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_AVR_FIXUP_KINDS_H
11+
#define LLVM_AVR_FIXUP_KINDS_H
12+
13+
#include "llvm/MC/MCFixup.h"
14+
15+
namespace llvm {
16+
namespace AVR {
17+
18+
/// The set of supported fixups.
19+
///
20+
/// Although most of the current fixup types reflect a unique relocation
21+
/// one can have multiple fixup types for a given relocation and thus need
22+
/// to be uniquely named.
23+
///
24+
/// \note This table *must* be in the same order of
25+
/// MCFixupKindInfo Infos[AVR::NumTargetFixupKinds]
26+
/// in `AVRAsmBackend.cpp`.
27+
enum Fixups {
28+
/// A 32-bit AVR fixup.
29+
fixup_32 = FirstTargetFixupKind,
30+
31+
/// A 7-bit PC-relative fixup for the family of conditional
32+
/// branches which take 7-bit targets (BRNE,BRGT,etc).
33+
fixup_7_pcrel,
34+
/// A 12-bit PC-relative fixup for the family of branches
35+
/// which take 12-bit targets (RJMP,RCALL,etc).
36+
/// \note Although the fixup is labelled as 13 bits, it
37+
/// is actually only encoded in 12. The reason for
38+
/// The nonmenclature is that AVR branch targets are
39+
/// rightshifted by 1, because instructions are always
40+
/// aligned to 2 bytes, so the 0'th bit is always 0.
41+
/// This way there is 13-bits of precision.
42+
fixup_13_pcrel,
43+
44+
/// A 16-bit address.
45+
fixup_16,
46+
/// A 16-bit program memory address.
47+
fixup_16_pm,
48+
49+
/// Replaces the 8-bit immediate with another value.
50+
fixup_ldi,
51+
52+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
53+
/// with the lower 8 bits of a 16-bit value (bits 0-7).
54+
fixup_lo8_ldi,
55+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
56+
/// with the upper 8 bits of a 16-bit value (bits 8-15).
57+
fixup_hi8_ldi,
58+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
59+
/// with the upper 8 bits of a 24-bit value (bits 16-23).
60+
fixup_hh8_ldi,
61+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
62+
/// with the upper 8 bits of a 32-bit value (bits 24-31).
63+
fixup_ms8_ldi,
64+
65+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
66+
/// with the lower 8 bits of a negated 16-bit value (bits 0-7).
67+
fixup_lo8_ldi_neg,
68+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
69+
/// with the upper 8 bits of a negated 16-bit value (bits 8-15).
70+
fixup_hi8_ldi_neg,
71+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
72+
/// with the upper 8 bits of a negated negated 24-bit value (bits 16-23).
73+
fixup_hh8_ldi_neg,
74+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
75+
/// with the upper 8 bits of a negated negated 32-bit value (bits 24-31).
76+
fixup_ms8_ldi_neg,
77+
78+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
79+
/// with the lower 8 bits of a 16-bit program memory address value (bits 0-7).
80+
fixup_lo8_ldi_pm,
81+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
82+
/// with the upper 8 bits of a 16-bit program memory address value (bits
83+
/// 8-15).
84+
fixup_hi8_ldi_pm,
85+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
86+
/// with the upper 8 bits of a 24-bit program memory address value (bits
87+
/// 16-23).
88+
fixup_hh8_ldi_pm,
89+
90+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
91+
/// with the lower 8 bits of a negated 16-bit program memory address value
92+
/// (bits 0-7).
93+
fixup_lo8_ldi_pm_neg,
94+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
95+
/// with the upper 8 bits of a negated 16-bit program memory address value
96+
/// (bits 8-15).
97+
fixup_hi8_ldi_pm_neg,
98+
/// Replaces the immediate operand of a 16-bit `Rd, K` instruction
99+
/// with the upper 8 bits of a negated 24-bit program memory address value
100+
/// (bits 16-23).
101+
fixup_hh8_ldi_pm_neg,
102+
103+
/// A 22-bit fixup for the target of a `CALL k` or `JMP k` instruction.
104+
fixup_call,
105+
106+
fixup_6,
107+
/// A symbol+addr fixup for the `LDD <x>+<n>, <r>" family of instructions.
108+
fixup_6_adiw,
109+
110+
fixup_lo8_ldi_gs,
111+
fixup_hi8_ldi_gs,
112+
113+
fixup_8,
114+
fixup_8_lo8,
115+
fixup_8_hi8,
116+
fixup_8_hlo8,
117+
118+
/// Fixup to calculate the difference between two symbols.
119+
/// Is the only stateful fixup. We do not support it yet.
120+
fixup_sym_diff,
121+
fixup_16_ldst,
122+
123+
fixup_lds_sts_16,
124+
125+
/// A 6-bit port address.
126+
fixup_port6,
127+
/// A 5-bit port address.
128+
fixup_port5,
129+
130+
// Marker
131+
LastTargetFixupKind,
132+
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
133+
};
134+
135+
namespace fixups {
136+
137+
/// Adjusts the value of a branch target.
138+
/// All branch targets in AVR are rightshifted by 1 to take advantage
139+
/// of the fact that all instructions are aligned to addresses of size
140+
/// 2, so bit 0 of an address is always 0. This gives us another bit
141+
/// of precision.
142+
/// \param[in,out] The target to adjust.
143+
template <typename T> inline void adjustBranchTarget(T &val) { val >>= 1; }
144+
145+
} // end of namespace fixups
146+
}
147+
} // end of namespace llvm::AVR
148+
149+
#endif // LLVM_AVR_FIXUP_KINDS_H
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
//===-- AVRMCExpr.cpp - AVR specific MC expression classes ----------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "AVRMCExpr.h"
11+
12+
#include "llvm/MC/MCAssembler.h"
13+
#include "llvm/MC/MCContext.h"
14+
#include "llvm/MC/MCStreamer.h"
15+
#include "llvm/MC/MCValue.h"
16+
#include "llvm/MC/MCAsmLayout.h"
17+
18+
namespace llvm {
19+
20+
namespace {
21+
22+
const struct ModifierEntry {
23+
const char * const Spelling;
24+
AVRMCExpr::VariantKind VariantKind;
25+
} ModifierNames[] = {
26+
{"lo8", AVRMCExpr::VK_AVR_LO8}, {"hi8", AVRMCExpr::VK_AVR_HI8},
27+
{"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8
28+
{"hlo8", AVRMCExpr::VK_AVR_HH8}, {"hhi8", AVRMCExpr::VK_AVR_HHI8},
29+
30+
{"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8},
31+
{"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8},
32+
};
33+
34+
} // end of anonymous namespace
35+
36+
const AVRMCExpr *AVRMCExpr::create(VariantKind Kind, const MCExpr *Expr,
37+
bool Negated, MCContext &Ctx) {
38+
return new (Ctx) AVRMCExpr(Kind, Expr, Negated);
39+
}
40+
41+
void AVRMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
42+
assert(Kind != VK_AVR_None);
43+
44+
if (isNegated())
45+
OS << '-';
46+
47+
OS << getName() << '(';
48+
getSubExpr()->print(OS, MAI);
49+
OS << ')';
50+
}
51+
52+
bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const {
53+
MCValue Value;
54+
55+
bool isRelocatable =
56+
getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr);
57+
58+
if (!isRelocatable)
59+
return false;
60+
61+
if (Value.isAbsolute()) {
62+
Result = evaluateAsInt64(Value.getConstant());
63+
return true;
64+
}
65+
66+
return false;
67+
}
68+
69+
bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result,
70+
const MCAsmLayout *Layout,
71+
const MCFixup *Fixup) const {
72+
MCValue Value;
73+
bool isRelocatable = SubExpr->evaluateAsRelocatable(Value, Layout, Fixup);
74+
75+
if (!isRelocatable)
76+
return false;
77+
78+
if (Value.isAbsolute()) {
79+
Result = MCValue::get(evaluateAsInt64(Value.getConstant()));
80+
} else {
81+
if (!Layout) return false;
82+
83+
MCContext &Context = Layout->getAssembler().getContext();
84+
const MCSymbolRefExpr *Sym = Value.getSymA();
85+
MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
86+
if (Modifier != MCSymbolRefExpr::VK_None)
87+
return false;
88+
89+
Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
90+
Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
91+
}
92+
93+
return true;
94+
}
95+
96+
int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const {
97+
if (Negated)
98+
Value *= -1;
99+
100+
switch (Kind) {
101+
case AVRMCExpr::VK_AVR_LO8:
102+
break;
103+
case AVRMCExpr::VK_AVR_HI8:
104+
Value >>= 8;
105+
break;
106+
case AVRMCExpr::VK_AVR_HH8:
107+
Value >>= 16;
108+
break;
109+
case AVRMCExpr::VK_AVR_HHI8:
110+
Value >>= 24;
111+
break;
112+
case AVRMCExpr::VK_AVR_PM_LO8:
113+
Value >>= 1;
114+
break;
115+
case AVRMCExpr::VK_AVR_PM_HI8:
116+
Value >>= 9;
117+
break;
118+
case AVRMCExpr::VK_AVR_PM_HH8:
119+
Value >>= 17;
120+
break;
121+
122+
case AVRMCExpr::VK_AVR_None:
123+
llvm_unreachable("Uninitialized expression.");
124+
}
125+
return static_cast<uint64_t>(Value) & 0xff;
126+
}
127+
128+
AVR::Fixups AVRMCExpr::getFixupKind() const {
129+
AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind;
130+
131+
switch (getKind()) {
132+
case VK_AVR_LO8:
133+
Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi;
134+
break;
135+
case VK_AVR_HI8:
136+
Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi;
137+
break;
138+
case VK_AVR_HH8:
139+
Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi;
140+
break;
141+
case VK_AVR_HHI8:
142+
Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi;
143+
break;
144+
145+
case VK_AVR_PM_LO8:
146+
Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm;
147+
break;
148+
case VK_AVR_PM_HI8:
149+
Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm;
150+
break;
151+
case VK_AVR_PM_HH8:
152+
Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm;
153+
break;
154+
155+
case VK_AVR_None:
156+
llvm_unreachable("Uninitialized expression");
157+
}
158+
159+
return Kind;
160+
}
161+
162+
void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
163+
Streamer.visitUsedExpr(*getSubExpr());
164+
}
165+
166+
const char *AVRMCExpr::getName() const {
167+
const auto &Modifier = std::find_if(
168+
std::begin(ModifierNames), std::end(ModifierNames),
169+
[this](ModifierEntry const &Mod) { return Mod.VariantKind == Kind; });
170+
171+
if (Modifier != std::end(ModifierNames)) {
172+
return Modifier->Spelling;
173+
}
174+
return nullptr;
175+
}
176+
177+
AVRMCExpr::VariantKind AVRMCExpr::getKindByName(StringRef Name) {
178+
const auto &Modifier = std::find_if(
179+
std::begin(ModifierNames), std::end(ModifierNames),
180+
[&Name](ModifierEntry const &Mod) { return Mod.Spelling == Name; });
181+
182+
if (Modifier != std::end(ModifierNames)) {
183+
return Modifier->VariantKind;
184+
}
185+
return VK_AVR_None;
186+
}
187+
188+
} // end of namespace llvm
189+

0 commit comments

Comments
 (0)