1718 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1718 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- AVRExpandPseudoInsts.cpp - Expand pseudo instructions -------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // 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/CodeGen/RegisterScavenging.h"
 | |
| #include "llvm/CodeGen/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 Register SCRATCH_REGISTER = AVR::R0;
 | |
|   /// The register that will always contain zero.
 | |
|   const Register ZERO_REGISTER = AVR::R1;
 | |
|   /// 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,
 | |
|                               Register 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);
 | |
|   bool isLogicImmOpRedundant(unsigned Op, unsigned ImmVal) const;
 | |
| 
 | |
|   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);
 | |
| 
 | |
|   /// Scavenges a free GPR8 register for use.
 | |
|   Register scavengeGPR8(MachineInstr &MI);
 | |
| };
 | |
| 
 | |
| 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();
 | |
| 
 | |
|   // We need to track liveness in order to use register scavenging.
 | |
|   MF.getProperties().set(MachineFunctionProperties::Property::TracksLiveness);
 | |
| 
 | |
|   for (Block &MBB : MF) {
 | |
|     bool ContinueExpanding = true;
 | |
|     unsigned ExpandCount = 0;
 | |
| 
 | |
|     // 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;
 | |
|   Register SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register 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;
 | |
|   Register SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register 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::
 | |
|   isLogicImmOpRedundant(unsigned Op, unsigned ImmVal) const {
 | |
| 
 | |
|   // ANDI Rd, 0xff is redundant.
 | |
|   if (Op == AVR::ANDIRdK && ImmVal == 0xff)
 | |
|     return true;
 | |
| 
 | |
|   // ORI Rd, 0x0 is redundant.
 | |
|   if (Op == AVR::ORIRdK && ImmVal == 0x0)
 | |
|     return true;
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool AVRExpandPseudo::
 | |
| expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register 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);
 | |
| 
 | |
|   if (!isLogicImmOpRedundant(Op, Lo8)) {
 | |
|     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();
 | |
|   }
 | |
| 
 | |
|   if (!isLogicImmOpRedundant(Op, Hi8)) {
 | |
|     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;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register 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;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register 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;
 | |
|   unsigned OpLo = AVR::SBCIRdK;
 | |
|   unsigned 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;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool DstIsKill = MI.getOperand(1).isKill();
 | |
|   bool ImpIsDead = MI.getOperand(2).isDead();
 | |
|   unsigned OpLo = AVR::COMRd;
 | |
|   unsigned 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::NEGWRd>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool DstIsKill = MI.getOperand(1).isKill();
 | |
|   bool ImpIsDead = MI.getOperand(2).isDead();
 | |
|   TRI->splitReg(DstReg, DstLoReg, DstHiReg);
 | |
| 
 | |
|   // Do NEG on the upper byte.
 | |
|   auto MIBHI =
 | |
|       buildMI(MBB, MBBI, AVR::NEGRd)
 | |
|           .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|           .addReg(DstHiReg, getKillRegState(DstIsKill));
 | |
|   // SREG is always implicitly dead
 | |
|   MIBHI->getOperand(2).setIsDead();
 | |
| 
 | |
|   // Do NEG on the lower byte.
 | |
|   buildMI(MBB, MBBI, AVR::NEGRd)
 | |
|       .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|       .addReg(DstLoReg, getKillRegState(DstIsKill));
 | |
| 
 | |
|   // Do an extra SBCI.
 | |
|   auto MISBCI =
 | |
|       buildMI(MBB, MBBI, AVR::SBCIRdK)
 | |
|           .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|           .addReg(DstHiReg, getKillRegState(DstIsKill))
 | |
|           .addImm(0);
 | |
|   if (ImpIsDead)
 | |
|     MISBCI->getOperand(3).setIsDead();
 | |
|   // SREG is always implicitly killed
 | |
|   MISBCI->getOperand(4).setIsKill();
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::CPWRdRr>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool DstIsKill = MI.getOperand(0).isKill();
 | |
|   bool SrcIsKill = MI.getOperand(1).isKill();
 | |
|   bool ImpIsDead = MI.getOperand(2).isDead();
 | |
|   unsigned OpLo = AVR::CPRdRr;
 | |
|   unsigned 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;
 | |
|   Register SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool DstIsKill = MI.getOperand(0).isKill();
 | |
|   bool SrcIsKill = MI.getOperand(1).isKill();
 | |
|   bool ImpIsDead = MI.getOperand(2).isDead();
 | |
|   unsigned OpLo = AVR::CPCRdRr;
 | |
|   unsigned 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;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   unsigned OpLo = AVR::LDIRdK;
 | |
|   unsigned 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.add(MachineOperand::CreateBA(BA, TF | AVRII::MO_LO));
 | |
|     MIBHI.add(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;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   unsigned OpLo = AVR::LDSRdK;
 | |
|   unsigned 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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register TmpReg = 0; // 0 for no temporary register
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool SrcIsKill = MI.getOperand(1).isKill();
 | |
|   unsigned OpLo = AVR::LDRdPtr;
 | |
|   unsigned OpHi = AVR::LDDRdPtrQ;
 | |
|   TRI->splitReg(DstReg, DstLoReg, DstHiReg);
 | |
| 
 | |
|   // Use a temporary register if src and dst registers are the same.
 | |
|   if (DstReg == SrcReg)
 | |
|     TmpReg = scavengeGPR8(MI);
 | |
| 
 | |
|   Register CurDstLoReg = (DstReg == SrcReg) ? TmpReg : DstLoReg;
 | |
|   Register CurDstHiReg = (DstReg == SrcReg) ? TmpReg : DstHiReg;
 | |
| 
 | |
|   // Load low byte.
 | |
|   auto MIBLO = buildMI(MBB, MBBI, OpLo)
 | |
|                    .addReg(CurDstLoReg, RegState::Define)
 | |
|                    .addReg(SrcReg);
 | |
| 
 | |
|   // Push low byte onto stack if necessary.
 | |
|   if (TmpReg)
 | |
|     buildMI(MBB, MBBI, AVR::PUSHRr).addReg(TmpReg);
 | |
| 
 | |
|   // Load high byte.
 | |
|   auto MIBHI = buildMI(MBB, MBBI, OpHi)
 | |
|     .addReg(CurDstHiReg, RegState::Define)
 | |
|     .addReg(SrcReg, getKillRegState(SrcIsKill))
 | |
|     .addImm(1);
 | |
| 
 | |
|   if (TmpReg) {
 | |
|     // Move the high byte into the final destination.
 | |
|     buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
 | |
| 
 | |
|     // Move the low byte from the scratch space into the final destination.
 | |
|     buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
 | |
|   }
 | |
| 
 | |
|   MIBLO.setMemRefs(MI.memoperands());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::LDWRdPtrPi>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool SrcIsDead = MI.getOperand(1).isKill();
 | |
|   unsigned OpLo = AVR::LDRdPtrPi;
 | |
|   unsigned 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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::LDWRdPtrPd>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool SrcIsDead = MI.getOperand(1).isKill();
 | |
|   unsigned OpLo = AVR::LDRdPtrPd;
 | |
|   unsigned 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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register TmpReg = 0; // 0 for no temporary register
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   unsigned Imm = MI.getOperand(2).getImm();
 | |
|   bool SrcIsKill = MI.getOperand(1).isKill();
 | |
|   unsigned OpLo = AVR::LDDRdPtrQ;
 | |
|   unsigned OpHi = AVR::LDDRdPtrQ;
 | |
|   TRI->splitReg(DstReg, DstLoReg, DstHiReg);
 | |
| 
 | |
|   // Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
 | |
|   // allowed for the instruction, 62 is the limit here.
 | |
|   assert(Imm <= 62 && "Offset is out of range");
 | |
| 
 | |
|   // Use a temporary register if src and dst registers are the same.
 | |
|   if (DstReg == SrcReg)
 | |
|     TmpReg = scavengeGPR8(MI);
 | |
| 
 | |
|   Register CurDstLoReg = (DstReg == SrcReg) ? TmpReg : DstLoReg;
 | |
|   Register CurDstHiReg = (DstReg == SrcReg) ? TmpReg : DstHiReg;
 | |
| 
 | |
|   // Load low byte.
 | |
|   auto MIBLO = buildMI(MBB, MBBI, OpLo)
 | |
|     .addReg(CurDstLoReg, RegState::Define)
 | |
|     .addReg(SrcReg)
 | |
|     .addImm(Imm);
 | |
| 
 | |
|   // Push low byte onto stack if necessary.
 | |
|   if (TmpReg)
 | |
|     buildMI(MBB, MBBI, AVR::PUSHRr).addReg(TmpReg);
 | |
| 
 | |
|   // Load high byte.
 | |
|   auto MIBHI = buildMI(MBB, MBBI, OpHi)
 | |
|     .addReg(CurDstHiReg, RegState::Define)
 | |
|     .addReg(SrcReg, getKillRegState(SrcIsKill))
 | |
|     .addImm(Imm + 1);
 | |
| 
 | |
|   if (TmpReg) {
 | |
|     // Move the high byte into the final destination.
 | |
|     buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
 | |
| 
 | |
|     // Move the low byte from the scratch space into the final destination.
 | |
|     buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
 | |
|   }
 | |
| 
 | |
|   MIBLO.setMemRefs(MI.memoperands());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::LPMWRdZ>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register TmpReg = 0; // 0 for no temporary register
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool SrcIsKill = MI.getOperand(1).isKill();
 | |
|   unsigned OpLo = AVR::LPMRdZPi;
 | |
|   unsigned OpHi = AVR::LPMRdZ;
 | |
|   TRI->splitReg(DstReg, DstLoReg, DstHiReg);
 | |
| 
 | |
|   // Use a temporary register if src and dst registers are the same.
 | |
|   if (DstReg == SrcReg)
 | |
|     TmpReg = scavengeGPR8(MI);
 | |
| 
 | |
|   Register CurDstLoReg = (DstReg == SrcReg) ? TmpReg : DstLoReg;
 | |
|   Register CurDstHiReg = (DstReg == SrcReg) ? TmpReg : DstHiReg;
 | |
| 
 | |
|   // Load low byte.
 | |
|   auto MIBLO = buildMI(MBB, MBBI, OpLo)
 | |
|       .addReg(CurDstLoReg, RegState::Define)
 | |
|       .addReg(SrcReg);
 | |
| 
 | |
|   // Push low byte onto stack if necessary.
 | |
|   if (TmpReg)
 | |
|     buildMI(MBB, MBBI, AVR::PUSHRr).addReg(TmpReg);
 | |
| 
 | |
|   // Load high byte.
 | |
|   auto MIBHI = buildMI(MBB, MBBI, OpHi)
 | |
|       .addReg(CurDstHiReg, RegState::Define)
 | |
|       .addReg(SrcReg, getKillRegState(SrcIsKill));
 | |
| 
 | |
|   if (TmpReg) {
 | |
|     // Move the high byte into the final destination.
 | |
|     buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
 | |
| 
 | |
|     // Move the low byte from the scratch space into the final destination.
 | |
|     buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
 | |
|   }
 | |
| 
 | |
|   MIBLO.setMemRefs(MI.memoperands());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 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).add(Op1).add(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).add(Op1).add(Op2);
 | |
| 
 | |
|       // Create the arithmetic op
 | |
|       buildMI(MBB, MBBI, ArithOpcode).add(Op1).add(Op1).add(Op2);
 | |
| 
 | |
|       // Create the store
 | |
|       buildMI(MBB, MBBI, StoreOpcode).add(Op2).add(Op1);
 | |
|   });
 | |
