Skip to content

Commit 8cfcc24

Browse files
Merge pull request #68524 from kateinoigakukun/katei/expose-wasm-sym
[wasm] Add `@_expose(wasm)` attribute for top-level functions
2 parents 631ad05 + ac440c3 commit 8cfcc24

File tree

18 files changed

+243
-52
lines changed

18 files changed

+243
-52
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,16 @@ in the generated C++ binding header.
427427
The optional "cxxName" string will be used as the name of
428428
the generated C++ declaration.
429429

430+
### `_expose(wasm[, <"wasmExportName">])`
431+
432+
Indicates that a particular function declaration should be
433+
exported from the linked WebAssembly.
434+
435+
The optional "wasmExportName" string will be used as the
436+
the export name.
437+
438+
It's the equivalent of clang's `__attribute__((export_name))`.
439+
430440
## `@_fixed_layout`
431441

432442
Same as `@frozen` but also works for classes.

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ SIMPLE_DECL_ATTR(_alwaysEmitConformanceMetadata, AlwaysEmitConformanceMetadata,
398398
OnProtocol | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
399399
132)
400400
DECL_ATTR(_expose, Expose,
401-
OnFunc | OnNominalType | OnVar | OnConstructor | LongAttribute | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
401+
OnFunc | OnNominalType | OnVar | AllowMultipleAttributes | OnConstructor | LongAttribute | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
402402
133)
403403
SIMPLE_DECL_ATTR(_spiOnly, SPIOnly,
404404
OnImport | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,

include/swift/AST/Attr.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ class DeclAttribute : public AttributeBase {
172172
kind : 1
173173
);
174174

175+
SWIFT_INLINE_BITFIELD(ExposeAttr, DeclAttribute, NumExposureKindBits,
176+
kind : NumExposureKindBits
177+
);
178+
175179
SWIFT_INLINE_BITFIELD(SynthesizedProtocolAttr, DeclAttribute, 1,
176180
isUnchecked : 1
177181
);
@@ -2309,15 +2313,23 @@ class BackDeployedAttr : public DeclAttribute {
23092313
/// header used by C/C++ to interoperate with Swift.
23102314
class ExposeAttr : public DeclAttribute {
23112315
public:
2312-
ExposeAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit)
2313-
: DeclAttribute(DAK_Expose, AtLoc, Range, Implicit), Name(Name) {}
2316+
ExposeAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range,
2317+
ExposureKind Kind, bool Implicit)
2318+
: DeclAttribute(DAK_Expose, AtLoc, Range, Implicit), Name(Name) {
2319+
Bits.ExposeAttr.kind = static_cast<unsigned>(Kind);
2320+
}
23142321

2315-
ExposeAttr(StringRef Name, bool Implicit)
2316-
: ExposeAttr(Name, SourceLoc(), SourceRange(), Implicit) {}
2322+
ExposeAttr(StringRef Name, ExposureKind Kind, bool Implicit)
2323+
: ExposeAttr(Name, SourceLoc(), SourceRange(), Kind, Implicit) {}
23172324

23182325
/// The exposed declaration name.
23192326
const StringRef Name;
23202327

2328+
/// Returns the kind of exposure.
2329+
ExposureKind getExposureKind() const {
2330+
return static_cast<ExposureKind>(Bits.ExposeAttr.kind);
2331+
}
2332+
23212333
static bool classof(const DeclAttribute *DA) {
23222334
return DA->getKind() == DAK_Expose;
23232335
}

include/swift/AST/AttrKind.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ enum class EffectsKind : uint8_t {
102102
enum : unsigned { NumEffectsKindBits =
103103
countBitsUsed(static_cast<unsigned>(EffectsKind::Last_EffectsKind)) };
104104

105+
/// This enum represents the possible values of the @_expose attribute.
106+
enum class ExposureKind: uint8_t {
107+
Cxx,
108+
Wasm,
109+
Last_ExposureKind = Wasm
110+
};
111+
112+
enum : unsigned { NumExposureKindBits =
113+
countBitsUsed(static_cast<unsigned>(ExposureKind::Last_ExposureKind)) };
105114

106115
enum DeclAttrKind : unsigned {
107116
#define DECL_ATTR(_, NAME, ...) DAK_##NAME,

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,9 @@ ERROR(section_not_at_top_level,none,
18381838
ERROR(section_empty_name,none,
18391839
"@_section section name cannot be empty", ())
18401840

1841+
ERROR(expose_wasm_not_at_top_level_func,none,
1842+
"@_expose attribute with 'wasm' can only be applied to global functions", ())
1843+
18411844
ERROR(expose_only_non_other_attr,none,
18421845
"@_expose attribute cannot be applied to an '%0' declaration", (StringRef))
18431846
ERROR(expose_inside_unexposed_decl,none,

include/swift/SIL/SILFunction.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,10 @@ class SILFunction
299299
/// Name of a section if @_section attribute was used, otherwise empty.
300300
StringRef Section;
301301

302+
/// Name of a Wasm export if @_expose(wasm) attribute was used, otherwise
303+
/// empty.
304+
StringRef WasmExportName;
305+
302306
/// Has value if there's a profile for this function
303307
/// Contains Function Entry Count
304308
ProfileCounter EntryCount;
@@ -1270,6 +1274,10 @@ class SILFunction
12701274
StringRef section() const { return Section; }
12711275
void setSection(StringRef value) { Section = value; }
12721276

1277+
/// Return Wasm export name if @_expose(wasm) was used, otherwise empty
1278+
StringRef wasmExportName() const { return WasmExportName; }
1279+
void setWasmExportName(StringRef value) { WasmExportName = value; }
1280+
12731281
/// Returns true if this function belongs to a declaration that returns
12741282
/// an opaque result type with one or more availability conditions that are
12751283
/// allowed to produce a different underlying type at runtime.

lib/AST/Attr.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,14 +1122,22 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
11221122
Printer << "@_cdecl(\"" << cast<CDeclAttr>(this)->Name << "\")";
11231123
break;
11241124

1125-
case DAK_Expose:
1125+
case DAK_Expose: {
11261126
Printer.printAttrName("@_expose");
1127-
Printer << "(Cxx";
1127+
auto Attr = cast<ExposeAttr>(this);
1128+
switch (Attr->getExposureKind()) {
1129+
case ExposureKind::Wasm:
1130+
Printer << "(wasm";
1131+
break;
1132+
case ExposureKind::Cxx:
1133+
Printer << "(Cxx";
1134+
break;
1135+
}
11281136
if (!cast<ExposeAttr>(this)->Name.empty())
11291137
Printer << ", \"" << cast<ExposeAttr>(this)->Name << "\"";
11301138
Printer << ")";
11311139
break;
1132-
1140+
}
11331141
case DAK_Section:
11341142
Printer.printAttrName("@_section");
11351143
Printer << "(\"" << cast<SectionAttr>(this)->Name << "\")";

lib/AST/SwiftNameTranslation.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
158158
CustomNamesOnly_t customNamesOnly) {
159159
ASTContext& ctx = VD->getASTContext();
160160

161-
if (const auto *Expose = VD->getAttrs().getAttribute<ExposeAttr>()) {
162-
if (!Expose->Name.empty())
163-
return Expose->Name;
161+
for (auto *EA : VD->getAttrs().getAttributes<ExposeAttr>()) {
162+
if (EA->getExposureKind() == ExposureKind::Cxx && !EA->Name.empty())
163+
return EA->Name;
164164
}
165165

166166
if (customNamesOnly)

lib/IRGen/GenDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3561,6 +3561,11 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
35613561
addUsedGlobal(fn);
35623562
if (!f->section().empty())
35633563
fn->setSection(f->section());
3564+
if (!f->wasmExportName().empty()) {
3565+
llvm::AttrBuilder attrBuilder(getLLVMContext());
3566+
attrBuilder.addAttribute("wasm-export-name", f->wasmExportName());
3567+
fn->addFnAttrs(attrBuilder);
3568+
}
35643569

35653570
// If `hasCReferences` is true, then the function is either marked with
35663571
// @_silgen_name OR @_cdecl. If it is the latter, it must have a definition

lib/Parse/ParseDecl.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3015,12 +3015,24 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
30153015
}
30163016

30173017
bool ParseSymbolName = true;
3018+
3019+
ExposureKind ExpKind;
30183020
if (DK == DAK_Expose) {
3019-
if (Tok.isNot(tok::identifier) || Tok.getText() != "Cxx") {
3021+
auto diagnoseExpectOption = [&]() {
30203022
diagnose(Tok.getLoc(), diag::attr_expected_option_such_as, AttrName,
30213023
"Cxx");
3022-
if (Tok.isNot(tok::identifier))
3023-
return makeParserSuccess();
3024+
ParseSymbolName = false;
3025+
};
3026+
if (Tok.isNot(tok::identifier)) {
3027+
diagnoseExpectOption();
3028+
return makeParserSuccess();
3029+
}
3030+
if (Tok.getText() == "Cxx") {
3031+
ExpKind = ExposureKind::Cxx;
3032+
} else if (Tok.getText() == "wasm") {
3033+
ExpKind = ExposureKind::Wasm;
3034+
} else {
3035+
diagnoseExpectOption();
30243036
DiscardAttribute = true;
30253037
}
30263038
consumeToken(tok::identifier);
@@ -3076,10 +3088,19 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
30763088
else if (DK == DAK_CDecl)
30773089
Attributes.add(new (Context) CDeclAttr(AsmName.value(), AtLoc,
30783090
AttrRange, /*Implicit=*/false));
3079-
else if (DK == DAK_Expose)
3091+
else if (DK == DAK_Expose) {
3092+
for (auto *EA : Attributes.getAttributes<ExposeAttr>()) {
3093+
// A single declaration cannot have two @_exported attributes with
3094+
// the same exposure kind.
3095+
if (EA->getExposureKind() == ExpKind) {
3096+
diagnose(Loc, diag::duplicate_attribute, false);
3097+
break;
3098+
}
3099+
}
30803100
Attributes.add(new (Context) ExposeAttr(
30813101
AsmName ? AsmName.value() : StringRef(""), AtLoc, AttrRange,
3082-
/*Implicit=*/false));
3102+
ExpKind, /*Implicit=*/false));
3103+
}
30833104
else
30843105
llvm_unreachable("out of sync with switch");
30853106
}

0 commit comments

Comments
 (0)