[llvm] r308849 - [AArch64] Redundant Copy Elimination - remove more zero copies.

Quentin Colombet via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 24 09:15:29 PDT 2017


Thanks Chad for the quick answer.

> On Jul 24, 2017, at 9:11 AM, Chad Rosier <mcrosier at codeaurora.org> wrote:
> 
> Hi Quentin,
> 
> The short answer is that change was basically noise across the board when the patch was committed.  

That was what I expected.

Cheers,
-Quentin

> Originally, the change was targeting a ~5% regression in SPEC2006/libquantum that was introduced after r306144.   However, the regression appear to be related to code layout and the benchmark somehow recovered prior to my commit.
> 
> The redundant copy elimination pass was originally designed to eliminate zero copies that were dominated by cbz/cbnz branches. However, in r306144 we/I transformed a bunch of cbz/cbnz to a Bcc, so this change was introduced to catch those cases missed due to r306144.
> 
> I was planning on working on the FIXME you mentioned this week and if anyone runs into a regression I'm happy to investigate accordingly.
> 
> Chad
> 
> On 7/24/2017 11:52 AM, Quentin Colombet wrote:
>> Hi Chad,
>> 
>> Out of curiosity, do you see any performance change with this commit?
>> In particular, I was curious to see if we are actually not introducing regressions because this instruction would have helped breaking dependencies in the out of order engine.
>> 
>> (Just curiosity, not something to act on since the next step is to replace w0 with wzr directly and thus the problem if any will go away.)
>> 
>> Cheers,
>> -Quentin
>>> On Jul 23, 2017, at 9:38 AM, Chad Rosier via llvm-commits <llvm-commits at lists.llvm.org> wrote:
>>> 
>>> Author: mcrosier
>>> Date: Sun Jul 23 09:38:08 2017
>>> New Revision: 308849
>>> 
>>> URL: http://llvm.org/viewvc/llvm-project?rev=308849&view=rev
>>> Log:
>>> [AArch64] Redundant Copy Elimination - remove more zero copies.
>>> 
>>> This patch removes unnecessary zero copies in BBs that are targets of b.eq/b.ne
>>> and we know the result of the compare instruction is zero.  For example,
>>> 
>>> BB#0:
>>>  subs w0, w1, w2
>>>  str w0, [x1]
>>>  b.ne .LBB0_2
>>> BB#1:
>>>  mov w0, wzr  ; <-- redundant
>>>  str w0, [x2]
>>> .LBB0_2
>>> 
>>> Differential Revision: https://reviews.llvm.org/D35075
>>> 
>>> Added:
>>>    llvm/trunk/test/CodeGen/AArch64/machine-zero-copy-remove.mir
>>> Modified:
>>>    llvm/trunk/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp
>>> 
>>> Modified: llvm/trunk/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp?rev=308849&r1=308848&r2=308849&view=diff
>>> ==============================================================================
>>> --- llvm/trunk/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp (original)
>>> +++ llvm/trunk/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp Sun Jul 23 09:38:08 2017
>>> @@ -5,27 +5,51 @@
>>> // This file is distributed under the University of Illinois Open Source
>>> // License. See LICENSE.TXT for details.
>>> //
>>> -// This pass removes unnecessary zero copies in BBs that are targets of
>>> -// cbz/cbnz instructions. For instance, the copy instruction in the code below
>>> -// can be removed because the CBZW jumps to BB#2 when W0 is zero.
>>> +// This pass removes unnecessary copies/moves in BBs based on a dominating
>>> +// condition.
>>> +//
>>> +// We handle three cases:
>>> +// 1. For BBs that are targets of CBZ/CBNZ instructions, we know the value of
>>> +//    the CBZ/CBNZ source register is zero on the taken/not-taken path. For
>>> +//    instance, the copy instruction in the code below can be removed because
>>> +//    the CBZW jumps to BB#2 when w0 is zero.
>>> +//
>>> //  BB#1:
>>> -//    CBZW %W0, <BB#2>
>>> -//  BB#2:
>>> -//    %W0 = COPY %WZR
>>> -// Similarly, this pass also handles non-zero copies.
>>> +//    cbz w0, .LBB0_2
>>> +//  .LBB0_2:
>>> +//    mov w0, wzr  ; <-- redundant
>>> +//
>>> +// 2. If the flag setting instruction defines a register other than WZR/XZR, we
>>> +//    can remove a zero copy in some cases.
>>> +//
>>> +//  BB#0:
>>> +//    subs w0, w1, w2
>>> +//    str w0, [x1]
>>> +//    b.ne .LBB0_2
>>> +//  BB#1:
>>> +//    mov w0, wzr  ; <-- redundant
>>> +//    str w0, [x2]
>>> +//  .LBB0_2
>>> +//
>>> +// 3. Finally, if the flag setting instruction is a comparison against a
>>> +//    constant (i.e., ADDS[W|X]ri, SUBS[W|X]ri), we can remove a mov immediate
>>> +//    in some cases.
>>> +//
>>> //  BB#0:
>>> -//    cmp x0, #1
>>> +//    subs xzr, x0, #1
>>> //    b.eq .LBB0_1
>>> //  .LBB0_1:
>>> -//    orr x0, xzr, #0x1
>>> +//    orr x0, xzr, #0x1  ; <-- redundant
>>> //
>>> // This pass should be run after register allocation.
>>> //
>>> // FIXME: This could also be extended to check the whole dominance subtree below
>>> // the comparison if the compile time regression is acceptable.
>>> //
>>> +// FIXME: Add support for handling CCMP instructions.
>>> +// FIXME: If the known register value is zero, we should be able to rewrite uses
>>> +//        to use WZR/XZR directly in some cases.
>>> //===----------------------------------------------------------------------===//
>>> -
>>> #include "AArch64.h"
>>> #include "llvm/ADT/Optional.h"
>>> #include "llvm/ADT/SetVector.h"
>>> @@ -45,7 +69,13 @@ namespace {
>>> class AArch64RedundantCopyElimination : public MachineFunctionPass {
>>>   const MachineRegisterInfo *MRI;
>>>   const TargetRegisterInfo *TRI;
>>> -  BitVector ClobberedRegs;
>>> +
>>> +  // DomBBClobberedRegs is used when computing known values in the dominating
>>> +  // BB.
>>> +  BitVector DomBBClobberedRegs;
>>> +
>>> +  // OptBBClobberedRegs is used when optimizing away redundant copies/moves.
>>> +  BitVector OptBBClobberedRegs;
>>> 
>>> public:
>>>   static char ID;
>>> @@ -60,10 +90,10 @@ public:
>>>     RegImm(MCPhysReg Reg, int32_t Imm) : Reg(Reg), Imm(Imm) {}
>>>   };
>>> 
>>> -  Optional<RegImm> knownRegValInBlock(MachineInstr &CondBr,
>>> -                                      MachineBasicBlock *MBB,
>>> -                                      MachineBasicBlock::iterator &FirstUse);
>>> -  bool optimizeCopy(MachineBasicBlock *MBB);
>>> +  bool knownRegValInBlock(MachineInstr &CondBr, MachineBasicBlock *MBB,
>>> +                          SmallVectorImpl<RegImm> &KnownRegs,
>>> +                          MachineBasicBlock::iterator &FirstUse);
>>> +  bool optimizeBlock(MachineBasicBlock *MBB);
>>>   bool runOnMachineFunction(MachineFunction &MF) override;
>>>   MachineFunctionProperties getRequiredProperties() const override {
>>>     return MachineFunctionProperties().set(
>>> @@ -103,13 +133,19 @@ static void trackRegDefs(const MachineIn
>>> 
>>> /// It's possible to determine the value of a register based on a dominating
>>> /// condition.  To do so, this function checks to see if the basic block \p MBB
>>> -/// is the target to which a conditional branch \p CondBr jumps and whose
>>> -/// equality comparison is against a constant.  If so, return a known physical
>>> -/// register and constant value pair.  Otherwise, return None.
>>> -Optional<AArch64RedundantCopyElimination::RegImm>
>>> -AArch64RedundantCopyElimination::knownRegValInBlock(
>>> +/// is the target of a conditional branch \p CondBr with an equality comparison.
>>> +/// If the branch is a CBZ/CBNZ, we know the value of its source operand is zero
>>> +/// in \p MBB for some cases.  Otherwise, we find and inspect the NZCV setting
>>> +/// instruction (e.g., SUBS, ADDS).  If this instruction defines a register
>>> +/// other than WZR/XZR, we know the value of the destination register is zero in
>>> +/// \p MMB for some cases.  In addition, if the NZCV setting instruction is
>>> +/// comparing against a constant we know the other source register is equal to
>>> +/// the constant in \p MBB for some cases.  If we find any constant values, push
>>> +/// a physical register and constant value pair onto the KnownRegs vector and
>>> +/// return true.  Otherwise, return false if no known values were found.
>>> +bool AArch64RedundantCopyElimination::knownRegValInBlock(
>>>     MachineInstr &CondBr, MachineBasicBlock *MBB,
>>> -    MachineBasicBlock::iterator &FirstUse) {
>>> +    SmallVectorImpl<RegImm> &KnownRegs, MachineBasicBlock::iterator &FirstUse) {
>>>   unsigned Opc = CondBr.getOpcode();
>>> 
>>>   // Check if the current basic block is the target block to which the
>>> @@ -119,41 +155,39 @@ AArch64RedundantCopyElimination::knownRe
>>>       ((Opc == AArch64::CBNZW || Opc == AArch64::CBNZX) &&
>>>        MBB != CondBr.getOperand(1).getMBB())) {
>>>     FirstUse = CondBr;
>>> -    return RegImm(CondBr.getOperand(0).getReg(), 0);
>>> +    KnownRegs.push_back(RegImm(CondBr.getOperand(0).getReg(), 0));
>>> +    return true;
>>>   }
>>> 
>>>   // Otherwise, must be a conditional branch.
>>>   if (Opc != AArch64::Bcc)
>>> -    return None;
>>> +    return false;
>>> 
>>>   // Must be an equality check (i.e., == or !=).
>>>   AArch64CC::CondCode CC = (AArch64CC::CondCode)CondBr.getOperand(0).getImm();
>>>   if (CC != AArch64CC::EQ && CC != AArch64CC::NE)
>>> -    return None;
>>> +    return false;
>>> 
>>>   MachineBasicBlock *BrTarget = CondBr.getOperand(1).getMBB();
>>>   if ((CC == AArch64CC::EQ && BrTarget != MBB) ||
>>>       (CC == AArch64CC::NE && BrTarget == MBB))
>>> -    return None;
>>> +    return false;
>>> 
>>>   // Stop if we get to the beginning of PredMBB.
>>>   MachineBasicBlock *PredMBB = *MBB->pred_begin();
>>>   assert(PredMBB == CondBr.getParent() &&
>>>          "Conditional branch not in predecessor block!");
>>>   if (CondBr == PredMBB->begin())
>>> -    return None;
>>> +    return false;
>>> 
>>>   // Registers clobbered in PredMBB between CondBr instruction and current
>>>   // instruction being checked in loop.
>>> -  ClobberedRegs.reset();
>>> +  DomBBClobberedRegs.reset();
>>> 
>>>   // Find compare instruction that sets NZCV used by CondBr.
>>>   MachineBasicBlock::reverse_iterator RIt = CondBr.getReverseIterator();
>>>   for (MachineInstr &PredI : make_range(std::next(RIt), PredMBB->rend())) {
>>> 
>>> -    // Track clobbered registers.
>>> -    trackRegDefs(PredI, ClobberedRegs, TRI);
>>> -
>>>     bool IsCMN = false;
>>>     switch (PredI.getOpcode()) {
>>>     default:
>>> @@ -167,36 +201,99 @@ AArch64RedundantCopyElimination::knownRe
>>>     // CMP is an alias for SUBS with a dead destination register.
>>>     case AArch64::SUBSWri:
>>>     case AArch64::SUBSXri: {
>>> +      MCPhysReg DstReg = PredI.getOperand(0).getReg();
>>>       MCPhysReg SrcReg = PredI.getOperand(1).getReg();
>>> 
>>> -      // Must not be a symbolic immediate.
>>> -      if (!PredI.getOperand(2).isImm())
>>> -        return None;
>>> -
>>> -      // The src register must not be modified between the cmp and conditional
>>> -      // branch.  This includes a self-clobbering compare.
>>> -      if (ClobberedRegs[SrcReg])
>>> -        return None;
>>> -
>>> -      // We've found the Cmp that sets NZCV.
>>> -      int32_t KnownImm = PredI.getOperand(2).getImm();
>>> -      int32_t Shift = PredI.getOperand(3).getImm();
>>> -      KnownImm <<= Shift;
>>> -      if (IsCMN)
>>> -        KnownImm = -KnownImm;
>>> +      bool Res = false;
>>> +      // If we're comparing against a non-symbolic immediate and the source
>>> +      // register of the compare is not modified (including a self-clobbering
>>> +      // compare) between the compare and conditional branch we known the value
>>> +      // of the 1st source operand.
>>> +      if (PredI.getOperand(2).isImm() && !DomBBClobberedRegs[SrcReg] &&
>>> +          SrcReg != DstReg) {
>>> +        // We've found the instruction that sets NZCV.
>>> +        int32_t KnownImm = PredI.getOperand(2).getImm();
>>> +        int32_t Shift = PredI.getOperand(3).getImm();
>>> +        KnownImm <<= Shift;
>>> +        if (IsCMN)
>>> +          KnownImm = -KnownImm;
>>> +        FirstUse = PredI;
>>> +        KnownRegs.push_back(RegImm(SrcReg, KnownImm));
>>> +        Res = true;
>>> +      }
>>> +
>>> +      // If this instructions defines something other than WZR/XZR, we know it's
>>> +      // result is zero in some cases.
>>> +      if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
>>> +        return Res;
>>> +
>>> +      // The destination register must not be modified between the NZCV setting
>>> +      // instruction and the conditional branch.
>>> +      if (DomBBClobberedRegs[DstReg])
>>> +        return Res;
>>> +
>>>       FirstUse = PredI;
>>> -      return RegImm(SrcReg, KnownImm);
>>> +      KnownRegs.push_back(RegImm(DstReg, 0));
>>> +      return true;
>>> +    }
>>> +
>>> +    // Look for NZCV setting instructions that define something other than
>>> +    // WZR/XZR.
>>> +    case AArch64::ADCSWr:
>>> +    case AArch64::ADCSXr:
>>> +    case AArch64::ADDSWrr:
>>> +    case AArch64::ADDSWrs:
>>> +    case AArch64::ADDSWrx:
>>> +    case AArch64::ADDSXrr:
>>> +    case AArch64::ADDSXrs:
>>> +    case AArch64::ADDSXrx:
>>> +    case AArch64::ADDSXrx64:
>>> +    case AArch64::ANDSWri:
>>> +    case AArch64::ANDSWrr:
>>> +    case AArch64::ANDSWrs:
>>> +    case AArch64::ANDSXri:
>>> +    case AArch64::ANDSXrr:
>>> +    case AArch64::ANDSXrs:
>>> +    case AArch64::BICSWrr:
>>> +    case AArch64::BICSWrs:
>>> +    case AArch64::BICSXrs:
>>> +    case AArch64::BICSXrr:
>>> +    case AArch64::SBCSWr:
>>> +    case AArch64::SBCSXr:
>>> +    case AArch64::SUBSWrr:
>>> +    case AArch64::SUBSWrs:
>>> +    case AArch64::SUBSWrx:
>>> +    case AArch64::SUBSXrr:
>>> +    case AArch64::SUBSXrs:
>>> +    case AArch64::SUBSXrx:
>>> +    case AArch64::SUBSXrx64: {
>>> +      MCPhysReg DstReg = PredI.getOperand(0).getReg();
>>> +      if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
>>> +        return false;
>>> +
>>> +      // The destination register of the NZCV setting instruction must not be
>>> +      // modified before the conditional branch.
>>> +      if (DomBBClobberedRegs[DstReg])
>>> +        return false;
>>> +
>>> +      // We've found the instruction that sets NZCV whose DstReg == 0.
>>> +      FirstUse = PredI;
>>> +      KnownRegs.push_back(RegImm(DstReg, 0));
>>> +      return true;
>>>     }
>>>     }
>>> 
>>>     // Bail if we see an instruction that defines NZCV that we don't handle.
>>>     if (PredI.definesRegister(AArch64::NZCV))
>>> -      return None;
>>> +      return false;
>>> +
>>> +    // Track clobbered registers.
>>> +    trackRegDefs(PredI, DomBBClobberedRegs, TRI);
>>>   }
>>> -  return None;
>>> +  return false;
>>> }
>>> 
>>> -bool AArch64RedundantCopyElimination::optimizeCopy(MachineBasicBlock *MBB) {
>>> +bool AArch64RedundantCopyElimination::optimizeBlock(MachineBasicBlock *MBB) {
>>>   // Check if the current basic block has a single predecessor.
>>>   if (MBB->pred_size() != 1)
>>>     return false;
>>> @@ -227,14 +324,11 @@ bool AArch64RedundantCopyElimination::op
>>>   do {
>>>     --Itr;
>>> 
>>> -    Optional<RegImm> KnownRegImm = knownRegValInBlock(*Itr, MBB, FirstUse);
>>> -    if (KnownRegImm == None)
>>> +    if (!knownRegValInBlock(*Itr, MBB, KnownRegs, FirstUse))
>>>       continue;
>>> 
>>> -    KnownRegs.push_back(*KnownRegImm);
>>> -
>>> -    // Reset the clobber list, which is used by knownRegValInBlock.
>>> -    ClobberedRegs.reset();
>>> +    // Reset the clobber list.
>>> +    OptBBClobberedRegs.reset();
>>> 
>>>     // Look backward in PredMBB for COPYs from the known reg to find other
>>>     // registers that are known to be a constant value.
>>> @@ -246,11 +340,11 @@ bool AArch64RedundantCopyElimination::op
>>>         MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();
>>>         MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();
>>>         for (auto &KnownReg : KnownRegs) {
>>> -          if (ClobberedRegs[KnownReg.Reg])
>>> +          if (OptBBClobberedRegs[KnownReg.Reg])
>>>             continue;
>>>           // If we have X = COPY Y, and Y is known to be zero, then now X is
>>>           // known to be zero.
>>> -          if (CopySrcReg == KnownReg.Reg && !ClobberedRegs[CopyDstReg]) {
>>> +          if (CopySrcReg == KnownReg.Reg && !OptBBClobberedRegs[CopyDstReg]) {
>>>             KnownRegs.push_back(RegImm(CopyDstReg, KnownReg.Imm));
>>>             if (SeenFirstUse)
>>>               FirstUse = PredI;
>>> @@ -258,7 +352,7 @@ bool AArch64RedundantCopyElimination::op
>>>           }
>>>           // If we have X = COPY Y, and X is known to be zero, then now Y is
>>>           // known to be zero.
>>> -          if (CopyDstReg == KnownReg.Reg && !ClobberedRegs[CopySrcReg]) {
>>> +          if (CopyDstReg == KnownReg.Reg && !OptBBClobberedRegs[CopySrcReg]) {
>>>             KnownRegs.push_back(RegImm(CopySrcReg, KnownReg.Imm));
>>>             if (SeenFirstUse)
>>>               FirstUse = PredI;
>>> @@ -271,10 +365,10 @@ bool AArch64RedundantCopyElimination::op
>>>       if (PredI == PredMBB->begin())
>>>         break;
>>> 
>>> -      trackRegDefs(*PredI, ClobberedRegs, TRI);
>>> +      trackRegDefs(*PredI, OptBBClobberedRegs, TRI);
>>>       // Stop if all of the known-zero regs have been clobbered.
>>>       if (all_of(KnownRegs, [&](RegImm KnownReg) {
>>> -            return ClobberedRegs[KnownReg.Reg];
>>> +            return OptBBClobberedRegs[KnownReg.Reg];
>>>           }))
>>>         break;
>>>     }
>>> @@ -290,7 +384,7 @@ bool AArch64RedundantCopyElimination::op
>>>   // UsedKnownRegs is the set of KnownRegs that have had uses added to MBB.
>>>   SmallSetVector<unsigned, 4> UsedKnownRegs;
>>>   MachineBasicBlock::iterator LastChange = MBB->begin();
>>> -  // Remove redundant Copy instructions unless KnownReg is modified.
>>> +  // Remove redundant copy/move instructions unless KnownReg is modified.
>>>   for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E;) {
>>>     MachineInstr *MI = &*I;
>>>     ++I;
>>> @@ -393,13 +487,14 @@ bool AArch64RedundantCopyElimination::ru
>>>   TRI = MF.getSubtarget().getRegisterInfo();
>>>   MRI = &MF.getRegInfo();
>>> 
>>> -  // Resize the clobber register bitfield tracker.  We do this once per
>>> -  // function and then clear the bitfield each time we optimize a copy.
>>> -  ClobberedRegs.resize(TRI->getNumRegs());
>>> +  // Resize the clobber register bitfield trackers.  We do this once per
>>> +  // function.
>>> +  DomBBClobberedRegs.resize(TRI->getNumRegs());
>>> +  OptBBClobberedRegs.resize(TRI->getNumRegs());
>>> 
>>>   bool Changed = false;
>>>   for (MachineBasicBlock &MBB : MF)
>>> -    Changed |= optimizeCopy(&MBB);
>>> +    Changed |= optimizeBlock(&MBB);
>>>   return Changed;
>>> }
>>> 
>>> 
>>> Added: llvm/trunk/test/CodeGen/AArch64/machine-zero-copy-remove.mir
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/machine-zero-copy-remove.mir?rev=308849&view=auto
>>> ==============================================================================
>>> --- llvm/trunk/test/CodeGen/AArch64/machine-zero-copy-remove.mir (added)
>>> +++ llvm/trunk/test/CodeGen/AArch64/machine-zero-copy-remove.mir Sun Jul 23 09:38:08 2017
>>> @@ -0,0 +1,565 @@
>>> +# RUN: llc -mtriple=aarch64--linux-gnu -run-pass=aarch64-copyelim %s -verify-machineinstrs -o - | FileCheck %s
>>> +---
>>> +# CHECK-LABEL: name: test1
>>> +# CHECK: ANDSWri %w0, 1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test1
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %x1, %x2
>>> +
>>> +    %w0 = ANDSWri %w0, 1, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x1, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test2
>>> +# CHECK: ANDSXri %x0, 1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test2
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2
>>> +
>>> +    %x0 = ANDSXri %x0, 1, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x1, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test3
>>> +# CHECK: ADDSWri %w0, 1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test3
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %x1, %x2
>>> +
>>> +    %w0 = ADDSWri %w0, 1, 0, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x1, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test4
>>> +# CHECK: ADDSXri %x0, 1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test4
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2
>>> +
>>> +    %x0 = ADDSXri %x0, 1, 0, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x1, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test5
>>> +# CHECK: SUBSWri %w0, 1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test5
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %x1, %x2
>>> +
>>> +    %w0 = SUBSWri %w0, 1, 0, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x1, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test6
>>> +# CHECK: SUBSXri %x0, 1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test6
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2
>>> +
>>> +    %x0 = SUBSXri %x0, 1, 0, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x1, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test7
>>> +# CHECK: ADDSWrr %w0, %w1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test7
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %w1, %x2, %x3
>>> +
>>> +    %w0 = ADDSWrr %w0, %w1, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test8
>>> +# CHECK: ADDSXrr %x0, %x1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test8
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2, %x3
>>> +
>>> +    %x0 = ADDSXrr %x0, %x1, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test9
>>> +# CHECK: ANDSWrr %w0, %w1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test9
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %w1, %x2, %x3
>>> +
>>> +    %w0 = ANDSWrr %w0, %w1, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test10
>>> +# CHECK: ANDSXrr %x0, %x1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test10
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2, %x3
>>> +
>>> +    %x0 = ANDSXrr %x0, %x1, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test11
>>> +# CHECK: BICSWrr %w0, %w1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test11
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %w1, %x2, %x3
>>> +
>>> +    %w0 = BICSWrr %w0, %w1, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test12
>>> +# CHECK: BICSXrr %x0, %x1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test12
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2, %x3
>>> +
>>> +    %x0 = BICSXrr %x0, %x1, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test13
>>> +# CHECK: SUBSWrr %w0, %w1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test13
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %w1, %x2, %x3
>>> +
>>> +    %w0 = SUBSWrr %w0, %w1, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test14
>>> +# CHECK: SUBSXrr %x0, %x1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test14
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2, %x3
>>> +
>>> +    %x0 = SUBSXrr %x0, %x1, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test15
>>> +# CHECK: ADDSWrs %w0, %w1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test15
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %w1, %x2, %x3
>>> +
>>> +    %w0 = ADDSWrs %w0, %w1, 0, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test16
>>> +# CHECK: ADDSXrs %x0, %x1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test16
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2, %x3
>>> +
>>> +    %x0 = ADDSXrs %x0, %x1, 0, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test17
>>> +# CHECK: ANDSWrs %w0, %w1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test17
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %w1, %x2, %x3
>>> +
>>> +    %w0 = ANDSWrs %w0, %w1, 0, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test18
>>> +# CHECK: ANDSXrs %x0, %x1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %xzr
>>> +name:            test18
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2, %x3
>>> +
>>> +    %x0 = ANDSXrs %x0, %x1, 0, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %x0 = COPY %xzr
>>> +    STRXui killed %x0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# CHECK-LABEL: name: test19
>>> +# CHECK: BICSWrs %w0, %w1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: COPY %wzr
>>> +name:            test19
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %w1, %x2, %x3
>>> +
>>> +    %w0 = BICSWrs %w0, %w1, 0, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x2, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x3
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x3, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# Unicorn test - we can remove a redundant copy and a redundant mov
>>> +# CHECK-LABEL: name: test20
>>> +# CHECK: SUBSWri %w1, 1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK-NOT: %w0 = COPY %wzr
>>> +# CHECK-NOT: %w1 = MOVi32imm 1
>>> +name:            test20
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w1, %x2
>>> +
>>> +    %w0 = SUBSWri %w1, 1, 0, implicit-def %nzcv
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %w0 = COPY %wzr
>>> +    %w1 = MOVi32imm 1
>>> +    STRWui killed %w0, %x2, 0
>>> +    STRWui killed %w1, killed %x2, 1
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +
>>> +...
>>> +# Negative test - MOVi32imm clobbers %w0
>>> +# CHECK-LABEL: name: test21
>>> +# CHECK: ANDSWri %w0, 1, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK: %w0 = COPY %wzr
>>> +name:            test21
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %x1, %x2
>>> +
>>> +    %w0 = ANDSWri %w0, 1, implicit-def %nzcv
>>> +    STRWui killed %w0, %x1, 0
>>> +    %w0 = MOVi32imm -1
>>> +    STRWui killed %w0, killed %x1, 1
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# Negative test - SUBSXri self-clobbers x0, so MOVi64imm can't be removed
>>> +# CHECK-LABEL: name: test22
>>> +# CHECK: SUBSXri %x0, 1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK: %x0 = MOVi64imm 1
>>> +name:            test22
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %x0, %x1, %x2
>>> +
>>> +    %x0 = SUBSXri %x0, 1, 0, implicit-def %nzcv
>>> +    STRXui killed %x0, killed %x1, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %x0 = MOVi64imm 1
>>> +    STRXui killed %x0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> +...
>>> +# Negative test - bb.1 has multiple preds
>>> +# CHECK-LABEL: name: test23
>>> +# CHECK: ADDSWri %w0, 1, 0, implicit-def %nzcv
>>> +# CHECK: bb.1:
>>> +# CHECK: COPY %wzr
>>> +name:            test23
>>> +tracksRegLiveness: true
>>> +body:             |
>>> +  bb.0.entry:
>>> +    liveins: %w0, %x1, %x2
>>> +
>>> +    %w0 = ADDSWri %w0, 1, 0, implicit-def %nzcv
>>> +    STRWui killed %w0, killed %x1, 0
>>> +    Bcc 1, %bb.2, implicit killed %nzcv
>>> +    B %bb.1
>>> +
>>> +  bb.3:
>>> +    B %bb.1
>>> +
>>> +  bb.1:
>>> +    liveins: %x2
>>> +
>>> +    %w0 = COPY %wzr
>>> +    STRWui killed %w0, killed %x2, 0
>>> +
>>> +  bb.2:
>>> +    RET_ReallyLR
>>> 
>>> 
>>> _______________________________________________
>>> 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