[llvm] c7a4efa - [AVR] Fix 16-bit LDDs with immediate overflows (#104923)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 29 00:28:20 PDT 2024


Author: Patryk Wychowaniec
Date: 2024-08-29T15:28:17+08:00
New Revision: c7a4efa4294789b1116f0c4a320c16fcb27cb62c

URL: https://github.com/llvm/llvm-project/commit/c7a4efa4294789b1116f0c4a320c16fcb27cb62c
DIFF: https://github.com/llvm/llvm-project/commit/c7a4efa4294789b1116f0c4a320c16fcb27cb62c.diff

LOG: [AVR] Fix 16-bit LDDs with immediate overflows (#104923)

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.

Added: 
    llvm/test/CodeGen/AVR/ldd-immediate-overflow.ll
    llvm/test/CodeGen/AVR/std-immediate-overflow.ll

Modified: 
    llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp b/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
index 77db876d47e446..a8927d834630ea 100644
--- a/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
@@ -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);
 

diff  --git a/llvm/test/CodeGen/AVR/ldd-immediate-overflow.ll b/llvm/test/CodeGen/AVR/ldd-immediate-overflow.ll
new file mode 100644
index 00000000000000..6f1a4b32bb054c
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/ldd-immediate-overflow.ll
@@ -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
+}

diff  --git a/llvm/test/CodeGen/AVR/std-immediate-overflow.ll b/llvm/test/CodeGen/AVR/std-immediate-overflow.ll
new file mode 100644
index 00000000000000..18ccb79d3a5f89
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/std-immediate-overflow.ll
@@ -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
+}


        


More information about the llvm-commits mailing list