| }
 | |
| 
 | |
| Register AVRExpandPseudo::scavengeGPR8(MachineInstr &MI) {
 | |
|   MachineBasicBlock &MBB = *MI.getParent();
 | |
|   RegScavenger RS;
 | |
| 
 | |
|   RS.enterBasicBlock(MBB);
 | |
|   RS.forward(MI);
 | |
| 
 | |
|   BitVector Candidates =
 | |
|       TRI->getAllocatableSet
 | |
|       (*MBB.getParent(), &AVR::GPR8RegClass);
 | |
| 
 | |
|   // Exclude all the registers being used by the instruction.
 | |
|   for (MachineOperand &MO : MI.operands()) {
 | |
|     if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() &&
 | |
|         !Register::isVirtualRegister(MO.getReg()))
 | |
|       Candidates.reset(MO.getReg());
 | |
|   }
 | |
| 
 | |
|   BitVector Available = RS.getRegsAvailable(&AVR::GPR8RegClass);
 | |
|   Available &= Candidates;
 | |
| 
 | |
|   signed Reg = Available.find_first();
 | |
|   assert(Reg != -1 && "ran out of registers");
 | |
|   return Reg;
 | |
| }
 | |
| 
 | |
| 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;
 | |
|   Register SrcLoReg, SrcHiReg;
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool SrcIsKill = MI.getOperand(1).isKill();
 | |
