Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 0226ba2

Browse files
committed
[AVR] Support the LDWRdPtr instruction with the same Src+Dst register
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301313 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent e9fd8c5 commit 0226ba2

File tree

4 files changed

+139
-87
lines changed

4 files changed

+139
-87
lines changed

lib/Target/AVR/AVRExpandPseudoInsts.cpp

+75-52
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ class AVRExpandPseudo : public MachineFunctionPass {
8888
unsigned ArithOpcode,
8989
Block &MBB,
9090
BlockIt MBBI);
91+
92+
/// Scavenges a free GPR8 register for use.
93+
unsigned scavengeGPR8(MachineInstr &MI);
9194
};
9295

9396
char AVRExpandPseudo::ID = 0;
@@ -577,24 +580,43 @@ bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {
577580
MachineInstr &MI = *MBBI;
578581
unsigned OpLo, OpHi, DstLoReg, DstHiReg;
579582
unsigned DstReg = MI.getOperand(0).getReg();
583+
unsigned TmpReg = 0; // 0 for no temporary register
580584
unsigned SrcReg = MI.getOperand(1).getReg();
581-
bool DstIsDead = MI.getOperand(0).isDead();
582585
bool SrcIsKill = MI.getOperand(1).isKill();
583586
OpLo = AVR::LDRdPtr;
584587
OpHi = AVR::LDDRdPtrQ;
585588
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
586589

587-
assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
590+
// Use a temporary register if src and dst registers are the same.
591+
if (DstReg == SrcReg)
592+
TmpReg = scavengeGPR8(MI);
593+
594+
unsigned CurDstLoReg = (DstReg == SrcReg) ? TmpReg : DstLoReg;
595+
unsigned CurDstHiReg = (DstReg == SrcReg) ? TmpReg : DstHiReg;
588596

597+
// Load low byte.
589598
auto MIBLO = buildMI(MBB, MBBI, OpLo)
590-
.addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
599+
.addReg(CurDstLoReg, RegState::Define)
591600
.addReg(SrcReg);
592601

602+
// Push low byte onto stack if necessary.
603+
if (TmpReg)
604+
buildMI(MBB, MBBI, AVR::PUSHRr).addReg(TmpReg);
605+
606+
// Load high byte.
593607
auto MIBHI = buildMI(MBB, MBBI, OpHi)
594-
.addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
608+
.addReg(CurDstHiReg, RegState::Define)
595609
.addReg(SrcReg, getKillRegState(SrcIsKill))
596610
.addImm(1);
597611

612+
if (TmpReg) {
613+
// Move the high byte into the final destination.
614+
buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
615+
616+
// Move the low byte from the scratch space into the final destination.
617+
buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
618+
}
619+
598620
MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
599621
MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
600622

@@ -669,70 +691,45 @@ bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
669691
MachineInstr &MI = *MBBI;
670692
unsigned OpLo, OpHi, DstLoReg, DstHiReg;
671693
unsigned DstReg = MI.getOperand(0).getReg();
694+
unsigned TmpReg = 0; // 0 for no temporary register
672695
unsigned SrcReg = MI.getOperand(1).getReg();
673696
unsigned Imm = MI.getOperand(2).getImm();
674-
bool DstIsDead = MI.getOperand(0).isDead();
675697
bool SrcIsKill = MI.getOperand(1).isKill();
676698
OpLo = AVR::LDDRdPtrQ;
677699
OpHi = AVR::LDDRdPtrQ;
678700
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
679701

680702
assert(Imm <= 63 && "Offset is out of range");
681703

682-
MachineInstr *MIBLO, *MIBHI;
683-
684-
// HACK: We shouldn't have instances of this instruction
685-
// where src==dest because the instruction itself is
686-
// marked earlyclobber. We do however get this instruction when
687-
// loading from stack slots where the earlyclobber isn't useful.
688-
//
689-
// In this case, just use a temporary register.
690-
if (DstReg == SrcReg) {
691-
RegScavenger RS;
692-
693-
RS.enterBasicBlock(MBB);
694-
RS.forward(MBBI);
695-
696-
BitVector Candidates =
697-
TRI->getAllocatableSet
698-
(*MBB.getParent(), &AVR::GPR8RegClass);
699-
700-
// Exclude all the registers being used by the instruction.
701-
for (MachineOperand &MO : MI.operands()) {
702-
if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() &&
703-
!TargetRegisterInfo::isVirtualRegister(MO.getReg()))
704-
Candidates.reset(MO.getReg());
705-
}
706-
707-
BitVector Available = RS.getRegsAvailable(&AVR::GPR8RegClass);
708-
Available &= Candidates;
704+
// Use a temporary register if src and dst registers are the same.
705+
if (DstReg == SrcReg)
706+
TmpReg = scavengeGPR8(MI);
709707

710-
signed TmpReg = Available.find_first();
711-
assert(TmpReg != -1 && "ran out of registers");
708+
unsigned CurDstLoReg = (DstReg == SrcReg) ? TmpReg : DstLoReg;
709+
unsigned CurDstHiReg = (DstReg == SrcReg) ? TmpReg : DstHiReg;
712710

713-
MIBLO = buildMI(MBB, MBBI, OpLo)
714-
.addReg(TmpReg, RegState::Define)
715-
.addReg(SrcReg)
716-
.addImm(Imm);
711+
// Load low byte.
712+
auto MIBLO = buildMI(MBB, MBBI, OpLo)
713+
.addReg(CurDstLoReg, RegState::Define)
714+
.addReg(SrcReg)
715+
.addImm(Imm);
717716

718-
buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstLoReg).addReg(TmpReg);
717+
// Push low byte onto stack if necessary.
718+
if (TmpReg)
719+
buildMI(MBB, MBBI, AVR::PUSHRr).addReg(TmpReg);
719720

