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

Yung, Douglas via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 16 16:13:14 PST 2016


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


More information about the llvm-commits mailing list