bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI);
- /// Specific shift implementation.
+ /// Specific shift implementation for int8.
bool expandLSLB7Rd(Block &MBB, BlockIt MBBI);
bool expandLSRB7Rd(Block &MBB, BlockIt MBBI);
bool expandASRB6Rd(Block &MBB, BlockIt MBBI);
bool expandASRB7Rd(Block &MBB, BlockIt MBBI);
+
+ /// Specific shift implementation for int16.
bool expandLSLW4Rd(Block &MBB, BlockIt MBBI);
bool expandLSRW4Rd(Block &MBB, BlockIt MBBI);
+ bool expandASRW7Rd(Block &MBB, BlockIt MBBI);
bool expandLSLW8Rd(Block &MBB, BlockIt MBBI);
bool expandLSRW8Rd(Block &MBB, BlockIt MBBI);
bool expandASRW8Rd(Block &MBB, BlockIt MBBI);
bool expandLSLW12Rd(Block &MBB, BlockIt MBBI);
bool expandLSRW12Rd(Block &MBB, BlockIt MBBI);
+ bool expandASRW14Rd(Block &MBB, BlockIt MBBI);
+ bool expandASRW15Rd(Block &MBB, BlockIt MBBI);
// Common implementation of LPMWRdZ and ELPMWRdZ.
bool expandLPMWELPMW(Block &MBB, BlockIt MBBI, bool IsExt);
// add hireg, hireg <==> lsl hireg
auto MILSL =
buildMI(MBB, MBBI, AVR::ADDRdRr)
- .addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
.addReg(DstHiReg, getKillRegState(DstIsKill))
.addReg(DstHiReg, getKillRegState(DstIsKill));
return true;
}
+bool AVRExpandPseudo::expandASRW7Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // lsl r24
+ // mov r24,r25
+ // rol r24
+ // sbc r25,r25
+
+ // lsl r24 <=> add r24, r24
+ buildMI(MBB, MBBI, AVR::ADDRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, RegState::Kill)
+ .addReg(DstLoReg, RegState::Kill);
+
+ // mov r24, r25
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg);
+
+ // rol r24 <=> adc r24, r24
+ buildMI(MBB, MBBI, AVR::ADCRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ // sbc r25, r25
+ auto MISBC =
+ buildMI(MBB, MBBI, AVR::SBCRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MISBC->getOperand(3).setIsDead();
+ // SREG is always implicitly killed
+ MISBC->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
bool AVRExpandPseudo::expandASRW8Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
.addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
.addReg(DstHiReg, getKillRegState(DstIsKill))
.addReg(DstHiReg, getKillRegState(DstIsKill));
+
if (ImpIsDead)
MIBHI->getOperand(3).setIsDead();
+ // SREG is always implicitly killed
+ MIBHI->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+bool AVRExpandPseudo::expandASRW14Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // lsl r25
+ // sbc r24, r24
+ // lsl r25
+ // mov r25, r24
+ // rol r24
+
+ // lsl r25 <=> add r25, r25
+ buildMI(MBB, MBBI, AVR::ADDRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, RegState::Kill)
+ .addReg(DstHiReg, RegState::Kill);
+
+ // sbc r24, r24
+ buildMI(MBB, MBBI, AVR::SBCRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, RegState::Kill)
+ .addReg(DstLoReg, RegState::Kill);
+
+ // lsl r25 <=> add r25, r25
+ buildMI(MBB, MBBI, AVR::ADDRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, RegState::Kill)
+ .addReg(DstHiReg, RegState::Kill);
+
+ // mov r25, r24
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg);
+
+ // rol r24 <=> adc r24, r24
+ auto MIROL =
+ buildMI(MBB, MBBI, AVR::ADCRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIROL->getOperand(3).setIsDead();
+ // SREG is always implicitly killed
+ MIROL->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return false;
+}
+
+bool AVRExpandPseudo::expandASRW15Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstLoReg, DstHiReg;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // lsl r25
+ // sbc r25, r25
+ // mov r24, r25
+
+ // lsl r25 <=> add r25, r25
+ buildMI(MBB, MBBI, AVR::ADDRdRr)
+ .addReg(DstHiReg, RegState::Define)
+ .addReg(DstHiReg, RegState::Kill)
+ .addReg(DstHiReg, RegState::Kill);
+
+ // sbc r25, r25
+ auto MISBC =
+ buildMI(MBB, MBBI, AVR::SBCRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, RegState::Kill)
+ .addReg(DstHiReg, RegState::Kill);
+ if (ImpIsDead)
+ MISBC->getOperand(3).setIsDead();
+ // SREG is always implicitly killed
+ MISBC->getOperand(4).setIsKill();
+
+ // mov r24, r25
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg);
MI.eraseFromParent();
return true;
MachineInstr &MI = *MBBI;
unsigned Imm = MI.getOperand(2).getImm();
switch (Imm) {
+ case 7:
+ return expandASRW7Rd(MBB, MBBI);
case 8:
return expandASRW8Rd(MBB, MBBI);
+ case 14:
+ return expandASRW14Rd(MBB, MBBI);
+ case 15:
+ return expandASRW15Rd(MBB, MBBI);
default:
llvm_unreachable("unimplemented asrwn");
return false;
--- /dev/null
+# RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s
+
+--- |
+ target triple = "avr--"
+ define void @test() {
+ entry:
+ ret void
+ }
+...
+
+---
+name: test
+body: |
+ bb.0.entry:
+ liveins: $r15r14, $r13r12, $r11r10, $r17r16
+
+ ; CHECK-LABEL: test
+
+ ; CHECK: $r14 = ADDRdRr killed $r14, killed $r14, implicit-def $sreg
+ ; CHECK-NEXT: $r14 = MOVRdRr $r15
+ ; CHECK-NEXT: $r14 = ADCRdRr $r14, $r14, implicit-def $sreg, implicit $sreg
+ ; CHECK-NEXT: $r15 = SBCRdRr $r15, $r15, implicit-def $sreg, implicit killed $sreg
+ $r15r14 = ASRWNRd $r15r14, 7, implicit-def $sreg
+
+ ; CHECK-NEXT: $r12 = MOVRdRr $r13
+ ; CHECK-NEXT: $r13 = ADDRdRr killed $r13, killed $r13, implicit-def $sreg
+ ; CHECK-NEXT: $r13 = SBCRdRr $r13, $r13, implicit-def $sreg, implicit killed $sreg
+ $r13r12 = ASRWNRd $r13r12, 8, implicit-def $sreg
+
+ ; CHECK-NEXT: $r11 = ADDRdRr killed $r11, killed $r11, implicit-def $sreg
+ ; CHECK-NEXT: $r10 = SBCRdRr killed $r10, killed $r10, implicit-def $sreg, implicit $sreg
+ ; CHECK-NEXT: $r11 = ADDRdRr killed $r11, killed $r11, implicit-def $sreg
+ ; CHECK-NEXT: $r11 = MOVRdRr $r10
+ ; CHECK-NEXT: $r10 = ADCRdRr $r10, $r10, implicit-def $sreg, implicit killed $sreg
+ $r11r10 = ASRWNRd $r11r10, 14, implicit-def $sreg
+
+ ; CHECK-NEXT: $r17 = ADDRdRr killed $r17, killed $r17, implicit-def $sreg
+ ; CHECK-NEXT: $r17 = SBCRdRr killed $r17, killed $r17, implicit-def $sreg, implicit killed $sreg
+ ; CHECK-NEXT: $r16 = MOVRdRr $r17
+ $r17r16 = ASRWNRd $r17r16, 15, implicit-def $sreg
+...