Skip to content

Commit ba75030

Browse files
authored
Merge pull request #23375 from bob-wilson/llvm-r355981
Stop using the _branchHint function
2 parents 9a55242 + ef1d9bc commit ba75030

File tree

5 files changed

+24
-35
lines changed

5 files changed

+24
-35
lines changed

docs/StandardLibraryProgrammersManual.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ Optionals can be unwrapped with `!`, which triggers a trap on nil. Alternatively
5353

5454
### Builtins
5555

56-
#### `_fastPath` and `_slowPath` (also, `_branchHint`)
56+
#### `_fastPath` and `_slowPath`
5757

5858
`_fastPath` returns its argument, wrapped in a Builtin.expect. This informs the optimizer that the vast majority of the time, the branch will be taken (i.e. the then branch is “hot”). The SIL optimizer may alter heuristics for anything dominated by the then branch. But the real performance impact comes from the fact that the SIL optimizer will consider anything dominated by the else branch to be infrequently executed (i.e. “cold”). This means that transformations that may increase code size have very conservative heuristics to keep the rarely executed code small.
5959

6060
The probabilities are passed through to LLVM as branch weight metadata, to leverage LLVM’s use of GCC style builtin_expect knowledge (e.g. for code layout and low-level inlining).
6161

6262
`_fastPath` probabilities are compounding, see the example below. For this reason, it can actually degrade performance in non-intuitive ways as it marks all other code (including subsequent `_fastPath`s) as being cold. Consider `_fastPath` as basically spraying the rest of the code with a Mr. Freeze-style ice gun.
6363

64-
`_slowPath` is the same as `_fastPath`, just with the branches swapped. Both are just wrappers around `_branchHint`, which is otherwise never called directly.
64+
`_slowPath` is the same as `_fastPath`, just with the branches swapped.
6565

6666
*Example:*
6767

