Skip to content

Commit 7d8acf6

Browse files
committed
[AVR] Wrap out-of-bounds relative jumps
1 parent 1b9805c commit 7d8acf6

File tree

5 files changed

+4228
-4215
lines changed

5 files changed

+4228
-4215
lines changed

llvm/lib/Target/AVR/AVRDevices.td

+31-19
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ def FeatureSmallStack
6060
"The device has an 8-bit "
6161
"stack pointer">;
6262

63+
// The device potentially requires emitting rjmp that wraps across the flash
64+
// boundary.
65+
//
66+
// We enable this for devices that have exactly 8 kB of flash memory and don't
67+
// support the `jmp` instruction - with this feature enabled, we try to convert
68+
// out-of-bounds relative jumps into in-bounds by wrapping the offset, e.g.
69+
// `rjmp +5000` becomes `rjmp -3192`.
70+
def FeatureWrappingRjmp
71+
: SubtargetFeature<"wrappingrjmp", "HasWrappingRjmp", "true",
72+
"The device potentially requires emitting rjmp that "
73+
"wraps across the flash boundary">;
74+
6375
// The device supports the 16-bit GPR pair MOVW instruction.
6476
def FeatureMOVW : SubtargetFeature<"movw", "HasMOVW", "true",
6577
"The device supports the 16-bit MOVW "
@@ -274,11 +286,11 @@ def : Device<"at86rf401", FamilyAVR2, ELFArchAVR25, [FeatureMOVW, FeatureLPMX]>;
274286
def : Device<"at90s4414", FamilyAVR2, ELFArchAVR2, [FeatureSmallStack]>;
275287
def : Device<"at90s4433", FamilyAVR2, ELFArchAVR2, [FeatureSmallStack]>;
276288
def : Device<"at90s4434", FamilyAVR2, ELFArchAVR2, [FeatureSmallStack]>;
277-
def : Device<"at90s8515", FamilyAVR2, ELFArchAVR2>;
278-
def : Device<"at90c8534", FamilyAVR2, ELFArchAVR2>;
279-
def : Device<"at90s8535", FamilyAVR2, ELFArchAVR2>;
280-
def : Device<"ata5272", FamilyAVR25, ELFArchAVR25>;
281-
def : Device<"ata6616c", FamilyAVR25, ELFArchAVR25>;
289+
def : Device<"at90s8515", FamilyAVR2, ELFArchAVR2, [FeatureWrappingRjmp]>;
290+
def : Device<"at90c8534", FamilyAVR2, ELFArchAVR2, [FeatureWrappingRjmp]>;
291+
def : Device<"at90s8535", FamilyAVR2, ELFArchAVR2, [FeatureWrappingRjmp]>;
292+
def : Device<"ata5272", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
293+
def : Device<"ata6616c", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
282294
def : Device<"attiny13", FamilyAVR25, ELFArchAVR25, [FeatureSmallStack]>;
283295
def : Device<"attiny13a", FamilyAVR25, ELFArchAVR25, [FeatureSmallStack]>;
284296
def : Device<"attiny2313", FamilyAVR25, ELFArchAVR25, [FeatureSmallStack]>;
@@ -288,24 +300,24 @@ def : Device<"attiny24a", FamilyAVR25, ELFArchAVR25, [FeatureSmallStack]>;
288300
def : Device<"attiny4313", FamilyAVR25, ELFArchAVR25>;
289301
def : Device<"attiny44", FamilyAVR25, ELFArchAVR25>;
290302
def : Device<"attiny44a", FamilyAVR25, ELFArchAVR25>;
291-
def : Device<"attiny84", FamilyAVR25, ELFArchAVR25>;
292-
def : Device<"attiny84a", FamilyAVR25, ELFArchAVR25>;
303+
def : Device<"attiny84", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
304+
def : Device<"attiny84a", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
293305
def : Device<"attiny25", FamilyAVR25, ELFArchAVR25, [FeatureSmallStack]>;
294306
def : Device<"attiny45", FamilyAVR25, ELFArchAVR25>;
295-
def : Device<"attiny85", FamilyAVR25, ELFArchAVR25>;
307+
def : Device<"attiny85", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
296308
def : Device<"attiny261", FamilyAVR25, ELFArchAVR25, [FeatureSmallStack]>;
297309
def : Device<"attiny261a", FamilyAVR25, ELFArchAVR25, [FeatureSmallStack]>;
298310
def : Device<"attiny441", FamilyAVR25, ELFArchAVR25>;
299311
def : Device<"attiny461", FamilyAVR25, ELFArchAVR25>;
300312
def : Device<"attiny461a", FamilyAVR25, ELFArchAVR25>;
301-
def : Device<"attiny841", FamilyAVR25, ELFArchAVR25>;
302-
def : Device<"attiny861", FamilyAVR25, ELFArchAVR25>;
303-
def : Device<"attiny861a", FamilyAVR25, ELFArchAVR25>;
304-
def : Device<"attiny87", FamilyAVR25, ELFArchAVR25>;
313+
def : Device<"attiny841", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
314+
def : Device<"attiny861", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
315+
def : Device<"attiny861a", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
316+
def : Device<"attiny87", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
305317
def : Device<"attiny43u", FamilyAVR25, ELFArchAVR25>;
306318
def : Device<"attiny48", FamilyAVR25, ELFArchAVR25>;
307-
def : Device<"attiny88", FamilyAVR25, ELFArchAVR25>;
308-
def : Device<"attiny828", FamilyAVR25, ELFArchAVR25>;
319+
def : Device<"attiny88", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
320+
def : Device<"attiny828", FamilyAVR25, ELFArchAVR25, [FeatureWrappingRjmp]>;
309321
def : Device<"at43usb355", FamilyAVR3, ELFArchAVR3>;
310322
def : Device<"at76c711", FamilyAVR3, ELFArchAVR3>;
311323
def : Device<"atmega103", FamilyAVR31, ELFArchAVR31>;
@@ -321,11 +333,11 @@ def : Device<"atmega16u2", FamilyAVR35, ELFArchAVR35>;
321333
def : Device<"atmega32u2", FamilyAVR35, ELFArchAVR35>;
322334
def : Device<"attiny1634", FamilyAVR35, ELFArchAVR35>;
323335
def : Device<"atmega8", FamilyAVR2, ELFArchAVR4,
324-
[FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
336+
[FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM, FeatureWrappingRjmp]>;
325337
def : Device<"ata6289", FamilyAVR4, ELFArchAVR4>;
326338
def : Device<"atmega8a", FamilyAVR2, ELFArchAVR4,
327-
[FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
328-
def : Device<"ata6285", FamilyAVR4, ELFArchAVR4>;
339+
[FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM, FeatureWrappingRjmp]>;
340+
def : Device<"ata6285", FamilyAVR4, ELFArchAVR4, [FeatureWrappingRjmp]>;
329341
def : Device<"ata6286", FamilyAVR4, ELFArchAVR4>;
330342
def : Device<"ata6612c", FamilyAVR4, ELFArchAVR4>;
331343
def : Device<"atmega48", FamilyAVR4, ELFArchAVR4>;
@@ -339,9 +351,9 @@ def : Device<"atmega88p", FamilyAVR4, ELFArchAVR4>;
339351
def : Device<"atmega88pa", FamilyAVR4, ELFArchAVR4>;
340352
def : Device<"atmega88pb", FamilyAVR4, ELFArchAVR4>;
341353
def : Device<"atmega8515", FamilyAVR2, ELFArchAVR4,
342-
[FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
354+
[FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM, FeatureWrappingRjmp]>;
343355
def : Device<"atmega8535", FamilyAVR2, ELFArchAVR4,
344-
[FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
356+
[FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM, FeatureWrappingRjmp]>;
345357
def : Device<"atmega8hva", FamilyAVR4, ELFArchAVR4>;
346358
def : Device<"at90pwm1", FamilyAVR4, ELFArchAVR4>;
347359
def : Device<"at90pwm2", FamilyAVR4, ELFArchAVR4>;

llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp

+35-34
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,13 @@
2727
#include "llvm/Support/MathExtras.h"
2828
#include "llvm/Support/raw_ostream.h"
2929

30-
// FIXME: we should be doing checks to make sure asm operands
31-
// are not out of bounds.
32-
3330
namespace adjust {
3431

3532
using namespace llvm;
3633

3734
static void signed_width(unsigned Width, uint64_t Value,
3835
std::string Description, const MCFixup &Fixup,
39-
MCContext *Ctx = nullptr) {
36+
MCContext *Ctx) {
4037
if (!isIntN(Width, Value)) {
4138
std::string Diagnostic = "out of range " + Description;
4239

@@ -46,17 +43,13 @@ static void signed_width(unsigned Width, uint64_t Value,
4643
Diagnostic += " (expected an integer in the range " + std::to_string(Min) +
4744
" to " + std::to_string(Max) + ")";
4845

49-
if (Ctx) {
50-
Ctx->reportError(Fixup.getLoc(), Diagnostic);
51-
} else {
52-
llvm_unreachable(Diagnostic.c_str());
53-
}
46+
Ctx->reportError(Fixup.getLoc(), Diagnostic);
5447
}
5548
}
5649

5750
static void unsigned_width(unsigned Width, uint64_t Value,
5851
std::string Description, const MCFixup &Fixup,
59-
MCContext *Ctx = nullptr) {
52+
MCContext *Ctx) {
6053
if (!isUIntN(Width, Value)) {
6154
std::string Diagnostic = "out of range " + Description;
6255

@@ -65,17 +58,13 @@ static void unsigned_width(unsigned Width, uint64_t Value,
6558
Diagnostic +=
6659
" (expected an integer in the range 0 to " + std::to_string(Max) + ")";
6760

68-
if (Ctx) {
69-
Ctx->reportError(Fixup.getLoc(), Diagnostic);
70-
} else {
71-
llvm_unreachable(Diagnostic.c_str());
72-
}
61+
Ctx->reportError(Fixup.getLoc(), Diagnostic);
7362
}
7463
}
7564

7665
/// Adjusts the value of a branch target before fixup application.
7766
static void adjustBranch(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
78-
MCContext *Ctx = nullptr) {
67+
MCContext *Ctx) {
7968
// We have one extra bit of precision because the value is rightshifted by
8069
// one.
8170
unsigned_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
@@ -86,13 +75,28 @@ static void adjustBranch(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
8675

8776
/// Adjusts the value of a relative branch target before fixup application.
8877
static void adjustRelativeBranch(unsigned Size, const MCFixup &Fixup,
89-
uint64_t &Value, MCContext *Ctx = nullptr) {
78+
uint64_t &Value, MCContext *Ctx) {
9079
// Jumps are relative to the current instruction.
9180
Value -= 2;
9281

9382
// We have one extra bit of precision because the value is rightshifted by
9483
// one.
95-
signed_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
84+
Size += 1;
85+
86+
if (!isIntN(Size, Value) &&
87+
Ctx->getSubtargetInfo()->hasFeature(AVR::FeatureWrappingRjmp)) {
88+
const int32_t FlashSize = 0x2000;
89+
int32_t SignedValue = Value;
90+
91+
uint64_t WrappedValue = SignedValue > 0 ? (uint64_t)(Value - FlashSize)
92+
: (uint64_t)(FlashSize + Value);
93+
94+
if (isIntN(Size, WrappedValue)) {
95+
Value = WrappedValue;
96+
}
97+
}
98+
99+
signed_width(Size, Value, std::string("branch target"), Fixup, Ctx);
96100

97101
// Rightshifts the value by one.
98102
AVR::fixups::adjustBranchTarget(Value);
@@ -105,7 +109,7 @@ static void adjustRelativeBranch(unsigned Size, const MCFixup &Fixup,
105109
///
106110
/// Offset of 0 (so the result is left shifted by 3 bits before application).
107111
static void fixup_call(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
108-
MCContext *Ctx = nullptr) {
112+
MCContext *Ctx) {
109113
adjustBranch(Size, Fixup, Value, Ctx);
110114

111115
auto top = Value & (0xf00000 << 6); // the top four bits
@@ -121,7 +125,7 @@ static void fixup_call(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
121125
/// 0000 00kk kkkk k000
122126
/// Offset of 0 (so the result is left shifted by 3 bits before application).
123127
static void fixup_7_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
124-
MCContext *Ctx = nullptr) {
128+
MCContext *Ctx) {
125129
adjustRelativeBranch(Size, Fixup, Value, Ctx);
126130

127131
// Because the value may be negative, we must mask out the sign bits
@@ -135,7 +139,7 @@ static void fixup_7_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
135139
/// 0000 kkkk kkkk kkkk
136140
/// Offset of 0 (so the result isn't left-shifted before application).
137141
static void fixup_13_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
138-
MCContext *Ctx = nullptr) {
142+
MCContext *Ctx) {
139143
adjustRelativeBranch(Size, Fixup, Value, Ctx);
140144

141145
// Because the value may be negative, we must mask out the sign bits
@@ -147,8 +151,7 @@ static void fixup_13_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
147151
///
148152
/// Resolves to:
149153
/// 10q0 qq10 0000 1qqq
150-
static void fixup_6(const MCFixup &Fixup, uint64_t &Value,
151-
MCContext *Ctx = nullptr) {
154+
static void fixup_6(const MCFixup &Fixup, uint64_t &Value, MCContext *Ctx) {
152155
unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
153156

154157
Value = ((Value & 0x20) << 8) | ((Value & 0x18) << 7) | (Value & 0x07);
@@ -160,7 +163,7 @@ static void fixup_6(const MCFixup &Fixup, uint64_t &Value,
160163
/// Resolves to:
161164
/// 0000 0000 kk00 kkkk
162165
static void fixup_6_adiw(const MCFixup &Fixup, uint64_t &Value,
163-
MCContext *Ctx = nullptr) {
166+
MCContext *Ctx) {
164167
unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
165168

166169
Value = ((Value & 0x30) << 2) | (Value & 0x0f);
@@ -170,8 +173,7 @@ static void fixup_6_adiw(const MCFixup &Fixup, uint64_t &Value,
170173
///
171174
/// Resolves to:
172175
/// 0000 0000 AAAA A000
173-
static void fixup_port5(const MCFixup &Fixup, uint64_t &Value,
174-
MCContext *Ctx = nullptr) {
176+
static void fixup_port5(const MCFixup &Fixup, uint64_t &Value, MCContext *Ctx) {
175177
unsigned_width(5, Value, std::string("port number"), Fixup, Ctx);
176178

177179
Value &= 0x1f;
@@ -183,8 +185,7 @@ static void fixup_port5(const MCFixup &Fixup, uint64_t &Value,
183185
///
184186
/// Resolves to:
185187
/// 1011 0AAd dddd AAAA
186-
static void fixup_port6(const MCFixup &Fixup, uint64_t &Value,
187-
MCContext *Ctx = nullptr) {
188+
static void fixup_port6(const MCFixup &Fixup, uint64_t &Value, MCContext *Ctx) {
188189
unsigned_width(6, Value, std::string("port number"), Fixup, Ctx);
189190

190191
Value = ((Value & 0x30) << 5) | (Value & 0x0f);
@@ -195,7 +196,7 @@ static void fixup_port6(const MCFixup &Fixup, uint64_t &Value,
195196
/// Resolves to:
196197
/// 1010 ikkk dddd kkkk
197198
static void fixup_lds_sts_16(const MCFixup &Fixup, uint64_t &Value,
198-
MCContext *Ctx = nullptr) {
199+
MCContext *Ctx) {
199200
unsigned_width(7, Value, std::string("immediate"), Fixup, Ctx);
200201
Value = ((Value & 0x70) << 8) | (Value & 0x0f);
201202
}
@@ -213,7 +214,7 @@ namespace ldi {
213214
/// 0000 KKKK 0000 KKKK
214215
/// Offset of 0 (so the result isn't left-shifted before application).
215216
static void fixup(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
216-
MCContext *Ctx = nullptr) {
217+
MCContext *Ctx) {
217218
uint64_t upper = Value & 0xf0;
218219
uint64_t lower = Value & 0x0f;
219220

@@ -223,25 +224,25 @@ static void fixup(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
223224
static void neg(uint64_t &Value) { Value *= -1; }
224225

225226
static void lo8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
226-
MCContext *Ctx = nullptr) {
227+
MCContext *Ctx) {
227228
Value &= 0xff;
228229
ldi::fixup(Size, Fixup, Value, Ctx);
229230
}
230231

231232
static void hi8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
232-
MCContext *Ctx = nullptr) {
233+
MCContext *Ctx) {
233234
Value = (Value & 0xff00) >> 8;
234235
ldi::fixup(Size, Fixup, Value, Ctx);
235236
}
236237

237238
static void hh8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
238-
MCContext *Ctx = nullptr) {
239+
MCContext *Ctx) {
239240
Value = (Value & 0xff0000) >> 16;
240241
ldi::fixup(Size, Fixup, Value, Ctx);
241242
}
242243

243244
static void ms8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
244-
MCContext *Ctx = nullptr) {
245+
MCContext *Ctx) {
245246
Value = (Value & 0xff000000) >> 24;
246247
ldi::fixup(Size, Fixup, Value, Ctx);
247248
}

0 commit comments

Comments
 (0)