xref: /llvm-project/bolt/include/bolt/Passes/CMOVConversion.h (revision 52cf07116bf0a8cab87b0f55176d198bcaa02575)
1 //===- bolt/Passes/CMOVConversion.h ----------------------------*- C++ -*-===//
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 pass finds the following patterns:
10 //         jcc
11 //        /   \
12 // (empty)    mov src, dst
13 //        \   /
14 //
15 // and replaces them with:
16 //
17 //   cmovcc src, dst
18 //
19 // The advantage of performing this conversion in BOLT (compared to compiler
20 // heuristic driven instruction selection) is that BOLT can use LBR
21 // misprediction information and only convert poorly predictable branches.
22 // Note that branch misprediction rate is different from branch bias.
23 // For well-predictable branches, it might be beneficial to leave jcc+mov as is
24 // from microarchitectural perspective to avoid unneeded dependencies (CMOV
25 // instruction has a dataflow dependence on flags and both operands).
26 //
27 //===----------------------------------------------------------------------===//
28 
29 #ifndef BOLT_PASSES_CMOVCONVERSION_H
30 #define BOLT_PASSES_CMOVCONVERSION_H
31 
32 #include "bolt/Passes/BinaryPasses.h"
33 
34 namespace llvm {
35 namespace bolt {
36 
37 /// Pass for folding eligible hammocks into CMOV's if profitable.
38 class CMOVConversion : public BinaryFunctionPass {
39   struct Stats {
40     /// Record how many possible cases there are.
41     uint64_t StaticPossible = 0;
42     uint64_t DynamicPossible = 0;
43 
44     /// Record how many cases were converted.
45     uint64_t StaticPerformed = 0;
46     uint64_t DynamicPerformed = 0;
47 
48     /// Record how many mispredictions were eliminated.
49     uint64_t PossibleMP = 0;
50     uint64_t RemovedMP = 0;
51 
52     Stats operator+(const Stats &O) {
53       StaticPossible += O.StaticPossible;
54       DynamicPossible += O.DynamicPossible;
55       StaticPerformed += O.StaticPerformed;
56       DynamicPerformed += O.DynamicPerformed;
57       PossibleMP += O.PossibleMP;
58       RemovedMP += O.RemovedMP;
59       return *this;
60     }
getStaticRatioStats61     double getStaticRatio() { return (double)StaticPerformed / StaticPossible; }
getDynamicRatioStats62     double getDynamicRatio() {
63       return (double)DynamicPerformed / DynamicPossible;
64     }
getMPRatioStats65     double getMPRatio() { return (double)RemovedMP / PossibleMP; }
66 
67     void dumpTo(raw_ostream &OS);
68   };
69   // BinaryContext-wide stats
70   Stats Global;
71 
72   void runOnFunction(BinaryFunction &Function);
73 
74 public:
CMOVConversion()75   explicit CMOVConversion() : BinaryFunctionPass(false) {}
76 
getName()77   const char *getName() const override { return "CMOV conversion"; }
78 
79   Error runOnFunctions(BinaryContext &BC) override;
80 };
81 
82 } // namespace bolt
83 } // namespace llvm
84 
85 #endif
86