@@ -84,8 +84,6 @@ if _fastPath(...) {
8484
return
8585
```
8686

87-
*NOTE: these are due for a rename and possibly a redesign. They conflate multiple notions that don’t match the average standard library programmer’s intuition.*
88-
8987

9088
#### `_onFastPath`
9189

lib/SILOptimizer/Analysis/ColdBlockInfo.cpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,30 +74,16 @@ ColdBlockInfo::BranchHint ColdBlockInfo::getBranchHint(SILValue Cond,
7474
return Hint;
7575
}
7676

77-
// Handle the @semantic function used for branch hints. The generic
78-
// fast/slowPath calls are frequently only inlined one level down to
79-
// _branchHint before inlining the call sites that they guard.
77+
// Handle the @semantic functions used for branch hints.
8078
auto AI = dyn_cast<ApplyInst>(Cond);
8179
if (!AI)
8280
return BranchHint::None;
8381

8482
if (auto *F = AI->getReferencedFunction()) {
8583
if (F->hasSemanticsAttrs()) {
86-
if (F->hasSemanticsAttr("branchhint")) {
87-
// A "branchint" model takes a Bool expected value as the second
88-
// argument.
89-
if (auto *SI = dyn_cast<StructInst>(AI->getArgument(1))) {
90-
assert(SI->getElements().size() == 1 && "Need Bool.value");
91-
if (auto *Literal =
92-
dyn_cast<IntegerLiteralInst>(SI->getElements()[0])) {
93-
return (Literal->getValue() == 0)
94-
? BranchHint::LikelyFalse : BranchHint::LikelyTrue;
95-
}
96-
}
97-
}
9884
// fastpath/slowpath attrs are untested because the inliner luckily
9985
// inlines them before the downstream calls.
100-
else if (F->hasSemanticsAttr("slowpath"))
86+
if (F->hasSemanticsAttr("slowpath"))
10187
return BranchHint::LikelyFalse;
10288
else if (F->hasSemanticsAttr("fastpath"))
10389
return BranchHint::LikelyTrue;

stdlib/public/core/Assert.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public func assert(
4545
) {
4646
// Only assert in debug mode.
4747
if _isDebugAssertConfiguration() {
48-
if !_branchHint(condition(), expected: true) {
48+
if !_fastPath(condition()) {
4949
_assertionFailure("Assertion failed", message(), file: file, line: line,
5050
flags: _fatalErrorFlags())
5151
}
@@ -87,7 +87,7 @@ public func precondition(
8787
) {
8888
// Only check in debug and release mode. In release mode just trap.
8989
if _isDebugAssertConfiguration() {
90-
if !_branchHint(condition(), expected: true) {
90+
if !_fastPath(condition()) {
9191
_assertionFailure("Precondition failed", message(), file: file, line: line,
9292
flags: _fatalErrorFlags())
9393
}
@@ -206,7 +206,7 @@ internal func _precondition(
206206
) {
207207
// Only check in debug and release mode. In release mode just trap.
208208
if _isDebugAssertConfiguration() {
209-
if !_branchHint(condition(), expected: true) {
209+
if !_fastPath(condition()) {
210210
_fatalErrorMessage("Fatal error", message, file: file, line: line,
211211
flags: _fatalErrorFlags())
212212
}
@@ -235,7 +235,7 @@ public func _overflowChecked<T>(
235235
) -> T {
236236
let (result, error) = args
237237
if _isDebugAssertConfiguration() {
238-
if _branchHint(error, expected: false) {
238+
if _slowPath(error) {
239239
_fatalErrorMessage("Fatal error", "Overflow/underflow",
240240
file: file, line: line, flags: _fatalErrorFlags())
241241
}
@@ -260,7 +260,7 @@ internal func _debugPrecondition(
260260
) {
261261
// Only check in debug mode.
262262
if _slowPath(_isDebugAssertConfiguration()) {
263-
if !_branchHint(condition(), expected: true) {
263+
if !_fastPath(condition()) {
264264
_fatalErrorMessage("Fatal error", message, file: file, line: line,
265265
flags: _fatalErrorFlags())
266266
}
@@ -290,7 +290,7 @@ internal func _internalInvariant(
290290
file: StaticString = #file, line: UInt = #line
291291
) {
292292
#if INTERNAL_CHECKS_ENABLED
293-
if !_branchHint(condition(), expected: true) {
293+
if !_fastPath(condition()) {
294294
_fatalErrorMessage("Fatal error", message, file: file, line: line,
295295
flags: _fatalErrorFlags())
296296
}

stdlib/public/core/Builtin.swift

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -273,24 +273,18 @@ internal func _minAllocationAlignment() -> Int {
273273
// semantics of these function calls. This won't be necessary with
274274
// mandatory generic inlining.
275275

276-
@usableFromInline @_transparent
277-
@_semantics("branchhint")
278-
internal func _branchHint(_ actual: Bool, expected: Bool) -> Bool {
279-
return Bool(Builtin.int_expect_Int1(actual._value, expected._value))
280-
}
281-
282276
/// Optimizer hint that `x` is expected to be `true`.
283277
@_transparent
284278
@_semantics("fastpath")
285279
public func _fastPath(_ x: Bool) -> Bool {
286-
return _branchHint(x, expected: true)
280+
return Bool(Builtin.int_expect_Int1(x._value, true._value))
287281
}
288282

289283
/// Optimizer hint that `x` is expected to be `false`.
290284
@_transparent
291285
@_semantics("slowpath")
292286
public func _slowPath(_ x: Bool) -> Bool {
293-
return _branchHint(x, expected: false)
287+
return Bool(Builtin.int_expect_Int1(x._value, false._value))
294288
}
295289

296290
/// Optimizer hint that the code where this function is called is on the fast
@@ -307,6 +301,17 @@ func _uncheckedUnsafeAssume(_ condition: Bool) {
307301
_ = Builtin.assume_Int1(condition._value)
308302
}
309303

304+
// This function is no longer used but must be kept for ABI compatibility
305+
// because references to it may have been inlined.
306+
@usableFromInline
307+
internal func _branchHint(_ actual: Bool, expected: Bool) -> Bool {
308+
// The LLVM intrinsic underlying int_expect_Int1 now requires an immediate
309+
// argument for the expected value so we cannot call it here. This should
310+
// never be called in cases where performance matters, so just return the
311+
// value without any branch hint.
312+
return actual
313+
}
314+
310315
//===--- Runtime shim wrappers --------------------------------------------===//
311316

312317
/// Returns `true` iff the class indicated by `theClass` uses native

test/SILOptimizer/performance_inliner.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ bb0:
752752
}
753753

754754
// Generic call to "branchHint" for use in specialized @slowPath
755-
sil public_external [transparent] [_semantics "branchhint"] @_TFs11_branchHintUs7Boolean__FTQ_Sb_Sb : $@convention(thin)(Bool, Bool) -> Bool {
755+
sil public_external [transparent] @_TFs11_branchHintUs7Boolean__FTQ_Sb_Sb : $@convention(thin)(Bool, Bool) -> Bool {
756756
bb0(%0 : $Bool, %1 : $Bool):
757757
return %0 : $Bool
758758
}

0 commit comments

Comments
 (0)