//=- AArch64RedundantCopyElimination.cpp - Remove useless copy for AArch64 -=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // This 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: // 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: // subs xzr, x0, #1 // b.eq .LBB0_1 // .LBB0_1: // 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/SetVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/iterator_range.h" #include "llvm/CodeGen/LiveRegUnits.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" usingnamespacellvm; #define DEBUG_TYPE … STATISTIC(NumCopiesRemoved, "Number of copies removed."); namespace { class AArch64RedundantCopyElimination : public MachineFunctionPass { … }; char AArch64RedundantCopyElimination::ID = …; } INITIALIZE_PASS(…) /// 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 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, SmallVectorImpl<RegImm> &KnownRegs, MachineBasicBlock::iterator &FirstUse) { … } bool AArch64RedundantCopyElimination::optimizeBlock(MachineBasicBlock *MBB) { … } bool AArch64RedundantCopyElimination::runOnMachineFunction( MachineFunction &MF) { … } FunctionPass *llvm::createAArch64RedundantCopyEliminationPass() { … }