diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 767db7a97cfa5..30a01354e97d1 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -221,7 +221,9 @@ namespace { DifferentiabilityWitnessesToEmit; /// Additional functions we might need to serialize. - llvm::SmallVector Worklist; + llvm::SmallVector functionWorklist; + + llvm::SmallVector globalWorklist; /// String storage for temporarily created strings which are referenced from /// the tables. @@ -244,7 +246,9 @@ namespace { bool emitDeclarationsForOnoneSupport); void addReferencedSILFunction(const SILFunction *F, bool DeclOnly = false); - void processSILFunctionWorklist(); + void addReferencedGlobalVariable(const SILGlobalVariable *gl); + + void processWorklists(); /// Helper function to update ListOfValues for MethodInst. Format: /// Attr, SILDeclRef (DeclID, Kind, uncurryLevel), and an operand. @@ -334,7 +338,7 @@ void SILSerializer::addMandatorySILFunction(const SILFunction *F, // Function body should be serialized unless it is a KeepAsPublic function // (which is typically a pre-specialization). if (!emitDeclarationsForOnoneSupport) - Worklist.push_back(F); + functionWorklist.push_back(F); } void SILSerializer::addReferencedSILFunction(const SILFunction *F, @@ -348,7 +352,7 @@ void SILSerializer::addReferencedSILFunction(const SILFunction *F, // serialize the body or just the declaration. if (shouldEmitFunctionBody(F)) { FuncsToEmit[F] = false; - Worklist.push_back(F); + functionWorklist.push_back(F); return; } @@ -357,7 +361,7 @@ void SILSerializer::addReferencedSILFunction(const SILFunction *F, F->hasForeignBody()); FuncsToEmit[F] = false; - Worklist.push_back(F); + functionWorklist.push_back(F); return; } @@ -365,15 +369,27 @@ void SILSerializer::addReferencedSILFunction(const SILFunction *F, FuncsToEmit[F] = true; } -void SILSerializer::processSILFunctionWorklist() { - while (!Worklist.empty()) { - const SILFunction *F = Worklist.back(); - Worklist.pop_back(); - assert(F != nullptr); +void SILSerializer::addReferencedGlobalVariable(const SILGlobalVariable *gl) { + if (GlobalsToEmit.insert(gl).second) + globalWorklist.push_back(gl); +} - assert(FuncsToEmit.count(F) > 0); - writeSILFunction(*F, FuncsToEmit[F]); - } + +void SILSerializer::processWorklists() { + do { + while (!functionWorklist.empty()) { + const SILFunction *F = functionWorklist.pop_back_val(); + assert(F != nullptr); + + assert(FuncsToEmit.count(F) > 0); + writeSILFunction(*F, FuncsToEmit[F]); + } + while (!globalWorklist.empty()) { + const SILGlobalVariable *gl = globalWorklist.pop_back_val(); + assert(GlobalsToEmit.count(gl) > 0); + writeSILGlobalVar(*gl); + } + } while (!functionWorklist.empty()); } /// We enumerate all values in a SILFunction beforehand to correctly @@ -1116,7 +1132,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { // Format: Name and type. Use SILOneOperandLayout. const AllocGlobalInst *AGI = cast(&SI); auto *G = AGI->getReferencedGlobal(); - GlobalsToEmit.insert(G); + addReferencedGlobalVariable(G); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), 0, 0, 0, @@ -1128,7 +1144,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { // Format: Name and type. Use SILOneOperandLayout. const GlobalAccessInst *GI = cast(&SI); auto *G = GI->getReferencedGlobal(); - GlobalsToEmit.insert(G); + addReferencedGlobalVariable(G); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), 0, @@ -2816,6 +2832,12 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { writeSILDefaultWitnessTable(wt); } + // Add global variables that must be emitted to the list. + for (const SILGlobalVariable &g : SILMod->getSILGlobals()) { + if (g.isSerialized() || ShouldSerializeAll) + addReferencedGlobalVariable(&g); + } + // Emit only declarations if it is a module with pre-specializations. // And only do it in optimized builds. bool emitDeclarationsForOnoneSupport = @@ -2835,7 +2857,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { } addMandatorySILFunction(&F, emitDeclarationsForOnoneSupport); - processSILFunctionWorklist(); + processWorklists(); } // Write out differentiability witnesses. @@ -2854,7 +2876,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { // Process SIL functions referenced by differentiability witnesses. // Note: this is necessary despite processing `FuncsToEmit` below because // `Worklist` is processed separately. - processSILFunctionWorklist(); + processWorklists(); // Now write function declarations for every function we've // emitted a reference to without emitting a function body for. @@ -2868,16 +2890,8 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { } } - // Add global variables that must be emitted to the list. - for (const SILGlobalVariable &g : SILMod->getSILGlobals()) - if (g.isSerialized() || ShouldSerializeAll) - GlobalsToEmit.insert(&g); - - // Now write out all referenced global variables. - for (auto *g : GlobalsToEmit) - writeSILGlobalVar(*g); - - assert(Worklist.empty() && "Did not emit everything in worklist"); + assert(functionWorklist.empty() && globalWorklist.empty() && + "Did not emit everything in worklists"); } void SILSerializer::writeSILModule(const SILModule *SILMod) { diff --git a/test/Concurrency/Runtime/exclusivity_custom_executors.swift b/test/Concurrency/Runtime/exclusivity_custom_executors.swift index 900363ff30436..8dd76ec1d3eb7 100644 --- a/test/Concurrency/Runtime/exclusivity_custom_executors.swift +++ b/test/Concurrency/Runtime/exclusivity_custom_executors.swift @@ -10,6 +10,9 @@ // Disabled until test hang can be looked at. // UNSUPPORTED: OS=windows-msvc +// rdar://82973061 +// XFAIL: linux + // This test makes sure that we properly save/restore access when we // synchronously launch a task from a serial executor. The access from the task // should be merged into the already created access set while it runs and then diff --git a/test/SIL/Serialization/function-global-function.sil b/test/SIL/Serialization/function-global-function.sil new file mode 100644 index 0000000000000..98c3ae38de89a --- /dev/null +++ b/test/SIL/Serialization/function-global-function.sil @@ -0,0 +1,26 @@ +// RUN: %target-sil-opt %s -serialize -o /dev/null + +sil_stage canonical + +import Builtin + +// Check that we don't crash if a serialiable function is referenced from the +// initializer of a global variable. + +sil_global [serialized] @globalFuncPtr : $@callee_guaranteed () -> () = { + %0 = function_ref @calledFromFuncPtr : $@convention(thin) () -> () + %initval = thin_to_thick_function %0 : $@convention(thin) () -> () to $@callee_guaranteed () -> () +} + +sil @caller : $@convention(thin) () -> () { +bb0: + %0 = global_addr @globalFuncPtr : $*@callee_guaranteed () -> () + %7 = tuple () + return %7 : $() +} + +sil shared [serializable] @calledFromFuncPtr : $@convention(thin) () -> () { +bb0: + %6 = tuple () + return %6 : $() +} diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp index 7681d2f5d10fb..e0dce223eaf9a 100644 --- a/tools/sil-opt/SILOpt.cpp +++ b/tools/sil-opt/SILOpt.cpp @@ -228,6 +228,9 @@ EmitVerboseSIL("emit-verbose-sil", static llvm::cl::opt EmitSIB("emit-sib", llvm::cl::desc("Emit serialized AST + SIL file(s)")); +static llvm::cl::opt +Serialize("serialize", llvm::cl::desc("Emit serialized AST + SIL file(s)")); + static llvm::cl::opt ModuleCachePath("module-cache-path", llvm::cl::desc("Clang module cache path")); @@ -564,7 +567,7 @@ int main(int argc, char **argv) { } } - if (EmitSIB) { + if (EmitSIB || Serialize) { llvm::SmallString<128> OutputFile; if (OutputFilename.size()) { OutputFile = OutputFilename; @@ -580,8 +583,8 @@ int main(int argc, char **argv) { SerializationOptions serializationOpts; serializationOpts.OutputPath = OutputFile.c_str(); - serializationOpts.SerializeAllSIL = true; - serializationOpts.IsSIB = true; + serializationOpts.SerializeAllSIL = EmitSIB; + serializationOpts.IsSIB = EmitSIB; serialize(CI.getMainModule(), serializationOpts, SILMod.get()); } else {