buildMI(MBB, MBBI, AVR::OUTARr).addImm(STI.getIORegRAMPZ()).addReg(BankReg);
// Load byte.
- auto MILB = buildMI(MBB, MBBI, AVR::ELPMRdZ)
- .addReg(DstReg, RegState::Define)
- .addReg(SrcReg, getKillRegState(SrcIsKill));
-
- MILB.setMemRefs(MI.memoperands());
+ if (STI.hasELPMX()) {
+ auto MILB = buildMI(MBB, MBBI, AVR::ELPMRdZ)
+ .addReg(DstReg, RegState::Define)
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
+ MILB.setMemRefs(MI.memoperands());
+ } else {
+ // For the basic 'ELPM' instruction, its operand[0] is the implicit
+ // 'Z' register, and its operand[1] is the implicit 'R0' register.
+ auto MILB = buildMI(MBB, MBBI, AVR::ELPM);
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstReg, RegState::Define)
+ .addReg(AVR::R0, RegState::Kill);
+ MILB.setMemRefs(MI.memoperands());
+ }
MI.eraseFromParent();
return true;
int ProgMemBank = AVR::getProgramMemoryBank(LD);
if (ProgMemBank < 0 || ProgMemBank > 5)
report_fatal_error("unexpected program memory bank");
+ if (ProgMemBank > 0 && !Subtarget->hasELPM())
+ report_fatal_error("unexpected program memory bank");
// This is a flash memory load, move the pointer into R31R30 and emit
// the lpm instruction.
Requires<[HasELPMX]>;
}
+ // This pseudo is combination of the OUT and ELPM instructions.
+ let Defs = [R0] in
+ def ELPMBRdZ : Pseudo<(outs GPR8:$dst), (ins ZREG:$z, LD8:$p),
+ "elpmb\t$dst, $z, $p", []>,
+ Requires<[HasELPM]>;
+
// These pseudos are combination of the OUT and ELPM instructions.
let Defs = [R31R30], hasSideEffects = 1 in {
- def ELPMBRdZ : Pseudo<(outs GPR8:$dst), (ins ZREG:$z, LD8:$p),
- "elpmb\t$dst, $z, $p", []>,
- Requires<[HasELPMX]>;
-
let Constraints = "@earlyclobber $dst" in
def ELPMWRdZ : Pseudo<(outs DREGS:$dst), (ins ZREG:$z, LD8:$p),
"elpmw\t$dst, $z, $p", []>,
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=avr --mcpu=atmega2560 -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -mtriple=avr -mattr=+movw -mattr=+elpm -mattr=+elpmx -mattr=+lpm -mattr=+lpmx -verify-machineinstrs \
+; RUN: | FileCheck %s
+; RUN: llc < %s -mtriple=avr -mattr=+movw -mattr=+elpm -mattr=-elpmx -mattr=+lpm -mattr=-lpmx -verify-machineinstrs \
+; RUN: | FileCheck --check-prefix=NOX %s
@arr0 = addrspace(1) constant [4 x i16] [i16 123, i16 24, i16 56, i16 37], align 1
@arr1 = addrspace(2) constant [4 x i16] [i16 123, i16 34, i16 46, i16 27], align 1
ret i16 %sub
}
-@arrb1 = addrspace(1) constant [4 x i8] c"{\188%", align 1
-@arrb3 = addrspace(3) constant [4 x i8] c"{\22.\1B", align 1
-@arrb5 = addrspace(5) constant [4 x i8] c"{\17-\11", align 1
+@arrb1 = addrspace(1) constant [4 x i8] c"abcd", align 1
+@arrb3 = addrspace(3) constant [4 x i8] c"1234", align 1
+@arrb5 = addrspace(5) constant [4 x i8] c"HJLQ", align 1
define signext i8 @foob0(i16 %a, i16 %b) {
; CHECK-LABEL: foob0:
; CHECK-NEXT: lsl r25
; CHECK-NEXT: sbc r25, r25
; CHECK-NEXT: ret
+;
+; NOX-LABEL: foob3:
+; NOX: ; %bb.0: ; %entry
+; NOX-NEXT: subi r22, lo8(-(arrb5))
+; NOX-NEXT: sbci r23, hi8(-(arrb5))
+; NOX-NEXT: movw r30, r22
+; NOX-NEXT: ldi r18, 4
+; NOX-NEXT: out 59, r18
+; NOX-NEXT: elpm
+; NOX-NEXT: mov r18, r0
+; NOX-NEXT: subi r24, lo8(-(arrb3))
+; NOX-NEXT: sbci r25, hi8(-(arrb3))
+; NOX-NEXT: movw r30, r24
+; NOX-NEXT: ldi r24, 2
+; NOX-NEXT: out 59, r24
+; NOX-NEXT: elpm
+; NOX-NEXT: mov r24, r0
+; NOX-NEXT: sub r24, r18
+; NOX-NEXT: mov r25, r24
+; NOX-NEXT: lsl r25
+; NOX-NEXT: sbc r25, r25
+; NOX-NEXT: ret
entry:
%arrayidx = getelementptr inbounds [4 x i8], [4 x i8] addrspace(3)* @arrb3, i16 0, i16 %a
%0 = load i8, i8 addrspace(3)* %arrayidx, align 1
; CHECK-NEXT: lsl r25
; CHECK-NEXT: sbc r25, r25
; CHECK-NEXT: ret
+;
+; NOX-LABEL: foob4:
+; NOX: ; %bb.0: ; %entry
+; NOX-NEXT: subi r22, lo8(-(arrb3))
+; NOX-NEXT: sbci r23, hi8(-(arrb3))
+; NOX-NEXT: movw r30, r22
+; NOX-NEXT: ldi r18, 2
+; NOX-NEXT: out 59, r18
+; NOX-NEXT: elpm
+; NOX-NEXT: mov r19, r0
+; NOX-NEXT: subi r24, lo8(-(arrb3))
+; NOX-NEXT: sbci r25, hi8(-(arrb3))
+; NOX-NEXT: movw r30, r24
+; NOX-NEXT: out 59, r18
+; NOX-NEXT: elpm
+; NOX-NEXT: mov r24, r0
+; NOX-NEXT: sub r24, r19
+; NOX-NEXT: mov r25, r24
+; NOX-NEXT: lsl r25
+; NOX-NEXT: sbc r25, r25
+; NOX-NEXT: ret
entry:
%arrayidx = getelementptr inbounds [4 x i8], [4 x i8] addrspace(3)* @arrb3, i16 0, i16 %a
%0 = load i8, i8 addrspace(3)* %arrayidx, align 1
--- /dev/null
+# RUN: llc -mtriple=avr -mattr=+elpm -mattr=+elpmx -start-before=greedy %s -o - \
+# RUN: | FileCheck %s
+# RUN: llc -mtriple=avr -mattr=+elpm -mattr=-elpmx -start-before=greedy %s -o - \
+# RUN: | FileCheck --check-prefix=NOX %s
+
+# This test checks the expansion of the 16-bit ELPM pseudo instruction and that
+# the register allocator won't use R31R30 as an output register (which would
+# lead to undefined behavior).
+
+--- |
+ target triple = "avr--"
+ define void @test_elpmbrdz() {
+ entry:
+ ret void
+ }
+...
+
+---
+name: test_elpmbrdz
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ liveins: $r31r30
+
+ ; CHECK-LABEL: test_elpmbrdz
+ ; CHECK: ; %bb.0:
+ ; CHECK-NEXT: ldi r24, 1
+ ; CHECK-NEXT: out
+ ; CHECK-NEXT: elpm r31, Z
+ ; CHECK-NEXT: ret
+
+ ; NOX-LABEL: test_elpmbrdz
+ ; NOX: ; %bb.0:
+ ; NOX-NEXT: ldi r24, 1
+ ; NOX-NEXT: out
+ ; NOX-NEXT: elpm
+ ; NOX-NEXT: mov r31, r0
+ ; NOX-NEXT: ret
+
+ %1:zreg = COPY killed $r31r30
+ %2:ld8 = LDIRdK 1
+ %3:gpr8 = ELPMBRdZ %1, %2, implicit-def dead $r0
+ $r31 = COPY %3
+ RET implicit $r31
+...