Skip to content

Commit ba0aac3

Browse files
authored
Merge pull request #76093 from kavon/coldsplit-2
ColdBlockInfo: overhaul analysis pass
2 parents 380f319 + 2caaad0 commit ba0aac3

File tree

13 files changed

+772
-127
lines changed

13 files changed

+772
-127
lines changed

include/swift/AST/SILOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ class SILOptions {
122122
/// within the optimizer. This influences static branch prediction.
123123
bool EnableThrowsPrediction = false;
124124

125+
/// Controls whether to say that blocks ending in an 'unreachable' are cold.
126+
bool EnableNoReturnCold = false;
127+
125128
/// Should we run any SIL performance optimizations
126129
///
127130
/// Useful when you want to enable -O LLVM opts but not -O SIL opts.

include/swift/Basic/ProfileCounter.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ class ProfileCounter {
2727
uint64_t count;
2828

2929
public:
30-
explicit ProfileCounter() : count(UINT64_MAX) {}
31-
ProfileCounter(uint64_t Count) : count(Count) {
30+
explicit constexpr ProfileCounter() : count(UINT64_MAX) {}
31+
constexpr ProfileCounter(uint64_t Count) : count(Count) {
3232
if (Count == UINT64_MAX) {
3333
count = UINT64_MAX - 1;
3434
}
@@ -40,6 +40,22 @@ class ProfileCounter {
4040
return count;
4141
}
4242
explicit operator bool() const { return hasValue(); }
43+
44+
/// Saturating addition of another counter to this one, meaning that overflow
45+
/// is avoided. If overflow would have happened, this function returns true
46+
/// and the maximum representable value will be set in this counter.
47+
bool add_saturating(ProfileCounter other) {
48+
assert(hasValue() && other.hasValue());
49+
50+
// Will we go over the max representable value by adding other?
51+
if (count > ((UINT64_MAX-1) - other.count)) {
52+
count = UINT64_MAX - 1;
53+
return true;
54+
}
55+
56+
count += other.count;
57+
return false;
58+
}
4359
};
4460
} // end namespace swift
4561

include/swift/Option/FrontendOptions.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,11 @@ def enable_throws_prediction : Flag<["-"], "enable-throws-prediction">,
545545
def disable_throws_prediction : Flag<["-"], "disable-throws-prediction">,
546546
HelpText<"Disables optimization assumption that functions rarely throw errors.">;
547547

548+
def enable_noreturn_prediction : Flag<["-"], "enable-noreturn-prediction">,
549+
HelpText<"Enables optimization assumption that calls to no-return functions are cold.">;
550+
def disable_noreturn_prediction : Flag<["-"], "disable-noreturn-prediction">,
551+
HelpText<"Disables optimization assumption that calls to no-return functions are cold.">;
552+
548553
def disable_access_control : Flag<["-"], "disable-access-control">,
549554
HelpText<"Don't respect access control restrictions">;
550555
def enable_access_control : Flag<["-"], "enable-access-control">,

include/swift/SILOptimizer/Analysis/ColdBlockInfo.h

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,52 +15,74 @@
1515

1616
#include "llvm/ADT/DenseMap.h"
1717
#include "swift/SIL/SILValue.h"
18+
#include "swift/Basic/FixedBitSet.h"
1819

1920
namespace swift {
2021
class DominanceAnalysis;
22+
class PostDominanceAnalysis;
2123
class SILBasicBlock;
24+
class CondBranchInst;
2225

2326
/// Cache a set of basic blocks that have been determined to be cold or hot.
2427
///
2528
/// This does not inherit from SILAnalysis because it is not worth preserving
2629
/// across passes.
2730
class ColdBlockInfo {
31+
public:
32+
// Represents the temperatures of edges flowing into a block.
33+
//
34+
// T = "top" -- both warm and cold edges
35+
// / \
36+
// Warm Cold
37+
// \ /
38+
// B = "bottom" -- neither warm or cold edges
39+
struct State {
40+
// Each state kind, as an integer, is its position in any bit vectors.
41+
enum Temperature {
42+
Warm = 0,
43+
Cold = 1
44+
};
45+
46+
// Number of states, excluding Top or Bottom, in this flow problem.
47+
static constexpr unsigned NumStates = 2;
48+
};
49+
50+
using Energy = FixedBitSet<State::NumStates, State::Temperature>;
51+
52+
private:
2853
DominanceAnalysis *DA;
54+
PostDominanceAnalysis *PDA;
2955

30-
/// Each block in this map has been determined to be either cold or hot.
31-
llvm::DenseMap<const SILBasicBlock*, bool> ColdBlockMap;
56+
/// Each block in this map has been determined to be cold and/or warm.
57+
/// Make sure to always use the set/resetToCold methods to update this!
58+
llvm::DenseMap<const SILBasicBlock*, Energy> EnergyMap;
3259

3360
// This is a cache and shouldn't be copied around.
3461
ColdBlockInfo(const ColdBlockInfo &) = delete;
3562
ColdBlockInfo &operator=(const ColdBlockInfo &) = delete;
63+
LLVM_DUMP_METHOD void dump() const;
3664

37-
/// Tri-value return code for checking branch hints.
38-
enum BranchHint : unsigned {
39-
None,
40-
LikelyTrue,
41-
LikelyFalse
42-
};
65+
/// Tracks whether any information was changed in the energy map.
66+
bool changedMap = false;
67+
void resetToCold(const SILBasicBlock *BB);
68+
void set(const SILBasicBlock *BB, State::Temperature temp);
4369

44-
enum {
45-
RecursionDepthLimit = 3
46-
};
70+
using ExpectedValue = std::optional<bool>;
4771

48-
BranchHint getBranchHint(SILValue Cond, int recursionDepth);
72+
void setExpectedCondition(CondBranchInst *CondBranch, ExpectedValue value);
4973

50-
bool isSlowPath(const SILBasicBlock *FromBB, const SILBasicBlock *ToBB,
51-
int recursionDepth);
74+
ExpectedValue searchForExpectedValue(SILValue Cond,
75+
unsigned recursionDepth = 0);
76+
void searchForExpectedValue(CondBranchInst *CondBranch);
5277

53-
bool isCold(const SILBasicBlock *BB,
54-
int recursionDepth);
78+
bool inferFromEdgeProfile(SILBasicBlock *BB);
5579

5680
public:
57-
ColdBlockInfo(DominanceAnalysis *DA): DA(DA) {}
81+
ColdBlockInfo(DominanceAnalysis *DA, PostDominanceAnalysis *PDA);
5882

59-
bool isSlowPath(const SILBasicBlock *FromBB, const SILBasicBlock *ToBB) {
60-
return isSlowPath(FromBB, ToBB, 0);
61-
}
83+
void analyze(SILFunction *F);
6284

63-
bool isCold(const SILBasicBlock *BB) { return isCold(BB, 0); }
85+
bool isCold(const SILBasicBlock *BB) const;
6486
};
6587
} // end namespace swift
6688

include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ class ShortestPathAnalysis {
429429
return;
430430

431431
BlockInfoStorage.resize(numBlocks);
432+
CBI.analyze(F);
432433

433434
// First step: compute the length of the blocks.
434435
unsigned BlockIdx = 0;

lib/DriverTool/sil_opt_main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ struct SILOptOptions {
293293
EnableThrowsPrediction = llvm::cl::opt<bool>("enable-throws-prediction",
294294
llvm::cl::desc("Enables optimization assumption that functions rarely throw errors."));
295295

296+
llvm::cl::opt<bool>
297+
EnableNoReturnCold = llvm::cl::opt<bool>("enable-noreturn-prediction",
298+
llvm::cl::desc("Enables optimization assumption that calls to no-return functions are cold."));
299+
296300
llvm::cl::opt<bool>
297301
EnableMoveInoutStackProtection = llvm::cl::opt<bool>("enable-move-inout-stack-protector",
298302
llvm::cl::desc("Enable the stack protector by moving values to temporaries."));
@@ -854,6 +858,7 @@ int sil_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
854858
SILOpts.EnableSpeculativeDevirtualization = options.EnableSpeculativeDevirtualization;
855859
SILOpts.EnableAsyncDemotion = options.EnableAsyncDemotion;
856860
SILOpts.EnableThrowsPrediction = options.EnableThrowsPrediction;
861+
SILOpts.EnableNoReturnCold = options.EnableNoReturnCold;
857862
SILOpts.IgnoreAlwaysInline = options.IgnoreAlwaysInline;
858863
SILOpts.EnableOSSAModules = options.EnableOSSAModules;
859864
SILOpts.EnableSILOpaqueValues = options.EnableSILOpaqueValues;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,6 +2690,9 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
26902690
Opts.EnableThrowsPrediction = Args.hasFlag(
26912691
OPT_enable_throws_prediction, OPT_disable_throws_prediction,
26922692
Opts.EnableThrowsPrediction);
2693+
Opts.EnableNoReturnCold = Args.hasFlag(
2694+
OPT_enable_noreturn_prediction, OPT_disable_noreturn_prediction,
2695+
Opts.EnableNoReturnCold);
26932696
Opts.EnableActorDataRaceChecks |= Args.hasFlag(
26942697
OPT_enable_actor_data_race_checks,
26952698
OPT_disable_actor_data_race_checks, /*default=*/false);

0 commit comments

Comments
 (0)