summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-check-conversion.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-05-29 18:01:11 -0700
committerGitHub <noreply@github.com>2024-05-29 18:01:11 -0700
commitefdbb954c57b89362e390f955d45f90e59d66878 (patch)
tree7b47d6e52d2de666af99f66a2fd3a5dc387ca5cc /source/slang/slang-check-conversion.cpp
parent83f176ba8a3bae5533470aed6a90663653f894b8 (diff)
Improve compile time performance. (#3857)
* Handle type check cache update on extensions more gracefully. * Correctness fix. * Cache implcit cast overload resolution results. * Fix. * More optimizations. * Cache implicit default ctor resolution. * Disable redundancy removal. * Fix. * Fix test. * Fix. * Correctness fix. * Fix. * Fix, * Fix test. * Small tweak.
Diffstat (limited to 'source/slang/slang-check-conversion.cpp')
-rw-r--r--source/slang/slang-check-conversion.cpp74
1 files changed, 66 insertions, 8 deletions
diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp
index 7dcc8975c..16f413055 100644
--- a/source/slang/slang-check-conversion.cpp
+++ b/source/slang/slang-check-conversion.cpp
@@ -1097,7 +1097,40 @@ namespace Slang
overloadContext.baseExpr = nullptr;
overloadContext.mode = OverloadResolveContext::Mode::JustTrying;
- AddTypeOverloadCandidates(toType, overloadContext);
+ // Since the lookup and resolution of all possible implicit conversions
+ // can be very costly, we use a cache to store the checking results.
+ ImplicitCastMethodKey implicitCastKey = ImplicitCastMethodKey(fromType, toType, fromExpr);
+ ImplicitCastMethod* cachedMethod = getShared()->tryGetImplicitCastMethod(implicitCastKey);
+
+ if (cachedMethod)
+ {
+ if (cachedMethod->conversionFuncOverloadCandidate.status != OverloadCandidate::Status::Applicable)
+ {
+ return _failedCoercion(toType, outToExpr, fromExpr);
+ }
+ overloadContext.bestCandidateStorage = cachedMethod->conversionFuncOverloadCandidate;
+ overloadContext.bestCandidate = &overloadContext.bestCandidateStorage;
+ if (!outToExpr)
+ {
+ // If we are not requesting to create an expression, we can return early.
+ if (outCost)
+ *outCost = cachedMethod->cost;
+ return true;
+ }
+ else
+ {
+ if (cachedMethod->isAmbiguous)
+ {
+ overloadContext.bestCandidate = nullptr;
+ overloadContext.bestCandidates.add(cachedMethod->conversionFuncOverloadCandidate);
+ }
+ }
+ }
+
+ if (!overloadContext.bestCandidate)
+ {
+ AddTypeOverloadCandidates(toType, overloadContext);
+ }
// After all of the overload candidates have been added
// to the context and processed, we need to see whether
@@ -1111,8 +1144,14 @@ namespace Slang
// even applicable, because if not, then we shouldn't
// consider the conversion as possible.
//
- if(overloadContext.bestCandidates[0].status != OverloadCandidate::Status::Applicable)
+ if (overloadContext.bestCandidates[0].status != OverloadCandidate::Status::Applicable)
+ {
+ if (!cachedMethod)
+ {
+ getShared()->cacheImplicitCastMethod(implicitCastKey, ImplicitCastMethod{});
+ }
return _failedCoercion(toType, outToExpr, fromExpr);
+ }
// If all of the candidates in `bestCandidates` are applicable,
// then we have an ambiguity.
@@ -1121,13 +1160,16 @@ namespace Slang
// all the conversions available.
//
ConversionCost bestCost = kConversionCost_Explicit;
+ ImplicitCastMethod method;
for(auto candidate : overloadContext.bestCandidates)
{
ConversionCost candidateCost = getImplicitConversionCostWithKnownArg(
candidate.item.declRef.getDecl(), toType, fromExpr);
-
- if(candidateCost < bestCost)
+ if (candidateCost < bestCost)
+ {
+ method.conversionFuncOverloadCandidate = candidate;
bestCost = candidateCost;
+ }
}
// Conceptually, we want to treat the conversion as
@@ -1141,9 +1183,15 @@ namespace Slang
*outToExpr = CreateErrorExpr(fromExpr);
}
+ if (!cachedMethod)
+ {
+ method.isAmbiguous = true;
+ method.cost = bestCost;
+ getShared()->cacheImplicitCastMethod(implicitCastKey, method);
+ }
+
if(outCost)
*outCost = bestCost;
-
return true;
}
else if(overloadContext.bestCandidate)
@@ -1155,8 +1203,14 @@ namespace Slang
// but it wasn't actually usable, so we will check for
// that case first.
//
- if(overloadContext.bestCandidate->status != OverloadCandidate::Status::Applicable)
+ if (overloadContext.bestCandidate->status != OverloadCandidate::Status::Applicable)
+ {
+ if (!cachedMethod)
+ {
+ getShared()->cacheImplicitCastMethod(implicitCastKey, ImplicitCastMethod{});
+ }
return _failedCoercion(toType, outToExpr, fromExpr);
+ }
// Next, we need to look at the implicit conversion
// cost associated with the initializer we are invoking.
@@ -1265,10 +1319,14 @@ namespace Slang
castExpr->arguments.clear();
castExpr->arguments.add(fromExpr);
}
-
+ if (!cachedMethod)
+ getShared()->cacheImplicitCastMethod(implicitCastKey, ImplicitCastMethod{ *overloadContext.bestCandidate, cost });
return true;
}
-
+ if (!cachedMethod)
+ {
+ getShared()->cacheImplicitCastMethod(implicitCastKey, ImplicitCastMethod{});
+ }
return _failedCoercion(toType, outToExpr, fromExpr);
}