Skip to content

Commit

Permalink
[AVR] Fix 16-bit LDDs with immediate overflows (#104923)
Browse files Browse the repository at this point in the history
16-bit loads are expanded into a pair of 8-bit loads, so the maximum
offset of such 16-bit loads must be 62, not 63.
  • Loading branch information
Patryk27 authored Aug 29, 2024
1 parent 8f96be9 commit c7a4efa
Show file tree
Hide file tree
Showing 3 changed files with 288 additions and 2 deletions.
9 changes: 7 additions & 2 deletions llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,13 @@ bool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base,
// offset allowed.
MVT VT = cast<MemSDNode>(Op)->getMemoryVT().getSimpleVT();

// We only accept offsets that fit in 6 bits (unsigned).
if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) {
// We only accept offsets that fit in 6 bits (unsigned), with the exception
// of 16-bit loads - those can only go up to 62, because we desugar them
// into a pair of 8-bit loads like `ldd rx, RHSC` + `ldd ry, RHSC + 1`.
bool OkI8 = VT == MVT::i8 && RHSC <= 63;
bool OkI16 = VT == MVT::i16 && RHSC <= 62;

if (OkI8 || OkI16) {
Base = N.getOperand(0);
Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);

Expand Down
144 changes: 144 additions & 0 deletions llvm/test/CodeGen/AVR/ldd-immediate-overflow.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
; RUN: llc -march=avr -filetype=asm -O1 < %s | FileCheck %s

define void @check60(ptr %1) {
; CHECK-LABEL: check60:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: ldd r24, Z+60
; CHECK-NEXT: ldd r25, Z+61
; CHECK-NEXT: ldd r18, Z+62
; CHECK-NEXT: ldd r19, Z+63
; CHECK-NEXT: sts 3, r19
; CHECK-NEXT: sts 2, r18
; CHECK-NEXT: sts 1, r25
; CHECK-NEXT: sts 0, r24
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i16 60
%3 = load i32, ptr %2, align 1
store i32 %3, ptr null, align 1
ret void
}

define void @check61(ptr %1) {
; CHECK-LABEL: check61:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: ldd r18, Z+61
; CHECK-NEXT: ldd r19, Z+62
; CHECK-NEXT: adiw r24, 63
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: ld r24, Z
; CHECK-NEXT: ldd r25, Z+1
; CHECK-NEXT: sts 3, r25
; CHECK-NEXT: sts 2, r24
; CHECK-NEXT: sts 1, r19
; CHECK-NEXT: sts 0, r18
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i16 61
%3 = load i32, ptr %2, align 1
store i32 %3, ptr null, align 1
ret void
}

define void @check62(ptr %1) {
; CHECK-LABEL: check62:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: ldd r18, Z+62
; CHECK-NEXT: ldd r19, Z+63
; CHECK-NEXT: adiw r24, 62
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: ldd r24, Z+2
; CHECK-NEXT: ldd r25, Z+3
; CHECK-NEXT: sts 3, r25
; CHECK-NEXT: sts 2, r24
; CHECK-NEXT: sts 1, r19
; CHECK-NEXT: sts 0, r18
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i16 62
%3 = load i32, ptr %2, align 1
store i32 %3, ptr null, align 1
ret void
}

define void @check63(ptr %1) {
; CHECK-LABEL: check63:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: adiw r24, 63
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: ld r24, Z
; CHECK-NEXT: ldd r25, Z+1
; CHECK-NEXT: ldd r18, Z+2
; CHECK-NEXT: ldd r19, Z+3
; CHECK-NEXT: sts 3, r19
; CHECK-NEXT: sts 2, r18
; CHECK-NEXT: sts 1, r25
; CHECK-NEXT: sts 0, r24
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i16 63
%3 = load i32, ptr %2, align 1
store i32 %3, ptr null, align 1
ret void
}

define void @check64(ptr %1) {
; CHECK-LABEL: check64:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: subi r24, 192
; CHECK-NEXT: sbci r25, 255
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: ld r24, Z
; CHECK-NEXT: ldd r25, Z+1
; CHECK-NEXT: ldd r18, Z+2
; CHECK-NEXT: ldd r19, Z+3
; CHECK-NEXT: sts 3, r19
; CHECK-NEXT: sts 2, r18
; CHECK-NEXT: sts 1, r25
; CHECK-NEXT: sts 0, r24
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i16 64
%3 = load i32, ptr %2, align 1
store i32 %3, ptr null, align 1
ret void
}

define void @check65(ptr %1) {
; CHECK-LABEL: check65:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: subi r24, 191
; CHECK-NEXT: sbci r25, 255
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: ld r24, Z
; CHECK-NEXT: ldd r25, Z+1
; CHECK-NEXT: ldd r18, Z+2
; CHECK-NEXT: ldd r19, Z+3
; CHECK-NEXT: sts 3, r19
; CHECK-NEXT: sts 2, r18
; CHECK-NEXT: sts 1, r25
; CHECK-NEXT: sts 0, r24
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i16 65
%3 = load i32, ptr %2, align 1
store i32 %3, ptr null, align 1
ret void
}
137 changes: 137 additions & 0 deletions llvm/test/CodeGen/AVR/std-immediate-overflow.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
; RUN: llc -march=avr -filetype=asm -O1 < %s | FileCheck %s

define void @check60(ptr %1) {
; CHECK-LABEL: check60:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: ldi r18, 0
; CHECK-NEXT: ldi r19, 0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: std Z+63, r19
; CHECK-NEXT: std Z+62, r18
; CHECK-NEXT: ldi r24, 210
; CHECK-NEXT: ldi r25, 4
; CHECK-NEXT: std Z+61, r25
; CHECK-NEXT: std Z+60, r24
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i8 60
store i32 1234, ptr %2
ret void
}

define void @check61(ptr %1) {
; CHECK-LABEL: check61:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: ldi r18, 210
; CHECK-NEXT: ldi r19, 4
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: std Z+62, r19
; CHECK-NEXT: std Z+61, r18
; CHECK-NEXT: adiw r24, 63
; CHECK-NEXT: ldi r18, 0
; CHECK-NEXT: ldi r19, 0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: std Z+1, r19
; CHECK-NEXT: st Z, r18

bb0:
%2 = getelementptr i8, ptr %1, i8 61
store i32 1234, ptr %2
ret void
}

define void @check62(ptr %1) {
; CHECK-LABEL: check62:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: ldi r18, 210
; CHECK-NEXT: ldi r19, 4
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: std Z+63, r19
; CHECK-NEXT: std Z+62, r18
; CHECK-NEXT: adiw r24, 62
; CHECK-NEXT: ldi r18, 0
; CHECK-NEXT: ldi r19, 0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: std Z+3, r19
; CHECK-NEXT: std Z+2, r18
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i8 62
store i32 1234, ptr %2
ret void
}

define void @check63(ptr %1) {
; CHECK-LABEL: check63:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: adiw r24, 63
; CHECK-NEXT: ldi r18, 0
; CHECK-NEXT: ldi r19, 0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: std Z+3, r19
; CHECK-NEXT: std Z+2, r18
; CHECK-NEXT: ldi r24, 210
; CHECK-NEXT: ldi r25, 4
; CHECK-NEXT: std Z+1, r25
; CHECK-NEXT: st Z, r24
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i8 63
store i32 1234, ptr %2
ret void
}

define void @check64(ptr %1) {
; CHECK-LABEL: check64:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: subi r24, 192
; CHECK-NEXT: sbci r25, 255
; CHECK-NEXT: ldi r18, 0
; CHECK-NEXT: ldi r19, 0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: std Z+3, r19
; CHECK-NEXT: std Z+2, r18
; CHECK-NEXT: ldi r24, 210
; CHECK-NEXT: ldi r25, 4
; CHECK-NEXT: std Z+1, r25
; CHECK-NEXT: st Z, r24
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i8 64
store i32 1234, ptr %2
ret void
}

define void @check65(ptr %1) {
; CHECK-LABEL: check65:
; CHECK-NEXT: %bb.0
; CHECK-NEXT: subi r24, 191
; CHECK-NEXT: sbci r25, 255
; CHECK-NEXT: ldi r18, 0
; CHECK-NEXT: ldi r19, 0
; CHECK-NEXT: mov r30, r24
; CHECK-NEXT: mov r31, r25
; CHECK-NEXT: std Z+3, r19
; CHECK-NEXT: std Z+2, r18
; CHECK-NEXT: ldi r24, 210
; CHECK-NEXT: ldi r25, 4
; CHECK-NEXT: std Z+1, r25
; CHECK-NEXT: st Z, r24
; CHECK-NEXT: ret

bb0:
%2 = getelementptr i8, ptr %1, i8 65
store i32 1234, ptr %2
ret void
}

0 comments on commit c7a4efa

Please sign in to comment.