Mercurial > hg > CbC > CbC_llvm
view lib/Target/AVR/AVRExpandPseudoInsts.cpp @ 120:1172e4bd9c6f
update 4.0.0
author | mir3636 |
---|---|
date | Fri, 25 Nov 2016 19:14:25 +0900 |
parents | |
children | 803732b1fca8 |
line wrap: on
line source
//===-- AVRExpandPseudoInsts.cpp - Expand pseudo instructions -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains a pass that expands pseudo instructions into target // instructions. This pass should be run after register allocation but before // the post-regalloc scheduling pass. // //===----------------------------------------------------------------------===// #include "AVR.h" #include "AVRInstrInfo.h" #include "AVRTargetMachine.h" #include "MCTargetDesc/AVRMCTargetDesc.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; namespace { /// Expands "placeholder" instructions marked as pseudo into /// actual AVR instructions. class AVRExpandPseudo : public MachineFunctionPass { public: static char ID; AVRExpandPseudo() : MachineFunctionPass(ID) {} bool runOnMachineFunction(MachineFunction &MF) override; StringRef getPassName() const override { return "AVR pseudo instruction expansion pass"; } private: typedef MachineBasicBlock Block; typedef Block::iterator BlockIt; const AVRRegisterInfo *TRI; const TargetInstrInfo *TII; /// The register to be used for temporary storage. const unsigned SCRATCH_REGISTER = AVR::R0; /// The IO address of the status register. const unsigned SREG_ADDR = 0x3f; bool expandMBB(Block &MBB); bool expandMI(Block &MBB, BlockIt MBBI); template <unsigned OP> bool expand(Block &MBB, BlockIt MBBI); MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode) { return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode)); } MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode, unsigned DstReg) { return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode), DstReg); } MachineRegisterInfo &getRegInfo(Block &MBB) { return MBB.getParent()->getRegInfo(); } bool expandArith(unsigned OpLo, unsigned OpHi, Block &MBB, BlockIt MBBI); bool expandLogic(unsigned Op, Block &MBB, BlockIt MBBI); bool expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI); template<typename Func> bool expandAtomic(Block &MBB, BlockIt MBBI, Func f); template<typename Func> bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI, Func f); bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI); bool expandAtomicArithmeticOp(unsigned MemOpcode, unsigned ArithOpcode, Block &MBB, BlockIt MBBI); }; char AVRExpandPseudo::ID = 0; bool AVRExpandPseudo::expandMBB(MachineBasicBlock &MBB) { bool Modified = false; BlockIt MBBI = MBB.begin(), E = MBB.end(); while (MBBI != E) { BlockIt NMBBI = std::next(MBBI); Modified |= expandMI(MBB, MBBI); MBBI = NMBBI; } return Modified; } bool AVRExpandPseudo::runOnMachineFunction(MachineFunction &MF) { bool Modified = false; const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>(); TRI = STI.getRegisterInfo(); TII = STI.getInstrInfo(); for (Block &MBB : MF) { bool ContinueExpanding = true; unsigned ExpandCount = 0; // Continue expanding the block until all pseudos are expanded. do { assert(ExpandCount < 10 && "pseudo expand limit reached"); bool BlockModified = expandMBB(MBB); Modified |= BlockModified; ExpandCount++; ContinueExpanding = BlockModified; } while (ContinueExpanding); } return Modified; } bool AVRExpandPseudo:: expandArith(unsigned OpLo, unsigned OpHi, Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned SrcLoReg, SrcHiReg, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(2).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool DstIsKill = MI.getOperand(1).isKill(); bool SrcIsKill = MI.getOperand(2).isKill(); bool ImpIsDead = MI.getOperand(3).isDead(); TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); TRI->splitReg(DstReg, DstLoReg, DstHiReg); buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(DstIsKill)) .addReg(SrcLoReg, getKillRegState(SrcIsKill)); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(DstIsKill)) .addReg(SrcHiReg, getKillRegState(SrcIsKill)); if (ImpIsDead) MIBHI->getOperand(3).setIsDead(); // SREG is always implicitly killed MIBHI->getOperand(4).setIsKill(); MI.eraseFromParent(); return true; } bool AVRExpandPseudo:: expandLogic(unsigned Op, Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned SrcLoReg, SrcHiReg, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(2).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool DstIsKill = MI.getOperand(1).isKill(); bool SrcIsKill = MI.getOperand(2).isKill(); bool ImpIsDead = MI.getOperand(3).isDead(); TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); TRI->splitReg(DstReg, DstLoReg, DstHiReg); auto MIBLO = buildMI(MBB, MBBI, Op) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(DstIsKill)) .addReg(SrcLoReg, getKillRegState(SrcIsKill)); // SREG is always implicitly dead MIBLO->getOperand(3).setIsDead(); auto MIBHI = buildMI(MBB, MBBI, Op) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(DstIsKill)) .addReg(SrcHiReg, getKillRegState(SrcIsKill)); if (ImpIsDead) MIBHI->getOperand(3).setIsDead(); MI.eraseFromParent(); return true; } bool AVRExpandPseudo:: expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(3).isDead(); unsigned Imm = MI.getOperand(2).getImm(); unsigned Lo8 = Imm & 0xff; unsigned Hi8 = (Imm >> 8) & 0xff; TRI->splitReg(DstReg, DstLoReg, DstHiReg); auto MIBLO = buildMI(MBB, MBBI, Op) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(SrcIsKill)) .addImm(Lo8); // SREG is always implicitly dead MIBLO->getOperand(3).setIsDead(); auto MIBHI = buildMI(MBB, MBBI, Op) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(SrcIsKill)) .addImm(Hi8); if (ImpIsDead) MIBHI->getOperand(3).setIsDead(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::ADDWRdRr>(Block &MBB, BlockIt MBBI) { return expandArith(AVR::ADDRdRr, AVR::ADCRdRr, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::ADCWRdRr>(Block &MBB, BlockIt MBBI) { return expandArith(AVR::ADCRdRr, AVR::ADCRdRr, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::SUBWRdRr>(Block &MBB, BlockIt MBBI) { return expandArith(AVR::SUBRdRr, AVR::SBCRdRr, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::SUBIWRdK>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(3).isDead(); TRI->splitReg(DstReg, DstLoReg, DstHiReg); auto MIBLO = buildMI(MBB, MBBI, AVR::SUBIRdK) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(SrcIsKill)); auto MIBHI = buildMI(MBB, MBBI, AVR::SBCIRdK) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(SrcIsKill)); switch (MI.getOperand(2).getType()) { case MachineOperand::MO_GlobalAddress: { const GlobalValue *GV = MI.getOperand(2).getGlobal(); int64_t Offs = MI.getOperand(2).getOffset(); unsigned TF = MI.getOperand(2).getTargetFlags(); MIBLO.addGlobalAddress(GV, Offs, TF | AVRII::MO_NEG | AVRII::MO_LO); MIBHI.addGlobalAddress(GV, Offs, TF | AVRII::MO_NEG | AVRII::MO_HI); break; } case MachineOperand::MO_Immediate: { unsigned Imm = MI.getOperand(2).getImm(); MIBLO.addImm(Imm & 0xff); MIBHI.addImm((Imm >> 8) & 0xff); break; } default: llvm_unreachable("Unknown operand type!"); } if (ImpIsDead) MIBHI->getOperand(3).setIsDead(); // SREG is always implicitly killed MIBHI->getOperand(4).setIsKill(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::SBCWRdRr>(Block &MBB, BlockIt MBBI) { return expandArith(AVR::SBCRdRr, AVR::SBCRdRr, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::SBCIWRdK>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(3).isDead(); unsigned Imm = MI.getOperand(2).getImm(); unsigned Lo8 = Imm & 0xff; unsigned Hi8 = (Imm >> 8) & 0xff; OpLo = AVR::SBCIRdK; OpHi = AVR::SBCIRdK; TRI->splitReg(DstReg, DstLoReg, DstHiReg); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(SrcIsKill)) .addImm(Lo8); // SREG is always implicitly killed MIBLO->getOperand(4).setIsKill(); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(SrcIsKill)) .addImm(Hi8); if (ImpIsDead) MIBHI->getOperand(3).setIsDead(); // SREG is always implicitly killed MIBHI->getOperand(4).setIsKill(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::ANDWRdRr>(Block &MBB, BlockIt MBBI) { return expandLogic(AVR::ANDRdRr, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::ANDIWRdK>(Block &MBB, BlockIt MBBI) { return expandLogicImm(AVR::ANDIRdK, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::ORWRdRr>(Block &MBB, BlockIt MBBI) { return expandLogic(AVR::ORRdRr, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::ORIWRdK>(Block &MBB, BlockIt MBBI) { return expandLogicImm(AVR::ORIRdK, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::EORWRdRr>(Block &MBB, BlockIt MBBI) { return expandLogic(AVR::EORRdRr, MBB, MBBI); } template <> bool AVRExpandPseudo::expand<AVR::COMWRd>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool DstIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(2).isDead(); OpLo = AVR::COMRd; OpHi = AVR::COMRd; TRI->splitReg(DstReg, DstLoReg, DstHiReg); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(DstIsKill)); // SREG is always implicitly dead MIBLO->getOperand(2).setIsDead(); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(DstIsKill)); if (ImpIsDead) MIBHI->getOperand(2).setIsDead(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::CPWRdRr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(1).getReg(); bool DstIsKill = MI.getOperand(0).isKill(); bool SrcIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(2).isDead(); OpLo = AVR::CPRdRr; OpHi = AVR::CPCRdRr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); TRI->splitReg(DstReg, DstLoReg, DstHiReg); // Low part buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, getKillRegState(DstIsKill)) .addReg(SrcLoReg, getKillRegState(SrcIsKill)); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, getKillRegState(DstIsKill)) .addReg(SrcHiReg, getKillRegState(SrcIsKill)); if (ImpIsDead) MIBHI->getOperand(2).setIsDead(); // SREG is always implicitly killed MIBHI->getOperand(3).setIsKill(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::CPCWRdRr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(1).getReg(); bool DstIsKill = MI.getOperand(0).isKill(); bool SrcIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(2).isDead(); OpLo = AVR::CPCRdRr; OpHi = AVR::CPCRdRr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); TRI->splitReg(DstReg, DstLoReg, DstHiReg); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, getKillRegState(DstIsKill)) .addReg(SrcLoReg, getKillRegState(SrcIsKill)); // SREG is always implicitly killed MIBLO->getOperand(3).setIsKill(); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, getKillRegState(DstIsKill)) .addReg(SrcHiReg, getKillRegState(SrcIsKill)); if (ImpIsDead) MIBHI->getOperand(2).setIsDead(); // SREG is always implicitly killed MIBHI->getOperand(3).setIsKill(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::LDIWRdK>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); OpLo = AVR::LDIRdK; OpHi = AVR::LDIRdK; TRI->splitReg(DstReg, DstLoReg, DstHiReg); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)); switch (MI.getOperand(1).getType()) { case MachineOperand::MO_GlobalAddress: { const GlobalValue *GV = MI.getOperand(1).getGlobal(); int64_t Offs = MI.getOperand(1).getOffset(); unsigned TF = MI.getOperand(1).getTargetFlags(); MIBLO.addGlobalAddress(GV, Offs, TF | AVRII::MO_LO); MIBHI.addGlobalAddress(GV, Offs, TF | AVRII::MO_HI); break; } case MachineOperand::MO_BlockAddress: { const BlockAddress *BA = MI.getOperand(1).getBlockAddress(); unsigned TF = MI.getOperand(1).getTargetFlags(); MIBLO.addOperand(MachineOperand::CreateBA(BA, TF | AVRII::MO_LO)); MIBHI.addOperand(MachineOperand::CreateBA(BA, TF | AVRII::MO_HI)); break; } case MachineOperand::MO_Immediate: { unsigned Imm = MI.getOperand(1).getImm(); MIBLO.addImm(Imm & 0xff); MIBHI.addImm((Imm >> 8) & 0xff); break; } default: llvm_unreachable("Unknown operand type!"); } MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::LDSWRdK>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); OpLo = AVR::LDSRdK; OpHi = AVR::LDSRdK; TRI->splitReg(DstReg, DstLoReg, DstHiReg); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)); switch (MI.getOperand(1).getType()) { case MachineOperand::MO_GlobalAddress: { const GlobalValue *GV = MI.getOperand(1).getGlobal(); int64_t Offs = MI.getOperand(1).getOffset(); unsigned TF = MI.getOperand(1).getTargetFlags(); MIBLO.addGlobalAddress(GV, Offs, TF); MIBHI.addGlobalAddress(GV, Offs + 1, TF); break; } case MachineOperand::MO_Immediate: { unsigned Imm = MI.getOperand(1).getImm(); MIBLO.addImm(Imm); MIBHI.addImm(Imm + 1); break; } default: llvm_unreachable("Unknown operand type!"); } MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); 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"); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg, getKillRegState(SrcIsKill)) .addImm(1); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::LDWRdPtrPi>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(1).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsDead = MI.getOperand(1).isKill(); OpLo = AVR::LDRdPtrPi; OpHi = AVR::LDRdPtrPi; TRI->splitReg(DstReg, DstLoReg, DstHiReg); assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same"); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg, RegState::Define) .addReg(SrcReg, RegState::Kill); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg, RegState::Define | getDeadRegState(SrcIsDead)) .addReg(SrcReg, RegState::Kill); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::LDWRdPtrPd>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(1).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsDead = MI.getOperand(1).isKill(); OpLo = AVR::LDRdPtrPd; OpHi = AVR::LDRdPtrPd; TRI->splitReg(DstReg, DstLoReg, DstHiReg); assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same"); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg, RegState::Define) .addReg(SrcReg, RegState::Kill); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg, RegState::Define | getDeadRegState(SrcIsDead)) .addReg(SrcReg, RegState::Kill); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); 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; TRI->splitReg(DstReg, DstLoReg, DstHiReg); assert(Imm < 63 && "Offset is out of range"); assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same"); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg) .addImm(Imm); auto 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()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template<typename Func> bool AVRExpandPseudo::expandAtomic(Block &MBB, BlockIt MBBI, Func f) { // Remove the pseudo instruction. MachineInstr &MI = *MBBI; // Store the SREG. buildMI(MBB, MBBI, AVR::INRdA) .addReg(SCRATCH_REGISTER, RegState::Define) .addImm(SREG_ADDR); // Disable exceptions. buildMI(MBB, MBBI, AVR::BCLRs).addImm(7); // CLI f(MI); // Restore the status reg. buildMI(MBB, MBBI, AVR::OUTARr) .addImm(SREG_ADDR) .addReg(SCRATCH_REGISTER); MI.eraseFromParent(); return true; } template<typename Func> bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI, Func f) { return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) { auto Op1 = MI.getOperand(0); auto Op2 = MI.getOperand(1); MachineInstr &NewInst = *buildMI(MBB, MBBI, Opcode) .addOperand(Op1).addOperand(Op2) .getInstr(); f(NewInst); }); } bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI) { return expandAtomicBinaryOp(Opcode, MBB, MBBI, [](MachineInstr &MI) {}); } bool AVRExpandPseudo::expandAtomicArithmeticOp(unsigned Width, unsigned ArithOpcode, Block &MBB, BlockIt MBBI) { return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) { auto Op1 = MI.getOperand(0); auto Op2 = MI.getOperand(1); unsigned LoadOpcode = (Width == 8) ? AVR::LDRdPtr : AVR::LDWRdPtr; unsigned StoreOpcode = (Width == 8) ? AVR::STPtrRr : AVR::STWPtrRr; // Create the load buildMI(MBB, MBBI, LoadOpcode).addOperand(Op1).addOperand(Op2); // Create the arithmetic op buildMI(MBB, MBBI, ArithOpcode) .addOperand(Op1).addOperand(Op1) .addOperand(Op2); // Create the store buildMI(MBB, MBBI, StoreOpcode).addOperand(Op2).addOperand(Op1); }); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoad8>(Block &MBB, BlockIt MBBI) { return expandAtomicBinaryOp(AVR::LDRdPtr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoad16>(Block &MBB, BlockIt MBBI) { return expandAtomicBinaryOp(AVR::LDWRdPtr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicStore8>(Block &MBB, BlockIt MBBI) { return expandAtomicBinaryOp(AVR::STPtrRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicStore16>(Block &MBB, BlockIt MBBI) { return expandAtomicBinaryOp(AVR::STWPtrRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd8>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(8, AVR::ADDRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd16>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(16, AVR::ADDWRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadSub8>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(8, AVR::SUBRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadSub16>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(16, AVR::SUBWRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd8>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(8, AVR::ANDRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd16>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(16, AVR::ANDWRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadOr8>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(8, AVR::ORRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadOr16>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(16, AVR::ORWRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadXor8>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(8, AVR::EORRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicLoadXor16>(Block &MBB, BlockIt MBBI) { return expandAtomicArithmeticOp(16, AVR::EORWRdRr, MBB, MBBI); } template<> bool AVRExpandPseudo::expand<AVR::AtomicFence>(Block &MBB, BlockIt MBBI) { // On AVR, there is only one core and so atomic fences do nothing. MBBI->eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::STSWKRr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg; unsigned SrcReg = MI.getOperand(1).getReg(); bool SrcIsKill = MI.getOperand(1).isKill(); OpLo = AVR::STSKRr; OpHi = AVR::STSKRr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); // Write the high byte first in case this address belongs to a special // I/O address with a special temporary register. auto MIBHI = buildMI(MBB, MBBI, OpHi); auto MIBLO = buildMI(MBB, MBBI, OpLo); switch (MI.getOperand(0).getType()) { case MachineOperand::MO_GlobalAddress: { const GlobalValue *GV = MI.getOperand(0).getGlobal(); int64_t Offs = MI.getOperand(0).getOffset(); unsigned TF = MI.getOperand(0).getTargetFlags(); MIBLO.addGlobalAddress(GV, Offs, TF); MIBHI.addGlobalAddress(GV, Offs + 1, TF); break; } case MachineOperand::MO_Immediate: { unsigned Imm = MI.getOperand(0).getImm(); MIBLO.addImm(Imm); MIBHI.addImm(Imm + 1); break; } default: llvm_unreachable("Unknown operand type!"); } MIBLO.addReg(SrcLoReg, getKillRegState(SrcIsKill)); MIBHI.addReg(SrcHiReg, getKillRegState(SrcIsKill)); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::STWPtrRr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(1).getReg(); bool DstIsKill = MI.getOperand(0).isKill(); bool SrcIsKill = MI.getOperand(1).isKill(); OpLo = AVR::STPtrRr; OpHi = AVR::STDPtrQRr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); //:TODO: need to reverse this order like inw and stsw? auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstReg) .addReg(SrcLoReg, getKillRegState(SrcIsKill)); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstReg, getKillRegState(DstIsKill)) .addImm(1) .addReg(SrcHiReg, getKillRegState(SrcIsKill)); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::STWPtrPiRr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(2).getReg(); unsigned Imm = MI.getOperand(3).getImm(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(2).isKill(); OpLo = AVR::STPtrPiRr; OpHi = AVR::STPtrPiRr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same"); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstReg, RegState::Define) .addReg(DstReg, RegState::Kill) .addReg(SrcLoReg, getKillRegState(SrcIsKill)) .addImm(Imm); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstReg, RegState::Kill) .addReg(SrcHiReg, getKillRegState(SrcIsKill)) .addImm(Imm); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::STWPtrPdRr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(2).getReg(); unsigned Imm = MI.getOperand(3).getImm(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(2).isKill(); OpLo = AVR::STPtrPdRr; OpHi = AVR::STPtrPdRr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same"); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstReg, RegState::Define) .addReg(DstReg, RegState::Kill) .addReg(SrcHiReg, getKillRegState(SrcIsKill)) .addImm(Imm); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstReg, RegState::Kill) .addReg(SrcLoReg, getKillRegState(SrcIsKill)) .addImm(Imm); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(2).getReg(); unsigned Imm = MI.getOperand(1).getImm(); bool DstIsKill = MI.getOperand(0).isKill(); bool SrcIsKill = MI.getOperand(2).isKill(); OpLo = AVR::STDPtrQRr; OpHi = AVR::STDPtrQRr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); assert(Imm < 63 && "Offset is out of range"); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstReg) .addImm(Imm) .addReg(SrcLoReg, getKillRegState(SrcIsKill)); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstReg, getKillRegState(DstIsKill)) .addImm(Imm + 1) .addReg(SrcHiReg, getKillRegState(SrcIsKill)); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned Imm = MI.getOperand(1).getImm(); unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); OpLo = AVR::INRdA; OpHi = AVR::INRdA; TRI->splitReg(DstReg, DstLoReg, DstHiReg); assert(Imm < 63 && "Address is out of range"); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addImm(Imm); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addImm(Imm + 1); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::OUTWARr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg; unsigned Imm = MI.getOperand(0).getImm(); unsigned SrcReg = MI.getOperand(1).getReg(); bool SrcIsKill = MI.getOperand(1).isKill(); OpLo = AVR::OUTARr; OpHi = AVR::OUTARr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); assert(Imm < 63 && "Address is out of range"); // 16 bit I/O writes need the high byte first auto MIBHI = buildMI(MBB, MBBI, OpHi) .addImm(Imm + 1) .addReg(SrcHiReg, getKillRegState(SrcIsKill)); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addImm(Imm) .addReg(SrcLoReg, getKillRegState(SrcIsKill)); MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::PUSHWRr>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, SrcLoReg, SrcHiReg; unsigned SrcReg = MI.getOperand(0).getReg(); bool SrcIsKill = MI.getOperand(0).isKill(); unsigned Flags = MI.getFlags(); OpLo = AVR::PUSHRr; OpHi = AVR::PUSHRr; TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); // Low part buildMI(MBB, MBBI, OpLo) .addReg(SrcLoReg, getKillRegState(SrcIsKill)) .setMIFlags(Flags); // High part buildMI(MBB, MBBI, OpHi) .addReg(SrcHiReg, getKillRegState(SrcIsKill)) .setMIFlags(Flags); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::POPWRd>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); unsigned Flags = MI.getFlags(); OpLo = AVR::POPRd; OpHi = AVR::POPRd; TRI->splitReg(DstReg, DstLoReg, DstHiReg); buildMI(MBB, MBBI, OpHi, DstHiReg).setMIFlags(Flags); // High buildMI(MBB, MBBI, OpLo, DstLoReg).setMIFlags(Flags); // Low MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool DstIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(2).isDead(); OpLo = AVR::LSLRd; OpHi = AVR::ROLRd; TRI->splitReg(DstReg, DstLoReg, DstHiReg); // Low part buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(DstIsKill)); auto MIBHI = buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(DstIsKill)); if (ImpIsDead) MIBHI->getOperand(2).setIsDead(); // SREG is always implicitly killed MIBHI->getOperand(3).setIsKill(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool DstIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(2).isDead(); OpLo = AVR::RORRd; OpHi = AVR::LSRRd; TRI->splitReg(DstReg, DstLoReg, DstHiReg); // High part buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(DstIsKill)); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(DstIsKill)); if (ImpIsDead) MIBLO->getOperand(2).setIsDead(); // SREG is always implicitly killed MIBLO->getOperand(3).setIsKill(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::RORWRd>(Block &MBB, BlockIt MBBI) { llvm_unreachable("RORW unimplemented"); return false; } template <> bool AVRExpandPseudo::expand<AVR::ROLWRd>(Block &MBB, BlockIt MBBI) { llvm_unreachable("ROLW unimplemented"); return false; } template <> bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool DstIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(2).isDead(); OpLo = AVR::RORRd; OpHi = AVR::ASRRd; TRI->splitReg(DstReg, DstLoReg, DstHiReg); // High part buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, getKillRegState(DstIsKill)); auto MIBLO = buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstLoReg, getKillRegState(DstIsKill)); if (ImpIsDead) MIBLO->getOperand(2).setIsDead(); // SREG is always implicitly killed MIBLO->getOperand(3).setIsKill(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::SEXT>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned DstLoReg, DstHiReg; // sext R17:R16, R17 // mov r16, r17 // lsl r17 // sbc r17, r17 // sext R17:R16, R13 // mov r16, r13 // mov r17, r13 // lsl r17 // sbc r17, r17 // sext R17:R16, R16 // mov r17, r16 // lsl r17 // sbc r17, r17 unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(1).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(2).isDead(); TRI->splitReg(DstReg, DstLoReg, DstHiReg); if (SrcReg != DstLoReg) { auto MOV = buildMI(MBB, MBBI, AVR::MOVRdRr) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg); if (SrcReg == DstHiReg) { MOV->getOperand(1).setIsKill(); } } if (SrcReg != DstHiReg) { buildMI(MBB, MBBI, AVR::MOVRdRr) .addReg(DstHiReg, RegState::Define) .addReg(SrcReg, getKillRegState(SrcIsKill)); } buildMI(MBB, MBBI, AVR::LSLRd) .addReg(DstHiReg, RegState::Define) .addReg(DstHiReg, RegState::Kill); auto SBC = buildMI(MBB, MBBI, AVR::SBCRdRr) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, RegState::Kill) .addReg(DstHiReg, RegState::Kill); if (ImpIsDead) SBC->getOperand(3).setIsDead(); // SREG is always implicitly killed SBC->getOperand(4).setIsKill(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::ZEXT>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned DstLoReg, DstHiReg; // zext R25:R24, R20 // mov R24, R20 // eor R25, R25 // zext R25:R24, R24 // eor R25, R25 // zext R25:R24, R25 // mov R24, R25 // eor R25, R25 unsigned DstReg = MI.getOperand(0).getReg(); unsigned SrcReg = MI.getOperand(1).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); bool SrcIsKill = MI.getOperand(1).isKill(); bool ImpIsDead = MI.getOperand(2).isDead(); TRI->splitReg(DstReg, DstLoReg, DstHiReg); if (SrcReg != DstLoReg) { buildMI(MBB, MBBI, AVR::MOVRdRr) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(SrcReg, getKillRegState(SrcIsKill)); } auto EOR = buildMI(MBB, MBBI, AVR::EORRdRr) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstHiReg, RegState::Kill) .addReg(DstHiReg, RegState::Kill); if (ImpIsDead) EOR->getOperand(3).setIsDead(); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::SPREAD>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned OpLo, OpHi, DstLoReg, DstHiReg; unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); unsigned Flags = MI.getFlags(); OpLo = AVR::INRdA; OpHi = AVR::INRdA; TRI->splitReg(DstReg, DstLoReg, DstHiReg); // Low part buildMI(MBB, MBBI, OpLo) .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) .addImm(0x3d) .setMIFlags(Flags); // High part buildMI(MBB, MBBI, OpHi) .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) .addImm(0x3e) .setMIFlags(Flags); MI.eraseFromParent(); return true; } template <> bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; unsigned SrcLoReg, SrcHiReg; unsigned SrcReg = MI.getOperand(1).getReg(); bool SrcIsKill = MI.getOperand(1).isKill(); unsigned Flags = MI.getFlags(); TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg); buildMI(MBB, MBBI, AVR::INRdA) .addReg(AVR::R0, RegState::Define) .addImm(SREG_ADDR) .setMIFlags(Flags); buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags); buildMI(MBB, MBBI, AVR::OUTARr) .addImm(0x3e) .addReg(SrcHiReg, getKillRegState(SrcIsKill)) .setMIFlags(Flags); buildMI(MBB, MBBI, AVR::OUTARr) .addImm(SREG_ADDR) .addReg(AVR::R0, RegState::Kill) .setMIFlags(Flags); buildMI(MBB, MBBI, AVR::OUTARr) .addImm(0x3d) .addReg(SrcLoReg, getKillRegState(SrcIsKill)) .setMIFlags(Flags); MI.eraseFromParent(); return true; } bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; int Opcode = MBBI->getOpcode(); #define EXPAND(Op) \ case Op: \ return expand<Op>(MBB, MI) switch (Opcode) { EXPAND(AVR::ADDWRdRr); EXPAND(AVR::ADCWRdRr); EXPAND(AVR::SUBWRdRr); EXPAND(AVR::SUBIWRdK); EXPAND(AVR::SBCWRdRr); EXPAND(AVR::SBCIWRdK); EXPAND(AVR::ANDWRdRr); EXPAND(AVR::ANDIWRdK); EXPAND(AVR::ORWRdRr); EXPAND(AVR::ORIWRdK); EXPAND(AVR::EORWRdRr); EXPAND(AVR::COMWRd); EXPAND(AVR::CPWRdRr); EXPAND(AVR::CPCWRdRr); EXPAND(AVR::LDIWRdK); EXPAND(AVR::LDSWRdK); EXPAND(AVR::LDWRdPtr); EXPAND(AVR::LDWRdPtrPi); EXPAND(AVR::LDWRdPtrPd); case AVR::LDDWRdYQ: //:FIXME: remove this once PR13375 gets fixed EXPAND(AVR::LDDWRdPtrQ); EXPAND(AVR::AtomicLoad8); EXPAND(AVR::AtomicLoad16); EXPAND(AVR::AtomicStore8); EXPAND(AVR::AtomicStore16); EXPAND(AVR::AtomicLoadAdd8); EXPAND(AVR::AtomicLoadAdd16); EXPAND(AVR::AtomicLoadSub8); EXPAND(AVR::AtomicLoadSub16); EXPAND(AVR::AtomicLoadAnd8); EXPAND(AVR::AtomicLoadAnd16); EXPAND(AVR::AtomicLoadOr8); EXPAND(AVR::AtomicLoadOr16); EXPAND(AVR::AtomicLoadXor8); EXPAND(AVR::AtomicLoadXor16); EXPAND(AVR::AtomicFence); EXPAND(AVR::STSWKRr); EXPAND(AVR::STWPtrRr); EXPAND(AVR::STWPtrPiRr); EXPAND(AVR::STWPtrPdRr); EXPAND(AVR::STDWPtrQRr); EXPAND(AVR::INWRdA); EXPAND(AVR::OUTWARr); EXPAND(AVR::PUSHWRr); EXPAND(AVR::POPWRd); EXPAND(AVR::LSLWRd); EXPAND(AVR::LSRWRd); EXPAND(AVR::RORWRd); EXPAND(AVR::ROLWRd); EXPAND(AVR::ASRWRd); EXPAND(AVR::SEXT); EXPAND(AVR::ZEXT); EXPAND(AVR::SPREAD); EXPAND(AVR::SPWRITE); } #undef EXPAND return false; } } // end of anonymous namespace namespace llvm { FunctionPass *createAVRExpandPseudoPass() { return new AVRExpandPseudo(); } } // end of namespace llvm