Skip to content

Commit 93ee4da

Browse files
committed
[AVR] Fix I/O instructions on XMEGA
Summary: On XMEGA, I/O address space is same as data address space - there is no 0x20 offset, because CPU General Purpose Registers are not mapped in data address space. From https://en.wikipedia.org/wiki/AVR_microcontrollers > In the XMEGA variant, the working register file is not mapped into the data address space; as such, it is not possible to treat any of the XMEGA's working registers as though they were SRAM. Instead, the I/O registers are mapped into the data address space starting at the very beginning of the address space. Reviewers: dylanmckay Reviewed By: dylanmckay Subscribers: hiraditya, Jim, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77207 Patch by Vlastimil Labsky.
1 parent 962c241 commit 93ee4da

File tree

5 files changed

+81
-16
lines changed

5 files changed

+81
-16
lines changed

llvm/lib/Target/AVR/AVRDevices.td

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ def FeatureTinyEncoding : SubtargetFeature<"tinyencoding",
121121
"The device has Tiny core specific "
122122
"instruction encodings">;
123123

124+
// The device has CPU registers mapped in data address space
125+
def FeatureMMR : SubtargetFeature<"memmappedregs", "m_hasMemMappedGPR",
126+
"true", "The device has CPU registers "
127+
"mapped in data address space">;
128+
124129
class ELFArch<string name> : SubtargetFeature<"", "ELFArch",
125130
!strconcat("ELF::",name), "">;
126131

@@ -152,7 +157,7 @@ def ELFArchXMEGA7 : ELFArch<"EF_AVR_ARCH_XMEGA7">;
152157
// device should have.
153158
def FamilyAVR0 : Family<"avr0", []>;
154159

155-
def FamilyAVR1 : Family<"avr1", [FamilyAVR0, FeatureLPM]>;
160+
def FamilyAVR1 : Family<"avr1", [FamilyAVR0, FeatureLPM, FeatureMMR]>;
156161

157162
def FamilyAVR2 : Family<"avr2",
158163
[FamilyAVR1, FeatureIJMPCALL, FeatureADDSUBIW,
@@ -190,11 +195,14 @@ def FamilyAVR6 : Family<"avr6",
190195

191196
def FamilyTiny : Family<"avrtiny",
192197
[FamilyAVR0, FeatureBREAK, FeatureSRAM,
193-
FeatureTinyEncoding]>;
198+
FeatureTinyEncoding, FeatureMMR]>;
194199

195200
def FamilyXMEGA : Family<"xmega",
196-
[FamilyAVR51, FeatureEIJMPCALL, FeatureSPMX,
197-
FeatureDES]>;
201+
[FamilyAVR0, FeatureLPM, FeatureIJMPCALL, FeatureADDSUBIW,
202+
FeatureSRAM, FeatureJMPCALL, FeatureMultiplication,
203+
FeatureMOVW, FeatureLPMX, FeatureSPM,
204+
FeatureBREAK, FeatureEIJMPCALL, FeatureSPMX,
205+
FeatureDES, FeatureELPM, FeatureELPMX]>;
198206

199207
def FamilyXMEGAU : Family<"xmegau",
200208
[FamilyXMEGA, FeatureRMW]>;
@@ -208,7 +216,7 @@ def FeatureSetSpecial : FeatureSet<"special",
208216
FeatureLPM, FeatureLPMX, FeatureELPM,
209217
FeatureELPMX, FeatureSPM, FeatureSPMX,
210218
FeatureDES, FeatureRMW,
211-
FeatureMultiplication, FeatureBREAK]>;
219+
FeatureMultiplication, FeatureBREAK, FeatureMMR]>;
212220

213221
//===---------------------------------------------------------------------===//
214222
// AVR microcontrollers supported.

