[llvm-branch-commits] [llvm] release/19.x: [AVR] Fix 16-bit LDDs with immediate overflows (#104923) (PR #106993)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Sep 2 07:03:45 PDT 2024
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/106993
Backport c7a4efa
Requested by: @EugeneZelenko
>From 2e14b75913fb4e90c7b833b351aee99dc9b0bdbd Mon Sep 17 00:00:00 2001
From: Patryk Wychowaniec <pwychowaniec at pm.me>
Date: Thu, 29 Aug 2024 09:28:17 +0200
Subject: [PATCH] [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.
(cherry picked from commit c7a4efa4294789b1116f0c4a320c16fcb27cb62c)
---
llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp | 9 +-
.../CodeGen/AVR/ldd-immediate-overflow.ll | 144 ++++++++++++++++++
.../CodeGen/AVR/std-immediate-overflow.ll | 137 +++++++++++++++++
3 files changed, 288 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/AVR/ldd-immediate-overflow.ll
create mode 100644 llvm/test/CodeGen/AVR/std-immediate-overflow.ll
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-branch-commits
mailing list