1//===---- LoongArchLateBranchOpt.cpp - Late Stage Branch Optimization -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// This file provides LoongArch specific target optimizations, currently it's
10/// limited to convert conditional branches into unconditional branches when
11/// the condition can be statically evaluated.
12///
13//===----------------------------------------------------------------------===//
14
15#include "LoongArchInstrInfo.h"
16#include "LoongArchSubtarget.h"
17
18using namespace llvm;
19
20#define LOONGARCH_LATE_BRANCH_OPT_NAME "LoongArch Late Branch Optimisation Pass"
21
22namespace {
23
24struct LoongArchLateBranchOpt : public MachineFunctionPass {
25 static char ID;
26
27 LoongArchLateBranchOpt() : MachineFunctionPass(ID) {}
28
29 StringRef getPassName() const override {
30 return LOONGARCH_LATE_BRANCH_OPT_NAME;
31 }
32
33 void getAnalysisUsage(AnalysisUsage &AU) const override {
34 MachineFunctionPass::getAnalysisUsage(AU);
35 }
36
37 bool runOnMachineFunction(MachineFunction &Fn) override;
38
39private:
40 bool runOnBasicBlock(MachineBasicBlock &MBB) const;
41
42 const LoongArchInstrInfo *TII = nullptr;
43};
44} // namespace
45
46char LoongArchLateBranchOpt::ID = 0;
47INITIALIZE_PASS(LoongArchLateBranchOpt, "loongarch-late-branch-opt",
48 LOONGARCH_LATE_BRANCH_OPT_NAME, false, false)
49
50bool LoongArchLateBranchOpt::runOnBasicBlock(MachineBasicBlock &MBB) const {
51 MachineBasicBlock *TBB, *FBB;
52 SmallVector<MachineOperand, 4> Cond;
53 if (TII->analyzeBranch(MBB, TBB, FBB, Cond, /*AllowModify=*/false))
54 return false;
55
56 if (!TBB || Cond.size() < 1)
57 return false;
58
59 // Try and convert a conditional branch that can be evaluated statically
60 // into an unconditional branch.
61 unsigned Opc = Cond[0].getImm();
62 MachineBasicBlock *Folded;
63 switch (Opc) {
64 case LoongArch::BEQZ:
65 case LoongArch::BNEZ:
66 if (Cond.size() < 2 || !Cond[1].isReg() ||
67 Cond[1].getReg() != LoongArch::R0)
68 return false;
69 Folded = (Opc == LoongArch::BEQZ) ? TBB : FBB;
70 break;
71 case LoongArch::BEQ:
72 case LoongArch::BNE:
73 if (Cond.size() < 3 || !Cond[1].isReg() || !Cond[2].isReg() ||
74 Cond[1].getReg() != Cond[2].getReg())
75 return false;
76 Folded = (Opc == LoongArch::BEQ) ? TBB : FBB;
77 break;
78 default:
79 return false;
80 }
81
82 // At this point, its legal to optimize.
83 TII->removeBranch(MBB);
84
85 // Only need to insert a branch if we're not falling through.
86 if (Folded) {
87 DebugLoc DL = MBB.findBranchDebugLoc();
88 TII->insertBranch(MBB, TBB: Folded, FBB: nullptr, Cond: {}, dl: DL);
89 }
90
91 // Update the successors. Remove them all and add back the correct one.
92 while (!MBB.succ_empty())
93 MBB.removeSuccessor(I: MBB.succ_end() - 1);
94
95 // If it's a fallthrough, we need to figure out where MBB is going.
96 if (!Folded) {
97 MachineFunction::iterator Fallthrough = ++MBB.getIterator();
98 if (Fallthrough != MBB.getParent()->end())
99 MBB.addSuccessor(Succ: &*Fallthrough);
100 } else
101 MBB.addSuccessor(Succ: Folded);
102
103 return true;
104}
105
106bool LoongArchLateBranchOpt::runOnMachineFunction(MachineFunction &Fn) {
107 if (skipFunction(F: Fn.getFunction()))
108 return false;
109
110 auto &ST = Fn.getSubtarget<LoongArchSubtarget>();
111 TII = ST.getInstrInfo();
112
113 bool Changed = false;
114 for (MachineBasicBlock &MBB : Fn)
115 Changed |= runOnBasicBlock(MBB);
116 return Changed;
117}
118
119FunctionPass *llvm::createLoongArchLateBranchOptPass() {
120 return new LoongArchLateBranchOpt();
121}
122