Skip to content

Stabilize the ABI of libswiftSwiftOnoneSupport #23518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/swift/AST/DiagnosticsSIL.def
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,13 @@ ERROR(circular_transparent,none,
NOTE(note_while_inlining,none,
"while inlining here", ())

// Pre-specializations
ERROR(cannot_prespecialize,none,
"Cannot pre-specialize %0", (StringRef))
ERROR(missing_prespecialization,none,
"Pre-specialized function %0 missing in SwiftOnoneSupport module",
(StringRef))

// Arithmetic diagnostics.
ERROR(integer_conversion_overflow,none,
"integer overflows when converted from %0 to %1",
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Demangling/Demangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ class Node {
// Only to be used by the demangler parsers.
void addChild(NodePointer Child, NodeFactory &Factory);
// Only to be used by the demangler parsers.
void removeChildAt(unsigned Pos, NodeFactory &factory);
void removeChildAt(unsigned Pos);

// Reverses the order of children.
void reverseChildren(size_t StartingAt = 0);
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ class FrontendOptions {
/// module appears to not be a public module.
Optional<bool> SerializeOptionsForDebugging;

/// When true, check if all required SwiftOnoneSupport symbols are present in
/// the module.
bool CheckOnoneSupportCompleteness = false;

/// If set, inserts instrumentation useful for testing the debugger.
bool DebuggerTestingTransform = false;

Expand Down
3 changes: 3 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,9 @@ def import_module : Separate<["-"], "import-module">,
def print_stats : Flag<["-"], "print-stats">,
HelpText<"Print various statistics">;

def check_onone_completeness : Flag<["-"], "check-onone-completeness">,
HelpText<"Print errors if the compile OnoneSupport module is missing symbols">;

def debugger_testing_transform : Flag<["-"], "debugger-testing-transform">,
HelpText<"Instrument the code with calls to an intrinsic that record the expected values of "
"local variables so they can be compared against the results from the debugger.">;
Expand Down
8 changes: 4 additions & 4 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,16 +266,16 @@ class SILModule {
SILModule(const SILModule&) = delete;
void operator=(const SILModule&) = delete;

/// Method which returns the SerializedSILLoader, creating the loader if it
/// has not been created yet.
SerializedSILLoader *getSILLoader();

/// Folding set for key path patterns.
llvm::FoldingSet<KeyPathPattern> KeyPathPatterns;

public:
~SILModule();

/// Method which returns the SerializedSILLoader, creating the loader if it
/// has not been created yet.
SerializedSILLoader *getSILLoader();

/// Add a callback for each newly deserialized SIL function body.
void registerDeserializationNotificationHandler(
std::unique_ptr<DeserializationNotificationHandler> &&handler);
Expand Down
6 changes: 6 additions & 0 deletions include/swift/SILOptimizer/Utils/Generics.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ class GenericFuncSpecializer {
/// prespecialization for -Onone support.
bool isKnownPrespecialization(StringRef SpecName);

/// Checks if all OnoneSupport pre-specializations are included in the module
/// as public functions.
///
/// Issues errors for all missing functions.
void checkCompletenessOfPrespecializations(SILModule &M);

/// Create a new apply based on an old one, but with a different
/// function being applied.
ApplySite replaceWithSpecializedFunction(ApplySite AI, SILFunction *NewF,
Expand Down
4 changes: 2 additions & 2 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ void Node::addChild(NodePointer Child, NodeFactory &Factory) {
}
}

void Node::removeChildAt(unsigned Pos, swift::Demangle::NodeFactory &factory) {
void Node::removeChildAt(unsigned Pos) {
switch (NodePayloadKind) {
case PayloadKind::OneChild:
assert(Pos == 0);
Expand Down Expand Up @@ -1255,7 +1255,7 @@ NodePointer Demangler::popFunctionParamLabels(NodePointer Type) {
auto Label = getChildIf(Param, Node::Kind::TupleElementName);

if (Label.first) {
Param->removeChildAt(Label.second, *this);
Param->removeChildAt(Label.second);
return createNodeWithAllocatedText(Node::Kind::Identifier,
Label.first->getText());
}
Expand Down
2 changes: 2 additions & 0 deletions lib/Frontend/ArgsToFrontendOptionsConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ bool ArgsToFrontendOptionsConverter::convert(
setUnsignedIntegerArgument(OPT_switch_checking_invocation_threshold_EQ, 10,
Opts.SwitchCheckingInvocationThreshold);

Opts.CheckOnoneSupportCompleteness = Args.hasArg(OPT_check_onone_completeness);

Opts.DebuggerTestingTransform = Args.hasArg(OPT_debugger_testing_transform);

computePlaygroundOptions();
Expand Down
6 changes: 6 additions & 0 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "swift/Parse/Lexer.h"
#include "swift/SIL/SILModule.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/Utils/Generics.h"
#include "swift/Serialization/SerializationOptions.h"
#include "swift/Serialization/SerializedModuleLoader.h"
#include "swift/Strings.h"
Expand Down Expand Up @@ -1110,6 +1111,11 @@ static void performSILOptimizations(CompilerInvocation &Invocation,
} else {
runSILOptimizationPasses(*SM);
}
if (Invocation.getFrontendOptions().CheckOnoneSupportCompleteness &&
// TODO: handle non-ObjC based stdlib builds, e.g. on linux.
Invocation.getLangOptions().EnableObjCInterop) {
checkCompletenessOfPrespecializations(*SM);
}
}

static void countStatsPostSILOpt(UnifiedStatsReporter &Stats,
Expand Down
176 changes: 97 additions & 79 deletions lib/SILOptimizer/Utils/Generics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/TypeMatcher.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/Basic/Statistic.h"
#include "swift/Serialization/SerializedSILLoader.h"
#include "swift/SIL/DebugUtils.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/OptimizationRemark.h"
#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
#include "swift/SILOptimizer/Utils/GenericCloner.h"
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/Strings.h"

using namespace swift;
Expand Down Expand Up @@ -2287,6 +2291,69 @@ SILArgument *ReabstractionThunkGenerator::convertReabstractionThunkArguments(
return ReturnValueAddr;
}

/// Create a pre-specialization of the library function with
/// \p UnspecializedName, using the substitutions from \p Apply.
static bool createPrespecialized(StringRef UnspecializedName,
ApplySite Apply,
SILOptFunctionBuilder &FuncBuilder) {
SILModule &M = FuncBuilder.getModule();
SILFunction *UnspecFunc = M.lookUpFunction(UnspecializedName);
if (UnspecFunc) {
if (!UnspecFunc->isDefinition())
M.loadFunction(UnspecFunc);
} else {
UnspecFunc = M.getSILLoader()->lookupSILFunction(UnspecializedName,
/*declarationOnly*/ false);
}

if (!UnspecFunc || !UnspecFunc->isDefinition())
return false;

ReabstractionInfo ReInfo(ApplySite(), UnspecFunc, Apply.getSubstitutionMap(),
IsNotSerialized, /*ConvertIndirectToDirect=*/true,
nullptr);

if (!ReInfo.canBeSpecialized())
return false;

GenericFuncSpecializer FuncSpecializer(FuncBuilder,
UnspecFunc, Apply.getSubstitutionMap(),
ReInfo);
SILFunction *SpecializedF = FuncSpecializer.lookupSpecialization();
if (!SpecializedF)
SpecializedF = FuncSpecializer.tryCreateSpecialization();
if (!SpecializedF)
return false;

SpecializedF->setLinkage(SILLinkage::Public);
SpecializedF->setSerialized(IsNotSerialized);
return true;
}

/// Create pre-specializations of the library function X if \p ProxyFunc has
/// @_semantics("prespecialize.X") attributes.
static bool createPrespecializations(ApplySite Apply, SILFunction *ProxyFunc,
SILOptFunctionBuilder &FuncBuilder) {
if (Apply.getSubstitutionMap().hasArchetypes())
return false;

SILModule &M = FuncBuilder.getModule();

bool prespecializeFound = false;
for (const std::string &semAttrStr : ProxyFunc->getSemanticsAttrs()) {
StringRef semAttr(semAttrStr);
if (semAttr.consume_front("prespecialize.")) {
prespecializeFound = true;
if (!createPrespecialized(semAttr, Apply, FuncBuilder)) {
M.getASTContext().Diags.diagnose(Apply.getLoc().getSourceLoc(),
diag::cannot_prespecialize,
semAttr);
}
}
}
return prespecializeFound;
}

void swift::trySpecializeApplyOfGeneric(
SILOptFunctionBuilder &FuncBuilder,
ApplySite Apply, DeadInstructionSet &DeadApplies,
Expand Down Expand Up @@ -2331,8 +2398,12 @@ void swift::trySpecializeApplyOfGeneric(
// as we do not SIL serialize their bodies.
// It is important to set this flag here, because it affects the
// mangling of the specialization's name.
if (Apply.getModule().isOptimizedOnoneSupportModule())
if (Apply.getModule().isOptimizedOnoneSupportModule()) {
if (createPrespecializations(Apply, RefF, FuncBuilder)) {
return;
}
Serialized = IsNotSerialized;
}

ReabstractionInfo ReInfo(Apply, RefF, Apply.getSubstitutionMap(),
Serialized, /*ConvertIndirectToDirect=*/true,
Expand Down Expand Up @@ -2499,91 +2570,38 @@ static bool linkSpecialization(SILModule &M, SILFunction *F) {
return false;
}

bool swift::isKnownPrespecialization(StringRef SpecName) {
// Completely disable for now.
#if false

/// The list of classes and functions from the stdlib
/// whose specializations we want to preserve.
static const char *const KnownPrespecializations[] = {
"Array",
"_ArrayBuffer",
"_ContiguousArrayBuffer",
"Range",
"RangeIterator",
"CountableRange",
"CountableRangeIterator",
"ClosedRange",
"ClosedRangeIterator",
"CountableClosedRange",
"CountableClosedRangeIterator",
"IndexingIterator",
"Collection",
"ReversedCollection",
"MutableCollection",
"BidirectionalCollection",
"RandomAccessCollection",
"ReversedRandomAccessCollection",
"RangeReplaceableCollection",
"_allocateUninitializedArray",
"UTF8",
"UTF16",
"String",
"_StringBuffer",
};

// TODO: Once there is an efficient API to check if
// a given symbol is a specialization of a specific type,
// use it instead. Doing demangling just for this check
// is just wasteful.
auto DemangledNameString =
swift::Demangle::demangleSymbolAsString(SpecName);

StringRef DemangledName = DemangledNameString;

LLVM_DEBUG(llvm::dbgs() << "Check if known: " << DemangledName << "\n");
#define PRESPEC_SYMBOL(s) MANGLE_AS_STRING(s),
static const char *PrespecSymbols[] = {
#include "OnonePrespecializations.def"
nullptr
};
#undef PRESPEC_SYMBOL

auto pos = DemangledName.find("generic ", 0);
auto oldpos = pos;
if (pos == StringRef::npos)
return false;
llvm::DenseSet<StringRef> PrespecSet;

// Create "of Swift"
llvm::SmallString<64> OfString;
llvm::raw_svector_ostream buffer(OfString);
buffer << "of ";
buffer << STDLIB_NAME <<'.';

StringRef OfStr = buffer.str();
LLVM_DEBUG(llvm::dbgs() << "Check substring: " << OfStr << "\n");

pos = DemangledName.find(OfStr, oldpos);

if (pos == StringRef::npos) {
// Create "of (extension in Swift).Swift"
llvm::SmallString<64> OfString;
llvm::raw_svector_ostream buffer(OfString);
buffer << "of (extension in " << STDLIB_NAME << "):";
buffer << STDLIB_NAME << '.';
OfStr = buffer.str();
pos = DemangledName.find(OfStr, oldpos);
LLVM_DEBUG(llvm::dbgs() << "Check substring: " << OfStr << "\n");
if (pos == StringRef::npos)
return false;
bool swift::isKnownPrespecialization(StringRef SpecName) {
if (PrespecSet.empty()) {
const char **Pos = &PrespecSymbols[0];
while (const char *Sym = *Pos++) {
PrespecSet.insert(Sym);
}
assert(!PrespecSet.empty());
}
return PrespecSet.count(SpecName) != 0;
}

pos += OfStr.size();

for (auto NameStr : KnownPrespecializations) {
StringRef Name = NameStr;
auto pos1 = DemangledName.find(Name, pos);
if (pos1 == pos && !isalpha(DemangledName[pos1+Name.size()])) {
return true;
void swift::checkCompletenessOfPrespecializations(SILModule &M) {
const char **Pos = &PrespecSymbols[0];
while (const char *Sym = *Pos++) {
StringRef FunctionName(Sym);
SILFunction *F = M.lookUpFunction(FunctionName);
if (!F || F->getLinkage() != SILLinkage::Public) {
M.getASTContext().Diags.diagnose(SourceLoc(),
diag::missing_prespecialization,
FunctionName);
}
}

#endif
return false;
}

/// Try to look up an existing specialization in the specialization cache.
Expand Down
Loading