Skip to content

Commit 57ef411

Browse files
authored
Merge pull request swiftlang#82869 from xedin/logic-infix-operators-perf
[CSOptimizer] Prefer logical infix operator if it has smaller overload set
2 parents 9ae27d7 + 1f8e487 commit 57ef411

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

include/swift/AST/Identifier.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ class Identifier {
140140
return is("??");
141141
}
142142

143+
// Returns whether this is a standard infix logical operator,
144+
// such as '&&', '||'.
145+
bool isStandardInfixLogicalOperator() const { return is("&&") || is("||"); }
146+
143147
/// isOperatorStartCodePoint - Return true if the specified code point is a
144148
/// valid start of an operator.
145149
static bool isOperatorStartCodePoint(uint32_t C) {

lib/Sema/CSOptimizer.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,14 @@ static bool isStandardComparisonOperator(Constraint *disjunction) {
251251
return false;
252252
}
253253

254+
static bool isStandardInfixLogicalOperator(Constraint *disjunction) {
255+
auto *choice = disjunction->getNestedConstraints()[0];
256+
if (auto *decl = getOverloadChoiceDecl(choice))
257+
return decl->isOperator() &&
258+
decl->getBaseIdentifier().isStandardInfixLogicalOperator();
259+
return false;
260+
}
261+
254262
static bool isOperatorNamed(Constraint *disjunction, StringRef name) {
255263
auto *choice = disjunction->getNestedConstraints()[0];
256264
if (auto *decl = getOverloadChoiceDecl(choice))
@@ -1856,6 +1864,16 @@ ConstraintSystem::selectDisjunction() {
18561864
bool isFirstOperator = isOperatorDisjunction(first);
18571865
bool isSecondOperator = isOperatorDisjunction(second);
18581866

1867+
// Infix logical operators are usually not overloaded and don't
1868+
// form disjunctions, but when they do, let's prefer them over
1869+
// other operators when they have fewer choices because it helps
1870+
// to split operator chains.
1871+
if (isFirstOperator && isSecondOperator) {
1872+
if (isStandardInfixLogicalOperator(first) !=
1873+
isStandardInfixLogicalOperator(second))
1874+
return firstActive < secondActive;
1875+
}
1876+
18591877
// Not all of the non-operator disjunctions are supported by the
18601878
// ranking algorithm, so to prevent eager selection of operators
18611879
// when nothing concrete is known about them, let's reset the score
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s
2+
// REQUIRES: asserts,no_asan
3+
4+
struct Predicate<T> : Equatable {}
5+
6+
func ||<T>(_: Predicate<T>, _: Predicate<T>) -> Predicate<T> {
7+
.init()
8+
}
9+
10+
func !=<Value, Operand>(_: Operand, _: Operand) -> Predicate<Value> where Operand : Equatable {
11+
.init()
12+
}
13+
14+
func !=<Value, Operand>(_: Operand, _: KeyPath<Value, Operand>) -> Predicate<Value> where Operand : Equatable {
15+
.init()
16+
}
17+
18+
func !=<Value, Operand>(_: KeyPath<Value, Operand>, _: Operand) -> Predicate<Value> where Operand : Equatable {
19+
.init()
20+
}
21+
22+
func !=<Value, Operand>(_: KeyPath<Value, Operand>, _: KeyPath<Value, Operand>) -> Predicate<Value> where Operand : Equatable {
23+
.init()
24+
}
25+
26+
enum Format : UInt, Equatable {
27+
case simple = 0
28+
}
29+
30+
struct Parameter {
31+
struct Buffers {
32+
struct Data {
33+
let format: Format
34+
}
35+
36+
let data: Data?
37+
}
38+
39+
var buffers: Buffers
40+
}
41+
42+
func test(arr: [Parameter]) {
43+
for p in arr {
44+
if (p.buffers.data != nil && p.buffers.data!.format != .simple) ||
45+
%for i in range(1, N):
46+
(p.buffers.data != nil && p.buffers.data!.format != .simple) ||
47+
%end
48+
(p.buffers.data != nil && p.buffers.data!.format != .simple) {
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)