From 80222b81c901f3ce85ddee4012669d885b98357f Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 12 May 2023 22:00:10 -0700 Subject: [PATCH 1/5] Add @_used and @_section attributes for global variables and top-level functions This adds: - @_used attribute that flags as a global variable or a top-level function as "do not dead-strip" via llvm.used, roughly the equivalent of __attribute__((used)) in C/C++. - @_section("...") attribute that places a global variable or a top-level function into a section with that name, roughly the equivalent of __attribute__((section("..."))) in C/C++. --- include/swift/AST/Attr.h | 18 ++++++ include/swift/AST/DiagnosticsSema.def | 7 +++ include/swift/SIL/SILFunction.h | 14 +++++ include/swift/SIL/SILGlobalVariable.h | 15 +++++ lib/AST/Attr.cpp | 7 +++ lib/IRGen/GenDecl.cpp | 12 ++++ lib/Parse/ParseDecl.cpp | 40 ++++++++++++++ lib/SIL/IR/SILFunction.cpp | 6 ++ lib/SIL/IR/SILFunctionBuilder.cpp | 9 +++ lib/SIL/IR/SILPrinter.cpp | 6 ++ lib/SIL/Parser/ParseSIL.cpp | 29 +++++++++- lib/Sema/TypeCheckAttr.cpp | 18 ++++++ lib/Sema/TypeCheckDeclOverride.cpp | 2 + lib/Serialization/ModuleFormat.h | 8 ++- lib/Serialization/Serialization.cpp | 9 +++ test/IRGen/section.swift | 64 ++++++++++++++++++++++ test/IRGen/used.swift | 32 +++++++++++ utils/gyb_syntax_support/AttributeKinds.py | 15 +++++ 18 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 test/IRGen/section.swift create mode 100644 test/IRGen/used.swift diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index cacb5faa4e36e..c8ff55152b424 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -502,6 +502,24 @@ class SILGenNameAttr : public DeclAttribute { } }; +/// Defines the @_section attribute. +class SectionAttr : public DeclAttribute { +public: + SectionAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit) + : DeclAttribute(DAK_Section, AtLoc, Range, Implicit), + Name(Name) {} + + SectionAttr(StringRef Name, bool Implicit) + : SectionAttr(Name, SourceLoc(), SourceRange(), Implicit) {} + + /// The section name. + const StringRef Name; + + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DAK_Section; + } +}; + /// Defines the @_cdecl attribute. class CDeclAttr : public DeclAttribute { public: diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 3efaf535c2739..1e9be77bf537c 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1702,6 +1702,13 @@ ERROR(cdecl_empty_name,none, ERROR(cdecl_throws,none, "raising errors from @_cdecl functions is not supported", ()) +ERROR(used_not_at_top_level,none, + "@_used can only be applied to global functions and variables", ()) +ERROR(section_not_at_top_level,none, + "@_section can only be applied to global functions and variables", ()) +ERROR(section_empty_name,none, + "@_section section name cannot be empty", ()) + ERROR(expose_only_non_other_attr,none, "@_expose attribute cannot be applied to an '%0' declaration", (StringRef)) ERROR(expose_inside_unexposed_decl,none, diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index bad7f11dd450b..0eb580a9864c7 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -291,6 +291,9 @@ class SILFunction /// The function's remaining set of specialize attributes. std::vector SpecializeAttrSet; + /// Name of a section if @_section attribute was used, otherwise empty. + StringRef Section; + /// Has value if there's a profile for this function /// Contains Function Entry Count ProfileCounter EntryCount; @@ -346,6 +349,9 @@ class SILFunction /// would indicate. unsigned HasCReferences : 1; + /// Whether attribute @_used was present + unsigned MarkedAsUsed : 1; + /// Whether cross-module references to this function should always use weak /// linking. unsigned IsAlwaysWeakImported : 1; @@ -1234,6 +1240,14 @@ class SILFunction return V && V->getAttrs().hasAttribute(); } + /// Return whether this function has attribute @_used on it + bool markedAsUsed() const { return MarkedAsUsed; } + void setMarkedAsUsed(bool value) { MarkedAsUsed = value; } + + /// Return custom section name if @_section was used, otherwise empty + StringRef section() const { return Section; } + void setSection(StringRef value) { Section = value; } + /// Returns true if this function belongs to a declaration that returns /// an opaque result type with one or more availability conditions that are /// allowed to produce a different underlying type at runtime. diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index 88661af4443e7..b6fefbdb3084c 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -190,6 +190,21 @@ class SILGlobalVariable StaticInitializerBlock.eraseAllInstructions(Module); } + /// Returns true if this global variable has `@_used` attribute. + bool markedAsUsed() const { + auto *V = getDecl(); + return V && V->getAttrs().hasAttribute(); + } + + /// 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/AST/Attr.cpp b/lib/AST/Attr.cpp index 67ae2f398014c..ef1836f4df717 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -1130,6 +1130,11 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, Printer << ")"; break; + case DAK_Section: + Printer.printAttrName("@_section"); + Printer << "(\"" << cast(this)->Name << "\")"; + break; + case DAK_ObjC: { Printer.printAttrName("@objc"); llvm::SmallString<32> scratch; @@ -1602,6 +1607,8 @@ StringRef DeclAttribute::getAttrName() const { return "backDeployed"; case DAK_Expose: return "_expose"; + case DAK_Section: + return "_section"; case DAK_Documentation: return "_documentation"; case DAK_MacroRole: diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 97608122f68df..7245fb3074cfa 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2699,6 +2699,12 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var, } if (!forDefinition) gvar->setComdat(nullptr); + + // Mark as llvm.used if @_used, set section if @_section + if (var->markedAsUsed()) + addUsedGlobal(gvar); + if (auto *sectionAttr = var->getSectionAttr()) + gvar->setSection(sectionAttr->Name); } if (forDefinition && !gvar->hasInitializer()) { if (initVal) { @@ -3468,6 +3474,12 @@ llvm::Function *IRGenModule::getAddrOfSILFunction( fn = createFunction(*this, link, signature, insertBefore, f->getOptimizationMode(), shouldEmitStackProtector(f)); + // Mark as llvm.used if @_used, set section if @_section + if (f->markedAsUsed()) + addUsedGlobal(fn); + if (!f->section().empty()) + fn->setSection(f->section()); + // If `hasCReferences` is true, then the function is either marked with // @_silgen_name OR @_cdecl. If it is the latter, it must have a definition // associated with it. The combination of the two allows us to identify the diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index edbf1cb0e8895..c96d6d97ef174 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2937,6 +2937,46 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, break; } + + case DAK_Section: { + if (!consumeIf(tok::l_paren)) { + diagnose(Loc, diag::attr_expected_lparen, AttrName, + DeclAttribute::isDeclModifier(DK)); + return makeParserSuccess(); + } + + if (Tok.isNot(tok::string_literal)) { + diagnose(Loc, diag::attr_expected_string_literal, AttrName); + return makeParserSuccess(); + } + + auto Name = getStringLiteralIfNotInterpolated( + Loc, ("'" + AttrName + "'").str()); + + consumeToken(tok::string_literal); + + if (Name.has_value()) + AttrRange = SourceRange(Loc, Tok.getRange().getStart()); + else + DiscardAttribute = true; + + if (!consumeIf(tok::r_paren)) { + diagnose(Loc, diag::attr_expected_rparen, AttrName, + DeclAttribute::isDeclModifier(DK)); + return makeParserSuccess(); + } + + // @_section in a local scope is not allowed. + if (CurDeclContext->isLocalContext()) { + diagnose(Loc, diag::attr_only_at_non_local_scope, AttrName); + } + + if (!DiscardAttribute) + Attributes.add(new (Context) SectionAttr(Name.value(), AtLoc, + AttrRange, /*Implicit=*/false)); + + break; + } case DAK_Alignment: { if (!consumeIf(tok::l_paren)) { diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index eca0c14b3e613..1d115c63d1e24 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -204,6 +204,7 @@ void SILFunction::init( this->InlineStrategy = inlineStrategy; this->Linkage = unsigned(Linkage); this->HasCReferences = false; + this->MarkedAsUsed = false; this->IsAlwaysWeakImported = false; this->IsDynamicReplaceable = isDynamic; this->ExactSelfClass = isExactSelfClass; @@ -280,11 +281,13 @@ void SILFunction::createSnapshot(int id) { newSnapshot->ObjCReplacementFor = ObjCReplacementFor; newSnapshot->SemanticsAttrSet = SemanticsAttrSet; newSnapshot->SpecializeAttrSet = SpecializeAttrSet; + newSnapshot->Section = Section; newSnapshot->Availability = Availability; newSnapshot->specialPurpose = specialPurpose; newSnapshot->perfConstraints = perfConstraints; newSnapshot->GlobalInitFlag = GlobalInitFlag; newSnapshot->HasCReferences = HasCReferences; + newSnapshot->MarkedAsUsed = MarkedAsUsed; newSnapshot->IsAlwaysWeakImported = IsAlwaysWeakImported; newSnapshot->HasOwnership = HasOwnership; newSnapshot->IsWithoutActuallyEscapingThunk = IsWithoutActuallyEscapingThunk; @@ -858,6 +861,9 @@ SILFunction::isPossiblyUsedExternally() const { if (isRuntimeAccessible()) return true; + if (markedAsUsed()) + return true; + // Declaration marked as `@_alwaysEmitIntoClient` that // returns opaque result type with availability conditions // has to be kept alive to emit opaque type metadata descriptor. diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index e61e3b598454a..9f667321330cb 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -161,6 +161,9 @@ void SILFunctionBuilder::addFunctionAttributes( if (Attrs.hasAttribute() || Attrs.hasAttribute()) F->setHasCReferences(true); + if (Attrs.hasAttribute()) + F->setMarkedAsUsed(true); + if (Attrs.hasAttribute()) { F->setPerfConstraints(PerformanceConstraints::NoLocks); } else if (Attrs.hasAttribute()) { @@ -195,6 +198,12 @@ void SILFunctionBuilder::addFunctionAttributes( return; auto *decl = constant.getDecl(); + // Don't add section for addressor functions (where decl is a global) + if (isa(decl)) { + if (auto *SA = Attrs.getAttribute()) + F->setSection(SA->Name); + } + // Only emit replacements for the objc entry point of objc methods. // There is one exception: @_dynamicReplacement(for:) of @objc methods in // generic classes. In this special case we use native replacement instead of diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index f85b8479b8a9d..1c70a65d4ac13 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -3236,6 +3236,12 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { OS << "[_specialize "; Attr->print(OS); OS << "] "; } + if (markedAsUsed()) + OS << "[used] "; + + if (!section().empty()) + OS << "[section \"" << section() << "\"] "; + // TODO: Handle clang node owners which don't have a name. if (hasClangNode() && getClangNodeOwner()->hasName()) { OS << "[clang "; diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index c393eb48b789e..adcbaf884ca3f 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -1034,6 +1034,8 @@ static bool parseDeclSILOptional(bool *isTransparent, Inline_t *inlineStrategy, OptimizationMode *optimizationMode, PerformanceConstraints *perfConstraints, + bool *markedAsUsed, + StringRef *section, bool *isLet, bool *isWeakImported, bool *needStackProtection, @@ -1122,6 +1124,23 @@ static bool parseDeclSILOptional(bool *isTransparent, *perfConstraints = PerformanceConstraints::NoLocks; else if (perfConstraints && SP.P.Tok.getText() == "no_allocation") *perfConstraints = PerformanceConstraints::NoAllocation; + else if (markedAsUsed && SP.P.Tok.getText() == "used") + *markedAsUsed = true; + else if (section && SP.P.Tok.getText() == "section") { + 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(); + *section = 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 (inlineStrategy && SP.P.Tok.getText() == "always_inline") *inlineStrategy = AlwaysInline; else if (MRK && SP.P.Tok.getText() == "readnone") @@ -6929,6 +6948,8 @@ bool SILParserState::parseDeclSIL(Parser &P) { Inline_t inlineStrategy = InlineDefault; OptimizationMode optimizationMode = OptimizationMode::NotSet; PerformanceConstraints perfConstr = PerformanceConstraints::None; + bool markedAsUsed = false; + StringRef section; SmallVector Semantics; SmallVector SpecAttrs; ValueDecl *ClangDecl = nullptr; @@ -6943,7 +6964,8 @@ bool SILParserState::parseDeclSIL(Parser &P) { &forceEnableLexicalLifetimes, &isExactSelfClass, &DynamicallyReplacedFunction, &AdHocWitnessFunction, &objCReplacementFor, &specialPurpose, &inlineStrategy, - &optimizationMode, &perfConstr, nullptr, &isWeakImported, + &optimizationMode, &perfConstr, &markedAsUsed, §ion, nullptr, + &isWeakImported, &needStackProtection, &availability, &isWithoutActuallyEscapingThunk, &Semantics, &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) || P.parseToken(tok::at_sign, diag::expected_sil_function_name) || @@ -7189,6 +7211,7 @@ 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, &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, State, M) || P.parseToken(tok::at_sign, diag::expected_sil_value_name) || @@ -7240,6 +7263,7 @@ bool SILParserState::parseSILProperty(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, 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, SP, M)) return true; @@ -7309,6 +7333,7 @@ bool SILParserState::parseSILVTable(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, 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, VTableState, M)) return true; @@ -7419,6 +7444,7 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) { if (parseDeclSILOptional(nullptr, &Serialized, 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)) @@ -7906,6 +7932,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { if (parseDeclSILOptional(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, nullptr, nullptr, nullptr, WitnessState, M)) return true; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index f46306bd76ca1..1c895080b15b2 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -253,6 +253,8 @@ class AttributeChecker : public AttributeVisitor { void visitCDeclAttr(CDeclAttr *attr); void visitExposeAttr(ExposeAttr *attr); + void visitUsedAttr(UsedAttr *attr); + void visitSectionAttr(SectionAttr *attr); void visitDynamicCallableAttr(DynamicCallableAttr *attr); @@ -2068,6 +2070,22 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) { } } +void AttributeChecker::visitUsedAttr(UsedAttr *attr) { + // Only top-level func/var decls are currently supported. + if (D->getDeclContext()->isTypeContext()) + diagnose(attr->getLocation(), diag::used_not_at_top_level); +} + +void AttributeChecker::visitSectionAttr(SectionAttr *attr) { + // Only top-level func/var decls are currently supported. + if (D->getDeclContext()->isTypeContext()) + diagnose(attr->getLocation(), diag::section_not_at_top_level); + + // The name must not be empty. + if (attr->Name.empty()) + diagnose(attr->getLocation(), diag::section_empty_name); +} + void AttributeChecker::visitUnsafeNoObjCTaggedPointerAttr( UnsafeNoObjCTaggedPointerAttr *attr) { // Only class protocols can have the attribute. diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 426e577764e4f..3c341969b2f8f 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1546,6 +1546,8 @@ namespace { UNINTERESTING_ATTR(UsableFromInline) UNINTERESTING_ATTR(ObjCNonLazyRealization) UNINTERESTING_ATTR(UnsafeNoObjCTaggedPointer) + UNINTERESTING_ATTR(Used) + UNINTERESTING_ATTR(Section) UNINTERESTING_ATTR(SwiftNativeObjCRuntimeBase) UNINTERESTING_ATTR(ShowInInterface) UNINTERESTING_ATTR(Specialize) diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 9c0731b1b5315..23913fcff7c91 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 = 783; // pack element type +const uint16_t SWIFTMODULE_VERSION_MINOR = 784; // used and section attrs /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2037,6 +2037,12 @@ namespace decls_block { BCBlob // _silgen_name >; + using SectionDeclAttrLayout = BCRecordLayout< + Section_DECL_ATTR, + BCFixed<1>, // implicit flag + BCBlob // _section + >; + using CDeclDeclAttrLayout = BCRecordLayout< CDecl_DECL_ATTR, BCFixed<1>, // implicit flag diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 0fef132a713e4..3fcea8be45b23 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3047,6 +3047,15 @@ class Serializer::DeclSerializer : public DeclVisitor { return; } + case DAK_Section: { + auto *theAttr = cast(DA); + auto abbrCode = S.DeclTypeAbbrCodes[SectionDeclAttrLayout::Code]; + SectionDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, + theAttr->isImplicit(), + theAttr->Name); + return; + } + case DAK_Documentation: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[DocumentationDeclAttrLayout::Code]; diff --git a/test/IRGen/section.swift b/test/IRGen/section.swift new file mode 100644 index 0000000000000..014f6c321984a --- /dev/null +++ b/test/IRGen/section.swift @@ -0,0 +1,64 @@ +// RUN: %target-swift-frontend -primary-file %s -emit-sil | %FileCheck %s --check-prefix=SIL --check-prefix=SIL-TOPLEVEL +// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=IR --check-prefix=IR-TOPLEVEL +// RUN: %target-swift-frontend -primary-file %s -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL --check-prefix=SIL-LIBRARY +// RUN: %target-swift-frontend -primary-file %s -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR --check-prefix=IR-LIBRARY + +// RUN: %target-swift-frontend -primary-file %s -S | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os +// RUN: %target-swift-frontend -primary-file %s -S -parse-as-library | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os + +// REQUIRES: swift_in_compiler + +@_section("__TEXT,__mysection") var g0: Int = 1 +@_section("__TEXT,__mysection") var g1: (Int, Int) = (42, 43) +@_section("__TEXT,__mysection") var g2: Bool = true +@_section("__TEXT,__mysection") public var g3: Bool = true +@_section("__TEXT,__mysection") func foo() {} + +// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g0: Int { get set } +// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g1: (Int, Int) { get set } +// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g2: Bool { get set } +// SIL: @_section("__TEXT,__mysection") func foo() +// SIL-LIBRARY: sil private [global_init_once_fn] @$s7section2g0_WZ : $@convention(c) +// SIL-LIBRARY: sil hidden [global_init] @$s7section2g0Sivau : $@convention(thin) +// SIL-LIBRARY: sil private [global_init_once_fn] @$s7section2g1_WZ : $@convention(c) +// SIL-LIBRARY: sil hidden [global_init] @$s7section2g1Si_Sitvau : $@convention(thin) +// SIL-LIBRARY: sil private [global_init_once_fn] @$s7section2g2_WZ : $@convention(c) +// SIL-LIBRARY: sil hidden [global_init] @$s7section2g2Sbvau : $@convention(thin) +// SIL-LIBRARY: sil private [global_init_once_fn] @$s7section2g3_WZ : $@convention(c) +// SIL-LIBRARY: sil [global_init] @$s7section2g3Sbvau : $@convention(thin) +// SIL: sil hidden [section "__TEXT,__mysection"] @$s7section3fooyyF : $@convention(thin) + +// IR-LIBRARY: @"$s7section2g0_Wz" = internal global i64 0 + +// IR-LIBRARY: @"$s7section2g0Sivp" = hidden global %TSi <{ i64 1 }>, section "__TEXT,__mysection" +// IR-TOPLEVEL: @"$s7section2g0Sivp" = hidden global %TSi zeroinitializer, section "__TEXT,__mysection" + +// IR-LIBRARY: @"$s7section2g1_Wz" = internal global i64 0 + +// IR-LIBRARY: @"$s7section2g1Si_Sitvp" = hidden global <{ %TSi, %TSi }> <{ %TSi <{ i64 42 }>, %TSi <{ i64 43 }> }>, section "__TEXT,__mysection" +// IR-TOPLEVEL: @"$s7section2g1Si_Sitvp" = hidden global <{ %TSi, %TSi }> zeroinitializer, section "__TEXT,__mysection" + +// IR-LIBRARY: @"$s7section2g2_Wz" = internal global i64 0 + +// IR-LIBRARY: @"$s7section2g2Sbvp" = hidden global %TSb <{ i1 true }>, section "__TEXT,__mysection" +// IR-TOPLEVEL: @"$s7section2g2Sbvp" = hidden global %TSb zeroinitializer, section "__TEXT,__mysection" + +// IR-LIBRARY: @"$s7section2g3_Wz" = internal global i64 0 + +// IR-LIBRARY: @"$s7section2g3Sbvp" = {{.*}}global %TSb <{ i1 true }>, section "__TEXT,__mysection" +// IR-TOPLEVEL: @"$s7section2g3Sbvp" = {{.*}}global %TSb zeroinitializer, section "__TEXT,__mysection" + +// IR: define {{.*}}@"$s7section3fooyyF"(){{.*}} section "__TEXT,__mysection" + +// ASM: .section{{.*}}__TEXT,__mysection +// ASM-NOT: .section +// ASM: $s7section3fooyyF: +// ASM-linux-gnu: .section{{.*}}__TEXT,__mysection +// ASM-NOT: .section +// ASM: $s7section2g0Sivp: +// ASM-NOT: .section +// ASM: $s7section2g1Si_Sitvp: +// ASM-NOT: .section +// ASM: $s7section2g2Sbvp: +// ASM-NOT: .section +// ASM: $s7section2g3Sbvp: diff --git a/test/IRGen/used.swift b/test/IRGen/used.swift new file mode 100644 index 0000000000000..6272e612bf085 --- /dev/null +++ b/test/IRGen/used.swift @@ -0,0 +1,32 @@ +// RUN: %target-swift-frontend -primary-file %s -emit-sil | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -primary-file %s -O -emit-sil | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=IR +// RUN: %target-swift-frontend -primary-file %s -O -emit-ir | %FileCheck %s --check-prefix=IR +// RUN: %target-swift-frontend -primary-file %s -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -primary-file %s -O -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -primary-file %s -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR +// RUN: %target-swift-frontend -primary-file %s -O -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR + +// REQUIRES: swift_in_compiler + +@_used var g0: Int = 1 +@_used var g1: (Int, Int) = (42, 43) +@_used var g2: Bool = true +@_used func foo() {} + +// SIL: @_used @_hasStorage @_hasInitialValue var g0: Int { get set } +// SIL: @_used @_hasStorage @_hasInitialValue var g1: (Int, Int) { get set } +// SIL: @_used @_hasStorage @_hasInitialValue var g2: Bool { get set } +// SIL: @_used func foo() + +// SIL: sil_global hidden @$s4used2g0Sivp : $Int +// SIL: sil_global hidden @$s4used2g1Si_Sitvp : $(Int, Int) +// SIL: sil_global hidden @$s4used2g2Sbvp : $Bool + +// SIL: sil hidden [used] @$s4used3fooyyF : $@convention(thin) + +// IR: @llvm{{(\.compiler)?}}.used = appending global [{{.*}} x i8*] [ +// IR-SAME: i8* bitcast (%TSi* @"$s4used2g0Sivp" to i8*) +// IR-SAME: i8* bitcast (<{ %TSi, %TSi }>* @"$s4used2g1Si_Sitvp" to i8*) +// IR-SAME: i8* bitcast (%TSb* @"$s4used2g2Sbvp" to i8*) +// IR-SAME: i8* bitcast (void ()* @"$s4used3fooyyF" to i8*) diff --git a/utils/gyb_syntax_support/AttributeKinds.py b/utils/gyb_syntax_support/AttributeKinds.py index b304fe7e2ac3b..13f6001dc23ea 100644 --- a/utils/gyb_syntax_support/AttributeKinds.py +++ b/utils/gyb_syntax_support/AttributeKinds.py @@ -922,6 +922,21 @@ def __init__(self, name, swift_name=None): ABIStableToAdd, ABIStableToRemove, APIStableToAdd, APIBreakingToRemove, # noqa: E501 code=142), DeclAttributeAlias('freestanding', 'MacroRole'), + + SimpleDeclAttribute('_used', 'Used', + OnAbstractFunction, OnVar, + UserInaccessible, + ABIBreakingToAdd, ABIBreakingToRemove, + APIBreakingToAdd, APIBreakingToRemove, + code=143), + + DeclAttribute('_section', 'Section', + OnAbstractFunction, OnVar, + UserInaccessible, + ABIBreakingToAdd, ABIBreakingToRemove, + APIBreakingToAdd, APIBreakingToRemove, + code=144), + ] DEPRECATED_MODIFIER_KINDS = [ From 6f60b67a067b47202b24f9017532e8224833d2c3 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 24 May 2023 16:29:18 -0700 Subject: [PATCH 2/5] Add EXPERIMENTAL_FEATURE(SymbolLinkageMarkers, true) --- docs/ReferenceGuides/UnderscoredAttributes.md | 12 ++++++++++++ include/swift/AST/DiagnosticsSema.def | 3 +++ include/swift/Basic/Features.def | 3 +++ lib/AST/ASTPrinter.cpp | 4 ++++ lib/Sema/TypeCheckAttr.cpp | 10 ++++++++++ test/IRGen/section.swift | 12 ++++++------ test/IRGen/used.swift | 16 ++++++++-------- 7 files changed, 46 insertions(+), 14 deletions(-) diff --git a/docs/ReferenceGuides/UnderscoredAttributes.md b/docs/ReferenceGuides/UnderscoredAttributes.md index ff51b7fe45eb0..5d01013af183e 100644 --- a/docs/ReferenceGuides/UnderscoredAttributes.md +++ b/docs/ReferenceGuides/UnderscoredAttributes.md @@ -832,6 +832,12 @@ Fully bypasses access control, allowing access to private declarations in the imported module. The imported module needs to be compiled with `-Xfrontend -enable-private-imports` for this to work. +## `@_section("section_name")` + +Places a global variable or a top-level function into a section of the object +file with the given name. It's the equivalent of clang's +`__attribute__((section))`. + ## `@_semantics("uniquely.recognized.id")` Allows the optimizer to make use of some key invariants in performance critical @@ -994,6 +1000,12 @@ for more details. This `async` function uses the pre-SE-0338 semantics of unsafely inheriting the caller's executor. This is an underscored feature because the right way of inheriting an executor is to pass in the required executor and switch to it. Unfortunately, there are functions in the standard library which need to inherit their caller's executor but cannot change their ABI because they were not defined as `@_alwaysEmitIntoClient` in the initial release. +## `@_used` + +Marks a global variable or a top-level function as "used externally" even if it +does not have visible users in the compilation unit. It's the equivalent of +clang's `__attribute__((used))`. + ## `@_weakLinked` Allows a declaration to be weakly-referenced, i.e., any references emitted by diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 1e9be77bf537c..bdf0f5157877a 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1702,6 +1702,9 @@ ERROR(cdecl_empty_name,none, ERROR(cdecl_throws,none, "raising errors from @_cdecl functions is not supported", ()) +// @_used and @_section +ERROR(section_linkage_markers_disabled,none, + "attribute requires '-enable-experimental-feature SymbolLinkageMarkers'", ()) ERROR(used_not_at_top_level,none, "@_used can only be applied to global functions and variables", ()) ERROR(section_not_at_top_level,none, diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index bb621bd5d2168..863f67879ecb4 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -122,6 +122,9 @@ EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures, false) EXPERIMENTAL_FEATURE(CodeItemMacros, true) EXPERIMENTAL_FEATURE(TupleConformances, false) +// Whether to enable @_used and @_section attributes +EXPERIMENTAL_FEATURE(SymbolLinkageMarkers, true) + // FIXME: MoveOnlyClasses is not intended to be in production, // but our tests currently rely on it, and we want to run those // tests in non-asserts builds too. diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 38c75481bcbea..4ebd08aaded96 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3211,6 +3211,10 @@ static bool usesFeatureTupleConformances(Decl *decl) { return false; } +static bool usesFeatureSymbolLinkageMarkers(Decl *decl) { + return false; +} + static bool usesFeatureLayoutPrespecialization(Decl *decl) { auto &attrs = decl->getAttrs(); return std::any_of(attrs.begin(), attrs.end(), [](auto *attr) { diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 1c895080b15b2..93ca4513b7c60 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2071,12 +2071,22 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) { } void AttributeChecker::visitUsedAttr(UsedAttr *attr) { + if (!Ctx.LangOpts.hasFeature(Feature::SymbolLinkageMarkers)) { + diagnoseAndRemoveAttr(attr, diag::section_linkage_markers_disabled); + return; + } + // Only top-level func/var decls are currently supported. if (D->getDeclContext()->isTypeContext()) diagnose(attr->getLocation(), diag::used_not_at_top_level); } void AttributeChecker::visitSectionAttr(SectionAttr *attr) { + if (!Ctx.LangOpts.hasFeature(Feature::SymbolLinkageMarkers)) { + diagnoseAndRemoveAttr(attr, diag::section_linkage_markers_disabled); + return; + } + // Only top-level func/var decls are currently supported. if (D->getDeclContext()->isTypeContext()) diagnose(attr->getLocation(), diag::section_not_at_top_level); diff --git a/test/IRGen/section.swift b/test/IRGen/section.swift index 014f6c321984a..1ff2556b2901b 100644 --- a/test/IRGen/section.swift +++ b/test/IRGen/section.swift @@ -1,10 +1,10 @@ -// RUN: %target-swift-frontend -primary-file %s -emit-sil | %FileCheck %s --check-prefix=SIL --check-prefix=SIL-TOPLEVEL -// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=IR --check-prefix=IR-TOPLEVEL -// RUN: %target-swift-frontend -primary-file %s -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL --check-prefix=SIL-LIBRARY -// RUN: %target-swift-frontend -primary-file %s -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR --check-prefix=IR-LIBRARY +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-sil | %FileCheck %s --check-prefix=SIL --check-prefix=SIL-TOPLEVEL +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-ir | %FileCheck %s --check-prefix=IR --check-prefix=IR-TOPLEVEL +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL --check-prefix=SIL-LIBRARY +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR --check-prefix=IR-LIBRARY -// RUN: %target-swift-frontend -primary-file %s -S | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os -// RUN: %target-swift-frontend -primary-file %s -S -parse-as-library | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -S | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -S -parse-as-library | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os // REQUIRES: swift_in_compiler diff --git a/test/IRGen/used.swift b/test/IRGen/used.swift index 6272e612bf085..c07700c76c78c 100644 --- a/test/IRGen/used.swift +++ b/test/IRGen/used.swift @@ -1,11 +1,11 @@ -// RUN: %target-swift-frontend -primary-file %s -emit-sil | %FileCheck %s --check-prefix=SIL -// RUN: %target-swift-frontend -primary-file %s -O -emit-sil | %FileCheck %s --check-prefix=SIL -// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=IR -// RUN: %target-swift-frontend -primary-file %s -O -emit-ir | %FileCheck %s --check-prefix=IR -// RUN: %target-swift-frontend -primary-file %s -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL -// RUN: %target-swift-frontend -primary-file %s -O -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL -// RUN: %target-swift-frontend -primary-file %s -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR -// RUN: %target-swift-frontend -primary-file %s -O -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-sil | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -O -emit-sil | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-ir | %FileCheck %s --check-prefix=IR +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -O -emit-ir | %FileCheck %s --check-prefix=IR +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -O -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -O -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR // REQUIRES: swift_in_compiler From cccc281c59db4c923235fc1bb954aa6e6cc28742 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 24 May 2023 19:41:52 -0700 Subject: [PATCH 3/5] Disallow non-constant globals with @_section attribute --- include/swift/AST/DiagnosticsSIL.def | 2 ++ .../Mandatory/PerformanceDiagnostics.cpp | 8 ++++++++ test/IRGen/section_non_const.swift | 13 +++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 test/IRGen/section_non_const.swift diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 49716b7874b97..310c336a8f24f 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -332,6 +332,8 @@ ERROR(performance_unknown_callees,none, "called function is not known at compile time and can have unpredictable performance", ()) ERROR(performance_callee_unavailable,none, "called function is not available in this module and can have unpredictable performance", ()) +ERROR(section_attr_on_non_const_global,none, + "global variable must be a compile-time constant to use @_section attribute", ()) NOTE(performance_called_from,none, "called from here", ()) diff --git a/lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp b/lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp index b0b06d412619f..04c50546ccf65 100644 --- a/lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp @@ -476,6 +476,14 @@ class PerformanceDiagnosticsPass : public SILModuleTransform { SILModule *module = getModule(); PerformanceDiagnostics diagnoser(*module, getAnalysis()); + + // Check that @_section is only on constant globals + for (SILGlobalVariable &g : module->getSILGlobals()) { + if (!g.getStaticInitializerValue() && g.getSectionAttr()) + module->getASTContext().Diags.diagnose( + g.getDecl()->getLoc(), diag::section_attr_on_non_const_global); + } + bool annotatedFunctionsFound = false; for (SILFunction &function : *module) { diff --git a/test/IRGen/section_non_const.swift b/test/IRGen/section_non_const.swift new file mode 100644 index 0000000000000..82f5f85744e1f --- /dev/null +++ b/test/IRGen/section_non_const.swift @@ -0,0 +1,13 @@ +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -parse-as-library -emit-sil %s -o /dev/null -verify + +// REQUIRES: swift_in_compiler + +@_section("__TEXT,__mysection") var g0: Int = 1 +@_section("__TEXT,__mysection") var g1: (Int, Int) = (1, 2) +@_section("__TEXT,__mysection") var g2: [Int] = [1, 2, 3] // expected-error {{global variable must be a compile-time constant to use @_section attribute}} +@_section("__TEXT,__mysection") var g3: [Int:Int] = [:] // expected-error {{global variable must be a compile-time constant to use @_section attribute}} +@_section("__TEXT,__mysection") var g4: UInt = 42 +@_section("__TEXT,__mysection") var g5: String = "hello" // expected-error {{global variable must be a compile-time constant to use @_section attribute}} +@_section("__TEXT,__mysection") var g6: Any = 1 // expected-error {{global variable must be a compile-time constant to use @_section attribute}} +@_section("__TEXT,__mysection") var g7: UInt8 = 42 +@_section("__TEXT,__mysection") var g8: Int = 5 * 5 From 0789ce96d338c682b71ab295ccf30e5d3323fc8d Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 24 May 2023 19:44:14 -0700 Subject: [PATCH 4/5] Implement usesFeatureSymbolLinkageMarkers --- lib/AST/ASTPrinter.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 4ebd08aaded96..0eb2e621ea8b5 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3212,7 +3212,14 @@ static bool usesFeatureTupleConformances(Decl *decl) { } static bool usesFeatureSymbolLinkageMarkers(Decl *decl) { - return false; + auto &attrs = decl->getAttrs(); + return std::any_of(attrs.begin(), attrs.end(), [](auto *attr) { + if (isa(attr)) + return true; + if (isa(attr)) + return true; + return false; + }); } static bool usesFeatureLayoutPrespecialization(Decl *decl) { From a8e8c41b649f95ba50332a17be94128787600b46 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 25 May 2023 19:37:04 -0700 Subject: [PATCH 5/5] Adjust section.swift test --- test/IRGen/section.swift | 68 +++++++++++++++------------------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/test/IRGen/section.swift b/test/IRGen/section.swift index 1ff2556b2901b..1325926a8c9a9 100644 --- a/test/IRGen/section.swift +++ b/test/IRGen/section.swift @@ -1,10 +1,6 @@ -// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-sil | %FileCheck %s --check-prefix=SIL --check-prefix=SIL-TOPLEVEL -// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-ir | %FileCheck %s --check-prefix=IR --check-prefix=IR-TOPLEVEL -// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL --check-prefix=SIL-LIBRARY -// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR --check-prefix=IR-LIBRARY - -// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -S | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os -// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -S -parse-as-library | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-sil -parse-as-library | %FileCheck %s --check-prefix=SIL +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -emit-ir -parse-as-library | %FileCheck %s --check-prefix=IR +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %s -S -parse-as-library | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os // REQUIRES: swift_in_compiler @@ -14,41 +10,29 @@ @_section("__TEXT,__mysection") public var g3: Bool = true @_section("__TEXT,__mysection") func foo() {} -// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g0: Int { get set } -// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g1: (Int, Int) { get set } -// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g2: Bool { get set } -// SIL: @_section("__TEXT,__mysection") func foo() -// SIL-LIBRARY: sil private [global_init_once_fn] @$s7section2g0_WZ : $@convention(c) -// SIL-LIBRARY: sil hidden [global_init] @$s7section2g0Sivau : $@convention(thin) -// SIL-LIBRARY: sil private [global_init_once_fn] @$s7section2g1_WZ : $@convention(c) -// SIL-LIBRARY: sil hidden [global_init] @$s7section2g1Si_Sitvau : $@convention(thin) -// SIL-LIBRARY: sil private [global_init_once_fn] @$s7section2g2_WZ : $@convention(c) -// SIL-LIBRARY: sil hidden [global_init] @$s7section2g2Sbvau : $@convention(thin) -// SIL-LIBRARY: sil private [global_init_once_fn] @$s7section2g3_WZ : $@convention(c) -// SIL-LIBRARY: sil [global_init] @$s7section2g3Sbvau : $@convention(thin) -// SIL: sil hidden [section "__TEXT,__mysection"] @$s7section3fooyyF : $@convention(thin) - -// IR-LIBRARY: @"$s7section2g0_Wz" = internal global i64 0 - -// IR-LIBRARY: @"$s7section2g0Sivp" = hidden global %TSi <{ i64 1 }>, section "__TEXT,__mysection" -// IR-TOPLEVEL: @"$s7section2g0Sivp" = hidden global %TSi zeroinitializer, section "__TEXT,__mysection" - -// IR-LIBRARY: @"$s7section2g1_Wz" = internal global i64 0 - -// IR-LIBRARY: @"$s7section2g1Si_Sitvp" = hidden global <{ %TSi, %TSi }> <{ %TSi <{ i64 42 }>, %TSi <{ i64 43 }> }>, section "__TEXT,__mysection" -// IR-TOPLEVEL: @"$s7section2g1Si_Sitvp" = hidden global <{ %TSi, %TSi }> zeroinitializer, section "__TEXT,__mysection" - -// IR-LIBRARY: @"$s7section2g2_Wz" = internal global i64 0 - -// IR-LIBRARY: @"$s7section2g2Sbvp" = hidden global %TSb <{ i1 true }>, section "__TEXT,__mysection" -// IR-TOPLEVEL: @"$s7section2g2Sbvp" = hidden global %TSb zeroinitializer, section "__TEXT,__mysection" - -// IR-LIBRARY: @"$s7section2g3_Wz" = internal global i64 0 - -// IR-LIBRARY: @"$s7section2g3Sbvp" = {{.*}}global %TSb <{ i1 true }>, section "__TEXT,__mysection" -// IR-TOPLEVEL: @"$s7section2g3Sbvp" = {{.*}}global %TSb zeroinitializer, section "__TEXT,__mysection" - -// IR: define {{.*}}@"$s7section3fooyyF"(){{.*}} section "__TEXT,__mysection" +// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g0: Int { get set } +// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g1: (Int, Int) { get set } +// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g2: Bool { get set } +// SIL: @_section("__TEXT,__mysection") func foo() +// SIL: sil private [global_init_once_fn] @$s7section2g0_WZ : $@convention(c) +// SIL: sil hidden [global_init] @$s7section2g0Sivau : $@convention(thin) +// SIL: sil private [global_init_once_fn] @$s7section2g1_WZ : $@convention(c) +// SIL: sil hidden [global_init] @$s7section2g1Si_Sitvau : $@convention(thin) +// SIL: sil private [global_init_once_fn] @$s7section2g2_WZ : $@convention(c) +// SIL: sil hidden [global_init] @$s7section2g2Sbvau : $@convention(thin) +// SIL: sil private [global_init_once_fn] @$s7section2g3_WZ : $@convention(c) +// SIL: sil [global_init] @$s7section2g3Sbvau : $@convention(thin) +// SIL: sil hidden [section "__TEXT,__mysection"] @$s7section3fooyyF : $@convention(thin) + +// IR: @"$s7section2g0_Wz" = internal global i64 0 +// IR: @"$s7section2g0Sivp" = hidden global %TSi <{ i64 1 }>, section "__TEXT,__mysection" +// IR: @"$s7section2g1_Wz" = internal global i64 0 +// IR: @"$s7section2g1Si_Sitvp" = hidden global <{ %TSi, %TSi }> <{ %TSi <{ i64 42 }>, %TSi <{ i64 43 }> }>, section "__TEXT,__mysection" +// IR: @"$s7section2g2_Wz" = internal global i64 0 +// IR: @"$s7section2g2Sbvp" = hidden global %TSb <{ i1 true }>, section "__TEXT,__mysection" +// IR: @"$s7section2g3_Wz" = internal global i64 0 +// IR: @"$s7section2g3Sbvp" = {{.*}}global %TSb <{ i1 true }>, section "__TEXT,__mysection" +// IR: define {{.*}}@"$s7section3fooyyF"(){{.*}} section "__TEXT,__mysection" // ASM: .section{{.*}}__TEXT,__mysection // ASM-NOT: .section