summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/ARC/ARCBranchFinalize.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARC/ARCBranchFinalize.cpp')
-rw-r--r--llvm/lib/Target/ARC/ARCBranchFinalize.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/llvm/lib/Target/ARC/ARCBranchFinalize.cpp b/llvm/lib/Target/ARC/ARCBranchFinalize.cpp
new file mode 100644
index 00000000000..0fb8a420d86
--- /dev/null
+++ b/llvm/lib/Target/ARC/ARCBranchFinalize.cpp
@@ -0,0 +1,183 @@
+//===- ARCBranchFinalize.cpp - ARC conditional branches ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass takes existing conditional branches and expands them into longer
+// range conditional branches.
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "arc-branch-finalize"
+
+#include "ARCInstrInfo.h"
+#include "ARCTargetMachine.h"
+#include "MCTargetDesc/ARCInfo.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include <vector>
+
+using namespace llvm;
+
+namespace llvm {
+
+void initializeARCBranchFinalizePass(PassRegistry &Registry);
+FunctionPass *createARCBranchFinalizePass();
+
+} // end namespace llvm
+
+namespace {
+
+class ARCBranchFinalize : public MachineFunctionPass {
+public:
+ static char ID;
+
+ ARCBranchFinalize() : MachineFunctionPass(ID) {
+ initializeARCBranchFinalizePass(*PassRegistry::getPassRegistry());
+ }
+
+ StringRef getPassName() const override {
+ return "ARC Branch Finalization Pass";
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+ void replaceWithBRcc(MachineInstr *MI) const;
+ void replaceWithCmpBcc(MachineInstr *MI) const;
+
+private:
+ const ARCInstrInfo *TII{nullptr};
+};
+
+char ARCBranchFinalize::ID = 0;
+
+} // end anonymous namespace
+
+INITIALIZE_PASS_BEGIN(ARCBranchFinalize, "arc-branch-finalize",
+ "ARC finalize branches", false, false)
+INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
+INITIALIZE_PASS_END(ARCBranchFinalize, "arc-branch-finalize",
+ "ARC finalize branches", false, false)
+
+// BRcc has 6 supported condition codes, which differ from the 16
+// condition codes supported in the predicated instructions:
+// EQ -- 000
+// NE -- 001
+// LT -- 010
+// GE -- 011
+// LO -- 100
+// HS -- 101
+static unsigned getCCForBRcc(unsigned CC) {
+ switch (CC) {
+ case ARCCC::EQ:
+ return 0;
+ case ARCCC::NE:
+ return 1;
+ case ARCCC::LT:
+ return 2;
+ case ARCCC::GE:
+ return 3;
+ case ARCCC::LO:
+ return 4;
+ case ARCCC::HS:
+ return 5;
+ default:
+ return -1U;
+ }
+}
+
+static bool isBRccPseudo(MachineInstr *MI) {
+ return !(MI->getOpcode() != ARC::BRcc_rr_p &&
+ MI->getOpcode() != ARC::BRcc_ru6_p);
+}
+
+static unsigned getBRccForPseudo(MachineInstr *MI) {
+ assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction.");
+ if (MI->getOpcode() == ARC::BRcc_rr_p)
+ return ARC::BRcc_rr;
+ return ARC::BRcc_ru6;
+}
+
+static unsigned getCmpForPseudo(MachineInstr *MI) {
+ assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction.");
+ if (MI->getOpcode() == ARC::BRcc_rr_p)
+ return ARC::CMP_rr;
+ return ARC::CMP_ru6;
+}
+
+void ARCBranchFinalize::replaceWithBRcc(MachineInstr *MI) const {
+ DEBUG(dbgs() << "Replacing pseudo branch with BRcc\n");
+ unsigned CC = getCCForBRcc(MI->getOperand(3).getImm());
+ if (CC != -1U) {
+ BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
+ TII->get(getBRccForPseudo(MI)))
+ .addMBB(MI->getOperand(0).getMBB())
+ .addReg(MI->getOperand(1).getReg())
+ .add(MI->getOperand(2))
+ .addImm(getCCForBRcc(MI->getOperand(3).getImm()));
+ MI->eraseFromParent();
+ } else {
+ replaceWithCmpBcc(MI);
+ }
+}
+
+void ARCBranchFinalize::replaceWithCmpBcc(MachineInstr *MI) const {
+ DEBUG(dbgs() << "Branch: " << *MI << "\n");
+ DEBUG(dbgs() << "Replacing pseudo branch with Cmp + Bcc\n");
+ BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
+ TII->get(getCmpForPseudo(MI)))
+ .addReg(MI->getOperand(1).getReg())
+ .add(MI->getOperand(2));
+ BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(ARC::Bcc))
+ .addMBB(MI->getOperand(0).getMBB())
+ .addImm(MI->getOperand(3).getImm());
+ MI->eraseFromParent();
+}
+
+bool ARCBranchFinalize::runOnMachineFunction(MachineFunction &MF) {
+ DEBUG(dbgs() << "Running ARC Branch Finalize on "
+ << MF.getFunction()->getName() << "\n");
+ std::vector<MachineInstr *> Branches;
+ bool Changed = false;
+ unsigned MaxSize = 0;
+ TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
+ std::map<MachineBasicBlock *, unsigned> BlockToPCMap;
+ std::vector<std::pair<MachineInstr *, unsigned>> BranchToPCList;
+ unsigned PC = 0;
+
+ for (auto &MBB : MF) {
+ BlockToPCMap.insert(std::make_pair(&MBB, PC));
+ for (auto &MI : MBB) {
+ unsigned Size = TII->getInstSizeInBytes(MI);
+ if (Size > 8 || Size == 0) {
+ DEBUG(dbgs() << "Unknown (or size 0) size for: " << MI << "\n");
+ } else {
+ MaxSize += Size;
+ }
+ if (MI.isBranch()) {
+ Branches.push_back(&MI);
+ BranchToPCList.emplace_back(&MI, PC);
+ }
+ PC += Size;
+ }
+ }
+ for (auto P : BranchToPCList) {
+ if (isBRccPseudo(P.first))
+ isInt<9>(MaxSize) ? replaceWithBRcc(P.first) : replaceWithCmpBcc(P.first);
+ }
+
+ DEBUG(dbgs() << "Estimated function size for " << MF.getFunction()->getName()
+ << ": " << MaxSize << "\n");
+
+ return Changed;
+}
+
+FunctionPass *llvm::createARCBranchFinalizePass() {
+ return new ARCBranchFinalize();
+}
OpenPOWER on IntegriCloud