blob: 77ce2235001a6d51862a62c088c663ebf98eeca4 [file] [log] [blame]
//===- bolt/Passes/CMOVConversion.h ----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This pass finds the following patterns:
// jcc
// / \
// (empty) mov src, dst
// \ /
//
// and replaces them with:
//
// cmovcc src, dst
//
// The advantage of performing this conversion in BOLT (compared to compiler
// heuristic driven instruction selection) is that BOLT can use LBR
// misprediction information and only convert poorly predictable branches.
// Note that branch misprediction rate is different from branch bias.
// For well-predictable branches, it might be beneficial to leave jcc+mov as is
// from microarchitectural perspective to avoid unneeded dependencies (CMOV
// instruction has a dataflow dependence on flags and both operands).
//
//===----------------------------------------------------------------------===//
#ifndef BOLT_PASSES_CMOVCONVERSION_H
#define BOLT_PASSES_CMOVCONVERSION_H
#include "bolt/Passes/BinaryPasses.h"
namespace llvm {
namespace bolt {
/// Pass for folding eligible hammocks into CMOV's if profitable.
class CMOVConversion : public BinaryFunctionPass {
struct Stats {
/// Record how many possible cases there are.
uint64_t StaticPossible = 0;
uint64_t DynamicPossible = 0;
/// Record how many cases were converted.
uint64_t StaticPerformed = 0;
uint64_t DynamicPerformed = 0;
/// Record how many mispredictions were eliminated.
uint64_t PossibleMP = 0;
uint64_t RemovedMP = 0;
Stats operator+(const Stats &O) {
StaticPossible += O.StaticPossible;
DynamicPossible += O.DynamicPossible;
StaticPerformed += O.StaticPerformed;
DynamicPerformed += O.DynamicPerformed;
PossibleMP += O.PossibleMP;
RemovedMP += O.RemovedMP;
return *this;
}
double getStaticRatio() { return (double)StaticPerformed / StaticPossible; }
double getDynamicRatio() {
return (double)DynamicPerformed / DynamicPossible;
}
double getMPRatio() { return (double)RemovedMP / PossibleMP; }
void dump();
};
// BinaryContext-wide stats
Stats Global;
void runOnFunction(BinaryFunction &Function);
public:
explicit CMOVConversion() : BinaryFunctionPass(false) {}
const char *getName() const override { return "CMOV conversion"; }
void runOnFunctions(BinaryContext &BC) override;
};
} // namespace bolt
} // namespace llvm
#endif