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(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 +}