Skip to content

Commit 4fa9dc9

Browse files
committed
[AVR] Fix incorrect expansion of the pseudo 'ELPMBRdZ' instruction
The 'ELPM' instruction has three forms: -------------------------- | form | feature | | ----------- | -------- | | ELPM | hasELPM | | ELPM Rd, Z | hasELPMX | | ELPM Rd, Z+ | hasELPMX | -------------------------- The second form is always used in the expansion of the pseudo instruction 'ELPMBRdZ'. But for devices without ELPMX but only with ELPM, only the first form can be emitted. Reviewed By: jacquesguan Differential Revision: https://reviews.llvm.org/D141221
1 parent 00c4343 commit 4fa9dc9

File tree

5 files changed

+117
-13
lines changed

5 files changed

+117
-13
lines changed

llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -871,11 +871,20 @@ bool AVRExpandPseudo::expand<AVR::ELPMBRdZ>(Block &MBB, BlockIt MBBI) {
871871
buildMI(MBB, MBBI, AVR::OUTARr).addImm(STI.getIORegRAMPZ()).addReg(BankReg);
872872

873873
// Load byte.
874-
auto MILB = buildMI(MBB, MBBI, AVR::ELPMRdZ)
875-
.addReg(DstReg, RegState::Define)
876-
.addReg(SrcReg, getKillRegState(SrcIsKill));
877-
878-
MILB.setMemRefs(MI.memoperands());
874+
if (STI.hasELPMX()) {
875+
auto MILB = buildMI(MBB, MBBI, AVR::ELPMRdZ)
876+
.addReg(DstReg, RegState::Define)
877+
.addReg(SrcReg, getKillRegState(SrcIsKill));
878+
MILB.setMemRefs(MI.memoperands());
879+
} else {
880+
// For the basic 'ELPM' instruction, its operand[0] is the implicit
881+
// 'Z' register, and its operand[1] is the implicit 'R0' register.
882+
auto MILB = buildMI(MBB, MBBI, AVR::ELPM);
883+
buildMI(MBB, MBBI, AVR::MOVRdRr)
884+
.addReg(DstReg, RegState::Define)
885+
.addReg(AVR::R0, RegState::Kill);
886+
MILB.setMemRefs(MI.memoperands());
887+
}
879888

880889
MI.eraseFromParent();
881890
return true;

llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,8 @@ template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
366366
int ProgMemBank = AVR::getProgramMemoryBank(LD);
367367
if (ProgMemBank < 0 || ProgMemBank > 5)
368368
report_fatal_error("unexpected program memory bank");
369+
if (ProgMemBank > 0 && !Subtarget->hasELPM())
370+
report_fatal_error("unexpected program memory bank");
369371

370372
// This is a flash memory load, move the pointer into R31R30 and emit
371373
// the lpm instruction.

llvm/lib/Target/AVR/AVRInstrInfo.td

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,12 +1742,14 @@ let mayLoad = 1, hasSideEffects = 0 in {
17421742
Requires<[HasELPMX]>;
17431743
}
17441744

1745+
// This pseudo is combination of the OUT and ELPM instructions.
1746+
let Defs = [R0] in
1747+
def ELPMBRdZ : Pseudo<(outs GPR8:$dst), (ins ZREG:$z, LD8:$p),
1748+
"elpmb\t$dst, $z, $p", []>,
1749+
Requires<[HasELPM]>;
1750+
17451751
// These pseudos are combination of the OUT and ELPM instructions.
17461752
let Defs = [R31R30], hasSideEffects = 1 in {
1747-
def ELPMBRdZ : Pseudo<(outs GPR8:$dst), (ins ZREG:$z, LD8:$p),
1748-
"elpmb\t$dst, $z, $p", []>,
1749-
Requires<[HasELPMX]>;
1750-
17511753
let Constraints = "@earlyclobber $dst" in
17521754
def ELPMWRdZ : Pseudo<(outs DREGS:$dst), (ins ZREG:$z, LD8:$p),
17531755
"elpmw\t$dst, $z, $p", []>,

llvm/test/CodeGen/AVR/elpm.ll

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2-
; RUN: llc < %s -mtriple=avr --mcpu=atmega2560 -verify-machineinstrs | FileCheck %s
2+
; RUN: llc < %s -mtriple=avr -mattr=+movw -mattr=+elpm -mattr=+elpmx -mattr=+lpm -mattr=+lpmx -verify-machineinstrs \
3+
; RUN: | FileCheck %s
4+
; RUN: llc < %s -mtriple=avr -mattr=+movw -mattr=+elpm -mattr=-elpmx -mattr=+lpm -mattr=-lpmx -verify-machineinstrs \
5+
; RUN: | FileCheck --check-prefix=NOX %s
36

47
@arr0 = addrspace(1) constant [4 x i16] [i16 123, i16 24, i16 56, i16 37], align 1
58
@arr1 = addrspace(2) constant [4 x i16] [i16 123, i16 34, i16 46, i16 27], align 1
@@ -129,9 +132,9 @@ entry:
129132
ret i16 %sub
130133
}
131134

132-
@arrb1 = addrspace(1) constant [4 x i8] c"{\188%", align 1
133-
@arrb3 = addrspace(3) constant [4 x i8] c"{\22.\1B", align 1
134-
@arrb5 = addrspace(5) constant [4 x i8] c"{\17-\11", align 1
135+
@arrb1 = addrspace(1) constant [4 x i8] c"abcd", align 1
136+
@arrb3 = addrspace(3) constant [4 x i8] c"1234", align 1
137+
@arrb5 = addrspace(5) constant [4 x i8] c"HJLQ", align 1
135138

136139
define signext i8 @foob0(i16 %a, i16 %b) {
137140
; CHECK-LABEL: foob0:
@@ -232,6 +235,28 @@ define signext i8 @foob3(i16 %a, i16 %b) {
232235
; CHECK-NEXT: lsl r25
233236
; CHECK-NEXT: sbc r25, r25
234237
; CHECK-NEXT: ret
238+
;
239+
; NOX-LABEL: foob3:
240+
; NOX: ; %bb.0: ; %entry
241+
; NOX-NEXT: subi r22, lo8(-(arrb5))
242+
; NOX-NEXT: sbci r23, hi8(-(arrb5))
243+
; NOX-NEXT: movw r30, r22
244+
; NOX-NEXT: ldi r18, 4
245+
; NOX-NEXT: out 59, r18
246+
; NOX-NEXT: elpm
247+
; NOX-NEXT: mov r18, r0
248+
; NOX-NEXT: subi r24, lo8(-(arrb3))
249+
; NOX-NEXT: sbci r25, hi8(-(arrb3))
250+
; NOX-NEXT: movw r30, r24
251+
; NOX-NEXT: ldi r24, 2
252+
; NOX-NEXT: out 59, r24
253+
; NOX-NEXT: elpm
254+
; NOX-NEXT: mov r24, r0
255+
; NOX-NEXT: sub r24, r18
256+
; NOX-NEXT: mov r25, r24
257+
; NOX-NEXT: lsl r25
258+
; NOX-NEXT: sbc r25, r25
259+
; NOX-NEXT: ret
235260
entry:
236261
%arrayidx = getelementptr inbounds [4 x i8], [4 x i8] addrspace(3)* @arrb3, i16 0, i16 %a
237262
%0 = load i8, i8 addrspace(3)* %arrayidx, align 1
@@ -260,6 +285,27 @@ define signext i8 @foob4(i16 %a, i16 %b) {
260285
; CHECK-NEXT: lsl r25
261286
; CHECK-NEXT: sbc r25, r25
262287
; CHECK-NEXT: ret
288+
;
289+
; NOX-LABEL: foob4:
290+
; NOX: ; %bb.0: ; %entry
291+
; NOX-NEXT: subi r22, lo8(-(arrb3))
292+
; NOX-NEXT: sbci r23, hi8(-(arrb3))
293+
; NOX-NEXT: movw r30, r22
294+
; NOX-NEXT: ldi r18, 2
295+
; NOX-NEXT: out 59, r18
296+
; NOX-NEXT: elpm
297+
; NOX-NEXT: mov r19, r0
298+
; NOX-NEXT: subi r24, lo8(-(arrb3))
299+
; NOX-NEXT: sbci r25, hi8(-(arrb3))
300+
; NOX-NEXT: movw r30, r24
301+
; NOX-NEXT: out 59, r18
302+
; NOX-NEXT: elpm
303+
; NOX-NEXT: mov r24, r0
304+
; NOX-NEXT: sub r24, r19
305+
; NOX-NEXT: mov r25, r24
306+
; NOX-NEXT: lsl r25
307+
; NOX-NEXT: sbc r25, r25
308+
; NOX-NEXT: ret
263309
entry:
264310
%arrayidx = getelementptr inbounds [4 x i8], [4 x i8] addrspace(3)* @arrb3, i16 0, i16 %a
265311
%0 = load i8, i8 addrspace(3)* %arrayidx, align 1
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# RUN: llc -mtriple=avr -mattr=+elpm -mattr=+elpmx -start-before=greedy %s -o - \
2+
# RUN: | FileCheck %s
3+
# RUN: llc -mtriple=avr -mattr=+elpm -mattr=-elpmx -start-before=greedy %s -o - \
4+
# RUN: | FileCheck --check-prefix=NOX %s
5+
6+
# This test checks the expansion of the 16-bit ELPM pseudo instruction and that
7+
# the register allocator won't use R31R30 as an output register (which would
8+
# lead to undefined behavior).
9+
10+
--- |
11+
target triple = "avr--"
12+
define void @test_elpmbrdz() {
13+
entry:
14+
ret void
15+
}
16+
...
17+
18+
---
19+
name: test_elpmbrdz
20+
tracksRegLiveness: true
21+
body: |
22+
bb.0.entry:
23+
liveins: $r31r30
24+
25+
; CHECK-LABEL: test_elpmbrdz
26+
; CHECK: ; %bb.0:
27+
; CHECK-NEXT: ldi r24, 1
28+
; CHECK-NEXT: out
29+
; CHECK-NEXT: elpm r31, Z
30+
; CHECK-NEXT: ret
31+
32+
; NOX-LABEL: test_elpmbrdz
33+
; NOX: ; %bb.0:
34+
; NOX-NEXT: ldi r24, 1
35+
; NOX-NEXT: out
36+
; NOX-NEXT: elpm
37+
; NOX-NEXT: mov r31, r0
38+
; NOX-NEXT: ret
39+
40+
%1:zreg = COPY killed $r31r30
41+
%2:ld8 = LDIRdK 1
42+
%3:gpr8 = ELPMBRdZ %1, %2, implicit-def dead $r0
43+
$r31 = COPY %3
44+
RET implicit $r31
45+
...

0 commit comments

Comments
 (0)