diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp index 440d852fa4bc8..90505aa82aa46 100644 --- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -2531,27 +2531,47 @@ bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { unsigned Flags = MI.getFlags(); TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); - buildMI(MBB, MBBI, AVR::INRdA) - .addReg(STI.getTmpRegister(), RegState::Define) - .addImm(STI.getIORegSREG()) - .setMIFlags(Flags); - - buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags); - - buildMI(MBB, MBBI, AVR::OUTARr) - .addImm(0x3e) - .addReg(SrcHiReg, getKillRegState(SrcIsKill)) - .setMIFlags(Flags); + // From the XMEGA series manual: + // To prevent corruption when updating the stack pointer from software, + // a write to SPL will automatically disable interrupts + // for up to four instructions or until the next I/O memory write. + if (STI.getELFArch() >= 102) { // An XMEGA device + + buildMI(MBB, MBBI, AVR::OUTARr) + .addImm(STI.getIORegSPL()) + .addReg(SrcLoReg, getKillRegState(SrcIsKill)) + .setMIFlags(Flags); + + buildMI(MBB, MBBI, AVR::OUTARr) + .addImm(STI.getIORegSPH()) + .addReg(SrcHiReg, getKillRegState(SrcIsKill)) + .setMIFlags(Flags); + + } else { // Disable interrupts for older devices (3 extra instructions) + + buildMI(MBB, MBBI, AVR::INRdA) + .addReg(STI.getTmpRegister(), RegState::Define) + .addImm(STI.getIORegSREG()) + .setMIFlags(Flags); + + buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags); + + if (STI.getIORegSPH() != -1) + buildMI(MBB, MBBI, AVR::OUTARr) + .addImm(STI.getIORegSPH()) + .addReg(SrcHiReg, getKillRegState(SrcIsKill)) + .setMIFlags(Flags); - buildMI(MBB, MBBI, AVR::OUTARr) - .addImm(STI.getIORegSREG()) - .addReg(STI.getTmpRegister(), RegState::Kill) - .setMIFlags(Flags); + buildMI(MBB, MBBI, AVR::OUTARr) + .addImm(STI.getIORegSREG()) + .addReg(STI.getTmpRegister(), RegState::Kill) + .setMIFlags(Flags); - buildMI(MBB, MBBI, AVR::OUTARr) - .addImm(0x3d) - .addReg(SrcLoReg, getKillRegState(SrcIsKill)) - .setMIFlags(Flags); + buildMI(MBB, MBBI, AVR::OUTARr) + .addImm(STI.getIORegSPL()) + .addReg(SrcLoReg, getKillRegState(SrcIsKill)) + .setMIFlags(Flags); + } MI.eraseFromParent(); return true; diff --git a/llvm/test/CodeGen/AVR/pseudo/SPWRITE.mir b/llvm/test/CodeGen/AVR/pseudo/SPWRITE.mir new file mode 100644 index 0000000000000..ed6e39c641b11 --- /dev/null +++ b/llvm/test/CodeGen/AVR/pseudo/SPWRITE.mir @@ -0,0 +1,47 @@ +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mtriple=avr -mcpu=attiny11 %s -o - \ +# RUN: | FileCheck --check-prefix=NOSPH %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mtriple=avr -mcpu=atmega328 %s -o - \ +# RUN: | FileCheck %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mtriple=avr -mcpu=attiny817 %s -o - \ +# RUN: | FileCheck --check-prefix=XMEGA %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mtriple=avr -mcpu=atxmega64a1 %s -o - \ +# RUN: | FileCheck --check-prefix=XMEGA %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mtriple=avr -mcpu=atxmega256a3u %s -o - \ +# RUN: | FileCheck --check-prefix=XMEGA %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mtriple=avr -mcpu=attiny1614 %s -o - \ +# RUN: | FileCheck --check-prefix=XMEGA %s +# RUN: llc -O0 -run-pass=avr-expand-pseudo -mtriple=avr -mcpu=avr128db28 %s -o - \ +# RUN: | FileCheck --check-prefix=XMEGA %s + +--- | + target triple = "avr--" + define void @test() { + entry: + ret void + } +... + +--- +name: test +body: | + bb.0.entry: + + ; CHECK-LABEL: test + ; CHECK: $r0 = INRdA 63 + ; CHECK: BCLRs 7, implicit-def $sreg + ; CHECK: OUTARr 62, $r15 + ; CHECK: OUTARr 63, killed $r0 + ; CHECK: OUTARr 61, $r14 + + ; NOSPH-LABEL: test + ; NOSPH: $r0 = INRdA 63 + ; NOSPH: BCLRs 7, implicit-def $sreg + ; NOSPH: OUTARr 63, killed $r0 + ; NOSPH: OUTARr 61, $r14 + + ; XMEGA-LABEL: test + ; XMEGA-LABEL: OUTARr 61, $r14 + ; XMEGA-LABEL: OUTARr 62, $r15 + + $sp = SPWRITE implicit-def $sp, implicit $sp, $r15r14 +...