|   unsigned OpLo = AVR::STSKRr;
 | |
|   unsigned 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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::STWPtrRr>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register SrcLoReg, SrcHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool SrcIsKill = MI.getOperand(1).isKill();
 | |
|   unsigned OpLo = AVR::STPtrRr;
 | |
|   unsigned 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)
 | |
|     .addImm(1)
 | |
|     .addReg(SrcHiReg, getKillRegState(SrcIsKill));
 | |
| 
 | |
|   MIBLO.setMemRefs(MI.memoperands());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::STWPtrPiRr>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register SrcLoReg, SrcHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register SrcReg = MI.getOperand(2).getReg();
 | |
|   unsigned Imm = MI.getOperand(3).getImm();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool SrcIsKill = MI.getOperand(2).isKill();
 | |
|   unsigned OpLo = AVR::STPtrPiRr;
 | |
|   unsigned 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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::STWPtrPdRr>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register SrcLoReg, SrcHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register SrcReg = MI.getOperand(2).getReg();
 | |
|   unsigned Imm = MI.getOperand(3).getImm();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool SrcIsKill = MI.getOperand(2).isKill();
 | |
|   unsigned OpLo = AVR::STPtrPdRr;
 | |
|   unsigned 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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register SrcLoReg, SrcHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register SrcReg = MI.getOperand(2).getReg();
 | |
