|
16 | 16 | #include "swift/AST/GenericEnvironment.h"
|
17 | 17 | #include "swift/AST/GenericSignatureBuilder.h"
|
18 | 18 | #include "swift/AST/TypeMatcher.h"
|
| 19 | +#include "swift/AST/DiagnosticEngine.h" |
| 20 | +#include "swift/AST/DiagnosticsSIL.h" |
19 | 21 | #include "swift/Basic/Statistic.h"
|
| 22 | +#include "swift/Serialization/SerializedSILLoader.h" |
20 | 23 | #include "swift/SIL/DebugUtils.h"
|
21 | 24 | #include "swift/SIL/InstructionUtils.h"
|
22 | 25 | #include "swift/SIL/OptimizationRemark.h"
|
23 | 26 | #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
|
24 | 27 | #include "swift/SILOptimizer/Utils/GenericCloner.h"
|
25 | 28 | #include "swift/SILOptimizer/Utils/SpecializationMangler.h"
|
| 29 | +#include "swift/Demangling/ManglingMacros.h" |
26 | 30 | #include "swift/Strings.h"
|
27 | 31 |
|
28 | 32 | using namespace swift;
|
@@ -2287,6 +2291,69 @@ SILArgument *ReabstractionThunkGenerator::convertReabstractionThunkArguments(
|
2287 | 2291 | return ReturnValueAddr;
|
2288 | 2292 | }
|
2289 | 2293 |
|
| 2294 | +/// Create a pre-specialization of the library function with |
| 2295 | +/// \p UnspecializedName, using the substitutions from \p Apply. |
| 2296 | +static bool createPrespecialized(StringRef UnspecializedName, |
| 2297 | + ApplySite Apply, |
| 2298 | + SILOptFunctionBuilder &FuncBuilder) { |
| 2299 | + SILModule &M = FuncBuilder.getModule(); |
| 2300 | + SILFunction *UnspecFunc = M.lookUpFunction(UnspecializedName); |
| 2301 | + if (UnspecFunc) { |
| 2302 | + if (!UnspecFunc->isDefinition()) |
| 2303 | + M.loadFunction(UnspecFunc); |
| 2304 | + } else { |
| 2305 | + UnspecFunc = M.getSILLoader()->lookupSILFunction(UnspecializedName, |
| 2306 | + /*declarationOnly*/ false); |
| 2307 | + } |
| 2308 | + |
| 2309 | + if (!UnspecFunc || !UnspecFunc->isDefinition()) |
| 2310 | + return false; |
| 2311 | + |
| 2312 | + ReabstractionInfo ReInfo(ApplySite(), UnspecFunc, Apply.getSubstitutionMap(), |
| 2313 | + IsNotSerialized, /*ConvertIndirectToDirect=*/true, |
| 2314 | + nullptr); |
| 2315 | + |
| 2316 | + if (!ReInfo.canBeSpecialized()) |
| 2317 | + return false; |
| 2318 | + |
| 2319 | + GenericFuncSpecializer FuncSpecializer(FuncBuilder, |
| 2320 | + UnspecFunc, Apply.getSubstitutionMap(), |
| 2321 | + ReInfo); |
| 2322 | + SILFunction *SpecializedF = FuncSpecializer.lookupSpecialization(); |
| 2323 | + if (!SpecializedF) |
| 2324 | + SpecializedF = FuncSpecializer.tryCreateSpecialization(); |
| 2325 | + if (!SpecializedF) |
| 2326 | + return false; |
| 2327 | + |
| 2328 | + SpecializedF->setLinkage(SILLinkage::Public); |
| 2329 | + SpecializedF->setSerialized(IsNotSerialized); |
| 2330 | + return true; |
| 2331 | +} |
| 2332 | + |
| 2333 | +/// Create pre-specializations of the library function X if \p ProxyFunc has |
| 2334 | +/// @_semantics("prespecialize.X") attributes. |
| 2335 | +static bool createPrespecializations(ApplySite Apply, SILFunction *ProxyFunc, |
| 2336 | + SILOptFunctionBuilder &FuncBuilder) { |
| 2337 | + if (Apply.getSubstitutionMap().hasArchetypes()) |
| 2338 | + return false; |
| 2339 | + |
| 2340 | + SILModule &M = FuncBuilder.getModule(); |
| 2341 | + |
| 2342 | + bool prespecializeFound = false; |
| 2343 | + for (const std::string &semAttrStr : ProxyFunc->getSemanticsAttrs()) { |
| 2344 | + StringRef semAttr(semAttrStr); |
| 2345 | + if (semAttr.consume_front("prespecialize.")) { |
| 2346 | + prespecializeFound = true; |
| 2347 | + if (!createPrespecialized(semAttr, Apply, FuncBuilder)) { |
| 2348 | + M.getASTContext().Diags.diagnose(Apply.getLoc().getSourceLoc(), |
| 2349 | + diag::cannot_prespecialize, |
| 2350 | + semAttr); |
| 2351 | + } |
| 2352 | + } |
| 2353 | + } |
| 2354 | + return prespecializeFound; |
| 2355 | +} |
| 2356 | + |
2290 | 2357 | void swift::trySpecializeApplyOfGeneric(
|
2291 | 2358 | SILOptFunctionBuilder &FuncBuilder,
|
2292 | 2359 | ApplySite Apply, DeadInstructionSet &DeadApplies,
|
@@ -2331,8 +2398,12 @@ void swift::trySpecializeApplyOfGeneric(
|
2331 | 2398 | // as we do not SIL serialize their bodies.
|
2332 | 2399 | // It is important to set this flag here, because it affects the
|
2333 | 2400 | // mangling of the specialization's name.
|
2334 |
| - if (Apply.getModule().isOptimizedOnoneSupportModule()) |
| 2401 | + if (Apply.getModule().isOptimizedOnoneSupportModule()) { |
| 2402 | + if (createPrespecializations(Apply, RefF, FuncBuilder)) { |
| 2403 | + return; |
| 2404 | + } |
2335 | 2405 | Serialized = IsNotSerialized;
|
| 2406 | + } |
2336 | 2407 |
|
2337 | 2408 | ReabstractionInfo ReInfo(Apply, RefF, Apply.getSubstitutionMap(),
|
2338 | 2409 | Serialized, /*ConvertIndirectToDirect=*/true,
|
@@ -2499,91 +2570,38 @@ static bool linkSpecialization(SILModule &M, SILFunction *F) {
|
2499 | 2570 | return false;
|
2500 | 2571 | }
|
2501 | 2572 |
|
2502 |
| -bool swift::isKnownPrespecialization(StringRef SpecName) { |
2503 |
| - // Completely disable for now. |
2504 |
| -#if false |
2505 |
| - |
2506 |
| - /// The list of classes and functions from the stdlib |
2507 |
| - /// whose specializations we want to preserve. |
2508 |
| - static const char *const KnownPrespecializations[] = { |
2509 |
| - "Array", |
2510 |
| - "_ArrayBuffer", |
2511 |
| - "_ContiguousArrayBuffer", |
2512 |
| - "Range", |
2513 |
| - "RangeIterator", |
2514 |
| - "CountableRange", |
2515 |
| - "CountableRangeIterator", |
2516 |
| - "ClosedRange", |
2517 |
| - "ClosedRangeIterator", |
2518 |
| - "CountableClosedRange", |
2519 |
| - "CountableClosedRangeIterator", |
2520 |
| - "IndexingIterator", |
2521 |
| - "Collection", |
2522 |
| - "ReversedCollection", |
2523 |
| - "MutableCollection", |
2524 |
| - "BidirectionalCollection", |
2525 |
| - "RandomAccessCollection", |
2526 |
| - "ReversedRandomAccessCollection", |
2527 |
| - "RangeReplaceableCollection", |
2528 |
| - "_allocateUninitializedArray", |
2529 |
| - "UTF8", |
2530 |
| - "UTF16", |
2531 |
| - "String", |
2532 |
| - "_StringBuffer", |
2533 |
| - }; |
2534 |
| - |
2535 |
| - // TODO: Once there is an efficient API to check if |
2536 |
| - // a given symbol is a specialization of a specific type, |
2537 |
| - // use it instead. Doing demangling just for this check |
2538 |
| - // is just wasteful. |
2539 |
| - auto DemangledNameString = |
2540 |
| - swift::Demangle::demangleSymbolAsString(SpecName); |
2541 |
| - |
2542 |
| - StringRef DemangledName = DemangledNameString; |
2543 |
| - |
2544 |
| - LLVM_DEBUG(llvm::dbgs() << "Check if known: " << DemangledName << "\n"); |
| 2573 | +#define PRESPEC_SYMBOL(s) MANGLE_AS_STRING(s), |
| 2574 | +static const char *PrespecSymbols[] = { |
| 2575 | +#include "OnonePrespecializations.def" |
| 2576 | + nullptr |
| 2577 | +}; |
| 2578 | +#undef PRESPEC_SYMBOL |
2545 | 2579 |
|
2546 |
| - auto pos = DemangledName.find("generic ", 0); |
2547 |
| - auto oldpos = pos; |
2548 |
| - if (pos == StringRef::npos) |
2549 |
| - return false; |
| 2580 | +llvm::DenseSet<StringRef> PrespecSet; |
2550 | 2581 |
|
2551 |
| - // Create "of Swift" |
2552 |
| - llvm::SmallString<64> OfString; |
2553 |
| - llvm::raw_svector_ostream buffer(OfString); |
2554 |
| - buffer << "of "; |
2555 |
| - buffer << STDLIB_NAME <<'.'; |
2556 |
| - |
2557 |
| - StringRef OfStr = buffer.str(); |
2558 |
| - LLVM_DEBUG(llvm::dbgs() << "Check substring: " << OfStr << "\n"); |
2559 |
| - |
2560 |
| - pos = DemangledName.find(OfStr, oldpos); |
2561 |
| - |
2562 |
| - if (pos == StringRef::npos) { |
2563 |
| - // Create "of (extension in Swift).Swift" |
2564 |
| - llvm::SmallString<64> OfString; |
2565 |
| - llvm::raw_svector_ostream buffer(OfString); |
2566 |
| - buffer << "of (extension in " << STDLIB_NAME << "):"; |
2567 |
| - buffer << STDLIB_NAME << '.'; |
2568 |
| - OfStr = buffer.str(); |
2569 |
| - pos = DemangledName.find(OfStr, oldpos); |
2570 |
| - LLVM_DEBUG(llvm::dbgs() << "Check substring: " << OfStr << "\n"); |
2571 |
| - if (pos == StringRef::npos) |
2572 |
| - return false; |
| 2582 | +bool swift::isKnownPrespecialization(StringRef SpecName) { |
| 2583 | + if (PrespecSet.empty()) { |
| 2584 | + const char **Pos = &PrespecSymbols[0]; |
| 2585 | + while (const char *Sym = *Pos++) { |
| 2586 | + PrespecSet.insert(Sym); |
| 2587 | + } |
| 2588 | + assert(!PrespecSet.empty()); |
2573 | 2589 | }
|
| 2590 | + return PrespecSet.count(SpecName) != 0; |
| 2591 | +} |
2574 | 2592 |
|
2575 |
| - pos += OfStr.size(); |
2576 |
| - |
2577 |
| - for (auto NameStr : KnownPrespecializations) { |
2578 |
| - StringRef Name = NameStr; |
2579 |
| - auto pos1 = DemangledName.find(Name, pos); |
2580 |
| - if (pos1 == pos && !isalpha(DemangledName[pos1+Name.size()])) { |
2581 |
| - return true; |
| 2593 | +void swift::checkCompletenessOfPrespecializations(SILModule &M) { |
| 2594 | + const char **Pos = &PrespecSymbols[0]; |
| 2595 | + while (const char *Sym = *Pos++) { |
| 2596 | + StringRef FunctionName(Sym); |
| 2597 | + SILFunction *F = M.lookUpFunction(FunctionName); |
| 2598 | + if (!F || F->getLinkage() != SILLinkage::Public) { |
| 2599 | + M.getASTContext().Diags.diagnose(SourceLoc(), |
| 2600 | + diag::missing_prespecialization, |
| 2601 | + FunctionName); |
2582 | 2602 | }
|
2583 | 2603 | }
|
2584 | 2604 |
|
2585 |
| -#endif |
2586 |
| - return false; |
2587 | 2605 | }
|
2588 | 2606 |
|
2589 | 2607 | /// Try to look up an existing specialization in the specialization cache.
|
|
0 commit comments