#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;
TRI = STI.getRegisterInfo();
TII = STI.getInstrInfo();
+ // We need to track liveness in order to use register scavenging.
+ MF.getProperties().set(MachineFunctionProperties::Property::TracksLiveness);
+
for (Block &MBB : MF) {
bool ContinueExpanding = true;
unsigned ExpandCount = 0;
assert(Imm <= 63 && "Offset is out of range");
- unsigned TmpLoReg = DstLoReg;
- unsigned TmpHiReg = DstHiReg;
+ MachineInstr *MIBLO, *MIBHI;
// HACK: We shouldn't have instances of this instruction
// where src==dest because the instruction itself is
//
// In this case, just use a temporary register.
if (DstReg == SrcReg) {
- TmpLoReg = SCRATCH_REGISTER;
- TmpHiReg = SCRATCH_REGISTER;
- }
+ RegScavenger RS;
- auto MIBLO = buildMI(MBB, MBBI, OpLo)
- .addReg(TmpLoReg, RegState::Define | getDeadRegState(DstIsDead))
- .addReg(SrcReg)
- .addImm(Imm);
+ RS.enterBasicBlock(MBB);
+ RS.forward(MBBI);
- // Push the low part of the temporary register to the stack.
- if (TmpLoReg != DstLoReg)
- buildMI(MBB, MBBI, AVR::PUSHRr)
- .addReg(AVR::R0);
+ BitVector Candidates =
+ TRI->getAllocatableSet
+ (*MBB.getParent(), &AVR::GPR8RegClass);
- auto MIBHI = buildMI(MBB, MBBI, OpHi)
- .addReg(TmpHiReg, RegState::Define | getDeadRegState(DstIsDead))
- .addReg(SrcReg, getKillRegState(SrcIsKill))
- .addImm(Imm + 1);
+ // 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());
+ }
- // If we need to use a temporary register.
- if (TmpHiReg != DstHiReg) {
- // Move the hi result from the tmp register to the destination.
- buildMI(MBB, MBBI, AVR::MOVRdRr)
- .addReg(DstHiReg).addReg(SCRATCH_REGISTER);
+ BitVector Available = RS.getRegsAvailable(&AVR::GPR8RegClass);
+ Available &= Candidates;
+
+ unsigned TmpReg = Available.find_first();
+ assert(TmpReg != -1 && "ran out of registers");
+
+ MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(TmpReg, RegState::Define)
+ .addReg(SrcReg)
+ .addImm(Imm);
+
+ buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstLoReg).addReg(TmpReg);
+
+ MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(TmpReg, RegState::Define)
+ .addReg(SrcReg, getKillRegState(SrcIsKill))
+ .addImm(Imm + 1);
+
+ 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);
- // Pop the lo result calculated previously and put it into
- // the lo destination.
- buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
+ MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, getKillRegState(SrcIsKill))
+ .addImm(Imm + 1);
}
MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
-# RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - 2>&1 | FileCheck %s
+# RUN: llc -O0 %s -o - 2>&1 | 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
--- |
target triple = "avr--"
+
define void @test_lddw() {
entry:
ret void
}
-...
+...
---
name: test_lddw
-registers:
- - { id: 0, class: _ }
-body: |
- ; CHECK-LABEL: bb.0.entry
+stack:
+ - { id: 0, type: spill-slot, offset: -4, size: 1, alignment: 1, callee-saved-register: '%r28' }
+body: |
bb.0.entry:
+ liveins: %r28, %r29
- ; CHECK-NEXT: early-clobber %r0 = LDDRdPtrQ %r29r28, 1
- ; CHECK-NEXT: PUSHRr %r0, implicit-def %sp, implicit %sp
- ; CHECK-NEXT: early-clobber %r0 = LDDRdPtrQ %r29r28, 2
- ; CHECK-NEXT: MOVRdRr %r29, %r0
- ; CHECK-NEXT: POPRd %r28, implicit-def %sp, implicit %sp
+ ; CHECK-LABEL: test_lddw
- early-clobber %r29r28 = LDDWRdYQ %r29r28, 1
+ ; 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
...