Skip to content

Commit

Permalink
Merge pull request #21280 from DougGregor/simd-operator-type-check-pe…
Browse files Browse the repository at this point in the history
…rf-hack-5.0

[5.0] [Constraint solver] De-prioritize SIMD operators.
  • Loading branch information
AnnaZaks committed Dec 13, 2018
2 parents 050c1db + f20b7b0 commit b490a2a
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 0 deletions.
31 changes: 31 additions & 0 deletions lib/Sema/CSStep.cpp
Expand Up @@ -490,6 +490,27 @@ bool DisjunctionStep::shouldStopAt(const DisjunctionChoice &choice) const {
shortCircuitDisjunctionAt(choice, lastChoice));
}

bool swift::isSIMDOperator(ValueDecl *value) {
if (!value)
return false;

auto func = dyn_cast<FuncDecl>(value);
if (!func)
return false;

if (!func->isOperator())
return false;

auto nominal = func->getDeclContext()->getSelfNominalTypeDecl();
if (!nominal)
return false;

if (nominal->getName().empty())
return false;

return nominal->getName().str().startswith_lower("simd");
}

bool DisjunctionStep::shortCircuitDisjunctionAt(
Constraint *currentChoice, Constraint *lastSuccessfulChoice) const {
auto &ctx = CS.getASTContext();
Expand Down Expand Up @@ -535,6 +556,16 @@ bool DisjunctionStep::shortCircuitDisjunctionAt(
if (currentChoice->getKind() == ConstraintKind::CheckedCast)
return true;

// If we have an operator from the SIMDOperators module, and the prior
// choice was not from the SIMDOperators module, we're done.
if (currentChoice->getKind() == ConstraintKind::BindOverload &&
isSIMDOperator(currentChoice->getOverloadChoice().getDecl()) &&
lastSuccessfulChoice->getKind() == ConstraintKind::BindOverload &&
!isSIMDOperator(lastSuccessfulChoice->getOverloadChoice().getDecl()) &&
!ctx.LangOpts.SolverEnableOperatorDesignatedTypes) {
return true;
}

return false;
}

Expand Down
37 changes: 37 additions & 0 deletions lib/Sema/ConstraintSystem.cpp
Expand Up @@ -1443,6 +1443,40 @@ static void tryOptimizeGenericDisjunction(ConstraintSystem &cs,
}
}

/// If there are any SIMD operators in the overload set, partition the set so
/// that the SIMD operators come at the end.
static ArrayRef<OverloadChoice> partitionSIMDOperators(
ArrayRef<OverloadChoice> choices,
SmallVectorImpl<OverloadChoice> &scratch) {
// If the first element isn't an operator, none of them are.
if (!choices[0].isDecl() ||
!isa<FuncDecl>(choices[0].getDecl()) ||
!cast<FuncDecl>(choices[0].getDecl())->isOperator() ||
choices[0].getDecl()->getASTContext().LangOpts
.SolverEnableOperatorDesignatedTypes)
return choices;

// Check whether we have any SIMD operators.
bool foundSIMDOperator = false;
for (const auto &choice : choices) {
if (isSIMDOperator(choice.getDecl())) {
foundSIMDOperator = true;
break;
}
}

if (!foundSIMDOperator)
return choices;

scratch.assign(choices.begin(), choices.end());
std::stable_partition(scratch.begin(), scratch.end(),
[](const OverloadChoice &choice) {
return !isSIMDOperator(choice.getDecl());
});

return scratch;
}

void ConstraintSystem::addOverloadSet(Type boundType,
ArrayRef<OverloadChoice> choices,
DeclContext *useDC,
Expand All @@ -1459,6 +1493,9 @@ void ConstraintSystem::addOverloadSet(Type boundType,

tryOptimizeGenericDisjunction(*this, choices, favoredChoice);

SmallVector<OverloadChoice, 4> scratchChoices;
choices = partitionSIMDOperators(choices, scratchChoices);

SmallVector<Constraint *, 4> overloads;

// As we do for other favored constraints, if a favored overload has been
Expand Down
3 changes: 3 additions & 0 deletions lib/Sema/ConstraintSystem.h
Expand Up @@ -3830,6 +3830,9 @@ bool exprNeedsParensOutsideFollowingOperator(
TypeChecker &TC, DeclContext *DC, Expr *expr, Expr *rootExpr,
PrecedenceGroupDecl *followingPG);

/// Determine whether this is a SIMD operator.
bool isSIMDOperator(ValueDecl *value);

} // end namespace swift

#endif // LLVM_SWIFT_SEMA_CONSTRAINT_SYSTEM_H
61 changes: 61 additions & 0 deletions validation-test/Sema/type_checker_perf/fast/rdar46541800.swift
@@ -0,0 +1,61 @@
// RUN: %target-typecheck-verify-swift
// REQUIRES: OS=macosx

import simd
import CoreGraphics
import Foundation

class SomeView {
func layoutSubviews() {
let descriptionTextViewFrame = CGRect.zero
let availableBounds = CGRect()
let descriptionLabelProperties = SomeView.descriptionTextViewLabelProperties()
let textSize = descriptionTextView.sizeThatFits(availableBounds.size)
let textInset = descriptionTextView.textInset(forBounds: CGRect(origin: .zero, size: textSize))
let descriptionTextBaselineOffset: CGFloat = CGFloat()
let displayScale: CGFloat = CGFloat()
let _ = (descriptionTextViewFrame.height
+ (-descriptionTextView.lastBaselineOffsetFromBottom - textInset.bottom + descriptionLabelProperties.lastBaselineOffsetFromBottom)
+ (-descriptionTextView.firstBaselineOffsetFromTop - textInset.top + descriptionTextBaselineOffset).ceilingValue(scale: displayScale)
)
}

static func descriptionTextViewLabelProperties() -> FontDescriptorBaselineProperties {
fatalError()
}

lazy var descriptionTextView: SomeOtherView = SomeOtherView()
}

class SomeOtherView {
init() { }
func sizeThatFits(_ size: CGSize) -> CGSize { return size }
}


struct FontDescriptorBaselineProperties {
// let fontDescriptor: MPUFontDescriptor
let defaultFirstBaselineOffsetFromTop: CGFloat
let defaultLastBaselineOffsetFromBottom: CGFloat
var firstBaselineOffsetFromTop: CGFloat { fatalError() }
var lastBaselineOffsetFromBottom: CGFloat {
fatalError()
}
}

struct EdgeInsets {
var top: CGFloat
var bottom: CGFloat
}

extension SomeOtherView {
func textInset(forBounds bounds: CGRect) -> EdgeInsets { fatalError() }
var firstBaselineOffsetFromTop: CGFloat { fatalError() }
var lastBaselineOffsetFromBottom: CGFloat {
fatalError()
}
}

extension CGFloat {
public func ceilingValue(scale: CGFloat) -> CGFloat { fatalError() }
}

0 comments on commit b490a2a

Please sign in to comment.