diff --git a/docs/SIL/FunctionAttributes.md b/docs/SIL/FunctionAttributes.md index 37ed3f1eb4f44..21a09bb33eb6f 100644 --- a/docs/SIL/FunctionAttributes.md +++ b/docs/SIL/FunctionAttributes.md @@ -228,3 +228,11 @@ Specifies that the optimizer and IRGen must not add runtime calls which are not in the function originally. This attribute is set for functions with performance constraints or functions which are called from functions with performance constraints. + +### Naming + +``` +sil-function-attribute :: '[' asmname "' identifier '" ']' +``` + +Specifies that the SIL function should be lowered to LLVM IR with the given function name. diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index aeaeb6c8d7bd8..d85e3e833c963 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -320,6 +320,11 @@ class SILFunction /// The function's remaining set of specialize attributes. std::vector SpecializeAttrSet; + /// The name that this function should have when it is lowered to LLVM IR. + /// + /// If empty, use the SIL function's name directly. + StringRef AsmName; + /// Name of a section if @_section attribute was used, otherwise empty. StringRef Section; @@ -1423,6 +1428,10 @@ class SILFunction bool markedAsUsed() const { return MarkedAsUsed; } void setMarkedAsUsed(bool value) { MarkedAsUsed = value; } + /// Return custom assembler name, otherwise empty. + StringRef asmName() const { return AsmName; } + void setAsmName(StringRef value) { AsmName = value; } + /// Return custom section name if @_section was used, otherwise empty StringRef section() const { return Section; } void setSection(StringRef value) { Section = value; } diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index fef50bee40ea0..895236b7136a4 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -60,6 +60,13 @@ class SILGlobalVariable /// binary. A pointer into the module's lookup table. StringRef Name; + /// The name that this variable should have when lowered to LLVM IR. If empty, + /// the mangled name of the variable will be used instead. + StringRef AsmName; + + /// Name of a section if @_section attribute was used, otherwise empty. + StringRef Section; + /// The lowered type of the variable. SILType LoweredType; @@ -150,7 +157,15 @@ class SILGlobalVariable } StringRef getName() const { return Name; } - + + /// Return custom assembler name, otherwise empty. + StringRef asmName() const { return AsmName; } + void setAsmName(StringRef value) { AsmName = value; } + + /// Return custom section name if @_section was used, otherwise empty + StringRef section() const { return Section; } + void setSection(StringRef value) { Section = value; } + void setDeclaration(bool isD) { IsDeclaration = isD; } /// True if this is a definition of the variable. @@ -232,15 +247,6 @@ class SILGlobalVariable void setMarkedAsUsed(bool used) { IsUsed = used; } - /// Returns a SectionAttr if this global variable has `@_section` attribute. - SectionAttr *getSectionAttr() const { - auto *V = getDecl(); - if (!V) - return nullptr; - - return V->getAttrs().getAttribute(); - } - /// Return whether this variable corresponds to a Clang node. bool hasClangNode() const; diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 51b866dd12499..cf41c9e353d0c 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2865,8 +2865,8 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var, addUsedGlobal(gvar); else if (var->shouldBePreservedForDebugger() && forDefinition) addUsedGlobal(gvar); - if (auto *sectionAttr = var->getSectionAttr()) - gvar->setSection(sectionAttr->Name); + if (!var->section().empty()) + gvar->setSection(var->section()); } if (forDefinition && !gvar->hasInitializer()) { if (initVal) { diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index e9323b7285576..6ff01de2bda52 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -408,6 +408,10 @@ std::string LinkEntity::mangleAsString(ASTContext &Ctx) const { } case Kind::SILFunction: { + auto asmName = getSILFunction()->asmName(); + if (!asmName.empty()) + return asmName.str(); + std::string Result(getSILFunction()->getName()); if (isDynamicallyReplaceable()) { Result.append("TI"); @@ -465,8 +469,13 @@ std::string LinkEntity::mangleAsString(ASTContext &Ctx) const { return Result; } - case Kind::SILGlobalVariable: + case Kind::SILGlobalVariable: { + auto asmName = getSILGlobalVariable()->asmName(); + if (!asmName.empty()) + return asmName.str(); + return getSILGlobalVariable()->getName().str(); + } case Kind::ReadOnlyGlobalObject: return getSILGlobalVariable()->getName().str() + "r"; diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index 241a39eb4126e..903c61f88ab4a 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -91,7 +91,7 @@ bool SILGlobalVariable::isPossiblyUsedExternally() const { if (markedAsUsed()) return true; - if (getSectionAttr()) + if (!section().empty()) return true; SILLinkage linkage = getLinkage(); @@ -151,7 +151,7 @@ SILInstruction *SILGlobalVariable::getStaticInitializerValue() { } bool SILGlobalVariable::mustBeInitializedStatically() const { - if (getSectionAttr()) + if (!section().empty()) return true; auto *decl = getDecl(); diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 4138ef3115552..d2c6062c4c91f 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -3709,6 +3709,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { if (!section().empty()) OS << "[section \"" << section() << "\"] "; + if (!asmName().empty()) + OS << "[asmname \"" << asmName() << "\"] "; + // TODO: Handle clang node owners which don't have a name. if (hasClangNode() && getClangNodeOwner()->hasName()) { OS << "[clang "; @@ -3777,6 +3780,12 @@ void SILGlobalVariable::print(llvm::raw_ostream &OS, bool Verbose) const { if (markedAsUsed()) OS << "[used] "; + if (!asmName().empty()) + OS << "[asmname \"" << asmName() << "\"] "; + + if (!section().empty()) + OS << "[section \"" << section() << "\"] "; + printName(OS); OS << " : " << LoweredType; diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 3ad66ec3616ac..e17ea880bda0c 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -679,7 +679,8 @@ static bool parseDeclSILOptional( SILFunction **usedAdHocRequirementWitness, Identifier *objCReplacementFor, SILFunction::Purpose *specialPurpose, Inline_t *inlineStrategy, OptimizationMode *optimizationMode, PerformanceConstraints *perfConstraints, - bool *isPerformanceConstraint, bool *markedAsUsed, StringRef *section, + bool *isPerformanceConstraint, bool *markedAsUsed, StringRef *asmName, + StringRef *section, bool *isLet, bool *isWeakImported, bool *needStackProtection, bool *isSpecialized, AvailabilityRange *availability, bool *isWithoutActuallyEscapingThunk, @@ -807,6 +808,20 @@ static bool parseDeclSILOptional( } *actorIsolation = *optIsolation; SP.P.consumeToken(tok::string_literal); + SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); + continue; + } else if (asmName && SP.P.Tok.getText() == "asmname") { + SP.P.consumeToken(tok::identifier); + if (SP.P.Tok.getKind() != tok::string_literal) { + SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list); + return true; + } + + // Drop the double quotes. + StringRef rawString = SP.P.Tok.getText().drop_front().drop_back(); + *asmName = SP.P.Context.getIdentifier(rawString).str(); + SP.P.consumeToken(tok::string_literal); + SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); continue; } else if (section && SP.P.Tok.getText() == "section") { @@ -7288,6 +7303,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { PerformanceConstraints perfConstr = PerformanceConstraints::None; bool isPerformanceConstraint = false; bool markedAsUsed = false; + StringRef asmName; StringRef section; SmallVector Semantics; SmallVector SpecAttrs; @@ -7306,7 +7322,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { &DynamicallyReplacedFunction, &AdHocWitnessFunction, &objCReplacementFor, &specialPurpose, &inlineStrategy, &optimizationMode, &perfConstr, &isPerformanceConstraint, - &markedAsUsed, §ion, nullptr, &isWeakImported, + &markedAsUsed, &asmName, §ion, nullptr, &isWeakImported, &needStackProtection, nullptr, &availability, &isWithoutActuallyEscapingThunk, &Semantics, &SpecAttrs, &ClangDecl, &MRK, &actorIsolation, FunctionState, M) || @@ -7363,6 +7379,9 @@ bool SILParserState::parseDeclSIL(Parser &P) { FunctionState.F->setPerfConstraints(perfConstr); FunctionState.F->setIsPerformanceConstraint(isPerformanceConstraint); FunctionState.F->setEffectsKind(MRK); + FunctionState.F->setMarkedAsUsed(markedAsUsed); + FunctionState.F->setAsmName(asmName); + FunctionState.F->setSection(section); if (ClangDecl) FunctionState.F->setClangNodeOwner(ClangDecl); @@ -7557,6 +7576,8 @@ bool SILParserState::parseSILGlobal(Parser &P) { SourceLoc NameLoc; SerializedKind_t isSerialized = IsNotSerialized; bool isMarkedAsUsed = false; + StringRef asmName; + StringRef section; bool isLet = false; SILParser State(P); @@ -7564,10 +7585,10 @@ bool SILParserState::parseSILGlobal(Parser &P) { parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, &isMarkedAsUsed, nullptr, - &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, State, - M) || + nullptr, nullptr, nullptr, &isMarkedAsUsed, &asmName, + §ion, &isLet, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + State, M) || P.parseToken(tok::at_sign, diag::expected_sil_value_name) || P.parseIdentifier(GlobalName, NameLoc, /*diagnoseDollarPrefix=*/false, diag::expected_sil_value_name) || @@ -7594,6 +7615,9 @@ bool SILParserState::parseSILGlobal(Parser &P) { GV->setLet(isLet); GV->setMarkedAsUsed(isMarkedAsUsed); + GV->setAsmName(asmName); + GV->setSection(section); + // Parse static initializer if exists. if (State.P.consumeIf(tok::equal) && State.P.consumeIf(tok::l_brace)) { SILBuilder B(GV); @@ -7621,7 +7645,7 @@ bool SILParserState::parseSILProperty(Parser &P) { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, SP, M)) + nullptr, nullptr, nullptr, nullptr, nullptr, SP, M)) return true; ValueDecl *VD; @@ -7691,7 +7715,8 @@ bool SILParserState::parseSILVTable(Parser &P) { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, VTableState, M)) + nullptr, nullptr, nullptr, nullptr, nullptr, + VTableState, M)) return true; @@ -7814,7 +7839,7 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, moveOnlyDeinitTableState, M)) return true; @@ -8359,8 +8384,9 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, &isSpecialized, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, WitnessState, M)) + nullptr, nullptr, nullptr, nullptr, nullptr, &isSpecialized, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + WitnessState, M)) return true; // Parse the protocol conformance. diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 909d377176e4b..3dcca948fdfc3 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -74,6 +74,9 @@ SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl, M, silLinkage, IsNotSerialized, mangledName, silTy, std::nullopt, gDecl); silGlobal->setDeclaration(!forDef); + if (auto sectionAttr = gDecl->getAttrs().getAttribute()) + silGlobal->setSection(sectionAttr->Name); + return silGlobal; } diff --git a/lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp b/lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp index 633fee2330050..9ebc9edb64ce9 100644 --- a/lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp @@ -730,7 +730,7 @@ class PerformanceDiagnosticsPass : public SILModuleTransform { "global inst", &g); auto *decl = g.getDecl(); - if (g.getSectionAttr()) { + if (!g.section().empty()) { module->getASTContext().Diags.diagnose( g.getDecl()->getLoc(), diag::bad_attr_on_non_const_global, "@_section"); diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 020dc84653d4d..7ca5179c8312e 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -984,7 +984,9 @@ llvm::Expected SILDeserializer::readSILFunctionChecked( assert(next.Kind == llvm::BitstreamEntry::Record); scratch.clear(); - llvm::Expected maybeKind = SILCursor.readRecord(next.ID, scratch); + StringRef blobData; + llvm::Expected maybeKind = SILCursor.readRecord(next.ID, scratch, + &blobData); if (!maybeKind) return maybeKind.takeError(); unsigned kind = maybeKind.get(); @@ -1010,6 +1012,21 @@ llvm::Expected SILDeserializer::readSILFunctionChecked( continue; } + if (kind == SIL_EXTRA_STRING) { + unsigned stringFlavor; + SILExtraStringLayout::readRecord(scratch, stringFlavor); + + switch (static_cast(stringFlavor)) { + case ExtraStringFlavor::AsmName: + fn->setAsmName(blobData); + break; + case ExtraStringFlavor::Section: + fn->setSection(blobData); + break; + } + continue; + } + assert(kind == SIL_SPECIALIZE_ATTR && "Missing specialization attribute"); unsigned exported; @@ -4080,8 +4097,10 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { DeclID dID; ModuleID parentModuleID; unsigned rawLinkage, serializedKind, IsDeclaration, IsLet, IsUsed; + unsigned numTrailingRecords; SILGlobalVarLayout::readRecord(scratch, rawLinkage, serializedKind, - IsDeclaration, IsLet, IsUsed, TyID, dID, + IsDeclaration, IsLet, IsUsed, + numTrailingRecords, TyID, dID, parentModuleID); if (TyID == 0) { LLVM_DEBUG(llvm::dbgs() << "SILGlobalVariable typeID is 0.\n"); @@ -4124,6 +4143,42 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { Callback->didDeserialize(MF->getAssociatedModule(), v); scratch.clear(); + + // Read trailing reecords. + for (unsigned recordIdx = 0; recordIdx < numTrailingRecords; ++recordIdx) { + StringRef blobData; + llvm::Expected maybeNext = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeNext) + return nullptr; + llvm::BitstreamEntry next = maybeNext.get(); + assert(next.Kind == llvm::BitstreamEntry::Record); + + scratch.clear(); + llvm::Expected maybeKind = SILCursor.readRecord(next.ID, scratch, + &blobData); + if (!maybeKind) + return nullptr; + unsigned kind = maybeKind.get(); + + if (kind == SIL_EXTRA_STRING) { + unsigned stringFlavor; + SILExtraStringLayout::readRecord(scratch, stringFlavor); + + switch (static_cast(stringFlavor)) { + case ExtraStringFlavor::AsmName: + v->setAsmName(blobData); + break; + case ExtraStringFlavor::Section: + v->setSection(blobData); + break; + } + continue; + } + + return nullptr; + } + maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd); if (!maybeEntry) MF->fatal(maybeEntry.takeError()); @@ -4131,6 +4186,7 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { if (entry.Kind == llvm::BitstreamEntry::EndBlock) return v; + scratch.clear(); maybeKind = SILCursor.readRecord(entry.ID, scratch, &blobData); if (!maybeKind) MF->fatal(maybeKind.takeError()); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index f650e43acaa07..5fcf46693e0fe 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 965; // WriteImplKindField and ReadWriteImplKindField size +const uint16_t SWIFTMODULE_VERSION_MINOR = 966; // SIL asmname/section /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index d433bf305d136..0722b16e45756 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -81,6 +81,13 @@ enum class KeyPathComputedComponentIdKindEncoding : uint8_t { DeclRef, }; +enum class ExtraStringFlavor : uint8_t { + /// asmname attributes + AsmName, + /// section attribute + Section, +}; + /// The record types within the "sil-index" block. /// /// \sa SIL_INDEX_BLOCK_ID @@ -186,6 +193,7 @@ namespace sil_block { SIL_SOURCE_LOC_REF, SIL_DEBUG_VALUE_DELIMITER, SIL_DEBUG_VALUE, + SIL_EXTRA_STRING, }; using SILInstNoOperandLayout = BCRecordLayout< @@ -295,6 +303,7 @@ namespace sil_block { BCFixed<1>, // Is this a declaration. BCFixed<1>, // Is this a let variable. BCFixed<1>, // Is this marked as "used". + BCVBR<8>, // # of trailing records TypeIDField, DeclIDField, ModuleIDField // Parent ModuleDecl * @@ -378,7 +387,7 @@ namespace sil_block { BCFixed<1>, // hasCReferences BCFixed<1>, // markedAsUsed BCFixed<3>, // side effect info. - BCVBR<8>, // number of specialize attributes + BCVBR<8>, // number of trailing records BCFixed<1>, // has qualified ownership BCFixed<1>, // force weak linking BC_AVAIL_TUPLE, // availability for weak linking @@ -419,6 +428,14 @@ namespace sil_block { BCFixed<1> // isDerived >; + /// Used for additional strings that can be associated with a record, + /// written out as records that trail + using SILExtraStringLayout = + BCRecordLayout, // string flavor + BCBlob // string data + >; + // Has an optional argument list where each argument is a typed valueref. using SILBasicBlockLayout = BCRecordLayout< SIL_BASIC_BLOCK, diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index e496b30e2da8b..478a5cd8404c7 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -311,6 +311,9 @@ namespace { void writeSILBlock(const SILModule *SILMod); void writeIndexTables(); + /// Write an extra-string record if the string itself is non-empty. + void writeExtraStringIfNonEmpty(ExtraStringFlavor flavor, StringRef string); + /// Serialize and write SILDebugScope graph in post order. void writeDebugScopes(const SILDebugScope *Scope, const SourceManager &SM); void writeSourceLoc(SILLocation SLoc, const SourceManager &SM); @@ -527,7 +530,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { usedAdHocWitnessFunctionID = S.addUniquedStringRef(fun->getName()); } - unsigned numAttrs = NoBody ? 0 : F.getSpecializeAttrs().size(); + unsigned numTrailingRecords = NoBody ? 0 : F.getSpecializeAttrs().size(); auto resilience = F.getModule().getSwiftModule()->getResilienceStrategy(); bool serializeDerivedEffects = // We must not serialize computed effects if library evolution is turned on, @@ -544,7 +547,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { [&](int effectIdx, int argumentIndex, bool isDerived) { if (isDerived && !serializeDerivedEffects) return; - numAttrs++; + numTrailingRecords++; }); std::optional available; @@ -554,6 +557,13 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { } ENCODE_VER_TUPLE(available, available) + // Each extra string emitted below needs to update the trailing record + // count here. + if (!F.asmName().empty()) + ++numTrailingRecords; + if (!F.section().empty()) + ++numTrailingRecords; + SILFunctionLayout::emitRecord( Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.getSerializedKind(), @@ -562,7 +572,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { (unsigned)F.getOptimizationMode(), (unsigned)F.getPerfConstraints(), (unsigned)F.getClassSubclassScope(), (unsigned)F.hasCReferences(), (unsigned)F.markedAsUsed(), (unsigned)F.getEffectsKind(), - (unsigned)numAttrs, (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), + (unsigned)numTrailingRecords, (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), (unsigned)F.isExactSelfClass(), (unsigned)F.isDistributed(), (unsigned)F.isRuntimeAccessible(), @@ -589,6 +599,11 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { argIdx, (unsigned)isGlobalSideEffects, (unsigned)isDerived); }); + // Each extra string emitted here needs to be reflected in the trailing + // record count above. + writeExtraStringIfNonEmpty(ExtraStringFlavor::AsmName, F.asmName()); + writeExtraStringIfNonEmpty(ExtraStringFlavor::Section, F.section()); + if (NoBody) return; @@ -3119,6 +3134,15 @@ void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { if (auto *parentModule = g.getParentModule()) parentModuleID = S.addModuleRef(parentModule); + unsigned numTrailingRecords = 0; + + // Each extra string emitted below needs to update the trailing record + // count here. + if (!g.asmName().empty()) + ++numTrailingRecords; + if (!g.section().empty()) + ++numTrailingRecords; + SILGlobalVarLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILGlobalVarLayout::Code], toStableSILLinkage(g.getLinkage()), @@ -3126,8 +3150,12 @@ void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { (unsigned)!g.isDefinition(), (unsigned)g.isLet(), (unsigned)g.markedAsUsed(), + numTrailingRecords, TyID, dID, parentModuleID); + writeExtraStringIfNonEmpty(ExtraStringFlavor::AsmName, g.asmName()); + writeExtraStringIfNonEmpty(ExtraStringFlavor::Section, g.section()); + // Don't emit the initializer instructions if not marked as "serialized". if (!g.isAnySerialized()) return; @@ -3292,6 +3320,16 @@ void SILSerializer::writeSourceLoc(SILLocation Loc, const SourceManager &SM) { FNameID, LocationKind, (unsigned)Loc.isImplicit()); } +void SILSerializer::writeExtraStringIfNonEmpty( + ExtraStringFlavor flavor, StringRef string) { + if (string.empty()) + return; + + SILExtraStringLayout::emitRecord( + Out, ScratchRecord, SILAbbrCodes[SILExtraStringLayout::Code], + static_cast(flavor), string); +} + void SILSerializer::writeDebugScopes(const SILDebugScope *Scope, const SourceManager &SM) { @@ -3658,6 +3696,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); + registerSILAbbr(); // Write out VTables first because it may require serializations of // non-transparent SILFunctions (body is not needed). diff --git a/test/Concurrency/global_function_pointer.swift b/test/Concurrency/global_function_pointer.swift index 6d1c02b9c073f..169080d5d8b50 100644 --- a/test/Concurrency/global_function_pointer.swift +++ b/test/Concurrency/global_function_pointer.swift @@ -24,7 +24,7 @@ public func callAsync() async { await asyncFunc() } -// CHECK-SIL-LABEL: sil_global @$s23global_function_pointer5gfptryyYacvp : $@async @callee_guaranteed () -> () = { +// CHECK-SIL-LABEL: sil_global [section "__DATA,__mysection"] @$s23global_function_pointer5gfptryyYacvp : $@async @callee_guaranteed () -> () = { // CHECK-SIL: %0 = function_ref @$s23global_function_pointer9callAsyncyyYaF : $@convention(thin) @async () -> () // CHECK-SIL-NEXT: %initval = thin_to_thick_function %0 : $@convention(thin) @async () -> () to $@async @callee_guaranteed () -> () // CHECK-SIL-NEXT: } diff --git a/test/IRGen/asmname.sil b/test/IRGen/asmname.sil new file mode 100644 index 0000000000000..7d8ad615efffc --- /dev/null +++ b/test/IRGen/asmname.sil @@ -0,0 +1,13 @@ +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s -DINT=i%target-ptrsize + +import Swift + +// CHECK: @v1 = {{(dllexport )?}}{{(protected )?}}global +sil_global [asmname "v1"] @$s4main13renamedGlobalSivp : $Int + +// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @f1() +sil [asmname "f1"] @$s4main15renamedFunctionyyF : $@convention(thin) () -> () { + %0 = tuple () + return %0 +} + diff --git a/test/SIL/Serialization/asmname.sil b/test/SIL/Serialization/asmname.sil new file mode 100644 index 0000000000000..2b7efca0bac4c --- /dev/null +++ b/test/SIL/Serialization/asmname.sil @@ -0,0 +1,16 @@ +// First parse this and then emit a *.sib. Then read in the *.sib, then recreate +// RUN: %empty-directory(%t) +// RUN: %target-sil-opt -sil-print-types %s -emit-sib -o %t/tmp.sib -module-name borrow +// RUN: %target-sil-opt -sil-print-types %t/tmp.sib -o %t/tmp.2.sib -module-name borrow +// RUN: %target-sil-opt -sil-print-types %t/tmp.2.sib -module-name asmname -emit-sorted-sil | %FileCheck %s + +import Swift + +// CHECK: sil_global [asmname "v1"] @$s4main13renamedGlobalSivp : $Int +sil_global [asmname "v1"] @$s4main13renamedGlobalSivp : $Int + +// CHECK: sil [asmname "f1"] @$s4main15renamedFunctionyyF : $@convention(thin) () -> () +sil [asmname "f1"] @$s4main15renamedFunctionyyF : $@convention(thin) () -> () { + %0 = tuple () + return %0 +} diff --git a/test/SIL/Serialization/section.sil b/test/SIL/Serialization/section.sil new file mode 100644 index 0000000000000..5575d7106f09a --- /dev/null +++ b/test/SIL/Serialization/section.sil @@ -0,0 +1,18 @@ +// First parse this and then emit a *.sib. Then read in the *.sib, then recreate +// RUN: %empty-directory(%t) +// RUN: %target-sil-opt -sil-print-types -enable-experimental-feature SymbolLinkageMarkers %s -emit-sib -o %t/tmp.sib -module-name borrow +// RUN: %target-sil-opt -sil-print-types -enable-experimental-feature SymbolLinkageMarkers %t/tmp.sib -o %t/tmp.2.sib -module-name borrow +// RUN: %target-sil-opt -sil-print-types -enable-experimental-feature SymbolLinkageMarkers %t/tmp.2.sib -module-name asmname -emit-sorted-sil | %FileCheck %s + +// REQUIRES: swift_feature_SymbolLinkageMarkers + +import Swift + +// CHECK: sil_global [section "__DATA,__mysection"] @v1 : $Int +sil_global [section "__DATA,__mysection"] @v1 : $Int + +// CHECK: sil [section "__TEXT,__mysection"] @f : $@convention(thin) () -> () +sil [section "__TEXT,__mysection"] @f : $@convention(thin) () -> () { + %0 = tuple () + return %0 +} diff --git a/test/embedded/modules-used.swift b/test/embedded/modules-used.swift index 6e653a8eafd23..71157af083a72 100644 --- a/test/embedded/modules-used.swift +++ b/test/embedded/modules-used.swift @@ -45,7 +45,7 @@ struct Main { } // CHECK-SIL: // i_am_not_referenced -// CHECK-SIL-NEXT: sil_global [serialized] [let] [used] @$e8MyModule19i_am_not_referencedSivp : $Int = { +// CHECK-SIL-NEXT: sil_global [serialized] [let] [used] [section "__DATA,__mysection"] @$e8MyModule19i_am_not_referencedSivp : $Int = { // CHECK: count: 1 // CHECK: mysection[0]: 42