|  | //===-- 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; | 
|  |  | 
|  | #define AVR_EXPAND_PSEUDO_NAME "AVR pseudo instruction expansion pass" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | /// Expands "placeholder" instructions marked as pseudo into | 
|  | /// actual AVR instructions. | 
|  | class AVRExpandPseudo : public MachineFunctionPass { | 
|  | public: | 
|  | static char ID; | 
|  |  | 
|  | AVRExpandPseudo() : MachineFunctionPass(ID) { | 
|  | initializeAVRExpandPseudoPass(*PassRegistry::getPassRegistry()); | 
|  | } | 
|  |  | 
|  | bool runOnMachineFunction(MachineFunction &MF) override; | 
|  |  | 
|  | StringRef getPassName() const override { return AVR_EXPAND_PSEUDO_NAME; } | 
|  |  | 
|  | 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"); | 
|  |  | 
|  | unsigned TmpLoReg = DstLoReg; | 
|  | unsigned TmpHiReg = DstHiReg; | 
|  |  | 
|  | // 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) { | 
|  | TmpLoReg = SCRATCH_REGISTER; | 
|  | TmpHiReg = SCRATCH_REGISTER; | 
|  | } | 
|  |  | 
|  | auto MIBLO = buildMI(MBB, MBBI, OpLo) | 
|  | .addReg(TmpLoReg, RegState::Define | getDeadRegState(DstIsDead)) | 
|  | .addReg(SrcReg) | 
|  | .addImm(Imm); | 
|  |  | 
|  | // Push the low part of the temporary register to the stack. | 
|  | if (TmpLoReg != DstLoReg) | 
|  | buildMI(MBB, MBBI, AVR::PUSHRr) | 
|  | .addReg(AVR::R0); | 
|  |  | 
|  | auto MIBHI = buildMI(MBB, MBBI, OpHi) | 
|  | .addReg(TmpHiReg, RegState::Define | getDeadRegState(DstIsDead)) | 
|  | .addReg(SrcReg, getKillRegState(SrcIsKill)) | 
|  | .addImm(Imm + 1); | 
|  |  | 
|  | // 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); | 
|  |  | 
|  | // Pop the lo result calculated previously and put it into | 
|  | // the lo destination. | 
|  | buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg); | 
|  | } | 
|  |  | 
|  | 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::LPMWRdZ>(Block &MBB, BlockIt MBBI) { | 
|  | llvm_unreachable("wide LPM is unimplemented"); | 
|  | } | 
|  |  | 
|  | template <> | 
|  | bool AVRExpandPseudo::expand<AVR::LPMWRdZPi>(Block &MBB, BlockIt MBBI) { | 
|  | llvm_unreachable("wide LPMPi is unimplemented"); | 
|  | } | 
|  |  | 
|  | 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::LPMWRdZ); | 
|  | EXPAND(AVR::LPMWRdZPi); | 
|  | 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 | 
|  |  | 
|  | INITIALIZE_PASS(AVRExpandPseudo, "avr-expand-pseudo", | 
|  | AVR_EXPAND_PSEUDO_NAME, false, false) | 
|  | namespace llvm { | 
|  |  | 
|  | FunctionPass *createAVRExpandPseudoPass() { return new AVRExpandPseudo(); } | 
|  |  | 
|  | } // end of namespace llvm |