llvm/lib/Target/AVR/AVRInstrInfo.td

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ def imm_com8 : Operand<i8> {
107107

108108
def ioaddr_XFORM : SDNodeXForm<imm,
109109
[{
110-
return CurDAG->getTargetConstant(uint8_t(N->getZExtValue()) - 0x20, SDLoc(N), MVT::i8);
110+
uint8_t offset = Subtarget->getIORegisterOffset();
111+
return CurDAG->getTargetConstant(uint8_t(N->getZExtValue()) - offset,
112+
SDLoc(N), MVT::i8);
111113
}]>;
112114

113115
def iobitpos8_XFORM : SDNodeXForm<imm,
@@ -124,20 +126,23 @@ def iobitposn8_XFORM : SDNodeXForm<imm,
124126

125127
def ioaddr8 : PatLeaf<(imm),
126128
[{
127-
uint64_t val = N->getZExtValue();
128-
return val >= 0x20 && val < 0x60;
129+
uint8_t offset = Subtarget->getIORegisterOffset();
130+
uint64_t val = N->getZExtValue() - offset;
131+
return val >= 0x0 && val < 0x40;
129132
}], ioaddr_XFORM>;
130133

131134
def lowioaddr8 : PatLeaf<(imm),
132135
[{
133-
uint64_t val = N->getZExtValue();
134-
return val >= 0x20 && val < 0x40;
136+
uint8_t offset = Subtarget->getIORegisterOffset();
137+
uint64_t val = N->getZExtValue() - offset;
138+
return val >= 0x0 && val < 0x20;
135139
}], ioaddr_XFORM>;
136140

137141
def ioaddr16 : PatLeaf<(imm),
138142
[{
139-
uint64_t val = N->getZExtValue();
140-
return val >= 0x20 && val < 0x5f;
143+
uint8_t offset = Subtarget->getIORegisterOffset();
144+
uint64_t val = N->getZExtValue() - offset;
145+
return val >= 0x0 && val < 0x3f;
141146
}], ioaddr_XFORM>;
142147

143148
def iobitpos8 : PatLeaf<(imm),

llvm/lib/Target/AVR/AVRSubtarget.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ namespace llvm {
2929

3030
AVRSubtarget::AVRSubtarget(const Triple &TT, const std::string &CPU,
3131
const std::string &FS, const AVRTargetMachine &TM)
32-
: AVRGenSubtargetInfo(TT, CPU, FS),
33-
ELFArch(0),
32+
: AVRGenSubtargetInfo(TT, CPU, FS), ELFArch(0),
3433

3534
// Subtarget features
3635
m_hasSRAM(false), m_hasJMPCALL(false), m_hasIJMPCALL(false),
3736
m_hasEIJMPCALL(false), m_hasADDSUBIW(false), m_hasSmallStack(false),
38-
m_hasMOVW(false), m_hasLPM(false), m_hasLPMX(false), m_hasELPM(false),
37+
m_hasMOVW(false), m_hasLPM(false), m_hasLPMX(false), m_hasELPM(false),
3938
m_hasELPMX(false), m_hasSPM(false), m_hasSPMX(false), m_hasDES(false),
4039
m_supportsRMW(false), m_supportsMultiplication(false), m_hasBREAK(false),
41-
m_hasTinyEncoding(false), m_FeatureSetDummy(false),
40+
m_hasTinyEncoding(false), m_hasMemMappedGPR(false),
41+
m_FeatureSetDummy(false),
4242

4343
InstrInfo(), FrameLowering(),
4444
TLInfo(TM, initializeSubtargetDependencies(CPU, FS, TM)), TSInfo() {

llvm/lib/Target/AVR/AVRSubtarget.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class AVRSubtarget : public AVRGenSubtargetInfo {
7171
bool supportsMultiplication() const { return m_supportsMultiplication; }
7272
bool hasBREAK() const { return m_hasBREAK; }
7373
bool hasTinyEncoding() const { return m_hasTinyEncoding; }
74+
bool hasMemMappedGPR() const { return m_hasMemMappedGPR; }
75+
76+
uint8_t getIORegisterOffset() const { return hasMemMappedGPR() ? 0x20 : 0x0; }
7477

7578
/// Gets the ELF architecture for the e_flags field
7679
/// of an ELF object file.
@@ -105,6 +108,7 @@ class AVRSubtarget : public AVRGenSubtargetInfo {
105108
bool m_supportsMultiplication;
106109
bool m_hasBREAK;
107110
bool m_hasTinyEncoding;
111+
bool m_hasMemMappedGPR;
108112

109113
// Dummy member, used by FeatureSet's. We cannot have a SubtargetFeature with
110114
// no variable, so we instead bind pseudo features to this variable.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
; RUN: llc -O0 < %s -march=avr -mcpu avrxmega1 | FileCheck %s -check-prefix=XMEGA
2+
; RUN: llc -O0 < %s -march=avr -mcpu avrxmega2 | FileCheck %s -check-prefix=XMEGA
3+
; RUN: llc -O0 < %s -march=avr -mcpu avrxmega3 | FileCheck %s -check-prefix=XMEGA
4+
; RUN: llc -O0 < %s -march=avr -mcpu avrxmega4 | FileCheck %s -check-prefix=XMEGA
5+
; RUN: llc -O0 < %s -march=avr -mcpu avrxmega5 | FileCheck %s -check-prefix=XMEGA
6+
; RUN: llc -O0 < %s -march=avr -mcpu avrxmega6 | FileCheck %s -check-prefix=XMEGA
7+
; RUN: llc -O0 < %s -march=avr -mcpu avrxmega7 | FileCheck %s -check-prefix=XMEGA
8+
; RUN: llc -O0 < %s -march=avr -mcpu avr2 | FileCheck %s -check-prefix=AVR
9+
; RUN: llc -O0 < %s -march=avr -mcpu avr25 | FileCheck %s -check-prefix=AVR
10+
; RUN: llc -O0 < %s -march=avr -mcpu avr3 | FileCheck %s -check-prefix=AVR
11+
; RUN: llc -O0 < %s -march=avr -mcpu avr31 | FileCheck %s -check-prefix=AVR
12+
; RUN: llc -O0 < %s -march=avr -mcpu avr35 | FileCheck %s -check-prefix=AVR
13+
; RUN: llc -O0 < %s -march=avr -mcpu avr4 | FileCheck %s -check-prefix=AVR
14+
; RUN: llc -O0 < %s -march=avr -mcpu avr5 | FileCheck %s -check-prefix=AVR
15+
; RUN: llc -O0 < %s -march=avr -mcpu avr51 | FileCheck %s -check-prefix=AVR
16+
; RUN: llc -O0 < %s -march=avr -mcpu avr6 | FileCheck %s -check-prefix=AVR
17+
18+
define i8 @read8_low_io() {
19+
; CHECK-LABEL: read8_low_io
20+
; XMEGA: in r24, 8
21+
; AVR: lds r24, 8
22+
%1 = load i8, i8* inttoptr (i16 8 to i8*)
23+
ret i8 %1
24+
}
25+
26+
define i8 @read8_hi_io() {
27+
; CHECK-LABEL: read8_hi_io
28+
; XMEGA: in r24, 40
29+
; AVR: in r24, 8
30+
%1 = load i8, i8* inttoptr (i16 40 to i8*)
31+
ret i8 %1
32+
}
33+
34+
define i8 @read8_maybe_io() {
35+
; CHECK-LABEL: read8_maybe_io
36+
; XMEGA: lds r24, 80
37+
; AVR: in r24, 48
38+
%1 = load i8, i8* inttoptr (i16 80 to i8*)
39+
ret i8 %1
40+
}
41+
42+
define i8 @read8_not_io(){
43+
; CHECK-LABEL: read8_not_io
44+
; XMEGA: lds r24, 160
45+
; AVR: lds r24, 160
46+
%1 = load i8, i8* inttoptr (i16 160 to i8*)
47+
ret i8 %1
48+
}

0 commit comments

Comments
 (0)