Skip to content

Commit da486df

Browse files
exscapedylanmckay
authored andcommitted
[AVR] Fix displacement overflow for LDDW/STDW
In some cases, the code generator attempts to generate instructions such as: lddw r24, Y+63 which expand to: ldd r24, Y+63 ldd r25, Y+64 # Oops! This is actually ld r25, Y in the binary This commit limits the first offset to 62, and thus the second to 63. It also updates some asserts in AVRExpandPseudoInsts.cpp, including for INW and OUTW, which appear to be unused.
1 parent 9a68de0 commit da486df

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed

lib/Target/AVR/AVRExpandPseudoInsts.cpp

+12-4
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,9 @@ bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
699699
OpHi = AVR::LDDRdPtrQ;
700700
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
701701

702-
assert(Imm <= 63 && "Offset is out of range");
702+
// Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
703+
// allowed for the instruction, 62 is the limit here.
704+
assert(Imm <= 62 && "Offset is out of range");
703705

704706
// Use a temporary register if src and dst registers are the same.
705707
if (DstReg == SrcReg)
@@ -1078,7 +1080,9 @@ bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
10781080
OpHi = AVR::STDPtrQRr;
10791081
TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
10801082

1081-
assert(Imm <= 63 && "Offset is out of range");
1083+
// Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
1084+
// allowed for the instruction, 62 is the limit here.
1085+
assert(Imm <= 62 && "Offset is out of range");
10821086

10831087
auto MIBLO = buildMI(MBB, MBBI, OpLo)
10841088
.addReg(DstReg)
@@ -1108,7 +1112,9 @@ bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) {
11081112
OpHi = AVR::INRdA;
11091113
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
11101114

1111-
assert(Imm <= 63 && "Address is out of range");
1115+
// Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
1116+
// allowed for the instruction, 62 is the limit here.
1117+
assert(Imm <= 62 && "Address is out of range");
11121118

11131119
auto MIBLO = buildMI(MBB, MBBI, OpLo)
11141120
.addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
@@ -1136,7 +1142,9 @@ bool AVRExpandPseudo::expand<AVR::OUTWARr>(Block &MBB, BlockIt MBBI) {
11361142
OpHi = AVR::OUTARr;
11371143
TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
11381144

1139-
assert(Imm <= 63 && "Address is out of range");
1145+
// Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
1146+
// allowed for the instruction, 62 is the limit here.
1147+
assert(Imm <= 62 && "Address is out of range");
11401148

11411149
// 16 bit I/O writes need the high byte first
11421150
auto MIBHI = buildMI(MBB, MBBI, OpHi)

lib/Target/AVR/AVRRegisterInfo.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
204204
// If the offset is too big we have to adjust and restore the frame pointer
205205
// to materialize a valid load/store with displacement.
206206
//:TODO: consider using only one adiw/sbiw chain for more than one frame index
207-
if (Offset > 63) {
207+
if (Offset > 62) {
208208
unsigned AddOpc = AVR::ADIWRdK, SubOpc = AVR::SBIWRdK;
209209
int AddOffset = Offset - 63 + 1;
210210

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; RUN: llc -O0 < %s -march=avr | FileCheck %s
2+
3+
define i32 @std_ldd_overflow() {
4+
%src = alloca [4 x i8]
5+
%dst = alloca [4 x i8]
6+
%buf = alloca [28 x i16]
7+
%1 = bitcast [4 x i8]* %src to i32*
8+
store i32 0, i32 *%1
9+
%2 = bitcast [4 x i8]* %dst to i8*
10+
%3 = bitcast [4 x i8]* %src to i8*
11+
call void @llvm.memcpy.p0i8.p0i8.i16(i8* %2, i8* %3, i16 4, i32 1, i1 false)
12+
; CHECK-NOT: std {{[XYZ]}}+64, {{r[0-9]+}}
13+
; CHECK-NOT: ldd {{r[0-9]+}}, {{[XYZ]}}+64
14+
15+
ret i32 0
16+
}
17+
18+
declare void @llvm.memcpy.p0i8.p0i8.i16(i8* nocapture writeonly, i8* nocapture readonly, i16, i32, i1)

0 commit comments

Comments
 (0)