From 8f515b1ef7ac3cb7350ca0b4ba173fd325b2f34c Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Tue, 25 Apr 2017 15:09:04 +0000 Subject: [PATCH] [AVR] Support the LDWRdPtr instruction with the same Src+Dst register llvm-svn: 301313 --- llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp | 127 ++++++++++++--------- .../CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir | 35 ++++++ .../CodeGen/AVR/pseudo/LDWRdPtr-same-src-dst.mir | 29 +++++ .../AVR/pseudo/expand-lddw-dst-src-same.mir | 35 ------ 4 files changed, 139 insertions(+), 87 deletions(-) create mode 100644 llvm/test/CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir create mode 100644 llvm/test/CodeGen/AVR/pseudo/LDWRdPtr-same-src-dst.mir delete mode 100644 llvm/test/CodeGen/AVR/pseudo/expand-lddw-dst-src-same.mir diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp index 13080a5..dd87f62 100644 --- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -88,6 +88,9 @@ private: unsigned ArithOpcode, Block &MBB, BlockIt MBBI); + + /// Scavenges a free GPR8 register for use. + unsigned scavengeGPR8(MachineInstr &MI); }; char AVRExpandPseudo::ID = 0; @@ -577,24 +580,43 @@ bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); + unsigned TmpReg = 0; // 0 for no temporary register unsigned SrcReg = MI.getOperand(1).getReg(); - bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(1).isKill(); OpLo = AVR::LDRdPtr; OpHi = AVR::LDDRdPtrQ; TRI->splitReg(DstReg, DstLoReg, DstHiReg); - assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same"); + // Use a temporary register if src and dst registers are the same. + if (DstReg == SrcReg) + TmpReg = scavengeGPR8(MI); + + unsigned CurDstLoReg = (DstReg == SrcReg) ? TmpReg : DstLoReg; + unsigned CurDstHiReg = (DstReg == SrcReg) ? TmpReg : DstHiReg; + // Load low byte. auto MIBLO = buildMI(MBB, MBBI, OpLo) - .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(CurDstLoReg, RegState::Define) .addReg(SrcReg); + // Push low byte onto stack if necessary. + if (TmpReg) + buildMI(MBB, MBBI, AVR::PUSHRr).addReg(TmpReg); + + // Load high byte. auto MIBHI = buildMI(MBB, MBBI, OpHi) - .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(CurDstHiReg, RegState::Define) .addReg(SrcReg, getKillRegState(SrcIsKill)) .addImm(1); + if (TmpReg) { + // Move the high byte into the final destination. + buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg); + + // Move the low byte from the scratch space into the final destination. + buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg); + } + MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); @@ -669,9 +691,9 @@ bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); + unsigned TmpReg = 0; // 0 for no temporary register unsigned SrcReg = MI.getOperand(1).getReg(); unsigned Imm = MI.getOperand(2).getImm(); - bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(1).isKill(); OpLo = AVR::LDDRdPtrQ; OpHi = AVR::LDDRdPtrQ; @@ -679,60 +701,35 @@ bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { assert(Imm <= 63 && "Offset is out of range"); - MachineInstr *MIBLO, *MIBHI; - - // HACK: We shouldn't have instances of this instruction - // where src==dest because the instruction itself is - // marked earlyclobber. We do however get this instruction when - // loading from stack slots where the earlyclobber isn't useful. - // - // In this case, just use a temporary register. - if (DstReg == SrcReg) { - RegScavenger RS; - - RS.enterBasicBlock(MBB); - RS.forward(MBBI); - - BitVector Candidates = - TRI->getAllocatableSet - (*MBB.getParent(), &AVR::GPR8RegClass); - - // Exclude all the registers being used by the instruction. - for (MachineOperand &MO : MI.operands()) { - if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() && - !TargetRegisterInfo::isVirtualRegister(MO.getReg())) - Candidates.reset(MO.getReg()); - } - - BitVector Available = RS.getRegsAvailable(&AVR::GPR8RegClass); - Available &= Candidates; + // Use a temporary register if src and dst registers are the same. + if (DstReg == SrcReg) + TmpReg = scavengeGPR8(MI); - signed TmpReg = Available.find_first(); - assert(TmpReg != -1 && "ran out of registers"); + unsigned CurDstLoReg = (DstReg == SrcReg) ? TmpReg : DstLoReg; + unsigned CurDstHiReg = (DstReg == SrcReg) ? TmpReg : DstHiReg; - MIBLO = buildMI(MBB, MBBI, OpLo) - .addReg(TmpReg, RegState::Define) - .addReg(SrcReg) - .addImm(Imm); + // Load low byte. + auto MIBLO = buildMI(MBB, MBBI, OpLo) + .addReg(CurDstLoReg, RegState::Define) + .addReg(SrcReg) + .addImm(Imm); - buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstLoReg).addReg(TmpReg); + // Push low byte onto stack if necessary. + if (TmpReg) + buildMI(MBB, MBBI, AVR::PUSHRr).addReg(TmpReg); - MIBHI = buildMI(MBB, MBBI, OpHi) - .addReg(TmpReg, RegState::Define) - .addReg(SrcReg, getKillRegState(SrcIsKill)) - .addImm(Imm + 1); + // Load high byte. + auto MIBHI = buildMI(MBB, MBBI, OpHi) + .addReg(CurDstHiReg, RegState::Define) + .addReg(SrcReg, getKillRegState(SrcIsKill)) + .addImm(Imm + 1); + if (TmpReg) { + // Move the high byte into the final destination. buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg); - } else { - MIBLO = buildMI(MBB, MBBI, OpLo) - .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) - .addReg(SrcReg) - .addImm(Imm); - MIBHI = buildMI(MBB, MBBI, OpHi) - .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) - .addReg(SrcReg, getKillRegState(SrcIsKill)) - .addImm(Imm + 1); + // Move the low byte from the scratch space into the final destination. + buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg); } MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); @@ -819,6 +816,32 @@ bool AVRExpandPseudo::expandAtomicArithmeticOp(unsigned Width, }); } +unsigned AVRExpandPseudo::scavengeGPR8(MachineInstr &MI) { + MachineBasicBlock &MBB = *MI.getParent(); + RegScavenger RS; + + RS.enterBasicBlock(MBB); + RS.forward(MI); + + BitVector Candidates = + TRI->getAllocatableSet + (*MBB.getParent(), &AVR::GPR8RegClass); + + // Exclude all the registers being used by the instruction. + for (MachineOperand &MO : MI.operands()) { + if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() && + !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + Candidates.reset(MO.getReg()); + } + + BitVector Available = RS.getRegsAvailable(&AVR::GPR8RegClass); + Available &= Candidates; + + signed Reg = Available.find_first(); + assert(Reg != -1 && "ran out of registers"); + return Reg; +} + template<> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { return expandAtomicBinaryOp(AVR::LDRdPtr, MBB, MBBI); diff --git a/llvm/test/CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir b/llvm/test/CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir new file mode 100644 index 0000000..b19e44e --- /dev/null +++ b/llvm/test/CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir @@ -0,0 +1,35 @@ +# RUN: llc -O0 %s -o - -march=avr | FileCheck %s + +# This test checks the expansion of the 16-bit 'LDDWRdPtrQ' pseudo instruction. +# +# This test ensures that the pseudo expander can correctly handle the case +# where we are expanding a 16-bit LDD instruction where the source and +# destination registers are the same. +# +# The instruction itself is earlyclobber and so ISel will never produce an +# instruction like this, but the stack slot loading can and will. + +--- | + target triple = "avr--" + define void @test_lddwrdptrq() { + entry: + ret void + } +... + +--- +name: test_lddwrdptrq +tracksRegLiveness: true +body: | + bb.0.entry: + + ; CHECK-LABEL: test_lddwrdptrq + + ; CHECK: ldd [[SCRATCH:r[0-9]+]], Z+10 + ; CHECK-NEXT: push [[SCRATCH]] + ; CHECK-NEXT: ldd [[SCRATCH]], Z+11 + ; CHECK-NEXT: mov r31, [[SCRATCH]] + ; CHECK-NEXT: pop r30 + + early-clobber %r31r30 = LDDWRdPtrQ undef %r31r30, 10 +... diff --git a/llvm/test/CodeGen/AVR/pseudo/LDWRdPtr-same-src-dst.mir b/llvm/test/CodeGen/AVR/pseudo/LDWRdPtr-same-src-dst.mir new file mode 100644 index 0000000..3e7fdcd --- /dev/null +++ b/llvm/test/CodeGen/AVR/pseudo/LDWRdPtr-same-src-dst.mir @@ -0,0 +1,29 @@ +# RUN: llc -O0 %s -o - | FileCheck %s + +# This test checks the expansion of the 16-bit LDWRdPtr pseudo instruction. + +--- | + target triple = "avr--" + define void @test_ldwrdptr() { + entry: + ret void + } +... + +--- +name: test_ldwrdptr +tracksRegLiveness: true +body: | + bb.0.entry: + + ; CHECK-LABEL: test_ldwrdptr + + ; CHECK: ld [[SCRATCH:r[0-9]+]], Z + ; CHECK-NEXT: push [[SCRATCH]] + ; CHECK-NEXT: ldd [[SCRATCH]], Z+1 + ; CHECK-NEXT: mov r31, [[SCRATCH]] + ; CHECK-NEXT: pop r30 + + early-clobber %r31r30 = LDWRdPtr undef %r31r30 +... + diff --git a/llvm/test/CodeGen/AVR/pseudo/expand-lddw-dst-src-same.mir b/llvm/test/CodeGen/AVR/pseudo/expand-lddw-dst-src-same.mir deleted file mode 100644 index 8427a2b..0000000 --- a/llvm/test/CodeGen/AVR/pseudo/expand-lddw-dst-src-same.mir +++ /dev/null @@ -1,35 +0,0 @@ -# RUN: llc -O0 %s -o - -march=avr | FileCheck %s - -# This test ensures that the pseudo expander can correctly handle the case -# where we are expanding a 16-bit LDD instruction where the source and -# destination registers are the same. -# -# The instruction itself is earlyclobber and so ISel will never produce an -# instruction like this, but the stack slot loading can and will. - ---- | - target triple = "avr--" - - define void @test_lddw() { - entry: - ret void - } - -... ---- -name: test_lddw -tracksRegLiveness: true -stack: - - { id: 0, type: spill-slot, offset: -4, size: 1, alignment: 1, callee-saved-register: '%r28' } -body: | - bb.0.entry: - liveins: %r28, %r29 - - ; CHECK-LABEL: test_lddw - - ; CHECK: ldd [[TMPREG:r[0-9]+]], Y+0 - ; CHECK-NEXT: mov r28, [[TMPREG]] - ; CHECK-NEXT: ldd [[TMPREG]], Y+1 - ; CHECK-NEXT: mov r29, [[TMPREG]] - dead early-clobber %r29r28 = LDDWRdYQ killed %r29r28, 0 -... -- 2.7.4