Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- HexagonCFGOptimizer.cpp - CFG optimizations ------------------------===//
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
#include "Hexagon.h"
10
#include "MCTargetDesc/HexagonMCTargetDesc.h"
11
#include "llvm/CodeGen/MachineBasicBlock.h"
12
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
13
#include "llvm/CodeGen/MachineFunction.h"
14
#include "llvm/CodeGen/MachineFunctionPass.h"
15
#include "llvm/CodeGen/MachineInstr.h"
16
#include "llvm/CodeGen/MachineOperand.h"
17
#include "llvm/CodeGen/TargetInstrInfo.h"
18
#include "llvm/CodeGen/TargetSubtargetInfo.h"
19
#include "llvm/Pass.h"
20
#include "llvm/Support/ErrorHandling.h"
21
#include <cassert>
22
#include <vector>
23
24
using namespace llvm;
25
26
#define DEBUG_TYPE "hexagon_cfg"
27
28
namespace llvm {
29
30
FunctionPass *createHexagonCFGOptimizer();
31
void initializeHexagonCFGOptimizerPass(PassRegistry&);
32
33
} // end namespace llvm
34
35
namespace {
36
37
class HexagonCFGOptimizer : public MachineFunctionPass {
38
private:
39
  void InvertAndChangeJumpTarget(MachineInstr &, MachineBasicBlock *);
40
  bool isOnFallThroughPath(MachineBasicBlock *MBB);
41
42
public:
43
  static char ID;
44
45
8.48k
  HexagonCFGOptimizer() : MachineFunctionPass(ID) {
46
8.48k
    initializeHexagonCFGOptimizerPass(*PassRegistry::getPassRegistry());
47
8.48k
  }
48
49
8.48k
  StringRef getPassName() const override { return "Hexagon CFG Optimizer"; }
50
  bool runOnMachineFunction(MachineFunction &Fn) override;
51
52
8.48k
  MachineFunctionProperties getRequiredProperties() const override {
53
8.48k
    return MachineFunctionProperties().set(
54
8.48k
        MachineFunctionProperties::Property::NoVRegs);
55
8.48k
  }
56
};
57
58
} // end anonymous namespace
59
60
char HexagonCFGOptimizer::ID = 0;
61
62
9.34k
static bool IsConditionalBranch(int Opc) {
63
9.34k
  switch (Opc) {
64
1.20k
    case Hexagon::J2_jumpt:
65
1.20k
    case Hexagon::J2_jumptpt:
66
1.31k
    case Hexagon::J2_jumpf:
67
1.31k
    case Hexagon::J2_jumpfpt:
68
1.31k
    case Hexagon::J2_jumptnew:
69
1.31k
    case Hexagon::J2_jumpfnew:
70
1.31k
    case Hexagon::J2_jumptnewpt:
71
1.31k
    case Hexagon::J2_jumpfnewpt:
72
1.31k
      return true;
73
9.34k
  }
74
8.02k
  return false;
75
9.34k
}
76
77
29
static bool IsUnconditionalJump(int Opc) {
78
29
  return (Opc == Hexagon::J2_jump);
79
29
}
80
81
void HexagonCFGOptimizer::InvertAndChangeJumpTarget(
82
0
    MachineInstr &MI, MachineBasicBlock *NewTarget) {
83
0
  const TargetInstrInfo *TII =
84
0
      MI.getParent()->getParent()->getSubtarget().getInstrInfo();
85
0
  int NewOpcode = 0;
86
0
  switch (MI.getOpcode()) {
87
0
  case Hexagon::J2_jumpt:
88
0
    NewOpcode = Hexagon::J2_jumpf;
89
0
    break;
90
0
  case Hexagon::J2_jumpf:
91
0
    NewOpcode = Hexagon::J2_jumpt;
92
0
    break;
93
0
  case Hexagon::J2_jumptnewpt:
94
0
    NewOpcode = Hexagon::J2_jumpfnewpt;
95
0
    break;
96
0
  case Hexagon::J2_jumpfnewpt:
97
0
    NewOpcode = Hexagon::J2_jumptnewpt;
98
0
    break;
99
0
  default:
100
0
    llvm_unreachable("Cannot handle this case");
101
0
  }
102
103
0
  MI.setDesc(TII->get(NewOpcode));
104
0
  MI.getOperand(1).setMBB(NewTarget);
105
0
}
106
107
0
bool HexagonCFGOptimizer::isOnFallThroughPath(MachineBasicBlock *MBB) {
108
0
  if (MBB->canFallThrough())
109
0
    return true;
110
0
  for (MachineBasicBlock *PB : MBB->predecessors())
111
0
    if (PB->isLayoutSuccessor(MBB) && PB->canFallThrough())
112
0
      return true;
113
0
  return false;
114
0
}
115
116
8.46k
bool HexagonCFGOptimizer::runOnMachineFunction(MachineFunction &Fn) {
117
8.46k
  if (skipFunction(Fn.getFunction()))
118
0
    return false;
119
120
  // Loop over all of the basic blocks.
121
11.6k
  for (MachineBasicBlock &MBB : Fn) {
122
    // Traverse the basic block.
123
11.6k
    MachineBasicBlock::iterator MII = MBB.getFirstTerminator();
124
11.6k
    if (MII != MBB.end()) {
125
9.34k
      MachineInstr &MI = *MII;
126
9.34k
      int Opc = MI.getOpcode();
127
9.34k
      if (IsConditionalBranch(Opc)) {
128
        // (Case 1) Transform the code if the following condition occurs:
129
        //   BB1: if (p0) jump BB3
130
        //   ...falls-through to BB2 ...
131
        //   BB2: jump BB4
132
        //   ...next block in layout is BB3...
133
        //   BB3: ...
134
        //
135
        //  Transform this to:
136
        //  BB1: if (!p0) jump BB4
137
        //  Remove BB2
138
        //  BB3: ...
139
        //
140
        // (Case 2) A variation occurs when BB3 contains a JMP to BB4:
141
        //   BB1: if (p0) jump BB3
142
        //   ...falls-through to BB2 ...
143
        //   BB2: jump BB4
144
        //   ...other basic blocks ...
145
        //   BB4:
146
        //   ...not a fall-thru
147
        //   BB3: ...
148
        //     jump BB4
149
        //
150
        // Transform this to:
151
        //   BB1: if (!p0) jump BB4
152
        //   Remove BB2
153
        //   BB3: ...
154
        //   BB4: ...
155
1.31k
        unsigned NumSuccs = MBB.succ_size();
156
1.31k
        MachineBasicBlock::succ_iterator SI = MBB.succ_begin();
157
1.31k
        MachineBasicBlock* FirstSucc = *SI;
158
1.31k
        MachineBasicBlock* SecondSucc = *(++SI);
159
1.31k
        MachineBasicBlock* LayoutSucc = nullptr;
160
1.31k
        MachineBasicBlock* JumpAroundTarget = nullptr;
161
162
1.31k
        if (MBB.isLayoutSuccessor(FirstSucc)) {
163
0
          LayoutSucc = FirstSucc;
164
0
          JumpAroundTarget = SecondSucc;
165
1.31k
        } else if (MBB.isLayoutSuccessor(SecondSucc)) {
166
1.30k
          LayoutSucc = SecondSucc;
167
1.30k
          JumpAroundTarget = FirstSucc;
168
1.30k
        } else {
169
          // Odd case...cannot handle.
170
4
        }
171
172
        // The target of the unconditional branch must be JumpAroundTarget.
173
        // TODO: If not, we should not invert the unconditional branch.
174
1.31k
        MachineBasicBlock* CondBranchTarget = nullptr;
175
1.31k
        if (MI.getOpcode() == Hexagon::J2_jumpt ||
176
1.31k
            MI.getOpcode() == Hexagon::J2_jumpf) {
177
1.31k
          CondBranchTarget = MI.getOperand(1).getMBB();
178
1.31k
        }
179
180
1.31k
        if (!LayoutSucc || (CondBranchTarget != JumpAroundTarget)) {
181
4
          continue;
182
4
        }
183
184
1.30k
        if ((NumSuccs == 2) && LayoutSucc && (LayoutSucc->pred_size() == 1)) {
185
          // Ensure that BB2 has one instruction -- an unconditional jump.
186
1.30k
          if ((LayoutSucc->size() == 1) &&
187
1.30k
              IsUnconditionalJump(LayoutSucc->front().getOpcode())) {
188
0
            assert(JumpAroundTarget && "jump target is needed to process second basic block");
189
0
            MachineBasicBlock* UncondTarget =
190
0
              LayoutSucc->front().getOperand(0).getMBB();
191
            // Check if the layout successor of BB2 is BB3.
192
0
            bool case1 = LayoutSucc->isLayoutSuccessor(JumpAroundTarget);
193
0
            bool case2 = JumpAroundTarget->isSuccessor(UncondTarget) &&
194
0
              !JumpAroundTarget->empty() &&
195
0
              IsUnconditionalJump(JumpAroundTarget->back().getOpcode()) &&
196
0
              JumpAroundTarget->pred_size() == 1 &&
197
0
              JumpAroundTarget->succ_size() == 1;
198
199
0
            if (case1 || case2) {
200
0
              InvertAndChangeJumpTarget(MI, UncondTarget);
201
0
              MBB.replaceSuccessor(JumpAroundTarget, UncondTarget);
202
203
              // Remove the unconditional branch in LayoutSucc.
204
0
              LayoutSucc->erase(LayoutSucc->begin());
205
0
              LayoutSucc->replaceSuccessor(UncondTarget, JumpAroundTarget);
206
207
              // This code performs the conversion for case 2, which moves
208
              // the block to the fall-thru case (BB3 in the code above).
209
0
              if (case2 && !case1) {
210
0
                JumpAroundTarget->moveAfter(LayoutSucc);
211
                // only move a block if it doesn't have a fall-thru. otherwise
212
                // the CFG will be incorrect.
213
0
                if (!isOnFallThroughPath(UncondTarget))
214
0
                  UncondTarget->moveAfter(JumpAroundTarget);
215
0
              }
216
217
              // Correct live-in information. Is used by post-RA scheduler
218
              // The live-in to LayoutSucc is now all values live-in to
219
              // JumpAroundTarget.
220
0
              std::vector<MachineBasicBlock::RegisterMaskPair> OrigLiveIn(
221
0
                  LayoutSucc->livein_begin(), LayoutSucc->livein_end());
222
0
              std::vector<MachineBasicBlock::RegisterMaskPair> NewLiveIn(
223
0
                  JumpAroundTarget->livein_begin(),
224
0
                  JumpAroundTarget->livein_end());
225
0
              for (const auto &OrigLI : OrigLiveIn)
226
0
                LayoutSucc->removeLiveIn(OrigLI.PhysReg);
227
0
              for (const auto &NewLI : NewLiveIn)
228
0
                LayoutSucc->addLiveIn(NewLI);
229
0
            }
230
0
          }
231
1.30k
        }
232
1.30k
      }
233
9.34k
    }
234
11.6k
  }
235
8.46k
  return true;
236
8.46k
}
237
238
//===----------------------------------------------------------------------===//
239
//                         Public Constructor Functions
240
//===----------------------------------------------------------------------===//
241
242
INITIALIZE_PASS(HexagonCFGOptimizer, "hexagon-cfg", "Hexagon CFG Optimizer",
243
                false, false)
244
245
8.48k
FunctionPass *llvm::createHexagonCFGOptimizer() {
246
8.48k
  return new HexagonCFGOptimizer();
247
8.48k
}