720-
MIBHI = buildMI(MBB, MBBI, OpHi)
721-
.addReg(TmpReg, RegState::Define)
722-
.addReg(SrcReg, getKillRegState(SrcIsKill))
723-
.addImm(Imm + 1);
721+
// Load high byte.
722+
auto MIBHI = buildMI(MBB, MBBI, OpHi)
723+
.addReg(CurDstHiReg, RegState::Define)
724+
.addReg(SrcReg, getKillRegState(SrcIsKill))
725+
.addImm(Imm + 1);
724726

727+
if (TmpReg) {
728+
// Move the high byte into the final destination.
725729
buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
726-
} else {
727-
MIBLO = buildMI(MBB, MBBI, OpLo)
728-
.addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
729-
.addReg(SrcReg)
730-
.addImm(Imm);
731730

732-
MIBHI = buildMI(MBB, MBBI, OpHi)
733-
.addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
734-
.addReg(SrcReg, getKillRegState(SrcIsKill))
735-
.addImm(Imm + 1);
731+
// Move the low byte from the scratch space into the final destination.
732+
buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
736733
}
737734

738735
MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
@@ -819,6 +816,32 @@ bool AVRExpandPseudo::expandAtomicArithmeticOp(unsigned Width,
819816
});
820817
}
821818

819+
unsigned AVRExpandPseudo::scavengeGPR8(MachineInstr &MI) {
820+
MachineBasicBlock &MBB = *MI.getParent();
821+
RegScavenger RS;
822+
823+
RS.enterBasicBlock(MBB);
824+
RS.forward(MI);
825+
826+
BitVector Candidates =
827+
TRI->getAllocatableSet
828+
(*MBB.getParent(), &AVR::GPR8RegClass);
829+
830+
// Exclude all the registers being used by the instruction.
831+
for (MachineOperand &MO : MI.operands()) {
832+
if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() &&
833+
!TargetRegisterInfo::isVirtualRegister(MO.getReg()))
834+
Candidates.reset(MO.getReg());
835+
}
836+
837+
BitVector Available = RS.getRegsAvailable(&AVR::GPR8RegClass);
838+
Available &= Candidates;
839+
840+
signed Reg = Available.find_first();
841+
assert(Reg != -1 && "ran out of registers");
842+
return Reg;
843+
}
844+
822845
template<>
823846
bool AVRExpandPseudo::expand<AVR::AtomicLoad8>(Block &MBB, BlockIt MBBI) {
824847
return expandAtomicBinaryOp(AVR::LDRdPtr, MBB, MBBI);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# RUN: llc -O0 %s -o - -march=avr | FileCheck %s
2+
3+
# This test checks the expansion of the 16-bit 'LDDWRdPtrQ' pseudo instruction.
4+
#
5+
# This test ensures that the pseudo expander can correctly handle the case
6+
# where we are expanding a 16-bit LDD instruction where the source and
7+
# destination registers are the same.
8+
#
9+
# The instruction itself is earlyclobber and so ISel will never produce an
10+
# instruction like this, but the stack slot loading can and will.
11+
12+
--- |
13+
target triple = "avr--"
14+
define void @test_lddwrdptrq() {
15+
entry:
16+
ret void
17+
}
18+
...
19+
20+
---
21+
name: test_lddwrdptrq
22+
tracksRegLiveness: true
23+
body: |
24+
bb.0.entry:
25+
26+
; CHECK-LABEL: test_lddwrdptrq
27+
28+
; CHECK: ldd [[SCRATCH:r[0-9]+]], Z+10
29+
; CHECK-NEXT: push [[SCRATCH]]
30+
; CHECK-NEXT: ldd [[SCRATCH]], Z+11
31+
; CHECK-NEXT: mov r31, [[SCRATCH]]
32+
; CHECK-NEXT: pop r30
33+
34+
early-clobber %r31r30 = LDDWRdPtrQ undef %r31r30, 10
35+
...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# RUN: llc -O0 %s -o - | FileCheck %s
2+
3+
# This test checks the expansion of the 16-bit LDWRdPtr pseudo instruction.
4+
5+
--- |
6+
target triple = "avr--"
7+
define void @test_ldwrdptr() {
8+
entry:
9+
ret void
10+
}
11+
...
12+
13+
---
14+
name: test_ldwrdptr
15+
tracksRegLiveness: true
16+
body: |
17+
bb.0.entry:
18+
19+
; CHECK-LABEL: test_ldwrdptr
20+
21+
; CHECK: ld [[SCRATCH:r[0-9]+]], Z
22+
; CHECK-NEXT: push [[SCRATCH]]
23+
; CHECK-NEXT: ldd [[SCRATCH]], Z+1
24+
; CHECK-NEXT: mov r31, [[SCRATCH]]
25+
; CHECK-NEXT: pop r30
26+
27+
early-clobber %r31r30 = LDWRdPtr undef %r31r30
28+
...
29+

test/CodeGen/AVR/pseudo/expand-lddw-dst-src-same.mir

-35
This file was deleted.

0 commit comments

Comments
 (0)