|   unsigned Imm = MI.getOperand(1).getImm();
 | |
|   bool DstIsKill = MI.getOperand(0).isKill();
 | |
|   bool SrcIsKill = MI.getOperand(2).isKill();
 | |
|   unsigned OpLo = AVR::STDPtrQRr;
 | |
|   unsigned OpHi = AVR::STDPtrQRr;
 | |
|   TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
 | |
| 
 | |
|   // Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
 | |
|   // allowed for the instruction, 62 is the limit here.
 | |
|   assert(Imm <= 62 && "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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   unsigned Imm = MI.getOperand(1).getImm();
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   unsigned OpLo = AVR::INRdA;
 | |
|   unsigned OpHi = AVR::INRdA;
 | |
|   TRI->splitReg(DstReg, DstLoReg, DstHiReg);
 | |
| 
 | |
|   // Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
 | |
|   // allowed for the instruction, 62 is the limit here.
 | |
|   assert(Imm <= 62 && "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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::OUTWARr>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register SrcLoReg, SrcHiReg;
 | |
|   unsigned Imm = MI.getOperand(0).getImm();
 | |
|   Register SrcReg = MI.getOperand(1).getReg();
 | |
|   bool SrcIsKill = MI.getOperand(1).isKill();
 | |
|   unsigned OpLo = AVR::OUTARr;
 | |
|   unsigned OpHi = AVR::OUTARr;
 | |
|   TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
 | |
| 
 | |
|   // Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
 | |
|   // allowed for the instruction, 62 is the limit here.
 | |
|   assert(Imm <= 62 && "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());
 | |
|   MIBHI.setMemRefs(MI.memoperands());
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::PUSHWRr>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register SrcLoReg, SrcHiReg;
 | |
|   Register SrcReg = MI.getOperand(0).getReg();
 | |
|   bool SrcIsKill = MI.getOperand(0).isKill();
 | |
|   unsigned Flags = MI.getFlags();
 | |
|   unsigned OpLo = AVR::PUSHRr;
 | |
|   unsigned 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;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   unsigned Flags = MI.getFlags();
 | |
|   unsigned OpLo = AVR::POPRd;
 | |
|   unsigned 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::ROLBRd>(Block &MBB, BlockIt MBBI) {
 | |
|   // In AVR, the rotate instructions behave quite unintuitively. They rotate
 | |
|   // bits through the carry bit in SREG, effectively rotating over 9 bits,
 | |
|   // instead of 8. This is useful when we are dealing with numbers over
 | |
|   // multiple registers, but when we actually need to rotate stuff, we have
 | |
|   // to explicitly add the carry bit.
 | |
| 
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   unsigned OpShift, OpCarry;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   OpShift = AVR::ADDRdRr;
 | |
|   OpCarry = AVR::ADCRdRr;
 | |
| 
 | |
|   // add r16, r16
 | |
|   // adc r16, r1
 | |
| 
 | |
|   // Shift part
 | |
|   buildMI(MBB, MBBI, OpShift)
 | |
|     .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|     .addReg(DstReg)
 | |
|     .addReg(DstReg);
 | |
| 
 | |
|   // Add the carry bit
 | |
|   auto MIB = buildMI(MBB, MBBI, OpCarry)
 | |
|     .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|     .addReg(DstReg)
 | |
|     .addReg(ZERO_REGISTER);
 | |
| 
 | |
|   // SREG is always implicitly killed
 | |
|   MIB->getOperand(2).setIsKill();
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::RORBRd>(Block &MBB, BlockIt MBBI) {
 | |
|   // In AVR, the rotate instructions behave quite unintuitively. They rotate
 | |
|   // bits through the carry bit in SREG, effectively rotating over 9 bits,
 | |
|   // instead of 8. This is useful when we are dealing with numbers over
 | |
|   // multiple registers, but when we actually need to rotate stuff, we have
 | |
|   // to explicitly add the carry bit.
 | |
| 
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   unsigned OpShiftOut, OpLoad, OpShiftIn, OpAdd;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   OpShiftOut = AVR::LSRRd;
 | |
|   OpLoad = AVR::LDIRdK;
 | |
|   OpShiftIn = AVR::RORRd;
 | |
|   OpAdd = AVR::ORRdRr;
 | |
| 
 | |
|   // lsr r16
 | |
|   // ldi r0, 0
 | |
|   // ror r0
 | |
|   // or r16, r17
 | |
| 
 | |
|   // Shift out
 | |
|   buildMI(MBB, MBBI, OpShiftOut)
 | |
|     .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|     .addReg(DstReg);
 | |
| 
 | |
|   // Put 0 in temporary register
 | |
|   buildMI(MBB, MBBI, OpLoad)
 | |
|     .addReg(SCRATCH_REGISTER, RegState::Define | getDeadRegState(true))
 | |
|     .addImm(0x00);
 | |
| 
 | |
|   // Shift in
 | |
|   buildMI(MBB, MBBI, OpShiftIn)
 | |
|     .addReg(SCRATCH_REGISTER, RegState::Define | getDeadRegState(true))
 | |
|     .addReg(SCRATCH_REGISTER);
 | |
| 
 | |
|   // Add the results together using an or-instruction
 | |
|   auto MIB = buildMI(MBB, MBBI, OpAdd)
 | |
|     .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|     .addReg(DstReg)
 | |
|     .addReg(SCRATCH_REGISTER);
 | |
| 
 | |
|   // SREG is always implicitly killed
 | |
|   MIB->getOperand(2).setIsKill();
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool DstIsKill = MI.getOperand(1).isKill();
 | |
|   bool ImpIsDead = MI.getOperand(2).isDead();
 | |
|   unsigned OpLo = AVR::ADDRdRr; // ADD Rd, Rd <==> LSL Rd
 | |
|   unsigned OpHi = AVR::ADCRdRr; // ADC Rd, Rd <==> ROL Rd
 | |
|   TRI->splitReg(DstReg, DstLoReg, DstHiReg);
 | |
| 
 | |
|   // Low part
 | |
|   buildMI(MBB, MBBI, OpLo)
 | |
|     .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|     .addReg(DstLoReg)
 | |
|     .addReg(DstLoReg, getKillRegState(DstIsKill));
 | |
| 
 | |
|   auto MIBHI = buildMI(MBB, MBBI, OpHi)
 | |
|     .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
 | |
|     .addReg(DstHiReg)
 | |
|     .addReg(DstHiReg, getKillRegState(DstIsKill));
 | |
| 
 | |
|   if (ImpIsDead)
 | |
|     MIBHI->getOperand(3).setIsDead();
 | |
| 
 | |
|   // SREG is always implicitly killed
 | |
|   MIBHI->getOperand(4).setIsKill();
 | |
| 
 | |
|   MI.eraseFromParent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <>
 | |
| bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
 | |
|   MachineInstr &MI = *MBBI;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool DstIsKill = MI.getOperand(1).isKill();
 | |
|   bool ImpIsDead = MI.getOperand(2).isDead();
 | |
|   unsigned OpLo = AVR::RORRd;
 | |
|   unsigned 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;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   bool DstIsKill = MI.getOperand(1).isKill();
 | |
|   bool ImpIsDead = MI.getOperand(2).isDead();
 | |
|   unsigned OpLo = AVR::RORRd;
 | |
|   unsigned 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;
 | |
|   Register 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
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register 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::ADDRdRr) // LSL Rd <==> ADD Rd, Rr
 | |
|     .addReg(DstHiReg, RegState::Define)
 | |
|     .addReg(DstHiReg)
 | |
|     .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;
 | |
|   Register 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
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   Register 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;
 | |
|   Register DstLoReg, DstHiReg;
 | |
|   Register DstReg = MI.getOperand(0).getReg();
 | |
|   bool DstIsDead = MI.getOperand(0).isDead();
 | |
|   unsigned Flags = MI.getFlags();
 | |
|   unsigned OpLo = AVR::INRdA;
 | |
|   unsigned 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;
 | |
|   Register SrcLoReg, SrcHiReg;
 | |
|   Register 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::NEGWRd);
 | |
|     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::ROLBRd);
 | |
|     EXPAND(AVR::RORBRd);
 | |
|     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
 |