[llvm] r287162 - [AVR] Add the pseudo instruction expansion pass

Dylan McKay via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 16 16:20:02 PST 2016


This should be fixed as of r287180, thanks for letting me know!

On Thu, Nov 17, 2016 at 1:16 PM, Dylan McKay <dylanmckay34 at gmail.com> wrote:

> You're right, I'll fix that up now.
>
> On Thu, Nov 17, 2016 at 1:13 PM, Yung, Douglas <douglas.yung at sony.com>
> wrote:
>
>> Hi Dylan,
>>
>> I believe your change caused the Windows hosted PS4 bot to start failing
>> during testing. Can you take a look?
>>
>> http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-
>> scei-ps4-windows10pro-fast/builds/1261
>>
>> Douglas Yung
>>
>> > -----Original Message-----
>> > From: llvm-commits [mailto:llvm-commits-bounces at lists.llvm.org] On
>> > Behalf Of Dylan McKay via llvm-commits
>> > Sent: Wednesday, November 16, 2016 13:58
>> > To: llvm-commits at lists.llvm.org
>> > Subject: [llvm] r287162 - [AVR] Add the pseudo instruction expansion
>> > pass
>> >
>> > Author: dylanmckay
>> > Date: Wed Nov 16 15:58:04 2016
>> > New Revision: 287162
>> >
>> > URL: http://llvm.org/viewvc/llvm-project?rev=287162&view=rev
>> > Log:
>> > [AVR] Add the pseudo instruction expansion pass
>> >
>> > Summary:
>> > A lot of the pseudo instructions are required because LLVM assumes that
>> > all integers of the same size as the pointer size are legal. This means
>> > that it will not currently expand 16-bit instructions to their 8-bit
>> > variants because it thinks 16-bit types are legal for the operations.
>> >
>> > This also adds all of the CodeGen tests that required the pass to run.
>> >
>> > Reviewers: arsenm, kparzysz
>> >
>> > Subscribers: wdng, mgorny, modocache, llvm-commits
>> >
>> > Differential Revision: https://reviews.llvm.org/D26577
>> >
>> > Added:
>> >     llvm/trunk/lib/Target/AVR/AVRExpandPseudoInsts.cpp
>> >     llvm/trunk/test/CodeGen/AVR/add.ll
>> >     llvm/trunk/test/CodeGen/AVR/alloca.ll
>> >     llvm/trunk/test/CodeGen/AVR/and.ll
>> >     llvm/trunk/test/CodeGen/AVR/atomics/fence.ll
>> >     llvm/trunk/test/CodeGen/AVR/atomics/load16.ll
>> >     llvm/trunk/test/CodeGen/AVR/atomics/load8.ll
>> >     llvm/trunk/test/CodeGen/AVR/atomics/store.ll
>> >     llvm/trunk/test/CodeGen/AVR/atomics/store16.ll
>> >     llvm/trunk/test/CodeGen/AVR/brind.ll
>> >     llvm/trunk/test/CodeGen/AVR/call.ll
>> >     llvm/trunk/test/CodeGen/AVR/cmp.ll
>> >     llvm/trunk/test/CodeGen/AVR/com.ll
>> >     llvm/trunk/test/CodeGen/AVR/directmem.ll
>> >     llvm/trunk/test/CodeGen/AVR/dynalloca.ll
>> >     llvm/trunk/test/CodeGen/AVR/eor.ll
>> >     llvm/trunk/test/CodeGen/AVR/error-srcreg-destreg-same.ll
>> >     llvm/trunk/test/CodeGen/AVR/expand-integer-failure.ll
>> >     llvm/trunk/test/CodeGen/AVR/frame.ll
>> >     llvm/trunk/test/CodeGen/AVR/inline-asm.ll
>> >     llvm/trunk/test/CodeGen/AVR/interrupts.ll
>> >     llvm/trunk/test/CodeGen/AVR/io.ll
>> >     llvm/trunk/test/CodeGen/AVR/load.ll
>> >     llvm/trunk/test/CodeGen/AVR/or.ll
>> >     llvm/trunk/test/CodeGen/AVR/progmem.ll
>> >     llvm/trunk/test/CodeGen/AVR/return.ll
>> >     llvm/trunk/test/CodeGen/AVR/sext.ll
>> >     llvm/trunk/test/CodeGen/AVR/store.ll
>> >     llvm/trunk/test/CodeGen/AVR/sub.ll
>> >     llvm/trunk/test/CodeGen/AVR/varargs.ll
>> >     llvm/trunk/test/CodeGen/AVR/xor.ll
>> >     llvm/trunk/test/CodeGen/AVR/zext.ll
>> > Modified:
>> >     llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp
>> >     llvm/trunk/lib/Target/AVR/CMakeLists.txt
>> >     llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll
>> >     llvm/trunk/test/CodeGen/AVR/lit.local.cfg
>> >
>> > Added: llvm/trunk/lib/Target/AVR/AVRExpandPseudoInsts.cpp
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/lib/Target/AVR/AVRExpandPseudoInsts.cpp?rev=287162&v
>> > iew=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/lib/Target/AVR/AVRExpandPseudoInsts.cpp (added)
>> > +++ llvm/trunk/lib/Target/AVR/AVRExpandPseudoInsts.cpp Wed Nov 16
>> > 15:58:04 2016
>> > @@ -0,0 +1,1431 @@
>> > +//===-- AVRExpandPseudoInsts.cpp - Expand pseudo instructions --------
>> > -----===//
>> > +//
>> > +//                     The LLVM Compiler Infrastructure
>> > +//
>> > +// This file is distributed under the University of Illinois Open
>> > Source
>> > +// License. See LICENSE.TXT for details.
>> > +//
>> > +//===-----------------------------------------------------------------
>> > -----===//
>> > +//
>> > +// This file contains a pass that expands pseudo instructions into
>> > target
>> > +// instructions. This pass should be run after register allocation but
>> > before
>> > +// the post-regalloc scheduling pass.
>> > +//
>> > +//===-----------------------------------------------------------------
>> > -----===//
>> > +
>> > +#include "AVR.h"
>> > +#include "AVRInstrInfo.h"
>> > +#include "AVRTargetMachine.h"
>> > +#include "MCTargetDesc/AVRMCTargetDesc.h"
>> > +
>> > +#include "llvm/CodeGen/MachineFunctionPass.h"
>> > +#include "llvm/CodeGen/MachineInstrBuilder.h"
>> > +#include "llvm/CodeGen/MachineRegisterInfo.h"
>> > +#include "llvm/Target/TargetRegisterInfo.h"
>> > +
>> > +using namespace llvm;
>> > +
>> > +namespace {
>> > +
>> > +/// Expands "placeholder" instructions marked as pseudo into
>> > +/// actual AVR instructions.
>> > +class AVRExpandPseudo : public MachineFunctionPass {
>> > +public:
>> > +  static char ID;
>> > +
>> > +  AVRExpandPseudo() : MachineFunctionPass(ID) {}
>> > +
>> > +  bool runOnMachineFunction(MachineFunction &MF) override;
>> > +
>> > +  StringRef getPassName() const override {
>> > +    return "AVR pseudo instruction expansion pass";
>> > +  }
>> > +
>> > +private:
>> > +  typedef MachineBasicBlock Block;
>> > +  typedef Block::iterator BlockIt;
>> > +
>> > +  const AVRRegisterInfo *TRI;
>> > +  const TargetInstrInfo *TII;
>> > +
>> > +  /// The register to be used for temporary storage.
>> > +  const unsigned SCRATCH_REGISTER = AVR::R0;
>> > +  /// The IO address of the status register.
>> > +  const unsigned SREG_ADDR = 0x3f;
>> > +
>> > +  bool expandMBB(Block &MBB);
>> > +  bool expandMI(Block &MBB, BlockIt MBBI);
>> > +  template <unsigned OP> bool expand(Block &MBB, BlockIt MBBI);
>> > +
>> > +  MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned
>> > Opcode) {
>> > +    return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode));
>> > +  }
>> > +
>> > +  MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned
>> > Opcode,
>> > +                              unsigned DstReg) {
>> > +    return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode),
>> > DstReg);
>> > +  }
>> > +
>> > +  MachineRegisterInfo &getRegInfo(Block &MBB) { return
>> > MBB.getParent()->getRegInfo(); }
>> > +
>> > +  bool expandArith(unsigned OpLo, unsigned OpHi, Block &MBB, BlockIt
>> > MBBI);
>> > +  bool expandLogic(unsigned Op, Block &MBB, BlockIt MBBI);
>> > +  bool expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI);
>> > +
>> > +  template<typename Func>
>> > +  bool expandAtomic(Block &MBB, BlockIt MBBI, Func f);
>> > +
>> > +  template<typename Func>
>> > +  bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI,
>> > Func f);
>> > +
>> > +  bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt
>> > MBBI);
>> > +
>> > +  bool expandAtomicArithmeticOp(unsigned MemOpcode,
>> > +                                unsigned ArithOpcode,
>> > +                                Block &MBB,
>> > +                                BlockIt MBBI);
>> > +};
>> > +
>> > +char AVRExpandPseudo::ID = 0;
>> > +
>> > +} // end of anonymous namespace
>> > +
>> > +bool AVRExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
>> > +  bool Modified = false;
>> > +
>> > +  BlockIt MBBI = MBB.begin(), E = MBB.end();
>> > +  while (MBBI != E) {
>> > +    BlockIt NMBBI = std::next(MBBI);
>> > +    Modified |= expandMI(MBB, MBBI);
>> > +    MBBI = NMBBI;
>> > +  }
>> > +
>> > +  return Modified;
>> > +}
>> > +
>> > +bool AVRExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
>> > +  bool Modified = false;
>> > +
>> > +  const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
>> > +  TRI = STI.getRegisterInfo();
>> > +  TII = STI.getInstrInfo();
>> > +
>> > +  for (Block &MBB : MF) {
>> > +    bool ContinueExpanding = true;
>> > +    unsigned ExpandCount = 0;
>> > +
>> > +    // Continue expanding the block until all pseudos are expanded.
>> > +    do {
>> > +      assert(ExpandCount < 10 && "pseudo expand limit reached");
>> > +
>> > +      bool BlockModified = expandMBB(MBB);
>> > +      Modified |= BlockModified;
>> > +      ExpandCount++;
>> > +
>> > +      ContinueExpanding = BlockModified;
>> > +    } while (ContinueExpanding);
>> > +  }
>> > +
>> > +  return Modified;
>> > +}
>> > +
>> > +bool AVRExpandPseudo::
>> > +expandArith(unsigned OpLo, unsigned OpHi, Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(2).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool DstIsKill = MI.getOperand(1).isKill();
>> > +  bool SrcIsKill = MI.getOperand(2).isKill();
>> > +  bool ImpIsDead = MI.getOperand(3).isDead();
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(DstIsKill))
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill));
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(DstIsKill))
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(3).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBHI->getOperand(4).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +bool AVRExpandPseudo::
>> > +expandLogic(unsigned Op, Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(2).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool DstIsKill = MI.getOperand(1).isKill();
>> > +  bool SrcIsKill = MI.getOperand(2).isKill();
>> > +  bool ImpIsDead = MI.getOperand(3).isDead();
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, Op)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(DstIsKill))
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill));
>> > +
>> > +  // SREG is always implicitly dead
>> > +  MIBLO->getOperand(3).setIsDead();
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, Op)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(DstIsKill))
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(3).setIsDead();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +bool AVRExpandPseudo::
>> > +expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(3).isDead();
>> > +  unsigned Imm = MI.getOperand(2).getImm();
>> > +  unsigned Lo8 = Imm & 0xff;
>> > +  unsigned Hi8 = (Imm >> 8) & 0xff;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, Op)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Lo8);
>> > +
>> > +  // SREG is always implicitly dead
>> > +  MIBLO->getOperand(3).setIsDead();
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, Op)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Hi8);
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(3).setIsDead();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::ADDWRdRr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  return expandArith(AVR::ADDRdRr, AVR::ADCRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::ADCWRdRr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  return expandArith(AVR::ADCRdRr, AVR::ADCRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::SUBWRdRr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  return expandArith(AVR::SUBRdRr, AVR::SBCRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::SUBIWRdK>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(3).isDead();
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, AVR::SUBIRdK)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(SrcIsKill));
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, AVR::SBCIRdK)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  switch (MI.getOperand(2).getType()) {
>> > +  case MachineOperand::MO_GlobalAddress: {
>> > +    const GlobalValue *GV = MI.getOperand(2).getGlobal();
>> > +    int64_t Offs = MI.getOperand(2).getOffset();
>> > +    unsigned TF = MI.getOperand(2).getTargetFlags();
>> > +    MIBLO.addGlobalAddress(GV, Offs, TF | AVRII::MO_NEG |
>> > AVRII::MO_LO);
>> > +    MIBHI.addGlobalAddress(GV, Offs, TF | AVRII::MO_NEG |
>> > AVRII::MO_HI);
>> > +    break;
>> > +  }
>> > +  case MachineOperand::MO_Immediate: {
>> > +    unsigned Imm = MI.getOperand(2).getImm();
>> > +    MIBLO.addImm(Imm & 0xff);
>> > +    MIBHI.addImm((Imm >> 8) & 0xff);
>> > +    break;
>> > +  }
>> > +  default:
>> > +    llvm_unreachable("Unknown operand type!");
>> > +  }
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(3).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBHI->getOperand(4).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::SBCWRdRr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  return expandArith(AVR::SBCRdRr, AVR::SBCRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::SBCIWRdK>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(3).isDead();
>> > +  unsigned Imm = MI.getOperand(2).getImm();
>> > +  unsigned Lo8 = Imm & 0xff;
>> > +  unsigned Hi8 = (Imm >> 8) & 0xff;
>> > +  OpLo = AVR::SBCIRdK;
>> > +  OpHi = AVR::SBCIRdK;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Lo8);
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBLO->getOperand(4).setIsKill();
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Hi8);
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(3).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBHI->getOperand(4).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::ANDWRdRr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  return expandLogic(AVR::ANDRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::ANDIWRdK>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  return expandLogicImm(AVR::ANDIRdK, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::ORWRdRr>(Block &MBB, BlockIt MBBI) {
>> > +  return expandLogic(AVR::ORRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::ORIWRdK>(Block &MBB, BlockIt MBBI) {
>> > +  return expandLogicImm(AVR::ORIRdK, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::EORWRdRr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  return expandLogic(AVR::EORRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::COMWRd>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool DstIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(2).isDead();
>> > +  OpLo = AVR::COMRd;
>> > +  OpHi = AVR::COMRd;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(DstIsKill));
>> > +
>> > +  // SREG is always implicitly dead
>> > +  MIBLO->getOperand(2).setIsDead();
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(DstIsKill));
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(2).setIsDead();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::CPWRdRr>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool DstIsKill = MI.getOperand(0).isKill();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(2).isDead();
>> > +  OpLo = AVR::CPRdRr;
>> > +  OpHi = AVR::CPCRdRr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  // Low part
>> > +  buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, getKillRegState(DstIsKill))
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill));
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, getKillRegState(DstIsKill))
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(2).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBHI->getOperand(3).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::CPCWRdRr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool DstIsKill = MI.getOperand(0).isKill();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(2).isDead();
>> > +  OpLo = AVR::CPCRdRr;
>> > +  OpHi = AVR::CPCRdRr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, getKillRegState(DstIsKill))
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill));
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBLO->getOperand(3).setIsKill();
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, getKillRegState(DstIsKill))
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(2).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBHI->getOperand(3).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::LDIWRdK>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  OpLo = AVR::LDIRdK;
>> > +  OpHi = AVR::LDIRdK;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead));
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead));
>> > +
>> > +  switch (MI.getOperand(1).getType()) {
>> > +  case MachineOperand::MO_GlobalAddress: {
>> > +    const GlobalValue *GV = MI.getOperand(1).getGlobal();
>> > +    int64_t Offs = MI.getOperand(1).getOffset();
>> > +    unsigned TF = MI.getOperand(1).getTargetFlags();
>> > +
>> > +    MIBLO.addGlobalAddress(GV, Offs, TF | AVRII::MO_LO);
>> > +    MIBHI.addGlobalAddress(GV, Offs, TF | AVRII::MO_HI);
>> > +    break;
>> > +  }
>> > +  case MachineOperand::MO_BlockAddress: {
>> > +    const BlockAddress *BA = MI.getOperand(1).getBlockAddress();
>> > +    unsigned TF = MI.getOperand(1).getTargetFlags();
>> > +
>> > +    MIBLO.addOperand(MachineOperand::CreateBA(BA, TF | AVRII::MO_LO));
>> > +    MIBHI.addOperand(MachineOperand::CreateBA(BA, TF | AVRII::MO_HI));
>> > +    break;
>> > +  }
>> > +  case MachineOperand::MO_Immediate: {
>> > +    unsigned Imm = MI.getOperand(1).getImm();
>> > +
>> > +    MIBLO.addImm(Imm & 0xff);
>> > +    MIBHI.addImm((Imm >> 8) & 0xff);
>> > +    break;
>> > +  }
>> > +  default:
>> > +    llvm_unreachable("Unknown operand type!");
>> > +  }
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::LDSWRdK>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  OpLo = AVR::LDSRdK;
>> > +  OpHi = AVR::LDSRdK;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead));
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead));
>> > +
>> > +  switch (MI.getOperand(1).getType()) {
>> > +  case MachineOperand::MO_GlobalAddress: {
>> > +    const GlobalValue *GV = MI.getOperand(1).getGlobal();
>> > +    int64_t Offs = MI.getOperand(1).getOffset();
>> > +    unsigned TF = MI.getOperand(1).getTargetFlags();
>> > +
>> > +    MIBLO.addGlobalAddress(GV, Offs, TF);
>> > +    MIBHI.addGlobalAddress(GV, Offs + 1, TF);
>> > +    break;
>> > +  }
>> > +  case MachineOperand::MO_Immediate: {
>> > +    unsigned Imm = MI.getOperand(1).getImm();
>> > +
>> > +    MIBLO.addImm(Imm);
>> > +    MIBHI.addImm(Imm + 1);
>> > +    break;
>> > +  }
>> > +  default:
>> > +    llvm_unreachable("Unknown operand type!");
>> > +  }
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  OpLo = AVR::LDRdPtr;
>> > +  OpHi = AVR::LDDRdPtrQ;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(SrcReg);
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(SrcReg, getKillRegState(SrcIsKill))
>> > +    .addImm(1);
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::LDWRdPtrPi>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsDead = MI.getOperand(1).isKill();
>> > +  OpLo = AVR::LDRdPtrPi;
>> > +  OpHi = AVR::LDRdPtrPi;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(SrcReg, RegState::Define)
>> > +    .addReg(SrcReg, RegState::Kill);
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(SrcReg, RegState::Define | getDeadRegState(SrcIsDead))
>> > +    .addReg(SrcReg, RegState::Kill);
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::LDWRdPtrPd>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsDead = MI.getOperand(1).isKill();
>> > +  OpLo = AVR::LDRdPtrPd;
>> > +  OpHi = AVR::LDRdPtrPd;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(SrcReg, RegState::Define)
>> > +    .addReg(SrcReg, RegState::Kill);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(SrcReg, RegState::Define | getDeadRegState(SrcIsDead))
>> > +    .addReg(SrcReg, RegState::Kill);
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  unsigned Imm = MI.getOperand(2).getImm();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  OpLo = AVR::LDDRdPtrQ;
>> > +  OpHi = AVR::LDDRdPtrQ;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  assert(Imm < 63 && "Offset is out of range");
>> > +  assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(SrcReg)
>> > +    .addImm(Imm);
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(SrcReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Imm + 1);
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template<typename Func>
>> > +bool AVRExpandPseudo::expandAtomic(Block &MBB, BlockIt MBBI, Func f) {
>> > +  // Remove the pseudo instruction.
>> > +  MachineInstr &MI = *MBBI;
>> > +
>> > +  // Store the SREG.
>> > +  buildMI(MBB, MBBI, AVR::INRdA)
>> > +    .addReg(SCRATCH_REGISTER, RegState::Define)
>> > +    .addImm(SREG_ADDR);
>> > +
>> > +  // Disable exceptions.
>> > +  buildMI(MBB, MBBI, AVR::BCLRs).addImm(7); // CLI
>> > +
>> > +  f(MI);
>> > +
>> > +  // Restore the status reg.
>> > +  buildMI(MBB, MBBI, AVR::OUTARr)
>> > +    .addImm(SREG_ADDR)
>> > +    .addReg(SCRATCH_REGISTER);
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template<typename Func>
>> > +bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode,
>> > +                                           Block &MBB,
>> > +                                           BlockIt MBBI,
>> > +                                           Func f) {
>> > +  return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
>> > +      auto Op1 = MI.getOperand(0);
>> > +      auto Op2 = MI.getOperand(1);
>> > +
>> > +      MachineInstr &NewInst = *buildMI(MBB, MBBI, Opcode)
>> > +        .addOperand(Op1).addOperand(Op2)
>> > +        .getInstr();
>> > +      f(NewInst);
>> > +  });
>> > +}
>> > +
>> > +bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode,
>> > +                                           Block &MBB,
>> > +                                           BlockIt MBBI) {
>> > +  return expandAtomicBinaryOp(Opcode, MBB, MBBI, [](MachineInstr &MI)
>> > {});
>> > +}
>> > +
>> > +bool AVRExpandPseudo::expandAtomicArithmeticOp(unsigned Width,
>> > +                                               unsigned ArithOpcode,
>> > +                                               Block &MBB,
>> > +                                               BlockIt MBBI) {
>> > +  return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
>> > +      auto Op1 = MI.getOperand(0);
>> > +      auto Op2 = MI.getOperand(1);
>> > +
>> > +      unsigned LoadOpcode = (Width == 8) ? AVR::LDRdPtr :
>> > AVR::LDWRdPtr;
>> > +      unsigned StoreOpcode = (Width == 8) ? AVR::STPtrRr :
>> > AVR::STWPtrRr;
>> > +
>> > +      // Create the load
>> > +      buildMI(MBB, MBBI, LoadOpcode).addOperand(Op1).addOperand(Op2);
>> > +
>> > +      // Create the arithmetic op
>> > +      buildMI(MBB, MBBI, ArithOpcode)
>> > +        .addOperand(Op1).addOperand(Op1)
>> > +        .addOperand(Op2);
>> > +
>> > +      // Create the store
>> > +      buildMI(MBB, MBBI, StoreOpcode).addOperand(Op2).addOperand(Op1);
>> > +  });
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoad8>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicBinaryOp(AVR::LDRdPtr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoad16>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicBinaryOp(AVR::LDWRdPtr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicStore8>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicBinaryOp(AVR::STPtrRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicStore16>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicBinaryOp(AVR::STWPtrRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd8>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(8, AVR::ADDRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd16>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(16, AVR::ADDWRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadSub8>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(8, AVR::SUBRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadSub16>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(16, AVR::SUBWRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd8>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(8, AVR::ANDRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd16>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(16, AVR::ANDWRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadOr8>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(8, AVR::ORRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadOr16>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(16, AVR::ORWRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadXor8>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(8, AVR::EORRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicLoadXor16>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  return expandAtomicArithmeticOp(16, AVR::EORWRdRr, MBB, MBBI);
>> > +}
>> > +
>> > +template<>
>> > +bool AVRExpandPseudo::expand<AVR::AtomicFence>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  // On AVR, there is only one core and so atomic fences do nothing.
>> > +  MBBI->eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::STSWKRr>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  OpLo = AVR::STSKRr;
>> > +  OpHi = AVR::STSKRr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +
>> > +  // Write the high byte first in case this address belongs to a
>> > special
>> > +  // I/O address with a special temporary register.
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi);
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo);
>> > +
>> > +  switch (MI.getOperand(0).getType()) {
>> > +  case MachineOperand::MO_GlobalAddress: {
>> > +    const GlobalValue *GV = MI.getOperand(0).getGlobal();
>> > +    int64_t Offs = MI.getOperand(0).getOffset();
>> > +    unsigned TF = MI.getOperand(0).getTargetFlags();
>> > +
>> > +    MIBLO.addGlobalAddress(GV, Offs, TF);
>> > +    MIBHI.addGlobalAddress(GV, Offs + 1, TF);
>> > +    break;
>> > +  }
>> > +  case MachineOperand::MO_Immediate: {
>> > +    unsigned Imm = MI.getOperand(0).getImm();
>> > +
>> > +    MIBLO.addImm(Imm);
>> > +    MIBHI.addImm(Imm + 1);
>> > +    break;
>> > +  }
>> > +  default:
>> > +    llvm_unreachable("Unknown operand type!");
>> > +  }
>> > +
>> > +  MIBLO.addReg(SrcLoReg, getKillRegState(SrcIsKill));
>> > +  MIBHI.addReg(SrcHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::STWPtrRr>(Block &MBB, BlockIt MBBI)
>> > {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool DstIsKill = MI.getOperand(0).isKill();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  OpLo = AVR::STPtrRr;
>> > +  OpHi = AVR::STDPtrQRr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +
>> > +  //:TODO: need to reverse this order like inw and stsw?
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstReg)
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill));
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstReg, getKillRegState(DstIsKill))
>> > +    .addImm(1)
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::STWPtrPiRr>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(2).getReg();
>> > +  unsigned Imm = MI.getOperand(3).getImm();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(2).isKill();
>> > +  OpLo = AVR::STPtrPiRr;
>> > +  OpHi = AVR::STPtrPiRr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +
>> > +  assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstReg, RegState::Define)
>> > +    .addReg(DstReg, RegState::Kill)
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Imm);
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstReg, RegState::Kill)
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Imm);
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::STWPtrPdRr>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(2).getReg();
>> > +  unsigned Imm = MI.getOperand(3).getImm();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(2).isKill();
>> > +  OpLo = AVR::STPtrPdRr;
>> > +  OpHi = AVR::STPtrPdRr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +
>> > +  assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstReg, RegState::Define)
>> > +    .addReg(DstReg, RegState::Kill)
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Imm);
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstReg, RegState::Kill)
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill))
>> > +    .addImm(Imm);
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt
>> > MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(2).getReg();
>> > +  unsigned Imm = MI.getOperand(1).getImm();
>> > +  bool DstIsKill = MI.getOperand(0).isKill();
>> > +  bool SrcIsKill = MI.getOperand(2).isKill();
>> > +  OpLo = AVR::STDPtrQRr;
>> > +  OpHi = AVR::STDPtrQRr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +
>> > +  assert(Imm < 63 && "Offset is out of range");
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstReg)
>> > +    .addImm(Imm)
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill));
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstReg, getKillRegState(DstIsKill))
>> > +    .addImm(Imm + 1)
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned Imm = MI.getOperand(1).getImm();
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  OpLo = AVR::INRdA;
>> > +  OpHi = AVR::INRdA;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  assert(Imm < 63 && "Address is out of range");
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addImm(Imm);
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addImm(Imm + 1);
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::OUTWARr>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
>> > +  unsigned Imm = MI.getOperand(0).getImm();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  OpLo = AVR::OUTARr;
>> > +  OpHi = AVR::OUTARr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +
>> > +  assert(Imm < 63 && "Address is out of range");
>> > +
>> > +  // 16 bit I/O writes need the high byte first
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addImm(Imm + 1)
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill));
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addImm(Imm)
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill));
>> > +
>> > +  MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +  MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::PUSHWRr>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
>> > +  unsigned SrcReg = MI.getOperand(0).getReg();
>> > +  bool SrcIsKill = MI.getOperand(0).isKill();
>> > +  unsigned Flags = MI.getFlags();
>> > +  OpLo = AVR::PUSHRr;
>> > +  OpHi = AVR::PUSHRr;
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +
>> > +  // Low part
>> > +  buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill))
>> > +    .setMIFlags(Flags);
>> > +
>> > +  // High part
>> > +  buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill))
>> > +    .setMIFlags(Flags);
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::POPWRd>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned Flags = MI.getFlags();
>> > +  OpLo = AVR::POPRd;
>> > +  OpHi = AVR::POPRd;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  buildMI(MBB, MBBI, OpHi, DstHiReg).setMIFlags(Flags); // High
>> > +  buildMI(MBB, MBBI, OpLo, DstLoReg).setMIFlags(Flags); // Low
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool DstIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(2).isDead();
>> > +  OpLo = AVR::LSLRd;
>> > +  OpHi = AVR::ROLRd;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  // Low part
>> > +  buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(DstIsKill));
>> > +
>> > +  auto MIBHI = buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(DstIsKill));
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBHI->getOperand(2).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBHI->getOperand(3).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool DstIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(2).isDead();
>> > +  OpLo = AVR::RORRd;
>> > +  OpHi = AVR::LSRRd;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  // High part
>> > +  buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(DstIsKill));
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(DstIsKill));
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBLO->getOperand(2).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBLO->getOperand(3).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::RORWRd>(Block &MBB, BlockIt MBBI) {
>> > +  llvm_unreachable("RORW unimplemented");
>> > +  return false;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::ROLWRd>(Block &MBB, BlockIt MBBI) {
>> > +  llvm_unreachable("ROLW unimplemented");
>> > +  return false;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool DstIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(2).isDead();
>> > +  OpLo = AVR::RORRd;
>> > +  OpHi = AVR::ASRRd;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  // High part
>> > +  buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, getKillRegState(DstIsKill));
>> > +
>> > +  auto MIBLO = buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstLoReg, getKillRegState(DstIsKill));
>> > +
>> > +  if (ImpIsDead)
>> > +    MIBLO->getOperand(2).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  MIBLO->getOperand(3).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <> bool AVRExpandPseudo::expand<AVR::SEXT>(Block &MBB,
>> > BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned DstLoReg, DstHiReg;
>> > +  // sext R17:R16, R17
>> > +  // mov     r16, r17
>> > +  // lsl     r17
>> > +  // sbc     r17, r17
>> > +  // sext R17:R16, R13
>> > +  // mov     r16, r13
>> > +  // mov     r17, r13
>> > +  // lsl     r17
>> > +  // sbc     r17, r17
>> > +  // sext R17:R16, R16
>> > +  // mov     r17, r16
>> > +  // lsl     r17
>> > +  // sbc     r17, r17
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(2).isDead();
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  if (SrcReg != DstLoReg) {
>> > +    auto MOV = buildMI(MBB, MBBI, AVR::MOVRdRr)
>> > +      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +      .addReg(SrcReg);
>> > +
>> > +    if (SrcReg == DstHiReg) {
>> > +      MOV->getOperand(1).setIsKill();
>> > +    }
>> > +  }
>> > +
>> > +  if (SrcReg != DstHiReg) {
>> > +    buildMI(MBB, MBBI, AVR::MOVRdRr)
>> > +      .addReg(DstHiReg, RegState::Define)
>> > +      .addReg(SrcReg, getKillRegState(SrcIsKill));
>> > +  }
>> > +
>> > +  buildMI(MBB, MBBI, AVR::LSLRd)
>> > +    .addReg(DstHiReg, RegState::Define)
>> > +    .addReg(DstHiReg, RegState::Kill);
>> > +
>> > +  auto SBC = buildMI(MBB, MBBI, AVR::SBCRdRr)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, RegState::Kill)
>> > +    .addReg(DstHiReg, RegState::Kill);
>> > +
>> > +  if (ImpIsDead)
>> > +    SBC->getOperand(3).setIsDead();
>> > +
>> > +  // SREG is always implicitly killed
>> > +  SBC->getOperand(4).setIsKill();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <> bool AVRExpandPseudo::expand<AVR::ZEXT>(Block &MBB,
>> > BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned DstLoReg, DstHiReg;
>> > +  // zext R25:R24, R20
>> > +  // mov      R24, R20
>> > +  // eor      R25, R25
>> > +  // zext R25:R24, R24
>> > +  // eor      R25, R25
>> > +  // zext R25:R24, R25
>> > +  // mov      R24, R25
>> > +  // eor      R25, R25
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  bool ImpIsDead = MI.getOperand(2).isDead();
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  if (SrcReg != DstLoReg) {
>> > +    buildMI(MBB, MBBI, AVR::MOVRdRr)
>> > +      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +      .addReg(SrcReg, getKillRegState(SrcIsKill));
>> > +  }
>> > +
>> > +  auto EOR = buildMI(MBB, MBBI, AVR::EORRdRr)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addReg(DstHiReg, RegState::Kill)
>> > +    .addReg(DstHiReg, RegState::Kill);
>> > +
>> > +  if (ImpIsDead)
>> > +    EOR->getOperand(3).setIsDead();
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::SPREAD>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned OpLo, OpHi, DstLoReg, DstHiReg;
>> > +  unsigned DstReg = MI.getOperand(0).getReg();
>> > +  bool DstIsDead = MI.getOperand(0).isDead();
>> > +  unsigned Flags = MI.getFlags();
>> > +  OpLo = AVR::INRdA;
>> > +  OpHi = AVR::INRdA;
>> > +  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
>> > +
>> > +  // Low part
>> > +  buildMI(MBB, MBBI, OpLo)
>> > +    .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addImm(0x3d)
>> > +    .setMIFlags(Flags);
>> > +
>> > +  // High part
>> > +  buildMI(MBB, MBBI, OpHi)
>> > +    .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
>> > +    .addImm(0x3e)
>> > +    .setMIFlags(Flags);
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +template <>
>> > +bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  unsigned SrcLoReg, SrcHiReg;
>> > +  unsigned SrcReg = MI.getOperand(1).getReg();
>> > +  bool SrcIsKill = MI.getOperand(1).isKill();
>> > +  unsigned Flags = MI.getFlags();
>> > +  TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
>> > +
>> > +  buildMI(MBB, MBBI, AVR::INRdA)
>> > +    .addReg(AVR::R0, RegState::Define)
>> > +    .addImm(SREG_ADDR)
>> > +    .setMIFlags(Flags);
>> > +
>> > +  buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags);
>> > +
>> > +  buildMI(MBB, MBBI, AVR::OUTARr)
>> > +    .addImm(0x3e)
>> > +    .addReg(SrcHiReg, getKillRegState(SrcIsKill))
>> > +    .setMIFlags(Flags);
>> > +
>> > +  buildMI(MBB, MBBI, AVR::OUTARr)
>> > +    .addImm(SREG_ADDR)
>> > +    .addReg(AVR::R0, RegState::Kill)
>> > +    .setMIFlags(Flags);
>> > +
>> > +  buildMI(MBB, MBBI, AVR::OUTARr)
>> > +    .addImm(0x3d)
>> > +    .addReg(SrcLoReg, getKillRegState(SrcIsKill))
>> > +    .setMIFlags(Flags);
>> > +
>> > +  MI.eraseFromParent();
>> > +  return true;
>> > +}
>> > +
>> > +bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
>> > +  MachineInstr &MI = *MBBI;
>> > +  int Opcode = MBBI->getOpcode();
>> > +
>> > +#define EXPAND(Op)               \
>> > +  case Op:                       \
>> > +    return expand<Op>(MBB, MI)
>> > +
>> > +  switch (Opcode) {
>> > +    EXPAND(AVR::ADDWRdRr);
>> > +    EXPAND(AVR::ADCWRdRr);
>> > +    EXPAND(AVR::SUBWRdRr);
>> > +    EXPAND(AVR::SUBIWRdK);
>> > +    EXPAND(AVR::SBCWRdRr);
>> > +    EXPAND(AVR::SBCIWRdK);
>> > +    EXPAND(AVR::ANDWRdRr);
>> > +    EXPAND(AVR::ANDIWRdK);
>> > +    EXPAND(AVR::ORWRdRr);
>> > +    EXPAND(AVR::ORIWRdK);
>> > +    EXPAND(AVR::EORWRdRr);
>> > +    EXPAND(AVR::COMWRd);
>> > +    EXPAND(AVR::CPWRdRr);
>> > +    EXPAND(AVR::CPCWRdRr);
>> > +    EXPAND(AVR::LDIWRdK);
>> > +    EXPAND(AVR::LDSWRdK);
>> > +    EXPAND(AVR::LDWRdPtr);
>> > +    EXPAND(AVR::LDWRdPtrPi);
>> > +    EXPAND(AVR::LDWRdPtrPd);
>> > +  case AVR::LDDWRdYQ: //:FIXME: remove this once PR13375 gets fixed
>> > +    EXPAND(AVR::LDDWRdPtrQ);
>> > +    EXPAND(AVR::AtomicLoad8);
>> > +    EXPAND(AVR::AtomicLoad16);
>> > +    EXPAND(AVR::AtomicStore8);
>> > +    EXPAND(AVR::AtomicStore16);
>> > +    EXPAND(AVR::AtomicLoadAdd8);
>> > +    EXPAND(AVR::AtomicLoadAdd16);
>> > +    EXPAND(AVR::AtomicLoadSub8);
>> > +    EXPAND(AVR::AtomicLoadSub16);
>> > +    EXPAND(AVR::AtomicLoadAnd8);
>> > +    EXPAND(AVR::AtomicLoadAnd16);
>> > +    EXPAND(AVR::AtomicLoadOr8);
>> > +    EXPAND(AVR::AtomicLoadOr16);
>> > +    EXPAND(AVR::AtomicLoadXor8);
>> > +    EXPAND(AVR::AtomicLoadXor16);
>> > +    EXPAND(AVR::AtomicFence);
>> > +    EXPAND(AVR::STSWKRr);
>> > +    EXPAND(AVR::STWPtrRr);
>> > +    EXPAND(AVR::STWPtrPiRr);
>> > +    EXPAND(AVR::STWPtrPdRr);
>> > +    EXPAND(AVR::STDWPtrQRr);
>> > +    EXPAND(AVR::INWRdA);
>> > +    EXPAND(AVR::OUTWARr);
>> > +    EXPAND(AVR::PUSHWRr);
>> > +    EXPAND(AVR::POPWRd);
>> > +    EXPAND(AVR::LSLWRd);
>> > +    EXPAND(AVR::LSRWRd);
>> > +    EXPAND(AVR::RORWRd);
>> > +    EXPAND(AVR::ROLWRd);
>> > +    EXPAND(AVR::ASRWRd);
>> > +    EXPAND(AVR::SEXT);
>> > +    EXPAND(AVR::ZEXT);
>> > +    EXPAND(AVR::SPREAD);
>> > +    EXPAND(AVR::SPWRITE);
>> > +  }
>> > +#undef EXPAND
>> > +  return false;
>> > +}
>> > +
>> > +namespace llvm {
>> > +
>> > +FunctionPass *createAVRExpandPseudoPass() { return new
>> > AVRExpandPseudo(); }
>> > +
>> > +} // end of namespace llvm
>> >
>> > Modified: llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp?rev=287162&r1=28
>> > 7161&r2=287162&view=diff
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp (original)
>> > +++ llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp Wed Nov 16 15:58:04
>> > 2016
>> > @@ -106,7 +106,7 @@ void AVRPassConfig::addPreRegAlloc() {
>> >    addPass(createAVRDynAllocaSRPass());
>> >  }
>> >
>> > -void AVRPassConfig::addPreSched2() { }
>> > +void AVRPassConfig::addPreSched2() {
>> > addPass(createAVRExpandPseudoPass()); }
>> >
>> >  void AVRPassConfig::addPreEmitPass() { }
>> >
>> >
>> > Modified: llvm/trunk/lib/Target/AVR/CMakeLists.txt
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/lib/Target/AVR/CMakeLists.txt?rev=287162&r1=287161&r
>> > 2=287162&view=diff
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/lib/Target/AVR/CMakeLists.txt (original)
>> > +++ llvm/trunk/lib/Target/AVR/CMakeLists.txt Wed Nov 16 15:58:04 2016
>> > @@ -18,6 +18,7 @@ add_public_tablegen_target(AVRCommonTabl
>> >
>> >  add_llvm_target(AVRCodeGen
>> >    AVRAsmPrinter.cpp
>> > +  AVRExpandPseudoInsts.cpp
>> >    AVRFrameLowering.cpp
>> >    AVRInstrInfo.cpp
>> >    AVRISelDAGToDAG.cpp
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/add.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/add.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/add.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/add.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,93 @@
>> > +; RUN: llc -mattr=addsubiw < %s -march=avr | FileCheck %s
>> > +
>> > +define i8 @add8_reg_reg(i8 %a, i8 %b) {
>> > +; CHECK-LABEL: add8_reg_reg:
>> > +; CHECK: add r24, r22
>> > +    %result = add i8 %a, %b
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i8 @add8_reg_imm(i8 %a) {
>> > +; CHECK-LABEL: add8_reg_imm:
>> > +; CHECK: subi r24, -5
>> > +    %result = add i8 %a, 5
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i8 @add8_reg_increment(i8 %a) {
>> > +; CHECK-LABEL: add8_reg_increment:
>> > +; CHECK: inc r24
>> > +    %result = add i8 %a, 1
>> > +    ret i8 %result
>> > +}
>> > +
>> > +
>> > +define i16 @add16_reg_reg(i16 %a, i16 %b) {
>> > +; CHECK-LABEL: add16_reg_reg:
>> > +; CHECK: add r24, r22
>> > +; CHECK: adc r25, r23
>> > +    %result = add i16 %a, %b
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i16 @add16_reg_imm(i16 %a) {
>> > +; CHECK-LABEL: add16_reg_imm:
>> > +; CHECK: adiw r24, 63
>> > +    %result = add i16 %a, 63
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i16 @add16_reg_imm_subi(i16 %a) {
>> > +; CHECK-LABEL: add16_reg_imm_subi:
>> > +; CHECK: subi r24, 133
>> > +; CHECK: sbci r25, 255
>> > +    %result = add i16 %a, 123
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i32 @add32_reg_reg(i32 %a, i32 %b) {
>> > +; CHECK-LABEL: add32_reg_reg:
>> > +; CHECK: add r22, r18
>> > +; CHECK: adc r23, r19
>> > +; CHECK: adc r24, r20
>> > +; CHECK: adc r25, r21
>> > +    %result = add i32 %a, %b
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i32 @add32_reg_imm(i32 %a) {
>> > +; CHECK-LABEL: add32_reg_imm:
>> > +; CHECK: subi r22, 251
>> > +; CHECK: sbci r23, 255
>> > +; CHECK: sbci r24, 255
>> > +; CHECK: sbci r25, 255
>> > +    %result = add i32 %a, 5
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i64 @add64_reg_reg(i64 %a, i64 %b) {
>> > +; CHECK-LABEL: add64_reg_reg:
>> > +; CHECK: add r18, r10
>> > +; CHECK: adc r20, r12
>> > +; CHECK: adc r21, r13
>> > +; CHECK: adc r22, r14
>> > +; CHECK: adc r23, r15
>> > +; CHECK: adc r24, r16
>> > +; CHECK: adc r25, r17
>> > +    %result = add i64 %a, %b
>> > +    ret i64 %result
>> > +}
>> > +
>> > +define i64 @add64_reg_imm(i64 %a) {
>> > +; CHECK-LABEL: add64_reg_imm:
>> > +; CHECK: subi r18, 251
>> > +; CHECK: sbci r19, 255
>> > +; CHECK: sbci r20, 255
>> > +; CHECK: sbci r21, 255
>> > +; CHECK: sbci r22, 255
>> > +; CHECK: sbci r23, 255
>> > +; CHECK: sbci r24, 255
>> > +; CHECK: sbci r25, 255
>> > +    %result = add i64 %a, 5
>> > +    ret i64 %result
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/alloca.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/alloca.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/alloca.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/alloca.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,84 @@
>> > +; RUN: llc < %s -march=avr -mattr=avr6 | FileCheck %s
>> > +
>> > +declare i16 @allocate(i16*, i16*)
>> > +
>> > +; Test taking an address of an alloca with a small offset (adiw)
>> > +define i16 @alloca_addressof_small() {
>> > +entry:
>> > +; CHECK-LABEL: alloca_addressof_small:
>> > +; Test that Y is saved
>> > +; CHECK: push r28
>> > +; CHECK: push r29
>> > +; CHECK: movw r24, r28
>> > +; CHECK: adiw r24, 17
>> > +; CHECK: movw {{.*}}, r28
>> > +; CHECK: adiw {{.*}}, 39
>> > +; CHECK: movw r22, {{.*}}
>> > +; CHECK: pop r29
>> > +; CHECK: pop r28
>> > +  %p = alloca [18 x i16]
>> > +  %k = alloca [14 x i16]
>> > +  %arrayidx = getelementptr inbounds [14 x i16], [14 x i16]* %k, i16
>> > 0, i16 8
>> > +  %arrayidx1 = getelementptr inbounds [18 x i16], [18 x i16]* %p, i16
>> > 0, i16 5
>> > +  %call = call i16 @allocate(i16* %arrayidx, i16* %arrayidx1)
>> > +  ret i16 %call
>> > +}
>> > +
>> > +; Test taking an address of an alloca with a big offset (subi/sbci
>> > pair)
>> > +define i16 @alloca_addressof_big() {
>> > +entry:
>> > +; CHECK-LABEL: alloca_addressof_big:
>> > +; CHECK: movw r24, r28
>> > +; CHECK: adiw r24, 17
>> > +; CHECK: movw r22, r28
>> > +; CHECK: subi r22, 145
>> > +; CHECK: sbci r23, 255
>> > +  %p = alloca [55 x i16]
>> > +  %k = alloca [14 x i16]
>> > +  %arrayidx = getelementptr inbounds [14 x i16], [14 x i16]* %k, i16
>> > 0, i16 8
>> > +  %arrayidx1 = getelementptr inbounds [55 x i16], [55 x i16]* %p, i16
>> > 0, i16 41
>> > +  %call = call i16 @allocate(i16* %arrayidx, i16* %arrayidx1)
>> > +  ret i16 %call
>> > +}
>> > +
>> > +; Test writing to an allocated variable with a small and a big offset
>> > +define i16 @alloca_write(i16 %x) {
>> > +entry:
>> > +; CHECK-LABEL: alloca_write:
>> > +; Big offset here
>> > +; CHECK: adiw r28, 57
>> > +; CHECK: std Y+62, {{.*}}
>> > +; CHECK: std Y+63, {{.*}}
>> > +; CHECK: sbiw r28, 57
>> > +; Small offset here
>> > +; CHECK: std Y+23, {{.*}}
>> > +; CHECK: std Y+24, {{.*}}
>> > +  %p = alloca [15 x i16]
>> > +  %k = alloca [14 x i16]
>> > +  %arrayidx = getelementptr inbounds [15 x i16], [15 x i16]* %p, i16
>> > 0, i16 45
>> > +  store i16 22, i16* %arrayidx
>> > +  %arrayidx1 = getelementptr inbounds [14 x i16], [14 x i16]* %k, i16
>> > 0, i16 11
>> > +  store i16 42, i16* %arrayidx1
>> > +  %arrayidx2 = getelementptr inbounds [14 x i16], [14 x i16]* %k, i16
>> > 0, i16 0
>> > +  %arrayidx3 = getelementptr inbounds [15 x i16], [15 x i16]* %p, i16
>> > 0, i16 0
>> > +  %call = call i16 @allocate(i16* %arrayidx2, i16* %arrayidx3)
>> > +  ret i16 %call
>> > +}
>> > +
>> > +; Test writing to an allocated variable with a huge offset that cant
>> > be
>> > +; materialized with adiw/sbiw but with a subi/sbci pair.
>> > +define void @alloca_write_huge() {
>> > +; CHECK-LABEL: alloca_write_huge:
>> > +; CHECK: subi r28, 41
>> > +; CHECK: sbci r29, 255
>> > +; CHECK: std Y+62, {{.*}}
>> > +; CHECK: std Y+63, {{.*}}
>> > +; CHECK: subi r28, 215
>> > +; CHECK: sbci r29, 0
>> > +  %k = alloca [140 x i16]
>> > +  %arrayidx = getelementptr inbounds [140 x i16], [140 x i16]* %k, i16
>> > 0, i16 138
>> > +  store i16 22, i16* %arrayidx
>> > +  %arraydecay = getelementptr inbounds [140 x i16], [140 x i16]* %k,
>> > i16 0, i16 0
>> > +  call i16 @allocate(i16* %arraydecay, i16* null)
>> > +  ret void
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/and.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/and.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/and.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/and.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,80 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +define i8 @and8_reg_reg(i8 %a, i8 %b) {
>> > +; CHECK-LABEL: and8_reg_reg:
>> > +; CHECK: and r24, r22
>> > +    %result = and i8 %a, %b
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i8 @and8_reg_imm(i8 %a) {
>> > +; CHECK-LABEL: and8_reg_imm:
>> > +; CHECK: andi r24, 5
>> > +    %result = and i8 %a, 5
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i16 @and16_reg_reg(i16 %a, i16 %b) {
>> > +; CHECK-LABEL: and16_reg_reg:
>> > +; CHECK: and r24, r22
>> > +; CHECK: and r25, r23
>> > +    %result = and i16 %a, %b
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i16 @and16_reg_imm(i16 %a) {
>> > +; CHECK-LABEL: and16_reg_imm:
>> > +; CHECK: andi r24, 210
>> > +; CHECK: andi r25, 4
>> > +    %result = and i16 %a, 1234
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i32 @and32_reg_reg(i32 %a, i32 %b) {
>> > +; CHECK-LABEL: and32_reg_reg:
>> > +; CHECK: and r22, r18
>> > +; CHECK: and r23, r19
>> > +; CHECK: and r24, r20
>> > +; CHECK: and r25, r21
>> > +    %result = and i32 %a, %b
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i32 @and32_reg_imm(i32 %a) {
>> > +; CHECK-LABEL: and32_reg_imm:
>> > +; CHECK: andi r22, 21
>> > +; CHECK: andi r23, 205
>> > +; CHECK: andi r24, 91
>> > +; CHECK: andi r25, 7
>> > +    %result = and i32 %a, 123456789
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i64 @and64_reg_reg(i64 %a, i64 %b) {
>> > +; CHECK-LABEL: and64_reg_reg:
>> > +; CHECK: and r18, r10
>> > +; CHECK: and r19, r11
>> > +; CHECK: and r20, r12
>> > +; CHECK: and r21, r13
>> > +; CHECK: and r22, r14
>> > +; CHECK: and r23, r15
>> > +; CHECK: and r24, r16
>> > +; CHECK: and r25, r17
>> > +    %result = and i64 %a, %b
>> > +    ret i64 %result
>> > +}
>> > +
>> > +define i64 @and64_reg_imm(i64 %a) {
>> > +; CHECK-LABEL: and64_reg_imm:
>> > +; CHECK: andi r18, 253
>> > +; CHECK: andi r19, 255
>> > +; CHECK: andi r20, 155
>> > +; CHECK: andi r21, 88
>> > +; CHECK: andi r22, 76
>> > +; CHECK: andi r23, 73
>> > +; CHECK: andi r24, 31
>> > +; CHECK: andi r25, 242
>> > +    %result = and i64 %a, 17446744073709551613
>> > +    ret i64 %result
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/atomics/fence.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/atomics/fence.ll?rev=287162&view=au
>> > to
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/atomics/fence.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/atomics/fence.ll Wed Nov 16 15:58:04
>> > 2016
>> > @@ -0,0 +1,13 @@
>> > +; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
>> > +
>> > +; Checks that atomic fences are simply removed from IR.
>> > +; AVR is always singlethreaded so fences do nothing.
>> > +
>> > +; CHECK_LABEL: atomic_fence8
>> > +; CHECK:      ; BB#0:
>> > +; CHECK-NEXT:   ret
>> > +define void @atomic_fence8() {
>> > +  fence acquire
>> > +  ret void
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/atomics/load16.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/atomics/load16.ll?rev=287162&view=a
>> > uto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/atomics/load16.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/atomics/load16.ll Wed Nov 16 15:58:04
>> > 2016
>> > @@ -0,0 +1,137 @@
>> > +; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
>> > +
>> > +; CHECK-LABEL: atomic_load16
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]
>> > +; CHECK-NEXT: ldd [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]+
>> > +; CHECK-NEXT: out 63, r0
>> > +define i16 @atomic_load16(i16* %foo) {
>> > +  %val = load atomic i16, i16* %foo unordered, align 2
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_swap16
>> > +; CHECK: call __sync_lock_test_and_set_2
>> > +define i16 @atomic_load_swap16(i16* %foo) {
>> > +  %val = atomicrmw xchg i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_cmp_swap16
>> > +; CHECK: call __sync_val_compare_and_swap_2
>> > +define i16 @atomic_load_cmp_swap16(i16* %foo) {
>> > +  %val = cmpxchg i16* %foo, i16 5, i16 10 acq_rel monotonic
>> > +  %value_loaded = extractvalue { i16, i1 } %val, 0
>> > +  ret i16 %value_loaded
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_add16
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
>> > +; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
>> > +; CHECK-NEXT: add [[RR1]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: adc [[RR2]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RD1]], [[RR1]]
>> > +; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i16 @atomic_load_add16(i16* %foo) {
>> > +  %val = atomicrmw add i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_sub16
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
>> > +; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
>> > +; CHECK-NEXT: sub [[RR1]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: sbc [[RR2]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RD1]], [[RR1]]
>> > +; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i16 @atomic_load_sub16(i16* %foo) {
>> > +  %val = atomicrmw sub i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_and16
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
>> > +; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
>> > +; CHECK-NEXT: and [[RR1]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: and [[RR2]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RD1]], [[RR1]]
>> > +; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i16 @atomic_load_and16(i16* %foo) {
>> > +  %val = atomicrmw and i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_or16
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
>> > +; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
>> > +; CHECK-NEXT: or [[RR1]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: or [[RR2]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RD1]], [[RR1]]
>> > +; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i16 @atomic_load_or16(i16* %foo) {
>> > +  %val = atomicrmw or i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_xor16
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
>> > +; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
>> > +; CHECK-NEXT: eor [[RR1]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: eor [[RR2]], [[TMP:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RD1]], [[RR1]]
>> > +; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i16 @atomic_load_xor16(i16* %foo) {
>> > +  %val = atomicrmw xor i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_nand16
>> > +; CHECK: call __sync_fetch_and_nand_2
>> > +define i16 @atomic_load_nand16(i16* %foo) {
>> > +  %val = atomicrmw nand i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_max16
>> > +; CHECK: call __sync_fetch_and_max_2
>> > +define i16 @atomic_load_max16(i16* %foo) {
>> > +  %val = atomicrmw max i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_min16
>> > +; CHECK: call __sync_fetch_and_min_2
>> > +define i16 @atomic_load_min16(i16* %foo) {
>> > +  %val = atomicrmw min i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_umax16
>> > +; CHECK: call __sync_fetch_and_umax_2
>> > +define i16 @atomic_load_umax16(i16* %foo) {
>> > +  %val = atomicrmw umax i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_umin16
>> > +; CHECK: call __sync_fetch_and_umin_2
>> > +define i16 @atomic_load_umin16(i16* %foo) {
>> > +  %val = atomicrmw umin i16* %foo, i16 13 seq_cst
>> > +  ret i16 %val
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/atomics/load8.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/atomics/load8.ll?rev=287162&view=au
>> > to
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/atomics/load8.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/atomics/load8.ll Wed Nov 16 15:58:04
>> > 2016
>> > @@ -0,0 +1,124 @@
>> > +; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
>> > +
>> > +; Tests atomic operations on AVR
>> > +
>> > +; CHECK-LABEL: atomic_load8
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i8 @atomic_load8(i8* %foo) {
>> > +  %val = load atomic i8, i8* %foo unordered, align 1
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_swap8
>> > +; CHECK: call __sync_lock_test_and_set_1
>> > +define i8 @atomic_load_swap8(i8* %foo) {
>> > +  %val = atomicrmw xchg i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_cmp_swap8
>> > +; CHECK: call __sync_val_compare_and_swap_1
>> > +define i8 @atomic_load_cmp_swap8(i8* %foo) {
>> > +  %val = cmpxchg i8* %foo, i8 5, i8 10 acq_rel monotonic
>> > +  %value_loaded = extractvalue { i8, i1 } %val, 0
>> > +  ret i8 %value_loaded
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_add8
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
>> > +; CHECK-NEXT: add [[RD]], [[RR1:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RR]], [[RD]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i8 @atomic_load_add8(i8* %foo) {
>> > +  %val = atomicrmw add i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_sub8
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
>> > +; CHECK-NEXT: sub [[RD]], [[RR1:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RR]], [[RD]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i8 @atomic_load_sub8(i8* %foo) {
>> > +  %val = atomicrmw sub i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_and8
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
>> > +; CHECK-NEXT: and [[RD]], [[RR1:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RR]], [[RD]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i8 @atomic_load_and8(i8* %foo) {
>> > +  %val = atomicrmw and i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_or8
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
>> > +; CHECK-NEXT: or [[RD]], [[RR1:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RR]], [[RD]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i8 @atomic_load_or8(i8* %foo) {
>> > +  %val = atomicrmw or i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_xor8
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
>> > +; CHECK-NEXT: eor [[RD]], [[RR1:r[0-9]+]]
>> > +; CHECK-NEXT: st [[RR]], [[RD]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define i8 @atomic_load_xor8(i8* %foo) {
>> > +  %val = atomicrmw xor i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_nand8
>> > +; CHECK: call __sync_fetch_and_nand_1
>> > +define i8 @atomic_load_nand8(i8* %foo) {
>> > +  %val = atomicrmw nand i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_max8
>> > +; CHECK: call __sync_fetch_and_max_1
>> > +define i8 @atomic_load_max8(i8* %foo) {
>> > +  %val = atomicrmw max i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_min8
>> > +; CHECK: call __sync_fetch_and_min_1
>> > +define i8 @atomic_load_min8(i8* %foo) {
>> > +  %val = atomicrmw min i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_umax8
>> > +; CHECK: call __sync_fetch_and_umax_1
>> > +define i8 @atomic_load_umax8(i8* %foo) {
>> > +  %val = atomicrmw umax i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_load_umin8
>> > +; CHECK: call __sync_fetch_and_umin_1
>> > +define i8 @atomic_load_umin8(i8* %foo) {
>> > +  %val = atomicrmw umin i8* %foo, i8 13 seq_cst
>> > +  ret i8 %val
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/atomics/store.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/atomics/store.ll?rev=287162&view=au
>> > to
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/atomics/store.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/atomics/store.ll Wed Nov 16 15:58:04
>> > 2016
>> > @@ -0,0 +1,37 @@
>> > +; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
>> > +
>> > +; CHECK-LABEL: atomic_store8
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: st [[RD:(X|Y|Z)]], [[RR:r[0-9]+]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define void @atomic_store8(i8* %foo) {
>> > +  store atomic i8 1, i8* %foo unordered, align 1
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_store16
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: st [[RD:(X|Y|Z)]], [[RR:r[0-9]+]]
>> > +; CHECK-NEXT: std [[RD]]+1, [[RR:r[0-9]+]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define void @atomic_store16(i16* %foo) {
>> > +  store atomic i16 1, i16* %foo unordered, align 2
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_store32
>> > +; CHECK: call __sync_lock_test_and_set_4
>> > +define void @atomic_store32(i32* %foo) {
>> > +  store atomic i32 1, i32* %foo unordered, align 4
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: atomic_store64
>> > +; CHECK: call __sync_lock_test_and_set_8
>> > +define void @atomic_store64(i64* %foo) {
>> > +  store atomic i64 1, i64* %foo unordered, align 8
>> > +  ret void
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/atomics/store16.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/atomics/store16.ll?rev=287162&view=
>> > auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/atomics/store16.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/atomics/store16.ll Wed Nov 16 15:58:04
>> > 2016
>> > @@ -0,0 +1,25 @@
>> > +; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
>> > +
>> > +; CHECK-LABEL: atomic_store16
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: st [[RD:(X|Y|Z)]], [[RR:r[0-9]+]]
>> > +; CHECK-NEXT: std [[RD:(X|Y|Z)]]+1, [[RR:r[0-9]+]]
>> > +; CHECK-NEXT: out 63, r0
>> > +define void @atomic_store16(i16* %foo) {
>> > +  store atomic i16 1, i16* %foo unordered, align 2
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: monotonic
>> > +; CHECK:      in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: st Z, r24
>> > +; CHECK-NEXT: std Z+1, r25
>> > +; CHECK-NEXT: out 63, r0
>> > +define void @monotonic(i16) {
>> > +entry-block:
>> > +  store atomic i16 %0, i16* undef monotonic, align 2
>> > +  ret void
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/brind.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/brind.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/brind.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/brind.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,20 @@
>> > +; RUN: llc -mattr=sram,eijmpcall < %s -march=avr | FileCheck %s
>> > +
>> > + at brind.k = private unnamed_addr constant [2 x i8*] [i8*
>> > blockaddress(@brind, %return), i8* blockaddress(@brind, %b)], align 1
>> > +
>> > +define i8 @brind(i8 %p) {
>> > +; CHECK-LABEL: brind:
>> > +; CHECK: ld r30
>> > +; CHECK: ldd r31
>> > +; CHECK: ijmp
>> > +entry:
>> > +  %idxprom = sext i8 %p to i16
>> > +  %arrayidx = getelementptr inbounds [2 x i8*], [2 x i8*]* @brind.k,
>> > i16 0, i16 %idxprom
>> > +  %s = load i8*, i8** %arrayidx
>> > +  indirectbr i8* %s, [label %return, label %b]
>> > +b:
>> > +  br label %return
>> > +return:
>> > +  %retval.0 = phi i8 [ 4, %b ], [ 2, %entry ]
>> > +  ret i8 %retval.0
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/call.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/call.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/call.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/call.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,211 @@
>> > +; RUN: llc < %s -march=avr -mattr=avr6 | FileCheck %s
>> > +
>> > +; TODO: test returning byval structs
>> > +
>> > +declare i8 @foo8_1(i8)
>> > +declare i8 @foo8_2(i8, i8, i8)
>> > +declare i8 @foo8_3(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8)
>> > +
>> > +declare i16 @foo16_1(i16, i16)
>> > +declare i16 @foo16_2(i16, i16, i16, i16, i16, i16, i16, i16, i16, i16,
>> > i16)
>> > +
>> > +declare i32 @foo32_1(i32, i32)
>> > +declare i32 @foo32_2(i32, i32, i32, i32, i32)
>> > +
>> > +declare i64 @foo64_1(i64)
>> > +declare i64 @foo64_2(i64, i64, i64)
>> > +
>> > +define i8 @calli8_reg() {
>> > +; CHECK-LABEL: calli8_reg:
>> > +; CHECK: ldi r24, 12
>> > +; CHECK: call foo8_1
>> > +; CHECK: ldi r24, 12
>> > +; CHECK: ldi r22, 13
>> > +; CHECK: ldi r20, 14
>> > +; CHECK: call foo8_2
>> > +    %result1 = call i8 @foo8_1(i8 12)
>> > +    %result2 = call i8 @foo8_2(i8 12, i8 13, i8 14)
>> > +    ret i8 %result2
>> > +}
>> > +
>> > +define i8 @calli8_stack() {
>> > +; CHECK-LABEL: calli8_stack:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 11
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: ldi [[REG1]], 10
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: call foo8_3
>> > +    %result1 = call i8 @foo8_3(i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8
>> > 7, i8 8, i8 9, i8 10, i8 11)
>> > +    ret i8 %result1
>> > +}
>> > +
>> > +define i16 @calli16_reg() {
>> > +; CHECK-LABEL: calli16_reg:
>> > +; CHECK: ldi r24, 1
>> > +; CHECK: ldi r25, 2
>> > +; CHECK: ldi r22, 2
>> > +; CHECK: ldi r23, 2
>> > +; CHECK: call foo16_1
>> > +    %result1 = call i16 @foo16_1(i16 513, i16 514)
>> > +    ret i16 %result1
>> > +}
>> > +
>> > +define i16 @calli16_stack() {
>> > +; CHECK-LABEL: calli16_stack:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 10
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 2
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 9
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 2
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: call foo16_2
>> > +    %result1 = call i16 @foo16_2(i16 512, i16 513, i16 514, i16 515,
>> > i16 516, i16 517, i16 518, i16 519, i16 520, i16 521, i16 522)
>> > +    ret i16 %result1
>> > +}
>> > +
>> > +define i32 @calli32_reg() {
>> > +; CHECK-LABEL: calli32_reg:
>> > +; CHECK: ldi r22, 64
>> > +; CHECK: ldi r23, 66
>> > +; CHECK: ldi r24, 15
>> > +; CHECK: ldi r25, 2
>> > +; CHECK: ldi r18, 128
>> > +; CHECK: ldi r19, 132
>> > +; CHECK: ldi r20, 30
>> > +; CHECK: ldi r21, 2
>> > +; CHECK: call foo32_1
>> > +    %result1 = call i32 @foo32_1(i32 34554432, i32 35554432)
>> > +    ret i32 %result1
>> > +}
>> > +
>> > +define i32 @calli32_stack() {
>> > +; CHECK-LABEL: calli32_stack:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 15
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 2
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 64
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 66
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: call foo32_2
>> > +    %result1 = call i32 @foo32_2(i32 1, i32 2, i32 3, i32 4, i32
>> > 34554432)
>> > +    ret i32 %result1
>> > +}
>> > +
>> > +define i64 @calli64_reg() {
>> > +; CHECK-LABEL: calli64_reg:
>> > +; CHECK: ldi r18, 255
>> > +; CHECK: ldi r19, 255
>> > +; CHECK: ldi r20, 155
>> > +; CHECK: ldi r21, 88
>> > +; CHECK: ldi r22, 76
>> > +; CHECK: ldi r23, 73
>> > +; CHECK: ldi r24, 31
>> > +; CHECK: ldi r25, 242
>> > +; CHECK: call foo64_1
>> > +    %result1 = call i64 @foo64_1(i64 17446744073709551615)
>> > +    ret i64 %result1
>> > +}
>> > +
>> > +define i64 @calli64_stack() {
>> > +; CHECK-LABEL: calli64_stack:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 31
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 242
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 76
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 73
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 155
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 88
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 255
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 255
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: call foo64_2
>> > +    %result1 = call i64 @foo64_2(i64 1, i64 2, i64
>> > 17446744073709551615)
>> > +    ret i64 %result1
>> > +}
>> > +
>> > +; Test passing arguments through the stack when the call frame is
>> > allocated
>> > +; in the prologue.
>> > +declare void @foo64_3(i64, i64, i64, i8, i16*)
>> > +
>> > +define void @testcallprologue() {
>> > +; CHECK-LABEL: testcallprologue:
>> > +; CHECK: push r28
>> > +; CHECK: push r29
>> > +; CHECK: sbiw r28, 28
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 88
>> > +; CHECK: std Y+9, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 11
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 10
>> > +; CHECK: std Y+7, [[REG1]]
>> > +; CHECK: std Y+8, [[REG2]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 13
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 12
>> > +; CHECK: std Y+5, [[REG1]]
>> > +; CHECK: std Y+6, [[REG2]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 15
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 14
>> > +; CHECK: std Y+3, [[REG1]]
>> > +; CHECK: std Y+4, [[REG2]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 8
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 9
>> > +; CHECK: std Y+1, [[REG1]]
>> > +; CHECK: std Y+2, [[REG2]]
>> > +; CHECK: pop r29
>> > +; CHECK: pop r28
>> > +  %p = alloca [8 x i16]
>> > +  %arraydecay = getelementptr inbounds [8 x i16], [8 x i16]* %p, i16
>> > 0, i16 0
>> > +  call void @foo64_3(i64 723685415333071112, i64 723685415333071112,
>> > i64 723685415333071112, i8 88, i16* %arraydecay)
>> > +  ret void
>> > +}
>> > +
>> > +define i32 @icall(i32 (i32)* %foo) {
>> > +; CHECK-LABEL: icall:
>> > +; CHECK: movw [[REG:r[0-9]+]], r24
>> > +; CHECK: ldi r22, 147
>> > +; CHECK: ldi r23, 248
>> > +; CHECK: ldi r24, 214
>> > +; CHECK: ldi r25, 198
>> > +; CHECK: movw r30, [[REG]]
>> > +; CHECK: icall
>> > +; CHECK: subi r22, 251
>> > +; CHECK: sbci r23, 255
>> > +; CHECK: sbci r24, 255
>> > +; CHECK: sbci r25, 255
>> > +  %1 = call i32 %foo(i32 3335977107)
>> > +  %2 = add nsw i32 %1, 5
>> > +  ret i32 %2
>> > +}
>> > +
>> > +; Calling external functions (like __divsf3) require extra processing
>> > for
>> > +; arguments and return values in the LowerCall function.
>> > +declare i32 @foofloat(float)
>> > +
>> > +define i32 @externcall(float %a, float %b) {
>> > +; CHECK-LABEL: externcall:
>> > +; CHECK: movw [[REG1:(r[0-9]+|[XYZ])]], r24
>> > +; CHECK: movw [[REG2:(r[0-9]+|[XYZ])]], r22
>> > +; CHECK: movw r22, r18
>> > +; CHECK: movw r24, r20
>> > +; CHECK: movw r18, [[REG2]]
>> > +; CHECK: movw r20, [[REG1]]
>> > +; CHECK: call __divsf3
>> > +; CHECK: call foofloat
>> > +; CHECK: subi r22, 251
>> > +; CHECK: sbci r23, 255
>> > +; CHECK: sbci r24, 255
>> > +; CHECK: sbci r25, 255
>> > +  %1 = fdiv float %b, %a
>> > +  %2 = call i32 @foofloat(float %1)
>> > +  %3 = add nsw i32 %2, 5
>> > +  ret i32 %3
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/cmp.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/cmp.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/cmp.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/cmp.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,148 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +declare void @f1(i8)
>> > +declare void @f2(i8)
>> > +define void @cmp8(i8 %a, i8 %b) {
>> > +; CHECK-LABEL: cmp8:
>> > +; CHECK: cp
>> > +; CHECK-NOT: cpc
>> > +  %cmp = icmp eq i8 %a, %b
>> > +  br i1 %cmp, label %if.then, label %if.else
>> > +if.then:
>> > +  tail call void @f1(i8 %a)
>> > +  br label %if.end
>> > +if.else:
>> > +  tail call void @f2(i8 %b)
>> > +  br label %if.end
>> > +if.end:
>> > +  ret void
>> > +}
>> > +
>> > +declare void @f3(i16)
>> > +declare void @f4(i16)
>> > +define void @cmp16(i16 %a, i16 %b) {
>> > +; CHECK-LABEL: cmp16:
>> > +; CHECK: cp
>> > +; CHECK-NEXT: cpc
>> > +  %cmp = icmp eq i16 %a, %b
>> > +  br i1 %cmp, label %if.then, label %if.else
>> > +if.then:
>> > +  tail call void @f3(i16 %a)
>> > +  br label %if.end
>> > +if.else:
>> > +  tail call void @f4(i16 %b)
>> > +  br label %if.end
>> > +if.end:
>> > +  ret void
>> > +}
>> > +
>> > +declare void @f5(i32)
>> > +declare void @f6(i32)
>> > +define void @cmp32(i32 %a, i32 %b) {
>> > +; CHECK-LABEL: cmp32:
>> > +; CHECK: cp
>> > +; CHECK-NEXT: cpc
>> > +; CHECK-NEXT: cpc
>> > +; CHECK-NEXT: cpc
>> > +  %cmp = icmp eq i32 %a, %b
>> > +  br i1 %cmp, label %if.then, label %if.else
>> > +if.then:
>> > +  tail call void @f5(i32 %a)
>> > +  br label %if.end
>> > +if.else:
>> > +  tail call void @f6(i32 %b)
>> > +  br label %if.end
>> > +if.end:
>> > +  ret void
>> > +}
>> > +
>> > +declare void @f7(i64)
>> > +declare void @f8(i64)
>> > +define void @cmp64(i64 %a, i64 %b) {
>> > +; CHECK-LABEL: cmp64:
>> > +; CHECK: cp
>> > +; CHECK-NEXT: cpc
>> > +; CHECK-NEXT: cpc
>> > +; CHECK-NEXT: cpc
>> > +; CHECK-NEXT: cpc
>> > +; CHECK-NEXT: cpc
>> > +; CHECK-NEXT: cpc
>> > +; CHECK-NEXT: cpc
>> > +  %cmp = icmp eq i64 %a, %b
>> > +  br i1 %cmp, label %if.then, label %if.else
>> > +if.then:
>> > +  tail call void @f7(i64 %a)
>> > +  br label %if.end
>> > +if.else:
>> > +  tail call void @f8(i64 %b)
>> > +  br label %if.end
>> > +if.end:
>> > +  ret void
>> > +}
>> > +
>> > +declare void @f9()
>> > +declare void @f10()
>> > +
>> > +define void @tst8(i8 %a) {
>> > +; CHECK-LABEL: tst8:
>> > +; CHECK: tst r24
>> > +; CHECK-NEXT: brmi
>> > +  %cmp = icmp sgt i8 %a, -1
>> > +  br i1 %cmp, label %if.then, label %if.else
>> > +if.then:
>> > +  tail call void @f9()
>> > +  br label %if.end
>> > +if.else:
>> > +  tail call void @f10()
>> > +  br label %if.end
>> > +if.end:
>> > +  ret void
>> > +}
>> > +
>> > +define void @tst16(i16 %a) {
>> > +; CHECK-LABEL: tst16:
>> > +; CHECK: tst r25
>> > +; CHECK-NEXT: brmi
>> > +  %cmp = icmp sgt i16 %a, -1
>> > +  br i1 %cmp, label %if.then, label %if.else
>> > +if.then:
>> > +  tail call void @f9()
>> > +  br label %if.end
>> > +if.else:
>> > +  tail call void @f10()
>> > +  br label %if.end
>> > +if.end:
>> > +  ret void
>> > +}
>> > +
>> > +define void @tst32(i32 %a) {
>> > +; CHECK-LABEL: tst32:
>> > +; CHECK: tst r25
>> > +; CHECK-NEXT: brmi
>> > +  %cmp = icmp sgt i32 %a, -1
>> > +  br i1 %cmp, label %if.then, label %if.else
>> > +if.then:
>> > +  tail call void @f9()
>> > +  br label %if.end
>> > +if.else:
>> > +  tail call void @f10()
>> > +  br label %if.end
>> > +if.end:
>> > +  ret void
>> > +}
>> > +
>> > +define void @tst64(i64 %a) {
>> > +; CHECK-LABEL: tst64:
>> > +; CHECK: tst r25
>> > +; CHECK-NEXT: brmi
>> > +  %cmp = icmp sgt i64 %a, -1
>> > +  br i1 %cmp, label %if.then, label %if.else
>> > +if.then:
>> > +  tail call void @f9()
>> > +  br label %if.end
>> > +if.else:
>> > +  tail call void @f10()
>> > +  br label %if.end
>> > +if.end:
>> > +  ret void
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/com.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/com.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/com.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/com.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,40 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +define i8 @com8(i8 %x) {
>> > +; CHECK-LABEL: com8:
>> > +; CHECK: com r24
>> > +  %neg = xor i8 %x, -1
>> > +  ret i8 %neg
>> > +}
>> > +
>> > +define i16 @com16(i16 %x) {
>> > +; CHECK-LABEL: com16:
>> > +; CHECK: com r24
>> > +; CHECK: com r25
>> > +  %neg = xor i16 %x, -1
>> > +  ret i16 %neg
>> > +}
>> > +
>> > +define i32 @com32(i32 %x) {
>> > +; CHECK-LABEL: com32:
>> > +; CHECK: com r22
>> > +; CHECK: com r23
>> > +; CHECK: com r24
>> > +; CHECK: com r25
>> > +  %neg = xor i32 %x, -1
>> > +  ret i32 %neg
>> > +}
>> > +
>> > +define i64 @com64(i64 %x) {
>> > +; CHECK-LABEL: com64:
>> > +; CHECK: com r18
>> > +; CHECK: com r19
>> > +; CHECK: com r20
>> > +; CHECK: com r21
>> > +; CHECK: com r22
>> > +; CHECK: com r23
>> > +; CHECK: com r24
>> > +; CHECK: com r25
>> > +  %neg = xor i64 %x, -1
>> > +  ret i64 %neg
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/directmem.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/directmem.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/directmem.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/directmem.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,345 @@
>> > +; RUN: llc -mattr=sram,addsubiw < %s -march=avr | FileCheck %s
>> > +
>> > + at char = common global i8 0
>> > + at char.array = common global [3 x i8] zeroinitializer
>> > + at char.static = internal global i8 0
>> > +
>> > + at int = common global i16 0
>> > + at int.array = common global [3 x i16] zeroinitializer
>> > + at int.static = internal global i16 0
>> > +
>> > + at long = common global i32 0
>> > + at long.array = common global [3 x i32] zeroinitializer
>> > + at long.static = internal global i32 0
>> > +
>> > + at longlong = common global i64 0
>> > + at longlong.array = common global [3 x i64] zeroinitializer
>> > + at longlong.static = internal global i64 0
>> > +
>> > +define void @global8_store() {
>> > +; CHECK-LABEL: global8_store:
>> > +; CHECK: ldi [[REG:r[0-9]+]], 6
>> > +; CHECK: sts char, [[REG]]
>> > +  store i8 6, i8* @char
>> > +  ret void
>> > +}
>> > +
>> > +define i8 @global8_load() {
>> > +; CHECK-LABEL: global8_load:
>> > +; CHECK: lds r24, char
>> > +  %result = load i8, i8* @char
>> > +  ret i8 %result
>> > +}
>> > +
>> > +define void @array8_store() {
>> > +; CHECK-LABEL: array8_store:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 1
>> > +; CHECK: sts char.array, [[REG1]]
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 2
>> > +; CHECK: sts char.array+1, [[REG2]]
>> > +; CHECK: ldi [[REG:r[0-9]+]], 3
>> > +; CHECK: sts char.array+2, [[REG]]
>> > +  store i8 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]*
>> > @char.array, i32 0, i64 0)
>> > +  store i8 2, i8* getelementptr inbounds ([3 x i8], [3 x i8]*
>> > @char.array, i32 0, i64 1)
>> > +  store i8 3, i8* getelementptr inbounds ([3 x i8], [3 x i8]*
>> > @char.array, i32 0, i64 2)
>> > +  ret void
>> > +}
>> > +
>> > +define i8 @array8_load() {
>> > +; CHECK-LABEL: array8_load:
>> > +; CHECK: lds r24, char.array+2
>> > +  %result = load i8, i8* getelementptr inbounds ([3 x i8], [3 x i8]*
>> > @char.array, i32 0, i64 2)
>> > +  ret i8 %result
>> > +}
>> > +
>> > +define i8 @static8_inc() {
>> > +; CHECK-LABEL: static8_inc:
>> > +; CHECK: lds r24, char.static
>> > +; CHECK: inc r24
>> > +; CHECK: sts char.static, r24
>> > +  %1 = load i8, i8* @char.static
>> > +  %inc = add nsw i8 %1, 1
>> > +  store i8 %inc, i8* @char.static
>> > +  ret i8 %inc
>> > +}
>> > +
>> > +define void @global16_store() {
>> > +; CHECK-LABEL: global16_store:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 187
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 170
>> > +; CHECK: sts int+1, [[REG2]]
>> > +; CHECK: sts int, [[REG1]]
>> > +  store i16 43707, i16* @int
>> > +  ret void
>> > +}
>> > +
>> > +define i16 @global16_load() {
>> > +; CHECK-LABEL: global16_load:
>> > +; CHECK: lds r24, int
>> > +; CHECK: lds r25, int+1
>> > +  %result = load i16, i16* @int
>> > +  ret i16 %result
>> > +}
>> > +
>> > +define void @array16_store() {
>> > +; CHECK-LABEL: array16_store:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 187
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 170
>> > +; CHECK: sts int.array+1, [[REG2]]
>> > +; CHECK: sts int.array, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 204
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 170
>> > +; CHECK: sts int.array+3, [[REG2]]
>> > +; CHECK: sts int.array+2, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 221
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 170
>> > +; CHECK: sts int.array+5, [[REG2]]
>> > +; CHECK: sts int.array+4, [[REG1]]
>> > +  store i16 43707, i16* getelementptr inbounds ([3 x i16], [3 x i16]*
>> > @int.array, i32 0, i64 0)
>> > +  store i16 43724, i16* getelementptr inbounds ([3 x i16], [3 x i16]*
>> > @int.array, i32 0, i64 1)
>> > +  store i16 43741, i16* getelementptr inbounds ([3 x i16], [3 x i16]*
>> > @int.array, i32 0, i64 2)
>> > +  ret void
>> > +}
>> > +
>> > +define i16 @array16_load() {
>> > +; CHECK-LABEL: array16_load:
>> > +; CHECK: lds r24, int.array+4
>> > +; CHECK: lds r25, int.array+5
>> > +  %result = load i16, i16* getelementptr inbounds ([3 x i16], [3 x
>> > i16]* @int.array, i32 0, i64 2)
>> > +  ret i16 %result
>> > +}
>> > +
>> > +define i16 @static16_inc() {
>> > +; CHECK-LABEL: static16_inc:
>> > +; CHECK: lds r24, int.static
>> > +; CHECK: lds r25, int.static+1
>> > +; CHECK: adiw r24, 1
>> > +; CHECK: sts int.static+1, r25
>> > +; CHECK: sts int.static, r24
>> > +  %1 = load i16, i16* @int.static
>> > +  %inc = add nsw i16 %1, 1
>> > +  store i16 %inc, i16* @int.static
>> > +  ret i16 %inc
>> > +}
>> > +
>> > +define void @global32_store() {
>> > +; CHECK-LABEL: global32_store:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 187
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 170
>> > +; CHECK: sts long+3, [[REG2]]
>> > +; CHECK: sts long+2, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 221
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 204
>> > +; CHECK: sts long+1, [[REG2]]
>> > +; CHECK: sts long, [[REG1]]
>> > +  store i32 2864434397, i32* @long
>> > +  ret void
>> > +}
>> > +
>> > +define i32 @global32_load() {
>> > +; CHECK-LABEL: global32_load:
>> > +; CHECK: lds r22, long
>> > +; CHECK: lds r23, long+1
>> > +; CHECK: lds r24, long+2
>> > +; CHECK: lds r25, long+3
>> > +  %result = load i32, i32* @long
>> > +  ret i32 %result
>> > +}
>> > +
>> > +define void @array32_store() {
>> > +; CHECK-LABEL: array32_store:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 27
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 172
>> > +; CHECK: sts long.array+3, [[REG2]]
>> > +; CHECK: sts long.array+2, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 68
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 13
>> > +; CHECK: sts long.array+1, [[REG2]]
>> > +; CHECK: sts long.array, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 102
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 85
>> > +; CHECK: sts long.array+7, [[REG2]]
>> > +; CHECK: sts long.array+6, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 136
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 119
>> > +; CHECK: sts long.array+5, [[REG2]]
>> > +; CHECK: sts long.array+4, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 170
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 153
>> > +; CHECK: sts long.array+11, [[REG2]]
>> > +; CHECK: sts long.array+10, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 204
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 187
>> > +; CHECK: sts long.array+9, [[REG2]]
>> > +; CHECK: sts long.array+8, [[REG1]]
>> > +  store i32 2887454020, i32* getelementptr inbounds ([3 x i32], [3 x
>> > i32]* @long.array, i32 0, i64 0)
>> > +  store i32 1432778632, i32* getelementptr inbounds ([3 x i32], [3 x
>> > i32]* @long.array, i32 0, i64 1)
>> > +  store i32 2578103244, i32* getelementptr inbounds ([3 x i32], [3 x
>> > i32]* @long.array, i32 0, i64 2)
>> > +  ret void
>> > +}
>> > +
>> > +define i32 @array32_load() {
>> > +; CHECK-LABEL: array32_load:
>> > +; CHECK: lds r22, long.array+8
>> > +; CHECK: lds r23, long.array+9
>> > +; CHECK: lds r24, long.array+10
>> > +; CHECK: lds r25, long.array+11
>> > +  %result = load i32, i32* getelementptr inbounds ([3 x i32], [3 x
>> > i32]* @long.array, i32 0, i64 2)
>> > +  ret i32 %result
>> > +}
>> > +
>> > +define i32 @static32_inc() {
>> > +; CHECK-LABEL: static32_inc:
>> > +; CHECK: lds r22, long.static
>> > +; CHECK: lds r23, long.static+1
>> > +; CHECK: lds r24, long.static+2
>> > +; CHECK: lds r25, long.static+3
>> > +; CHECK: subi r22, 255
>> > +; CHECK: sbci r23, 255
>> > +; CHECK: sbci r24, 255
>> > +; CHECK: sbci r25, 255
>> > +; CHECK: sts long.static+3, r25
>> > +; CHECK: sts long.static+2, r24
>> > +; CHECK: sts long.static+1, r23
>> > +; CHECK: sts long.static, r22
>> > +  %1 = load i32, i32* @long.static
>> > +  %inc = add nsw i32 %1, 1
>> > +  store i32 %inc, i32* @long.static
>> > +  ret i32 %inc
>> > +}
>> > +
>> > +define void @global64_store() {
>> > +; CHECK-LABEL: global64_store:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 34
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 17
>> > +; CHECK: sts longlong+7, [[REG2]]
>> > +; CHECK: sts longlong+6, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 68
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 51
>> > +; CHECK: sts longlong+5, [[REG2]]
>> > +; CHECK: sts longlong+4, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 102
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 85
>> > +; CHECK: sts longlong+3, [[REG2]]
>> > +; CHECK: sts longlong+2, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 136
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 119
>> > +; CHECK: sts longlong+1, [[REG2]]
>> > +; CHECK: sts longlong, [[REG1]]
>> > +  store i64 1234605616436508552, i64* @longlong
>> > +  ret void
>> > +}
>> > +
>> > +define i64 @global64_load() {
>> > +; CHECK-LABEL: global64_load:
>> > +; CHECK: lds r18, longlong
>> > +; CHECK: lds r19, longlong+1
>> > +; CHECK: lds r20, longlong+2
>> > +; CHECK: lds r21, longlong+3
>> > +; CHECK: lds r22, longlong+4
>> > +; CHECK: lds r23, longlong+5
>> > +; CHECK: lds r24, longlong+6
>> > +; CHECK: lds r25, longlong+7
>> > +  %result = load i64, i64* @longlong
>> > +  ret i64 %result
>> > +}
>> > +
>> > +define void @array64_store() {
>> > +; CHECK-LABEL: array64_store:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 34
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 17
>> > +; CHECK: sts longlong.array+7, [[REG2]]
>> > +; CHECK: sts longlong.array+6, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 68
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 51
>> > +; CHECK: sts longlong.array+5, [[REG2]]
>> > +; CHECK: sts longlong.array+4, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 102
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 85
>> > +; CHECK: sts longlong.array+3, [[REG2]]
>> > +; CHECK: sts longlong.array+2, [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 136
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 119
>> > +; CHECK: sts longlong.array+1, [[REG2]]
>> > +; CHECK: sts longlong.array, [[REG1]]
>> > +  store i64 1234605616436508552, i64* getelementptr inbounds ([3 x
>> > i64], [3 x i64]* @longlong.array, i64 0, i64 0)
>> > +  store i64 81985529216486895, i64* getelementptr inbounds ([3 x i64],
>> > [3 x i64]* @longlong.array, i64 0, i64 1)
>> > +  store i64 1836475854449306472, i64* getelementptr inbounds ([3 x
>> > i64], [3 x i64]* @longlong.array, i64 0, i64 2)
>> > +  ret void
>> > +}
>> > +
>> > +define i64 @array64_load() {
>> > +; CHECK-LABEL: array64_load:
>> > +; CHECK: lds r18, longlong.array+16
>> > +; CHECK: lds r19, longlong.array+17
>> > +; CHECK: lds r20, longlong.array+18
>> > +; CHECK: lds r21, longlong.array+19
>> > +; CHECK: lds r22, longlong.array+20
>> > +; CHECK: lds r23, longlong.array+21
>> > +; CHECK: lds r24, longlong.array+22
>> > +; CHECK: lds r25, longlong.array+23
>> > +  %result = load i64, i64* getelementptr inbounds ([3 x i64], [3 x
>> > i64]* @longlong.array, i64 0, i64 2)
>> > +  ret i64 %result
>> > +}
>> > +
>> > +define i64 @static64_inc() {
>> > +; CHECK-LABEL: static64_inc:
>> > +; CHECK: lds r18, longlong.static
>> > +; CHECK: lds r19, longlong.static+1
>> > +; CHECK: lds r20, longlong.static+2
>> > +; CHECK: lds r21, longlong.static+3
>> > +; CHECK: lds r22, longlong.static+4
>> > +; CHECK: lds r23, longlong.static+5
>> > +; CHECK: lds r24, longlong.static+6
>> > +; CHECK: lds r25, longlong.static+7
>> > +; CHECK: subi r18, 255
>> > +; CHECK: sbci r19, 255
>> > +; CHECK: sbci r20, 255
>> > +; CHECK: sbci r21, 255
>> > +; CHECK: sbci r22, 255
>> > +; CHECK: sbci r23, 255
>> > +; CHECK: sbci r24, 255
>> > +; CHECK: sbci r25, 255
>> > +; CHECK: sts longlong.static+7, r25
>> > +; CHECK: sts longlong.static+6, r24
>> > +; CHECK: sts longlong.static+5, r23
>> > +; CHECK: sts longlong.static+4, r22
>> > +; CHECK: sts longlong.static+3, r21
>> > +; CHECK: sts longlong.static+2, r20
>> > +; CHECK: sts longlong.static+1, r19
>> > +; CHECK: sts longlong.static, r18
>> > +  %1 = load i64, i64* @longlong.static
>> > +  %inc = add nsw i64 %1, 1
>> > +  store i64 %inc, i64* @longlong.static
>> > +  ret i64 %inc
>> > +}
>> > +
>> > +define i8 @constantaddr_read8() {
>> > +; CHECK-LABEL: constantaddr_read8:
>> > +; CHECK: lds r24, 1234
>> > +  %1 = load i8, i8* inttoptr (i16 1234 to i8*)
>> > +  ret i8 %1
>> > +}
>> > +
>> > +define i16 @constantaddr_read16() {
>> > +; CHECK-LABEL: constantaddr_read16:
>> > +; CHECK: lds r24, 1234
>> > +; CHECK: lds r25, 1235
>> > +  %1 = load i16, i16* inttoptr (i16 1234 to i16*)
>> > +  ret i16 %1
>> > +}
>> > +
>> > +define void @constantaddr_write8() {
>> > +; CHECK-LABEL: constantaddr_write8:
>> > +; CHECK: sts 1234
>> > +  store i8 22, i8* inttoptr (i16 1234 to i8*)
>> > +  ret void
>> > +}
>> > +
>> > +define void @constantaddr_write16() {
>> > +; CHECK-LABEL: constantaddr_write16:
>> > +; CHECK: sts 1235
>> > +; CHECK: sts 1234
>> > +  store i16 2222, i16* inttoptr (i16 1234 to i16*)
>> > +  ret void
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/dynalloca.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/dynalloca.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/dynalloca.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/dynalloca.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,78 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +declare void @foo(i16*, i16*, i8*)
>> > +
>> > +define void @test1(i16 %x) {
>> > +; CHECK-LABEL: test1:
>> > +; CHECK: out 61, r28
>> > +; SP copy
>> > +; CHECK-NEXT: in [[SPCOPY1:r[0-9]+]], 61
>> > +; CHECK-NEXT: in [[SPCOPY2:r[0-9]+]], 62
>> > +; allocate first dynalloca
>> > +; CHECK: in {{.*}}, 61
>> > +; CHECK: in {{.*}}, 62
>> > +; CHECK: sub
>> > +; CHECK: sbc
>> > +; CHECK: in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: out 62, {{.*}}
>> > +; CHECK-NEXT: out 63, r0
>> > +; CHECK-NEXT: out 61, {{.*}}
>> > +; Test writes
>> > +; CHECK: std Z+12, {{.*}}
>> > +; CHECK: std Z+13, {{.*}}
>> > +; CHECK: std Z+7, {{.*}}
>> > +; CHECK-NOT: std
>> > +; Test SP restore
>> > +; CHECK: in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: out 62, [[SPCOPY2]]
>> > +; CHECK-NEXT: out 63, r0
>> > +; CHECK-NEXT: out 61, [[SPCOPY1]]
>> > +  %a = alloca [8 x i16]
>> > +  %vla = alloca i16, i16 %x
>> > +  %add = shl nsw i16 %x, 1
>> > +  %vla1 = alloca i8, i16 %add
>> > +  %arrayidx = getelementptr inbounds [8 x i16], [8 x i16]* %a, i16 0,
>> > i16 2
>> > +  store i16 3, i16* %arrayidx
>> > +  %arrayidx2 = getelementptr inbounds i16, i16* %vla, i16 6
>> > +  store i16 4, i16* %arrayidx2
>> > +  %arrayidx3 = getelementptr inbounds i8, i8* %vla1, i16 7
>> > +  store i8 44, i8* %arrayidx3
>> > +  %arraydecay = getelementptr inbounds [8 x i16], [8 x i16]* %a, i16
>> > 0, i16 0
>> > +  call void @foo(i16* %arraydecay, i16* %vla, i8* %vla1)
>> > +  ret void
>> > +}
>> > +
>> > +declare void @foo2(i16*, i64, i64, i64)
>> > +
>> > +; Test that arguments are passed through pushes into the call instead
>> > of
>> > +; allocating the call frame space in the prologue. Also test that SP
>> > is restored
>> > +; after the call frame is restored and not before.
>> > +define void @dynalloca2(i16 %x) {
>> > +; CHECK-LABEL: dynalloca2:
>> > +; CHECK: in [[SPCOPY1:r[0-9]+]], 61
>> > +; CHECK: in [[SPCOPY2:r[0-9]+]], 62
>> > +; CHECK: push
>> > +; CHECK-NOT: st
>> > +; CHECK-NOT: std
>> > +; CHECK: call
>> > +; Call frame restore
>> > +; CHECK-NEXT: in r30, 61
>> > +; CHECK-NEXT: in r31, 62
>> > +; CHECK-NEXT: adiw r30, 8
>> > +; CHECK-NEXT: in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: out 62, r31
>> > +; CHECK-NEXT: out 63, r0
>> > +; CHECK-NEXT: out 61, r30
>> > +; SP restore
>> > +; CHECK: in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: out 62, r29
>> > +; CHECK-NEXT: out 63, r0
>> > +; CHECK-NEXT: out 61, r28
>> > +  %vla = alloca i16, i16 %x
>> > +  call void @foo2(i16* %vla, i64 0, i64 0, i64 0)
>> > +  ret void
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/eor.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/eor.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/eor.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/eor.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,92 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +; Tests for the exclusive OR operation.
>> > +
>> > +define i8 @eor8_reg_reg(i8 %a, i8 %b) {
>> > +; CHECK-LABEL: eor8_reg_reg:
>> > +; CHECK: eor r24, r22
>> > +    %result = xor i8 %a, %b
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i8 @eor8_reg_imm(i8 %a) {
>> > +; CHECK-LABEL: eor8_reg_imm:
>> > +; CHECK: ldi r25, 5
>> > +; CHECK: eor r24, r25
>> > +    %result = xor i8 %a, 5
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i16 @eor16_reg_reg(i16 %a, i16 %b) {
>> > +; CHECK-LABEL: eor16_reg_reg:
>> > +; CHECK: eor r24, r22
>> > +; CHECK: eor r25, r23
>> > +    %result = xor i16 %a, %b
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i16 @eor16_reg_imm(i16 %a) {
>> > +; CHECK-LABEL: eor16_reg_imm:
>> > +; CHECK: ldi r18, 210
>> > +; CHECK: ldi r19, 4
>> > +; CHECK: eor r24, r18
>> > +; CHECK: eor r25, r19
>> > +    %result = xor i16 %a, 1234
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i32 @eor32_reg_reg(i32 %a, i32 %b) {
>> > +; CHECK-LABEL: eor32_reg_reg:
>> > +; CHECK: eor r22, r18
>> > +; CHECK: eor r23, r19
>> > +; CHECK: eor r24, r20
>> > +; CHECK: eor r25, r21
>> > +    %result = xor i32 %a, %b
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i32 @eor32_reg_imm(i32 %a) {
>> > +; CHECK-LABEL: eor32_reg_imm:
>> > +; CHECK: ldi r18, 210
>> > +; CHECK: ldi r19, 4
>> > +; CHECK: eor r22, r18
>> > +; CHECK: eor r23, r19
>> > +    %result = xor i32 %a, 1234
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i64 @eor64_reg_reg(i64 %a, i64 %b) {
>> > +; CHECK-LABEL: eor64_reg_reg:
>> > +; CHECK: eor r18, r10
>> > +; CHECK: eor r19, r11
>> > +; CHECK: eor r20, r12
>> > +; CHECK: eor r21, r13
>> > +; CHECK: eor r22, r14
>> > +; CHECK: eor r23, r15
>> > +; CHECK: eor r24, r16
>> > +; CHECK: eor r25, r17
>> > +    %result = xor i64 %a, %b
>> > +    ret i64 %result
>> > +}
>> > +
>> > +define i64 @eor64_reg_imm(i64 %a) {
>> > +; CHECK-LABEL: eor64_reg_imm:
>> > +; CHECK: ldi r30, 253
>> > +; CHECK: ldi r31, 255
>> > +; CHECK: eor r18, r30
>> > +; CHECK: eor r19, r31
>> > +; CHECK: ldi r30, 155
>> > +; CHECK: ldi r31, 88
>> > +; CHECK: eor r20, r30
>> > +; CHECK: eor r21, r31
>> > +; CHECK: ldi r30, 76
>> > +; CHECK: ldi r31, 73
>> > +; CHECK: eor r22, r30
>> > +; CHECK: eor r23, r31
>> > +; CHECK: ldi r30, 31
>> > +; CHECK: ldi r31, 242
>> > +; CHECK: eor r24, r30
>> > +; CHECK: eor r25, r31
>> > +    %result = xor i64 %a, 17446744073709551613
>> > +    ret i64 %result
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/error-srcreg-destreg-same.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/error-srcreg-destreg-
>> > same.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/error-srcreg-destreg-same.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/error-srcreg-destreg-same.ll Wed Nov 16
>> > 15:58:04 2016
>> > @@ -0,0 +1,56 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +; XFAIL: *
>> > +
>> > +; This occurs when compiling Rust libcore.
>> > +;
>> > +; Assertion failed:
>> > +; (DstReg != SrcReg && "SrcReg and DstReg cannot be the same")
>> > +;   lib/Target/AVR/AVRExpandPseudoInsts.cpp, line 817
>> > +;
>> > +; https://github.com/avr-llvm/llvm/issues/229
>> > +
>> > +; CHECK-LABEL: rust_eh_personality
>> > +declare void @rust_eh_personality()
>> > +
>> > +; CHECK-LABEL: __udivmoddi4
>> > +define void @__udivmoddi4(i64 %arg, i64 %arg1) personality i32 (...)*
>> > bitcast (void ()* @rust_eh_personality to i32 (...)*) {
>> > +entry-block:
>> > +  %tmp = lshr i64 %arg, 32
>> > +  %tmp2 = trunc i64 %tmp to i32
>> > +  %tmp3 = trunc i64 %arg to i32
>> > +  %tmp4 = add i64 %arg1, -1
>> > +  br label %bb135
>> > +
>> > +bb133.loopexit:
>> > +  ret void
>> > +
>> > +bb135:
>> > +  %carry.0120 = phi i64 [ 0, %entry-block ], [ %phitmp, %bb135 ]
>> > +  %q.sroa.12.1119 = phi i32 [ %tmp3, %entry-block ], [
>> > %q.sroa.12.0.extract.trunc, %bb135 ]
>> > +  %q.sroa.0.1118 = phi i32 [ 0, %entry-block ], [
>> > %q.sroa.0.0.extract.trunc, %bb135 ]
>> > +  %r.sroa.0.1116 = phi i32 [ %tmp2, %entry-block ], [ undef, %bb135 ]
>> > +  %r.sroa.0.0.insert.ext62 = zext i32 %r.sroa.0.1116 to i64
>> > +  %r.sroa.0.0.insert.insert64 = or i64 0, %r.sroa.0.0.insert.ext62
>> > +  %tmp5 = shl nuw nsw i64 %r.sroa.0.0.insert.ext62, 1
>> > +  %q.sroa.12.0.insert.ext101 = zext i32 %q.sroa.12.1119 to i64
>> > +  %q.sroa.12.0.insert.shift102 = shl nuw i64
>> > %q.sroa.12.0.insert.ext101, 32
>> > +  %q.sroa.0.0.insert.ext87 = zext i32 %q.sroa.0.1118 to i64
>> > +  %q.sroa.0.0.insert.insert89 = or i64 %q.sroa.12.0.insert.shift102,
>> > %q.sroa.0.0.insert.ext87
>> > +  %tmp6 = lshr i64 %q.sroa.12.0.insert.ext101, 31
>> > +  %tmp7 = lshr i64 %r.sroa.0.0.insert.insert64, 31
>> > +  %tmp8 = shl nuw nsw i64 %q.sroa.0.0.insert.ext87, 1
>> > +  %tmp9 = or i64 %tmp8, %carry.0120
>> > +  %q.sroa.0.0.extract.trunc = trunc i64 %tmp9 to i32
>> > +  %tmp10 = lshr i64 %q.sroa.0.0.insert.insert89, 31
>> > +  %q.sroa.12.0.extract.trunc = trunc i64 %tmp10 to i32
>> > +  %r.sroa.13.0.insert.shift72 = shl i64 %tmp7, 32
>> > +  %.masked114 = and i64 %tmp5, 4294967294
>> > +  %r.sroa.0.0.insert.ext57 = or i64 %tmp6, %.masked114
>> > +  %r.sroa.0.0.insert.insert59 = or i64 %r.sroa.0.0.insert.ext57,
>> > %r.sroa.13.0.insert.shift72
>> > +  %tmp11 = sub i64 %tmp4, %r.sroa.0.0.insert.insert59
>> > +  %tmp12 = ashr i64 %tmp11, 63
>> > +  %phitmp = and i64 %tmp12, 1
>> > +  %tmp13 = icmp ult i32 undef, 32
>> > +  br i1 %tmp13, label %bb135, label %bb133.loopexit
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/expand-integer-failure.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/expand-integer-
>> > failure.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/expand-integer-failure.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/expand-integer-failure.ll Wed Nov 16
>> > 15:58:04 2016
>> > @@ -0,0 +1,23 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +; XFAIL: *
>> > +
>> > +; Causes an assertion error
>> > +; Assertion failed: (Lo.getValueType() ==
>> > TLI.getTypeToTransformTo(*DAG.getContext(), Op.getValueType()) &&
>> > +;   Hi.getValueType() == Lo.getValueType() &&
>> > +;   "Invalid type for expanded integer"),
>> > +; function SetExpandedInteger
>> > +; file lib/CodeGen/SelectionDAG/LegalizeTypes.cpp
>> > +
>> > +; CHECK-LABEL: foo
>> > +define void @foo(i16 %a) {
>> > +ifcont:
>> > +  %cmp_result = icmp eq i16 %a, 255
>> > +  %bool_result = uitofp i1 %cmp_result to double
>> > +  %result = fcmp one double 0.000000e+00, %bool_result
>> > +  br i1 %result, label %then, label %else
>> > +then:
>> > +  ret void
>> > +else:
>> > +  ret void
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/frame.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/frame.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/frame.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/frame.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,65 @@
>> > +; RUN: llc -mattr=mul < %s -march=avr | FileCheck %s
>> > +
>> > +declare float @dsin(float)
>> > +declare float @dcos(float)
>> > +declare float @dasin(float)
>> > +
>> > +; Test prologue and epilogue insertion
>> > +define float @f3(float %days) {
>> > +entry:
>> > +; CHECK-LABEL: f3:
>> > +; prologue code:
>> > +; CHECK: push r28
>> > +; CHECK: push r29
>> > +; CHECK: in r28, 61
>> > +; CHECK-NEXT: in r29, 62
>> > +; CHECK-NEXT: sbiw r28, [[SIZE:[0-9]+]]
>> > +; CHECK-NEXT: in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: out 62, r29
>> > +; CHECK-NEXT: out 63, r0
>> > +; CHECK-NEXT: out 61, r28
>> > +; epilogue code:
>> > +; CHECK: adiw r28, [[SIZE]]
>> > +; CHECK-NEXT: in r0, 63
>> > +; CHECK-NEXT: cli
>> > +; CHECK-NEXT: out 62, r29
>> > +; CHECK-NEXT: out 63, r0
>> > +; CHECK-NEXT: out 61, r28
>> > +; CHECK: pop r29
>> > +; CHECK: pop r28
>> > +  %mul = fmul float %days, 0x3FEF8A6C60000000
>> > +  %add = fadd float %mul, 0x40718776A0000000
>> > +  %mul1 = fmul float %days, 0x3FEF8A09A0000000
>> > +  %add2 = fadd float %mul1, 0x4076587740000000
>> > +  %mul3 = fmul float %days, 0x3E81B35CC0000000
>> > +  %sub = fsub float 0x3FFEA235C0000000, %mul3
>> > +  %call = call float @dsin(float %add2)
>> > +  %mul4 = fmul float %sub, %call
>> > +  %mul5 = fmul float %days, 0x3E27C04CA0000000
>> > +  %sub6 = fsub float 0x3F94790B80000000, %mul5
>> > +  %mul7 = fmul float %add2, 2.000000e+00
>> > +  %call8 = call float @dsin(float %mul7)
>> > +  %mul9 = fmul float %sub6, %call8
>> > +  %add10 = fadd float %mul4, %mul9
>> > +  %add11 = fadd float %add, %add10
>> > +  %mul12 = fmul float %days, 0x3E13C5B640000000
>> > +  %sub13 = fsub float 0x3F911C1180000000, %mul12
>> > +  %mul14 = fmul float %add, 2.000000e+00
>> > +  %call15 = call float @dsin(float %mul14)
>> > +  %mul16 = fmul float %call15, 0x3FF1F736C0000000
>> > +  %mul17 = fmul float %sub13, 2.000000e+00
>> > +  %mul19 = fmul float %mul17, %call
>> > +  %sub20 = fsub float %mul16, %mul19
>> > +  %mul21 = fmul float %sub13, 4.000000e+00
>> > +  %mul22 = fmul float %mul21, 0x3FF1F736C0000000
>> > +  %mul24 = fmul float %mul22, %call
>> > +  %call26 = call float @dcos(float %mul14)
>> > +  %mul27 = fmul float %mul24, %call26
>> > +  %add28 = fadd float %sub20, %mul27
>> > +  %call29 = call float @dsin(float %add11)
>> > +  %mul30 = fmul float %call29, 0x3FF0AB6960000000
>> > +  %call31 = call float @dasin(float %mul30)
>> > +  %add32 = fadd float %call31, %add28
>> > +  ret float %add32
>> > +}
>> >
>> > Modified: llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/high-pressure-on-
>> > ptrregs.ll?rev=287162&r1=287161&r2=287162&view=diff
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll (original)
>> > +++ llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll Wed Nov 16
>> > 15:58:04 2016
>> > @@ -1,4 +1,5 @@
>> >  ; RUN: llc < %s -march=avr | FileCheck %s
>> > +; XFAIL: *
>> >
>> >  ; This tests how LLVM handles IR which puts very high
>> >  ; presure on the PTRREGS class for the register allocator.
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/inline-asm.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/inline-asm.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/inline-asm.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/inline-asm.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,337 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +; XFAIL: *
>> > +
>> > +;CHECK-LABEL: no_operands:
>> > +define void @no_operands() {
>> > +  ;CHECK: add r24, r22
>> > +  call void asm sideeffect "add r24, r22", ""() nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: input_operand:
>> > +define void @input_operand(i8 %a) {
>> > +  ;CHECK: add r24, r24
>> > +  call void asm sideeffect "add $0, $0", "r"(i8 %a) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: simple_upper_regs:
>> > +define void @simple_upper_regs(i8 %p0, i8 %p1, i8 %p2, i8 %p3,
>> > +                               i8 %p4, i8 %p5, i8 %p6, i8 %p7) {
>> > +  ;CHECK: some_instr r17, r22, r20, r18, r16, r19, r21, r23
>> > +  call void asm sideeffect "some_instr $0, $1, $2, $3, $4, $5, $6,
>> > $7",
>> > +                           "a,a,a,a,a,a,a,a" (i8 %p0, i8 %p1, i8 %p2,
>> > i8 %p3,
>> > +                                              i8 %p4, i8 %p5, i8 %p6,
>> > i8 %p7) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: upper_regs:
>> > +define void @upper_regs(i8 %p0) {
>> > +  ;CHECK: some_instr r24
>> > +  call void asm sideeffect "some_instr $0", "d" (i8 %p0) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: lower_regs:
>> > +define void @lower_regs(i8 %p0) {
>> > +  ;CHECK: some_instr r15
>> > +  call void asm sideeffect "some_instr $0", "l" (i8 %p0) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: special_upper_regs:
>> > +define void @special_upper_regs(i8 %p0, i8 %p1, i8 %p2, i8 %p3) {
>> > +  ;CHECK: some_instr r24,r28,r26,r30
>> > +  call void asm sideeffect "some_instr $0,$1,$2,$3", "w,w,w,w" (i8
>> > %p0, i8 %p1, i8 %p2, i8 %p3) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: xyz_reg:
>> > +define void @xyz_reg(i16 %var) {
>> > +  ;CHECK: some_instr r26, r28, r30
>> > +  call void asm sideeffect "some_instr $0, $1, $2", "x,y,z" (i16 %var,
>> > i16 %var, i16 %var) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;TODO
>> > +; How to use SP reg properly in inline asm??
>> > +; define void @sp_reg(i16 %var)
>> > +
>> > +;CHECK-LABEL: ptr_reg:
>> > +define void @ptr_reg(i16 %var0, i16 %var1, i16 %var2) {
>> > +  ;CHECK: some_instr r28, r26, r30
>> > +  call void asm sideeffect "some_instr $0, $1, $2", "e,e,e" (i16
>> > %var0, i16 %var1, i16 %var2) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: base_ptr_reg:
>> > +define void @base_ptr_reg(i16 %var0, i16 %var1) {
>> > +  ;CHECK: some_instr r28, r30
>> > +  call void asm sideeffect "some_instr $0, $1", "b,b" (i16 %var0, i16
>> > %var1) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: input_output_operand:
>> > +define i8 @input_output_operand(i8 %a, i8 %b) {
>> > +  ;CHECK: add r24, r24
>> > +  %1 = call i8 asm "add $0, $1", "=r,r"(i8 %a) nounwind
>> > +  ret i8 %1
>> > +}
>> > +
>> > +;CHECK-LABEL: temp_reg:
>> > +define void @temp_reg(i8 %a) {
>> > +  ;CHECK: some_instr r0
>> > +  call void asm sideeffect "some_instr $0", "t" (i8 %a) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_0_63:
>> > +define void @int_0_63() {
>> > +  ;CHECK: some_instr 5
>> > +  call void asm sideeffect "some_instr $0", "I" (i8 5) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_minus63_0:
>> > +define void @int_minus63_0() {
>> > +  ;CHECK: some_instr -5
>> > +  call void asm sideeffect "some_instr $0", "J" (i8 -5) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_2_2:
>> > +define void @int_2_2() {
>> > +  ;CHECK: some_instr 2
>> > +  call void asm sideeffect "some_instr $0", "K" (i8 2) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_0_0:
>> > +define void @int_0_0() {
>> > +  ;CHECK: some_instr 0
>> > +  call void asm sideeffect "some_instr $0", "L" (i8 0) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_0_255:
>> > +define void @int_0_255() {
>> > +  ;CHECK: some_instr 254
>> > +  call void asm sideeffect "some_instr $0", "M" (i8 254) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_minus1_minus1:
>> > +define void @int_minus1_minus1() {
>> > +  ;CHECK: some_instr -1
>> > +  call void asm sideeffect "some_instr $0", "N" (i8 -1) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_8_or_16_or_24:
>> > +define void @int_8_or_16_or_24() {
>> > +  ;CHECK: some_instr 8, 16, 24
>> > +  call void asm sideeffect "some_instr $0, $1, $2", "O,O,O" (i8 8, i8
>> > 16, i8 24) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_1_1:
>> > +define void @int_1_1() {
>> > +  ;CHECK: some_instr 1
>> > +  call void asm sideeffect "some_instr $0", "P" (i8 1) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: int_minus6_5:
>> > +define void @int_minus6_5() {
>> > +  ;CHECK: some_instr -6
>> > +  call void asm sideeffect "some_instr $0", "R" (i8 -6) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +;CHECK-LABEL: float_0_0:
>> > +define void @float_0_0() {
>> > +  ;CHECK: some_instr 0
>> > +  call void asm sideeffect "some_instr $0", "G" (float 0.0) nounwind
>> > +  ret void
>> > +}
>> > +
>> > +
>> > +; Memory constraint
>> > +
>> > + at a = internal global i16 0, align 4
>> > + at b = internal global i16 0, align 4
>> > +
>> > +; CHECK-LABEL: mem_global:
>> > +define void @mem_global() {
>> > +  ;CHECK: some_instr Y, Z
>> > +  call void asm "some_instr $0, $1", "=*Q,=*Q"(i16* @a, i16* @b)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: mem_params:
>> > +define void @mem_params(i16* %a, i16* %b) {
>> > +  ;CHECK: some_instr Y, Z
>> > +  call void asm "some_instr $0, $1", "=*Q,=*Q"(i16* %a, i16* %b)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: mem_local:
>> > +define void @mem_local() {
>> > +  %a = alloca i16
>> > +  %b = alloca i16
>> > +  ;CHECK: some_instr Y+3, Y+1
>> > +  call void asm "some_instr $0, $1", "=*Q,=*Q"(i16* %a, i16* %b)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: mem_mixed:
>> > +define void @mem_mixed() {
>> > +  %a = alloca i16
>> > +  %b = alloca i16
>> > +  ;CHECK: some_instr Z, Y+3, Y+1
>> > +  call void asm "some_instr $0, $1, $2", "=*Q,=*Q,=*Q"(i16* @a, i16*
>> > %a, i16* %b)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: mem_gep:
>> > +define i8 @mem_gep(i8* %p) {
>> > +entry:
>> > +; CHECK: movw r30, r24
>> > +  %arrayidx = getelementptr inbounds i8, i8* %p, i16 1
>> > +; CHECK: ld r24, Z+1
>> > +  %0 = tail call i8 asm sideeffect "ld $0, $1\0A\09", "=r,*Q"(i8*
>> > %arrayidx)
>> > +  ret i8 %0
>> > +}
>> > +
>> > +; Multibyte references
>> > +
>> > +; CHECK-LABEL: multibyte_i16
>> > +define void @multibyte_i16(i16 %a) {
>> > +entry:
>> > +; CHECK: instr r24 r25
>> > +  call void asm sideeffect "instr ${0:A} ${0:B}", "r"(i16 %a)
>> > +; CHECK: instr r25 r24
>> > +  call void asm sideeffect "instr ${0:B} ${0:A}", "r"(i16 %a)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_i32
>> > +define void @multibyte_i32(i32 %a) {
>> > +entry:
>> > +; CHECK: instr r22 r23 r24 r25
>> > +  call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}",
>> > "r"(i32 %a)
>> > +; CHECK: instr r25 r24 r23 r22
>> > +  call void asm sideeffect "instr ${0:D} ${0:C} ${0:B} ${0:A}",
>> > "r"(i32 %a)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_alternative_name
>> > +define void @multibyte_alternative_name(i16* %p) {
>> > +entry:
>> > +; CHECK: instr Z
>> > +  call void asm sideeffect "instr ${0:a}", "e" (i16* %p)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_a_i32
>> > +define void @multibyte_a_i32() {
>> > +entry:
>> > +  %a = alloca i32
>> > +  %0 = load i32, i32* %a
>> > +; CHECK: instr r20 r21 r22 r23
>> > +  call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}",
>> > "a"(i32 %0)
>> > +  ret void
>> > +}
>> > +
>> > + at c = internal global i32 0
>> > +
>> > +; CHECK-LABEL: multibyte_b_i32
>> > +define void @multibyte_b_i32() {
>> > +entry:
>> > +  %0 = load i32, i32* @c
>> > +; CHECK: instr r28 r29 r30 r31
>> > +  call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}",
>> > "b"(i32 %0)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_d_i32
>> > +define void @multibyte_d_i32() {
>> > +entry:
>> > +  %a = alloca i32
>> > +  %0 = load i32, i32* %a
>> > +; CHECK: instr r18 r19 r24 r25
>> > +  call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}",
>> > "d"(i32 %0)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_e_i32
>> > +define void @multibyte_e_i32() {
>> > +entry:
>> > +  %a = alloca i32
>> > +  %0 = load i32, i32* %a
>> > +; CHECK: instr r26 r27 r30 r31
>> > +  call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}",
>> > "e"(i32 %0)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_l_i32
>> > +define void @multibyte_l_i32() {
>> > +entry:
>> > +  %a = alloca i32
>> > +  %0 = load i32, i32* %a
>> > +; CHECK: instr r12 r13 r14 r15
>> > +  call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}",
>> > "l"(i32 %0)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_a_i16
>> > +define void @multibyte_a_i16() {
>> > +entry:
>> > +  %a = alloca i16
>> > +  %0 = load i16, i16* %a
>> > +; CHECK: instr r22 r23
>> > +  call void asm sideeffect "instr ${0:A} ${0:B}", "a"(i16 %0)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_b_i16
>> > +define void @multibyte_b_i16() {
>> > +entry:
>> > +  %a = alloca i16
>> > +  %0 = load i16, i16* %a
>> > +; CHECK: instr r30 r31
>> > +  call void asm sideeffect "instr ${0:A} ${0:B}", "b"(i16 %0)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_d_i16
>> > +define void @multibyte_d_i16() {
>> > +entry:
>> > +  %a = alloca i16
>> > +  %0 = load i16, i16* %a
>> > +; CHECK: instr r24 r25
>> > +  call void asm sideeffect "instr ${0:A} ${0:B}", "d"(i16 %0)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_e_i16
>> > +define void @multibyte_e_i16() {
>> > +entry:
>> > +  %a = alloca i16
>> > +  %0 = load i16, i16* %a
>> > +; CHECK: instr r30 r31
>> > +  call void asm sideeffect "instr ${0:A} ${0:B}", "e"(i16 %0)
>> > +  ret void
>> > +}
>> > +
>> > +; CHECK-LABEL: multibyte_l_i16
>> > +define void @multibyte_l_i16() {
>> > +entry:
>> > +  %a = alloca i16
>> > +  %0 = load i16, i16* %a
>> > +; CHECK: instr r14 r15
>> > +  call void asm sideeffect "instr ${0:A} ${0:B}", "l"(i16 %0)
>> > +  ret void
>> > +}
>> > +
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/interrupts.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/interrupts.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/interrupts.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/interrupts.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,33 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +define avr_intrcc void @interrupt_handler() {
>> > +; CHECK-LABEL: interrupt_handler:
>> > +; CHECK: sei
>> > +; CHECK-NEXT: push r0
>> > +; CHECK-NEXT: push r1
>> > +; CHECK-NEXT: in r0, 63
>> > +; CHECK-NEXT: push r0
>> > +; CHECK: eor r0, r0
>> > +; CHECK: pop r0
>> > +; CHECK-NEXT: out 63, r0
>> > +; CHECK-NEXT: pop r1
>> > +; CHECK-NEXT: pop r0
>> > +; CHECK-NEXT: reti
>> > +  ret void
>> > +}
>> > +
>> > +define avr_signalcc void @signal_handler() {
>> > +; CHECK-LABEL: signal_handler:
>> > +; CHECK-NOT: sei
>> > +; CHECK: push r0
>> > +; CHECK-NEXT: push r1
>> > +; CHECK-NEXT: in r0, 63
>> > +; CHECK-NEXT: push r0
>> > +; CHECK: eor r0, r0
>> > +; CHECK: pop r0
>> > +; CHECK-NEXT: out 63, r0
>> > +; CHECK-NEXT: pop r1
>> > +; CHECK-NEXT: pop r0
>> > +; CHECK-NEXT: reti
>> > +  ret void
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/io.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/io.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/io.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/io.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,97 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +define i8 @read8() {
>> > +; CHECK-LABEL: read8
>> > +; CHECK: in r24, 8
>> > +  %1 = load i8, i8* inttoptr (i16 40 to i8*)
>> > +  ret i8 %1
>> > +}
>> > +
>> > +define i16 @read16() {
>> > +; CHECK-LABEL: read16
>> > +; CHECK: in r24, 8
>> > +; CHECK: in r25, 9
>> > +  %1 = load i16, i16* inttoptr (i16 40 to i16*)
>> > +  ret i16 %1
>> > +}
>> > +
>> > +define i32 @read32() {
>> > +; CHECK-LABEL: read32
>> > +; CHECK: in r22, 8
>> > +; CHECK: in r23, 9
>> > +; CHECK: in r24, 10
>> > +; CHECK: in r25, 11
>> > +  %1 = load i32, i32* inttoptr (i16 40 to i32*)
>> > +  ret i32 %1
>> > +}
>> > +
>> > +define i64 @read64() {
>> > +; CHECK-LABEL: read64
>> > +; CHECK: in r18, 8
>> > +; CHECK: in r19, 9
>> > +; CHECK: in r20, 10
>> > +; CHECK: in r21, 11
>> > +; CHECK: in r22, 12
>> > +; CHECK: in r23, 13
>> > +; CHECK: in r24, 14
>> > +; CHECK: in r25, 15
>> > +  %1 = load i64, i64* inttoptr (i16 40 to i64*)
>> > +  ret i64 %1
>> > +}
>> > +
>> > +define void @write8() {
>> > +; CHECK-LABEL: write8
>> > +; CHECK: out 8
>> > +  store i8 22, i8* inttoptr (i16 40 to i8*)
>> > +  ret void
>> > +}
>> > +
>> > +define void @write16() {
>> > +; CHECK-LABEL: write16
>> > +; CHECK: out 9
>> > +; CHECK: out 8
>> > +  store i16 1234, i16* inttoptr (i16 40 to i16*)
>> > +  ret void
>> > +}
>> > +
>> > +define void @write32() {
>> > +; CHECK-LABEL: write32
>> > +; CHECK: out 11
>> > +; CHECK: out 10
>> > +; CHECK: out 9
>> > +; CHECK: out 8
>> > +  store i32 12345678, i32* inttoptr (i16 40 to i32*)
>> > +  ret void
>> > +}
>> > +
>> > +define void @write64() {
>> > +; CHECK-LABEL: write64
>> > +; CHECK: out 15
>> > +; CHECK: out 14
>> > +; CHECK: out 13
>> > +; CHECK: out 12
>> > +; CHECK: out 11
>> > +; CHECK: out 10
>> > +; CHECK: out 9
>> > +; CHECK: out 8
>> > +  store i64 1234567891234567, i64* inttoptr (i16 40 to i64*)
>> > +  ret void
>> > +}
>> > +
>> > +define void @sbi8() {
>> > +; CHECK-LABEL: sbi8
>> > +; CHECK: sbi 8, 5
>> > +  %1 = load i8, i8* inttoptr (i16 40 to i8*)
>> > +  %or = or i8 %1, 32
>> > +  store i8 %or, i8* inttoptr (i16 40 to i8*)
>> > +  ret void
>> > +}
>> > +
>> > +define void @cbi8() {
>> > +; CHECK-LABEL: cbi8
>> > +; CHECK: cbi 8, 5
>> > +  %1 = load volatile i8, i8* inttoptr (i16 40 to i8*)
>> > +  %and = and i8 %1, -33
>> > +  store volatile i8 %and, i8* inttoptr (i16 40 to i8*)
>> > +  ret void
>> > +}
>> >
>> > Modified: llvm/trunk/test/CodeGen/AVR/lit.local.cfg
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/lit.local.cfg?rev=287162&r1=287161&
>> > r2=287162&view=diff
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/lit.local.cfg (original)
>> > +++ llvm/trunk/test/CodeGen/AVR/lit.local.cfg Wed Nov 16 15:58:04 2016
>> > @@ -1,3 +1,27 @@
>> >  if not 'AVR' in config.root.targets:
>> >      config.unsupported = True
>> >
>> > +config.suffixes = ['.ll', '.cpp']
>> > +
>> > +import os, lit.TestRunner
>> > +from lit.formats import ShTest
>> > +
>> > +targets = set(config.root.targets_to_build.split())
>> > +if not 'AVR' in targets:
>> > +  config.unsupported = True
>> > +
>> > +if 'AVRLIT_PORT' in os.environ:
>> > +  config.environment['AVRLIT_PORT'] = os.environ['AVRLIT_PORT']
>> > +
>> > +class AVRCodeGenTest(ShTest):
>> > +  def __init__(self):
>> > +    ShTest.__init__(self)
>> > +
>> > +  def execute(self, test, litConfig):
>> > +    if test.getSourcePath().endswith('.cpp') and not 'AVRLIT_PORT' in
>> > os.environ:
>> > +      return (lit.Test.UNSUPPORTED, 'AVRLIT_PORT environment variable
>> > is not set')
>> > +
>> > +    return ShTest.execute(self, test, litConfig)
>> > +
>> > +
>> > +config.test_format = AVRCodeGenTest()
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/load.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/load.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/load.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/load.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,142 @@
>> > +; RUN: llc -mattr=avr6,sram < %s -march=avr | FileCheck %s
>> > +
>> > +define i8 @load8(i8* %x) {
>> > +; CHECK-LABEL: load8:
>> > +; CHECK: ld r24, {{[XYZ]}}
>> > +  %1 = load i8, i8* %x
>> > +  ret i8 %1
>> > +}
>> > +
>> > +define i16 @load16(i16* %x) {
>> > +; CHECK-LABEL: load16:
>> > +; CHECK: ld r24, {{[YZ]}}
>> > +; CHECK: ldd r25, {{[YZ]}}+1
>> > +  %1 = load i16, i16* %x
>> > +  ret i16 %1
>> > +}
>> > +
>> > +define i8 @load8disp(i8* %x) {
>> > +; CHECK-LABEL: load8disp:
>> > +; CHECK: ldd r24, {{[YZ]}}+63
>> > +  %1 = getelementptr inbounds i8, i8* %x, i64 63
>> > +  %2 = load i8, i8* %1
>> > +  ret i8 %2
>> > +}
>> > +
>> > +define i8 @load8nodisp(i8* %x) {
>> > +; CHECK-LABEL: load8nodisp:
>> > +; CHECK: movw r26, r24
>> > +; CHECK: subi r26, 192
>> > +; CHECK: sbci r27, 255
>> > +; CHECK: ld r24, {{[XYZ]}}
>> > +  %1 = getelementptr inbounds i8, i8* %x, i64 64
>> > +  %2 = load i8, i8* %1
>> > +  ret i8 %2
>> > +}
>> > +
>> > +define i16 @load16disp(i16* %x) {
>> > +; CHECK-LABEL: load16disp:
>> > +; CHECK: ldd r24, {{[YZ]}}+62
>> > +; CHECK: ldd r25, {{[YZ]}}+63
>> > +  %1 = getelementptr inbounds i16, i16* %x, i64 31
>> > +  %2 = load i16, i16* %1
>> > +  ret i16 %2
>> > +}
>> > +
>> > +define i16 @load16nodisp(i16* %x) {
>> > +; CHECK-LABEL: load16nodisp:
>> > +; CHECK: movw r30, r24
>> > +; CHECK: subi r30, 192
>> > +; CHECK: sbci r31, 255
>> > +; CHECK: ld r24, {{[YZ]}}
>> > +; CHECK: ldd r25, {{[YZ]}}+1
>> > +  %1 = getelementptr inbounds i16, i16* %x, i64 32
>> > +  %2 = load i16, i16* %1
>> > +  ret i16 %2
>> > +}
>> > +
>> > +define i8 @load8postinc(i8* %x, i8 %y) {
>> > +; CHECK-LABEL: load8postinc:
>> > +; CHECK: ld {{.*}}, {{[XYZ]}}+
>> > +entry:
>> > +  %tobool6 = icmp eq i8 %y, 0
>> > +  br i1 %tobool6, label %while.end, label %while.body
>> > +while.body:                                       ; preds = %entry,
>> > %while.body
>> > +  %r.09 = phi i8 [ %add, %while.body ], [ 0, %entry ]
>> > +  %y.addr.08 = phi i8 [ %dec, %while.body ], [ %y, %entry ]
>> > +  %x.addr.07 = phi i8* [ %incdec.ptr, %while.body ], [ %x, %entry ]
>> > +  %dec = add i8 %y.addr.08, -1
>> > +  %incdec.ptr = getelementptr inbounds i8, i8* %x.addr.07, i16 1
>> > +  %0 = load i8, i8* %x.addr.07
>> > +  %add = add i8 %0, %r.09
>> > +  %tobool = icmp eq i8 %dec, 0
>> > +  br i1 %tobool, label %while.end, label %while.body
>> > +while.end:                                        ; preds =
>> > %while.body, %entry
>> > +  %r.0.lcssa = phi i8 [ 0, %entry ], [ %add, %while.body ]
>> > +  ret i8 %r.0.lcssa
>> > +}
>> > +
>> > +define i16 @load16postinc(i16* %x, i16 %y) {
>> > +; CHECK-LABEL: load16postinc:
>> > +; CHECK: ld {{.*}}, {{[XYZ]}}+
>> > +; CHECK: ld {{.*}}, {{[XYZ]}}+
>> > +entry:
>> > +  %tobool2 = icmp eq i16 %y, 0
>> > +  br i1 %tobool2, label %while.end, label %while.body
>> > +while.body:                                       ; preds = %entry,
>> > %while.body
>> > +  %r.05 = phi i16 [ %add, %while.body ], [ 0, %entry ]
>> > +  %y.addr.04 = phi i16 [ %dec, %while.body ], [ %y, %entry ]
>> > +  %x.addr.03 = phi i16* [ %incdec.ptr, %while.body ], [ %x, %entry ]
>> > +  %dec = add nsw i16 %y.addr.04, -1
>> > +  %incdec.ptr = getelementptr inbounds i16, i16* %x.addr.03, i16 1
>> > +  %0 = load i16, i16* %x.addr.03
>> > +  %add = add nsw i16 %0, %r.05
>> > +  %tobool = icmp eq i16 %dec, 0
>> > +  br i1 %tobool, label %while.end, label %while.body
>> > +while.end:                                        ; preds =
>> > %while.body, %entry
>> > +  %r.0.lcssa = phi i16 [ 0, %entry ], [ %add, %while.body ]
>> > +  ret i16 %r.0.lcssa
>> > +}
>> > +
>> > +define i8 @load8predec(i8* %x, i8 %y) {
>> > +; CHECK-LABEL: load8predec:
>> > +; CHECK: ld {{.*}}, -{{[XYZ]}}
>> > +entry:
>> > +  %tobool6 = icmp eq i8 %y, 0
>> > +  br i1 %tobool6, label %while.end, label %while.body
>> > +while.body:                                       ; preds = %entry,
>> > %while.body
>> > +  %r.09 = phi i8 [ %add, %while.body ], [ 0, %entry ]
>> > +  %y.addr.08 = phi i8 [ %dec, %while.body ], [ %y, %entry ]
>> > +  %x.addr.07 = phi i8* [ %incdec.ptr, %while.body ], [ %x, %entry ]
>> > +  %dec = add i8 %y.addr.08, -1
>> > +  %incdec.ptr = getelementptr inbounds i8, i8* %x.addr.07, i16 -1
>> > +  %0 = load i8, i8* %incdec.ptr
>> > +  %add = add i8 %0, %r.09
>> > +  %tobool = icmp eq i8 %dec, 0
>> > +  br i1 %tobool, label %while.end, label %while.body
>> > +while.end:                                        ; preds =
>> > %while.body, %entry
>> > +  %r.0.lcssa = phi i8 [ 0, %entry ], [ %add, %while.body ]
>> > +  ret i8 %r.0.lcssa
>> > +}
>> > +
>> > +define i16 @load16predec(i16* %x, i16 %y) {
>> > +; CHECK-LABEL: load16predec:
>> > +; CHECK: ld {{.*}}, -{{[XYZ]}}
>> > +; CHECK: ld {{.*}}, -{{[XYZ]}}
>> > +entry:
>> > +  %tobool2 = icmp eq i16 %y, 0
>> > +  br i1 %tobool2, label %while.end, label %while.body
>> > +while.body:                                       ; preds = %entry,
>> > %while.body
>> > +  %r.05 = phi i16 [ %add, %while.body ], [ 0, %entry ]
>> > +  %y.addr.04 = phi i16 [ %dec, %while.body ], [ %y, %entry ]
>> > +  %x.addr.03 = phi i16* [ %incdec.ptr, %while.body ], [ %x, %entry ]
>> > +  %dec = add nsw i16 %y.addr.04, -1
>> > +  %incdec.ptr = getelementptr inbounds i16, i16* %x.addr.03, i16 -1
>> > +  %0 = load i16, i16* %incdec.ptr
>> > +  %add = add nsw i16 %0, %r.05
>> > +  %tobool = icmp eq i16 %dec, 0
>> > +  br i1 %tobool, label %while.end, label %while.body
>> > +while.end:                                        ; preds =
>> > %while.body, %entry
>> > +  %r.0.lcssa = phi i16 [ 0, %entry ], [ %add, %while.body ]
>> > +  ret i16 %r.0.lcssa
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/or.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/or.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/or.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/or.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,80 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +define i8 @or8_reg_reg(i8 %a, i8 %b) {
>> > +; CHECK-LABEL: or8_reg_reg:
>> > +; CHECK: or r24, r22
>> > +    %result = or i8 %a, %b
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i8 @or8_reg_imm(i8 %a) {
>> > +; CHECK-LABEL: or8_reg_imm:
>> > +; CHECK: ori r24, 5
>> > +    %result = or i8 %a, 5
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i16 @or16_reg_reg(i16 %a, i16 %b) {
>> > +; CHECK-LABEL: or16_reg_reg:
>> > +; CHECK: or r24, r22
>> > +; CHECK: or r25, r23
>> > +    %result = or i16 %a, %b
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i16 @or16_reg_imm(i16 %a) {
>> > +; CHECK-LABEL: or16_reg_imm:
>> > +; CHECK: ori r24, 210
>> > +; CHECK: ori r25, 4
>> > +    %result = or i16 %a, 1234
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i32 @or32_reg_reg(i32 %a, i32 %b) {
>> > +; CHECK-LABEL: or32_reg_reg:
>> > +; CHECK: or r22, r18
>> > +; CHECK: or r23, r19
>> > +; CHECK: or r24, r20
>> > +; CHECK: or r25, r21
>> > +    %result = or i32 %a, %b
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i32 @or32_reg_imm(i32 %a) {
>> > +; CHECK-LABEL: or32_reg_imm:
>> > +; CHECK: ori r22, 21
>> > +; CHECK: ori r23, 205
>> > +; CHECK: ori r24, 91
>> > +; CHECK: ori r25, 7
>> > +    %result = or i32 %a, 123456789
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i64 @or64_reg_reg(i64 %a, i64 %b) {
>> > +; CHECK-LABEL: or64_reg_reg:
>> > +; CHECK: or r18, r10
>> > +; CHECK: or r19, r11
>> > +; CHECK: or r20, r12
>> > +; CHECK: or r21, r13
>> > +; CHECK: or r22, r14
>> > +; CHECK: or r23, r15
>> > +; CHECK: or r24, r16
>> > +; CHECK: or r25, r17
>> > +    %result = or i64 %a, %b
>> > +    ret i64 %result
>> > +}
>> > +
>> > +define i64 @or64_reg_imm(i64 %a) {
>> > +; CHECK-LABEL: or64_reg_imm:
>> > +; CHECK: ori r18, 204
>> > +; CHECK: ori r19, 204
>> > +; CHECK: ori r20, 204
>> > +; CHECK: ori r21, 204
>> > +; CHECK: ori r22, 204
>> > +; CHECK: ori r23, 204
>> > +; CHECK: ori r24, 204
>> > +; CHECK: ori r25, 204
>> > +    %result = or i64 %a, 14757395258967641292
>> > +    ret i64 %result
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/progmem.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/progmem.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/progmem.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/progmem.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,70 @@
>> > +; RUN: llc < %s -march=avr -mattr=movw,lpm | FileCheck %s
>> > +; XFAIL: *
>> > +
>> > +; Tests the standard LPM instruction
>> > +
>> > +define i8 @test8(i8 addrspace(1)* %p) {
>> > +; CHECK-LABEL: test8:
>> > +; CHECK: movw r30, r24
>> > +; CHECK: lpm r24, Z
>> > +  %1 = load i8, i8 addrspace(1)* %p
>> > +  ret i8 %1
>> > +}
>> > +
>> > +define i16 @test16(i16 addrspace(1)* %p) {
>> > +; CHECK-LABEL: test16:
>> > +; CHECK: movw r30, r24
>> > +; CHECK: lpm r24, Z+
>> > +; CHECK: lpm r25, Z+
>> > +  %1 = load i16, i16 addrspace(1)* %p
>> > +  ret i16 %1
>> > +}
>> > +
>> > +define i8 @test8postinc(i8 addrspace(1)* %x, i8 %y) {
>> > +; CHECK-LABEL: test8postinc:
>> > +; CHECK: movw r30, r24
>> > +; CHECK: lpm {{.*}}, Z+
>> > +entry:
>> > +  %cmp10 = icmp sgt i8 %y, 0
>> > +  br i1 %cmp10, label %for.body, label %for.end
>> > +
>> > +for.body:                                         ; preds = %entry,
>> > %for.body
>> > +  %ret.013 = phi i8 [ %add, %for.body ], [ 0, %entry ]
>> > +  %i.012 = phi i8 [ %inc, %for.body ], [ 0, %entry ]
>> > +  %x.addr.011 = phi i8 addrspace(1)* [ %incdec.ptr, %for.body ], [ %x,
>> > %entry ]
>> > +  %incdec.ptr = getelementptr inbounds i8, i8 addrspace(1)*
>> > %x.addr.011, i16 1
>> > +  %0 = load i8, i8 addrspace(1)* %x.addr.011
>> > +  %add = add i8 %0, %ret.013
>> > +  %inc = add i8 %i.012, 1
>> > +  %exitcond = icmp eq i8 %inc, %y
>> > +  br i1 %exitcond, label %for.end, label %for.body
>> > +
>> > +for.end:                                          ; preds = %for.body,
>> > %entry
>> > +  %ret.0.lcssa = phi i8 [ 0, %entry ], [ %add, %for.body ]
>> > +  ret i8 %ret.0.lcssa
>> > +}
>> > +
>> > +define i16 @test16postinc(i16 addrspace(1)* %x, i8 %y) {
>> > +; CHECK-LABEL: test16postinc:
>> > +; CHECK: movw r30, r24
>> > +; CHECK: lpm {{.*}}, Z+
>> > +; CHECK: lpm {{.*}}, Z+
>> > +entry:
>> > +  %cmp5 = icmp sgt i8 %y, 0
>> > +  br i1 %cmp5, label %for.body, label %for.end
>> > +
>> > +for.body:                                         ; preds = %entry,
>> > %for.body
>> > +  %ret.08 = phi i16 [ %add, %for.body ], [ 0, %entry ]
>> > +  %i.07 = phi i8 [ %inc, %for.body ], [ 0, %entry ]
>> > +  %x.addr.06 = phi i16 addrspace(1)* [ %incdec.ptr, %for.body ], [ %x,
>> > %entry ]
>> > +  %incdec.ptr = getelementptr inbounds i16, i16 addrspace(1)*
>> > %x.addr.06, i16 1
>> > +  %0 = load i16, i16 addrspace(1)* %x.addr.06
>> > +  %add = add nsw i16 %0, %ret.08
>> > +  %inc = add i8 %i.07, 1
>> > +  %exitcond = icmp eq i8 %inc, %y
>> > +  br i1 %exitcond, label %for.end, label %for.body
>> > +
>> > +for.end:                                          ; preds = %for.body,
>> > %entry
>> > +  %ret.0.lcssa = phi i16 [ 0, %entry ], [ %add, %for.body ]
>> > +  ret i16 %ret.0.lcssa
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/return.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/return.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/return.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/return.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,142 @@
>> > +; RUN: llc -mattr=avr6,sram < %s -march=avr | FileCheck %s
>> > +
>> > +;TODO: test returning byval structs
>> > +; TODO: test naked functions
>> > +
>> > +define void @return_void() {
>> > +; CHECK: return_void:{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: ret
>> > +    ret void
>> > +}
>> > +
>> > +define i8 @return8_imm() {
>> > +; CHECK-LABEL: return8_imm:
>> > +; CHECK: ldi r24, 5
>> > +    ret i8 5
>> > +}
>> > +
>> > +define i8 @return8_arg(i8 %x) {
>> > +; CHECK: return8_arg:{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: ret
>> > +    ret i8 %x
>> > +}
>> > +
>> > +define i8 @return8_arg2(i8 %x, i8 %y, i8 %z) {
>> > +; CHECK-LABEL: return8_arg2:
>> > +; CHECK: mov r24, r20
>> > +    ret i8 %z
>> > +}
>> > +
>> > +define i16 @return16_imm() {
>> > +; CHECK-LABEL: return16_imm:
>> > +; CHECK: ldi r24, 57
>> > +; CHECK: ldi r25, 48
>> > +    ret i16 12345
>> > +}
>> > +
>> > +define i16 @return16_arg(i16 %x) {
>> > +; CHECK: return16_arg:{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: ret
>> > +    ret i16 %x
>> > +}
>> > +
>> > +define i16 @return16_arg2(i16 %x, i16 %y, i16 %z) {
>> > +; CHECK-LABEL: return16_arg2:
>> > +; CHECK: movw r24, r20
>> > +    ret i16 %z
>> > +}
>> > +
>> > +define i32 @return32_imm() {
>> > +; CHECK-LABEL: return32_imm:
>> > +; CHECK: ldi r22, 21
>> > +; CHECK: ldi r23, 205
>> > +; CHECK: ldi r24, 91
>> > +; CHECK: ldi r25, 7
>> > +    ret i32 123456789
>> > +}
>> > +
>> > +define i32 @return32_arg(i32 %x) {
>> > +; CHECK: return32_arg:{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: ret
>> > +    ret i32 %x
>> > +}
>> > +
>> > +define i32 @return32_arg2(i32 %x, i32 %y, i32 %z) {
>> > +; CHECK-LABEL: return32_arg2:
>> > +; CHECK: movw r22, r14
>> > +; CHECK: movw r24, r16
>> > +    ret i32 %z
>> > +}
>> > +
>> > +define i64 @return64_imm() {
>> > +; CHECK-LABEL: return64_imm:
>> > +; CHECK: ldi r18, 204
>> > +; CHECK: ldi r19, 204
>> > +; CHECK: ldi r20, 104
>> > +; CHECK: ldi r21, 37
>> > +; CHECK: ldi r22, 25
>> > +; CHECK: ldi r23, 22
>> > +; CHECK: ldi r24, 236
>> > +; CHECK: ldi r25, 190
>> > +    ret i64 13757395258967641292
>> > +}
>> > +
>> > +define i64 @return64_arg(i64 %x) {
>> > +; CHECK: return64_arg:{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
>> > +; CHECK-NEXT: ret
>> > +    ret i64 %x
>> > +}
>> > +
>> > +define i64 @return64_arg2(i64 %x, i64 %y, i64 %z) {
>> > +; CHECK-LABEL: return64_arg2:
>> > +; CHECK: push r28
>> > +; CHECK: push r29
>> > +; CHECK: ldd r18, Y+5
>> > +; CHECK: ldd r19, Y+6
>> > +; CHECK: ldd r20, Y+7
>> > +; CHECK: ldd r21, Y+8
>> > +; CHECK: ldd r22, Y+9
>> > +; CHECK: ldd r23, Y+10
>> > +; CHECK: ldd r24, Y+11
>> > +; CHECK: ldd r25, Y+12
>> > +; CHECK: pop r29
>> > +; CHECK: pop r28
>> > +    ret i64 %z
>> > +}
>> > +
>> > +define i32 @return64_trunc(i32 %a, i32 %b, i32 %c, i64 %d) {
>> > +; CHECK-LABEL: return64_trunc:
>> > +; CHECK: push r28
>> > +; CHECK: push r29
>> > +; CHECK: ldd r22, Y+5
>> > +; CHECK: ldd r23, Y+6
>> > +; CHECK: ldd r24, Y+7
>> > +; CHECK: ldd r25, Y+8
>> > +; CHECK: pop r29
>> > +; CHECK: pop r28
>> > +  %result = trunc i64 %d to i32
>> > +  ret i32 %result
>> > +}
>> > +
>> > +define i32 @naked(i32 %x) naked {
>> > +; CHECK-LABEL: naked:
>> > +; CHECK-NOT: ret
>> > +  ret i32 %x
>> > +}
>> > +
>> > +define avr_intrcc void @interrupt_handler() {
>> > +; CHECK-LABEL: interrupt_handler:
>> > +; CHECK: reti
>> > +  ret void
>> > +}
>> > +
>> > +define avr_signalcc void @signal_handler() {
>> > +; CHECK-LABEL: signal_handler:
>> > +; CHECK: reti
>> > +  ret void
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/sext.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/sext.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/sext.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/sext.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,29 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +; sext R17:R16, R13
>> > +; mov r16, r13
>> > +; mov r17, r13
>> > +; lsl r17
>> > +; sbc r17, r17
>> > +define i16 @sext1(i8 %x, i8 %y) {
>> > +; CHECK-LABEL: sext1:
>> > +; CHECK: mov r24, r22
>> > +; CHECK: mov r25, r22
>> > +; CHECK: lsl r25
>> > +; CHECK: sbc r25, r25
>> > +  %1 = sext i8 %y to i16
>> > +  ret i16 %1
>> > +}
>> > +
>> > +; sext R17:R16, R16
>> > +; mov r17, r16
>> > +; lsl r17
>> > +; sbc r17, r17
>> > +define i16 @sext2(i8 %x) {
>> > +; CHECK-LABEL: sext2:
>> > +; CHECK: mov r25, r24
>> > +; CHECK: lsl r25
>> > +; CHECK: sbc r25, r25
>> > +  %1 = sext i8 %x to i16
>> > +  ret i16 %1
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/store.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/store.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/store.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/store.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,130 @@
>> > +; RUN: llc -mattr=avr6,sram < %s -march=avr | FileCheck %s
>> > +
>> > +define void @store8(i8* %x, i8 %y) {
>> > +; CHECK-LABEL: store8:
>> > +; CHECK: st {{[XYZ]}}, r22
>> > +  store i8 %y, i8* %x
>> > +  ret void
>> > +}
>> > +
>> > +define void @store16(i16* %x, i16 %y) {
>> > +; CHECK-LABEL: store16:
>> > +; CHECK: st {{[YZ]}}, r22
>> > +; CHECK: std {{[YZ]}}+1, r23
>> > +  store i16 %y, i16* %x
>> > +  ret void
>> > +}
>> > +
>> > +define void @store8disp(i8* %x, i8 %y) {
>> > +; CHECK-LABEL: store8disp:
>> > +; CHECK: std {{[YZ]}}+63, r22
>> > +  %arrayidx = getelementptr inbounds i8, i8* %x, i16 63
>> > +  store i8 %y, i8* %arrayidx
>> > +  ret void
>> > +}
>> > +
>> > +define void @store8nodisp(i8* %x, i8 %y) {
>> > +; CHECK-LABEL: store8nodisp:
>> > +; CHECK: movw r26, r24
>> > +; CHECK: subi r26, 192
>> > +; CHECK: sbci r27, 255
>> > +; CHECK: st {{[XYZ]}}, r22
>> > +  %arrayidx = getelementptr inbounds i8, i8* %x, i16 64
>> > +  store i8 %y, i8* %arrayidx
>> > +  ret void
>> > +}
>> > +
>> > +define void @store16disp(i16* %x, i16 %y) {
>> > +; CHECK-LABEL: store16disp:
>> > +; CHECK: std {{[YZ]}}+62, r22
>> > +; CHECK: std {{[YZ]}}+63, r23
>> > +  %arrayidx = getelementptr inbounds i16, i16* %x, i16 31
>> > +  store i16 %y, i16* %arrayidx
>> > +  ret void
>> > +}
>> > +
>> > +define void @store16nodisp(i16* %x, i16 %y) {
>> > +; CHECK-LABEL: store16nodisp:
>> > +; CHECK: movw r30, r24
>> > +; CHECK: subi r30, 192
>> > +; CHECK: sbci r31, 255
>> > +; CHECK: st {{[YZ]}}, r22
>> > +; CHECK: std {{[YZ]}}+1, r23
>> > +  %arrayidx = getelementptr inbounds i16, i16* %x, i16 32
>> > +  store i16 %y, i16* %arrayidx
>> > +  ret void
>> > +}
>> > +
>> > +define void @store8postinc(i8* %x, i8 %y) {
>> > +; CHECK-LABEL: store8postinc:
>> > +; CHECK: st {{[XYZ]}}+, {{.*}}
>> > +entry:
>> > +  %tobool3 = icmp eq i8 %y, 0
>> > +  br i1 %tobool3, label %while.end, label %while.body
>> > +while.body:                                       ; preds = %entry,
>> > %while.body
>> > +  %dec5.in = phi i8 [ %dec5, %while.body ], [ %y, %entry ]
>> > +  %x.addr.04 = phi i8* [ %incdec.ptr, %while.body ], [ %x, %entry ]
>> > +  %dec5 = add i8 %dec5.in, -1
>> > +  %incdec.ptr = getelementptr inbounds i8, i8* %x.addr.04, i16 1
>> > +  store i8 %dec5, i8* %x.addr.04
>> > +  %tobool = icmp eq i8 %dec5, 0
>> > +  br i1 %tobool, label %while.end, label %while.body
>> > +while.end:                                        ; preds =
>> > %while.body, %entry
>> > +  ret void
>> > +}
>> > +
>> > +define void @store16postinc(i16* %x, i16 %y) {
>> > +; CHECK-LABEL: store16postinc:
>> > +; CHECK: st {{[XYZ]}}+, {{.*}}
>> > +; CHECK: st {{[XYZ]}}+, {{.*}}
>> > +entry:
>> > +  %tobool3 = icmp eq i16 %y, 0
>> > +  br i1 %tobool3, label %while.end, label %while.body
>> > +while.body:                                       ; preds = %entry,
>> > %while.body
>> > +  %dec5.in = phi i16 [ %dec5, %while.body ], [ %y, %entry ]
>> > +  %x.addr.04 = phi i16* [ %incdec.ptr, %while.body ], [ %x, %entry ]
>> > +  %dec5 = add nsw i16 %dec5.in, -1
>> > +  %incdec.ptr = getelementptr inbounds i16, i16* %x.addr.04, i16 1
>> > +  store i16 %dec5, i16* %x.addr.04
>> > +  %tobool = icmp eq i16 %dec5, 0
>> > +  br i1 %tobool, label %while.end, label %while.body
>> > +while.end:                                        ; preds =
>> > %while.body, %entry
>> > +  ret void
>> > +}
>> > +
>> > +define void @store8predec(i8* %x, i8 %y) {
>> > +; CHECK-LABEL: store8predec:
>> > +; CHECK: st -{{[XYZ]}}, {{.*}}
>> > +entry:
>> > +  %tobool3 = icmp eq i8 %y, 0
>> > +  br i1 %tobool3, label %while.end, label %while.body
>> > +while.body:                                       ; preds = %entry,
>> > %while.body
>> > +  %dec5.in = phi i8 [ %dec5, %while.body ], [ %y, %entry ]
>> > +  %x.addr.04 = phi i8* [ %incdec.ptr, %while.body ], [ %x, %entry ]
>> > +  %dec5 = add i8 %dec5.in, -1
>> > +  %incdec.ptr = getelementptr inbounds i8, i8* %x.addr.04, i16 -1
>> > +  store i8 %dec5, i8* %incdec.ptr
>> > +  %tobool = icmp eq i8 %dec5, 0
>> > +  br i1 %tobool, label %while.end, label %while.body
>> > +while.end:                                        ; preds =
>> > %while.body, %entry
>> > +  ret void
>> > +}
>> > +
>> > +define void @store16predec(i16* %x, i16 %y) {
>> > +; CHECK-LABEL: store16predec:
>> > +; CHECK: st -{{[XYZ]}}, {{.*}}
>> > +; CHECK: st -{{[XYZ]}}, {{.*}}
>> > +entry:
>> > +  %tobool3 = icmp eq i16 %y, 0
>> > +  br i1 %tobool3, label %while.end, label %while.body
>> > +while.body:                                       ; preds = %entry,
>> > %while.body
>> > +  %dec5.in = phi i16 [ %dec5, %while.body ], [ %y, %entry ]
>> > +  %x.addr.04 = phi i16* [ %incdec.ptr, %while.body ], [ %x, %entry ]
>> > +  %dec5 = add nsw i16 %dec5.in, -1
>> > +  %incdec.ptr = getelementptr inbounds i16, i16* %x.addr.04, i16 -1
>> > +  store i16 %dec5, i16* %incdec.ptr
>> > +  %tobool = icmp eq i16 %dec5, 0
>> > +  br i1 %tobool, label %while.end, label %while.body
>> > +while.end:                                        ; preds =
>> > %while.body, %entry
>> > +  ret void
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/sub.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/sub.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/sub.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/sub.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,92 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +define i8 @sub8_reg_reg(i8 %a, i8 %b) {
>> > +; CHECK-LABEL: sub8_reg_reg:
>> > +; CHECK: sub r24, r22
>> > +    %result = sub i8 %a, %b
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i8 @sub8_reg_imm(i8 %a) {
>> > +; CHECK-LABEL: sub8_reg_imm:
>> > +; CHECK: subi r24, 5
>> > +    %result = sub i8 %a, 5
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i8 @sub8_reg_decrement(i8 %a) {
>> > +; CHECK-LABEL: sub8_reg_decrement:
>> > +; CHECK: dec r24
>> > +    %result = sub i8 %a, 1
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i16 @sub16_reg_reg(i16 %a, i16 %b) {
>> > +; CHECK-LABEL: sub16_reg_reg:
>> > +; CHECK: sub r24, r22
>> > +; CHECK: sbc r25, r23
>> > +    %result = sub i16 %a, %b
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i16 @sub16_reg_imm(i16 %a) {
>> > +; CHECK-LABEL: sub16_reg_imm:
>> > +; CHECK: sbiw r24, 63
>> > +    %result = sub i16 %a, 63
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i16 @sub16_reg_imm_subi(i16 %a) {
>> > +; CHECK-LABEL: sub16_reg_imm_subi:
>> > +; CHECK: subi r24, 210
>> > +; CHECK: sbci r25, 4
>> > +    %result = sub i16 %a, 1234
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i32 @sub32_reg_reg(i32 %a, i32 %b) {
>> > +; CHECK-LABEL: sub32_reg_reg:
>> > +; CHECK: sub r22, r18
>> > +; CHECK: sbc r23, r19
>> > +; CHECK: sbc r24, r20
>> > +; CHECK: sbc r25, r21
>> > +    %result = sub i32 %a, %b
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i32 @sub32_reg_imm(i32 %a) {
>> > +; CHECK-LABEL: sub32_reg_imm:
>> > +; CHECK: subi r22, 21
>> > +; CHECK: sbci r23, 205
>> > +; CHECK: sbci r24, 91
>> > +; CHECK: sbci r25, 7
>> > +    %result = sub i32 %a, 123456789
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i64 @sub64_reg_reg(i64 %a, i64 %b) {
>> > +; CHECK-LABEL: sub64_reg_reg:
>> > +; CHECK: sub r18, r10
>> > +; CHECK: sbc r20, r12
>> > +; CHECK: sbc r21, r13
>> > +; CHECK: sbc r22, r14
>> > +; CHECK: sbc r23, r15
>> > +; CHECK: sbc r24, r16
>> > +; CHECK: sbc r25, r17
>> > +    %result = sub i64 %a, %b
>> > +    ret i64 %result
>> > +}
>> > +
>> > +define i64 @sub64_reg_imm(i64 %a) {
>> > +; CHECK-LABEL: sub64_reg_imm:
>> > +; CHECK: subi r18, 204
>> > +; CHECK: sbci r19, 204
>> > +; CHECK: sbci r20, 104
>> > +; CHECK: sbci r21, 37
>> > +; CHECK: sbci r22, 25
>> > +; CHECK: sbci r23, 22
>> > +; CHECK: sbci r24, 236
>> > +; CHECK: sbci r25, 190
>> > +    %result = sub i64 %a, 13757395258967641292
>> > +    ret i64 %result
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/varargs.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/varargs.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/varargs.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/varargs.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,59 @@
>> > +; RUN: llc -mattr=sram,movw,addsubiw < %s -march=avr | FileCheck %s
>> > +
>> > +declare void @llvm.va_start(i8*)
>> > +declare i16 @vsprintf(i8* nocapture, i8* nocapture, i8*)
>> > +declare void @llvm.va_end(i8*)
>> > +
>> > +define i16 @varargs1(i8* nocapture %x, ...) {
>> > +; CHECK-LABEL: varargs1:
>> > +; CHECK: movw r20, r28
>> > +; CHECK: subi r20, 215
>> > +; CHECK: sbci r21, 255
>> > +; CHECK: movw r24, r28
>> > +; CHECK: adiw r24, 3
>> > +; CHECK: ldd r22, Y+39
>> > +; CHECK: ldd r23, Y+40
>> > +; CHECK: call
>> > +  %buffer = alloca [32 x i8]
>> > +  %ap = alloca i8*
>> > +  %ap1 = bitcast i8** %ap to i8*
>> > +  call void @llvm.va_start(i8* %ap1)
>> > +  %arraydecay = getelementptr inbounds [32 x i8], [32 x i8]* %buffer,
>> > i16 0, i16 0
>> > +  %1 = load i8*, i8** %ap
>> > +  %call = call i16 @vsprintf(i8* %arraydecay, i8* %x, i8* %1)
>> > +  call void @llvm.va_end(i8* %ap1)
>> > +  ret i16 0
>> > +}
>> > +
>> > +define i16 @varargs2(i8* nocapture %x, ...) {
>> > +; CHECK-LABEL: varargs2:
>> > +; CHECK: ld r24, Z
>> > +; CHECK: ldd r25, Z+1
>> > +  %ap = alloca i8*
>> > +  %ap1 = bitcast i8** %ap to i8*
>> > +  call void @llvm.va_start(i8* %ap1)
>> > +  %1 = va_arg i8** %ap, i16
>> > +  call void @llvm.va_end(i8* %ap1)
>> > +  ret i16 %1
>> > +}
>> > +
>> > +declare void @var1223(i16, ...)
>> > +define void @varargcall() {
>> > +; CHECK-LABEL: varargcall:
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 191
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 223
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 189
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 205
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: ldi [[REG1:r[0-9]+]], 205
>> > +; CHECK: ldi [[REG2:r[0-9]+]], 171
>> > +; CHECK: push [[REG2]]
>> > +; CHECK: push [[REG1]]
>> > +; CHECK: call
>> > +; CHECK: adiw r30, 6
>> > +  tail call void (i16, ...) @var1223(i16 -21555, i16 -12867, i16 -
>> > 8257)
>> > +  ret void
>> > +}
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/xor.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/xor.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/xor.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/xor.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,41 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +define i8 @xor8_reg_reg(i8 %a, i8 %b) {
>> > +; CHECK-LABEL: xor8_reg_reg:
>> > +; CHECK: eor r24, r22
>> > +    %result = xor i8 %a, %b
>> > +    ret i8 %result
>> > +}
>> > +
>> > +define i16 @xor16_reg_reg(i16 %a, i16 %b) {
>> > +; CHECK-LABEL: xor16_reg_reg:
>> > +; CHECK: eor r24, r22
>> > +; CHECK: eor r25, r23
>> > +    %result = xor i16 %a, %b
>> > +    ret i16 %result
>> > +}
>> > +
>> > +define i32 @xor32_reg_reg(i32 %a, i32 %b) {
>> > +; CHECK-LABEL: xor32_reg_reg:
>> > +; CHECK: eor r22, r18
>> > +; CHECK: eor r23, r19
>> > +; CHECK: eor r24, r20
>> > +; CHECK: eor r25, r21
>> > +    %result = xor i32 %a, %b
>> > +    ret i32 %result
>> > +}
>> > +
>> > +define i64 @xor64_reg_reg(i64 %a, i64 %b) {
>> > +; CHECK-LABEL: xor64_reg_reg:
>> > +; CHECK: eor r18, r10
>> > +; CHECK: eor r19, r11
>> > +; CHECK: eor r20, r12
>> > +; CHECK: eor r21, r13
>> > +; CHECK: eor r22, r14
>> > +; CHECK: eor r23, r15
>> > +; CHECK: eor r24, r16
>> > +; CHECK: eor r25, r17
>> > +    %result = xor i64 %a, %b
>> > +    ret i64 %result
>> > +}
>> > +
>> >
>> > Added: llvm/trunk/test/CodeGen/AVR/zext.ll
>> > URL: http://llvm.org/viewvc/llvm-
>> > project/llvm/trunk/test/CodeGen/AVR/zext.ll?rev=287162&view=auto
>> > =======================================================================
>> > =======
>> > --- llvm/trunk/test/CodeGen/AVR/zext.ll (added)
>> > +++ llvm/trunk/test/CodeGen/AVR/zext.ll Wed Nov 16 15:58:04 2016
>> > @@ -0,0 +1,31 @@
>> > +; RUN: llc < %s -march=avr | FileCheck %s
>> > +
>> > +; zext R25:R24, R24
>> > +; eor R25, R25
>> > +define i16 @zext1(i8 %x) {
>> > +; CHECK-LABEL: zext1:
>> > +; CHECK: eor r25, r25
>> > +  %1 = zext i8 %x to i16
>> > +  ret i16 %1
>> > +}
>> > +
>> > +; zext R25:R24, R20
>> > +; mov R24, R20
>> > +; eor R25, R25
>> > +define i16 @zext2(i8 %x, i8 %y) {
>> > +; CHECK-LABEL: zext2:
>> > +; CHECK: mov r24, r22
>> > +; CHECK: eor r25, r25
>> > +  %1 = zext i8 %y to i16
>> > +  ret i16 %1
>> > +}
>> > +
>> > +; zext R25:R24, R24
>> > +; eor R25, R25
>> > +define i16 @zext_i1(i1 %x) {
>> > +; CHECK-LABEL: zext_i1:
>> > +; CHECK: eor r25, r25
>> > +  %1 = zext i1 %x to i16
>> > +  ret i16 %1
>> > +}
>> > +
>> >
>> >
>> > _______________________________________________
>> > llvm-commits mailing list
>> > llvm-commits at lists.llvm.org
>> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20161117/5f11af29/attachment-0001.html>


More information about the llvm-commits mailing list