summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorJun Bum Lim <junbuml@codeaurora.org>2016-02-16 20:02:39 +0000
committerJun Bum Lim <junbuml@codeaurora.org>2016-02-16 20:02:39 +0000
commitb389d9b9af204a5891a0e1c4f077ca8fca231890 (patch)
tree28c58627d27b50aa041871b02df9ed8558c0be00 /llvm/lib/Target
parentba2a01645b54020f6f852edddd1e40d3a096e093 (diff)
downloadbcm5719-llvm-b389d9b9af204a5891a0e1c4f077ca8fca231890.tar.gz
bcm5719-llvm-b389d9b9af204a5891a0e1c4f077ca8fca231890.zip
[AArch64] Add pass to remove redundant copy after RA
Summary: This change will add a pass to remove unnecessary zero copies in target blocks of cbz/cbnz instructions. E.g., the copy instruction in the code below can be removed because the cbz jumps to BB1 when x0 is zero : BB0: cbz x0, .BB1 BB1: mov x0, xzr Jun Reviewers: gberry, jmolloy, HaoLiu, MatzeB, mcrosier Subscribers: mcrosier, mssimpso, haicheng, bmakam, llvm-commits, aemerson, rengolin Differential Revision: http://reviews.llvm.org/D16203 llvm-svn: 261004
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/AArch64/AArch64.h1
-rw-r--r--llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp170
-rw-r--r--llvm/lib/Target/AArch64/AArch64TargetMachine.cpp9
-rw-r--r--llvm/lib/Target/AArch64/CMakeLists.txt1
4 files changed, 181 insertions, 0 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h
index 21106c9ad29..d4c9e6bcdfe 100644
--- a/llvm/lib/Target/AArch64/AArch64.h
+++ b/llvm/lib/Target/AArch64/AArch64.h
@@ -27,6 +27,7 @@ class FunctionPass;
class MachineFunctionPass;
FunctionPass *createAArch64DeadRegisterDefinitions();
+FunctionPass *createAArch64RedundantCopyEliminationPass();
FunctionPass *createAArch64ConditionalCompares();
FunctionPass *createAArch64AdvSIMDScalar();
FunctionPass *createAArch64BranchRelaxation();
diff --git a/llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp b/llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp
new file mode 100644
index 00000000000..4a1e25254fc
--- /dev/null
+++ b/llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp
@@ -0,0 +1,170 @@
+//=- AArch64RedundantCopyElimination.cpp - Remove useless copy for AArch64 -=//
+//
+// The LLVM Compiler Infrastructure
+//
+// 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.
+// BB#1:
+// CBZW %W0, <BB#2>
+// BB#2:
+// %W0 = COPY %WZR
+// This pass should be run after register allocation.
+//
+// FIXME: This should be extended to handle any constant other than zero. E.g.,
+// cmp w0, #1
+// b.eq .BB1
+// BB1:
+// mov w0, #1
+//
+// FIXME: This could also be extended to check the whole dominance subtree below
+// the comparison if the compile time regression is acceptable.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AArch64.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "aarch64-copyelim"
+
+STATISTIC(NumCopiesRemoved, "Number of copies removed.");
+
+namespace llvm {
+void initializeAArch64RedundantCopyEliminationPass(PassRegistry &);
+}
+
+namespace {
+class AArch64RedundantCopyElimination : public MachineFunctionPass {
+ const MachineRegisterInfo *MRI;
+ const TargetRegisterInfo *TRI;
+
+public:
+ static char ID;
+ AArch64RedundantCopyElimination() : MachineFunctionPass(ID) {}
+ bool optimizeCopy(MachineBasicBlock *MBB);
+ bool runOnMachineFunction(MachineFunction &MF) override;
+ const char *getPassName() const override {
+ return "AArch64 Redundant Copy Elimination";
+ }
+};
+char AArch64RedundantCopyElimination::ID = 0;
+}
+
+INITIALIZE_PASS(AArch64RedundantCopyElimination, "aarch64-copyelim",
+ "AArch64 redundant copy elimination pass", false, false)
+
+bool AArch64RedundantCopyElimination::optimizeCopy(MachineBasicBlock *MBB) {
+ // Check if the current basic block has a single predecessor.
+ if (MBB->pred_size() != 1)
+ return false;
+
+ MachineBasicBlock *PredMBB = *MBB->pred_begin();
+ MachineBasicBlock::iterator CompBr = PredMBB->getLastNonDebugInstr();
+ if (CompBr == PredMBB->end() || PredMBB->succ_size() != 2)
+ return false;
+
+ unsigned LastOpc = CompBr->getOpcode();
+ // Check if the current basic block is the target block to which the cbz/cbnz
+ // instruction jumps when its Wt/Xt is zero.
+ if (LastOpc == AArch64::CBZW || LastOpc == AArch64::CBZX) {
+ if (MBB != CompBr->getOperand(1).getMBB())
+ return false;
+ } else if (LastOpc == AArch64::CBNZW || LastOpc == AArch64::CBNZX) {
+ if (MBB == CompBr->getOperand(1).getMBB())
+ return false;
+ } else {
+ return false;
+ }
+
+ unsigned TargetReg = CompBr->getOperand(0).getReg();
+ if (!TargetReg)
+ return false;
+ assert(TargetRegisterInfo::isPhysicalRegister(TargetReg) &&
+ "Expect physical register");
+
+ // Remember all registers aliasing with TargetReg.
+ SmallSetVector<unsigned, 8> TargetRegs;
+ for (MCRegAliasIterator AI(TargetReg, TRI, true); AI.isValid(); ++AI)
+ TargetRegs.insert(*AI);
+
+ bool Changed = false;
+ // Remove redundant Copy instructions unless TargetReg is modified.
+ for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E;) {
+ MachineInstr *MI = &*I;
+ ++I;
+ if (MI->isCopy() && MI->getOperand(0).isReg() &&
+ MI->getOperand(1).isReg()) {
+
+ unsigned DefReg = MI->getOperand(0).getReg();
+ unsigned SrcReg = MI->getOperand(1).getReg();
+
+ if ((SrcReg == AArch64::XZR || SrcReg == AArch64::WZR) &&
+ !MRI->isReserved(DefReg) &&
+ (TargetReg == DefReg || TRI->isSuperRegister(DefReg, TargetReg))) {
+
+ CompBr->clearRegisterKills(DefReg, TRI);
+ if (MBB->isLiveIn(DefReg))
+ // Clear any kills of TargetReg between CompBr and MI.
+ for (MachineInstr &MMI :
+ make_range(MBB->begin()->getIterator(), MI->getIterator()))
+ MMI.clearRegisterKills(DefReg, TRI);
+ else
+ MBB->addLiveIn(DefReg);
+
+ DEBUG(dbgs() << "Remove redundant Copy : ");
+ DEBUG((MI)->print(dbgs()));
+
+ MI->eraseFromParent();
+ Changed = true;
+ NumCopiesRemoved++;
+ continue;
+ }
+ }
+
+ for (const MachineOperand &MO : MI->operands()) {
+ // FIXME: It is possible to use the register mask to check if all
+ // registers in TargetRegs are not clobbered. For now, we treat it like
+ // a basic block boundary.
+ if (MO.isRegMask())
+ return Changed;
+ if (!MO.isReg())
+ continue;
+ unsigned Reg = MO.getReg();
+
+ if (!Reg)
+ continue;
+
+ assert(TargetRegisterInfo::isPhysicalRegister(Reg) &&
+ "Expect physical register");
+
+ // Stop if the TargetReg is modified.
+ if (MO.isDef() && TargetRegs.count(Reg))
+ return Changed;
+ }
+ }
+ return Changed;
+}
+
+bool AArch64RedundantCopyElimination::runOnMachineFunction(
+ MachineFunction &MF) {
+ TRI = MF.getSubtarget().getRegisterInfo();
+ MRI = &MF.getRegInfo();
+ bool Changed = false;
+ for (MachineBasicBlock &MBB : MF)
+ Changed |= optimizeCopy(&MBB);
+ return Changed;
+}
+
+FunctionPass *llvm::createAArch64RedundantCopyEliminationPass() {
+ return new AArch64RedundantCopyElimination();
+}
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 1599f6879d4..6b07dbcf234 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -61,6 +61,11 @@ EnableDeadRegisterElimination("aarch64-dead-def-elimination", cl::Hidden,
cl::init(true));
static cl::opt<bool>
+EnableRedundantCopyElimination("aarch64-redundant-copy-elim",
+ cl::desc("Enable the redundant copy elimination pass"),
+ cl::init(true), cl::Hidden);
+
+static cl::opt<bool>
EnableLoadStoreOpt("aarch64-load-store-opt", cl::desc("Enable the load/store pair"
" optimization pass"), cl::init(true), cl::Hidden);
@@ -316,6 +321,10 @@ void AArch64PassConfig::addPreRegAlloc() {
}
void AArch64PassConfig::addPostRegAlloc() {
+ // Remove redundant copy instructions.
+ if (TM->getOptLevel() != CodeGenOpt::None && EnableRedundantCopyElimination)
+ addPass(createAArch64RedundantCopyEliminationPass());
+
// Change dead register definitions to refer to the zero register.
if (TM->getOptLevel() != CodeGenOpt::None && EnableDeadRegisterElimination)
addPass(createAArch64DeadRegisterDefinitions());
diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt
index 4e91dbb9bbc..06c684da432 100644
--- a/llvm/lib/Target/AArch64/CMakeLists.txt
+++ b/llvm/lib/Target/AArch64/CMakeLists.txt
@@ -30,6 +30,7 @@ add_llvm_target(AArch64CodeGen
AArch64A53Fix835769.cpp
AArch64FrameLowering.cpp
AArch64ConditionOptimizer.cpp
+ AArch64RedundantCopyElimination.cpp
AArch64ISelDAGToDAG.cpp
AArch64ISelLowering.cpp
AArch64InstrInfo.cpp
OpenPOWER on IntegriCloud