This is an archive of the discontinued LLVM Phabricator instance.

[WebAssembly] Add `wasm-exported` function attribute
AbandonedPublic

Authored by sbc100 on Mar 21 2020, 10:57 AM.

Details

Summary

This matches the existing wasm-export-name attribute but exports that symbol
but its llvm symbol name. This corresponds directly to the existing
WASM_SYMBOL_EXPORTED symbol flag.

This allows the existing emscripten macro EMSCERIPTEN_KEEPALIVE to be
implemented in terms of this attribute rather then the current
workaround which uses overload the used attribute.

Diff Detail

Event Timeline

sbc100 created this revision.Mar 21 2020, 10:57 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 21 2020, 10:57 AM
kripken accepted this revision.Mar 23 2020, 4:11 PM
kripken added inline comments.
clang/include/clang/Basic/AttrDocs.td
5535

"the be" => "the function to be"

This revision is now accepted and ready to land.Mar 23 2020, 4:11 PM

Instead of creating a new LLVM-IR-level attribute here, could you have clang translate the attribute to "wasm-export-name", to keep the LLVM-IR level simpler?

Also, I myself would be more comfortable with this change if it were restricted to Emscripten for now. export_name already exists and works in both Emscripten and non-Emscripten targets. If there's demand for this new syntax outside of Emscripten, I'm happy to reconsider, but until then it seems better to be conservative. Obviously it's not possible to completely prevent people from becoming dependent on C++ ABI details, but we can avoid giving them tools that make it easy to do the wrong thing. And we can keep the ecosystem simpler if we don't have multiple ways to do the same thing.

What about your idea of using the default keyword rather than adding a new clang attr? I quite liked that approach.

I was thinking of dropping the new clang attr in favor of the default keyword in the current attr, but actually keeping the llvm attr, since it corresponds quite nicely to the existing EXPORTED symbol attribute in the binary format and avoid duplication in the .ll, .s and .o formats.

Herald added projects: Restricted Project, Restricted Project. · View Herald Transcript

What about your idea of using the default keyword rather than adding a new clang attr? I quite liked that approach.

IIRC I tried this approach but wan't able to make it works since a single attribute can't both take a string and a fix value like default.

sbc100 edited the summary of this revision. (Show Details)Mar 23 2023, 10:39 AM
sbc100 edited the summary of this revision. (Show Details)
sbc100 edited the summary of this revision. (Show Details)
sbc100 retitled this revision from [WebAssembly] Add wasm-exported function attribute to [WebAssembly] Add `exported` function attribute.
sbc100 retitled this revision from [WebAssembly] Add `exported` function attribute to [WebAssembly] Add `wasm-exported` function attribute.
sbc100 edited the summary of this revision. (Show Details)
sbc100 updated this revision to Diff 507807.Mar 23 2023, 10:43 AM
  • update test
sbc100 edited the summary of this revision. (Show Details)Mar 23 2023, 10:59 AM

I've limited to new attribute to only the emcripten triple.

sbc100 updated this revision to Diff 507826.Mar 23 2023, 11:03 AM
sbc100 edited the summary of this revision. (Show Details)
  • limit to emscripten

I just figured out that this cannot replace the current use of __attribute__((used)) in emscripten because function attributes only work for functions and we need this mechanism to work for global data addresses too. There is simply no way to do something like Fn->addFnAttr("wasm-exported"); for a GlobalValue that isn't a function (as far as I can tell).

The changes need a release note at some point, and this is missing all of the usual sema diagnostic tests (wrong subject, wrong number of args, wrong target, etc).

That said, are we sure this attribute is sufficiently compelling to add it in the first place? This seems like an attribute needed for one? use case, but it's using a pretty general name for the attribute (exported). For example, it's not clear to me why this cannot be solved with the existing export_name attribute (e.g., __attribute__((export_name("foo"))) void foo();)

clang/include/clang/Basic/AttrDocs.td
5533–5536

I think more details would be helpful here. The docs for export_name:

WebAssembly functions are exported via string name. By default when a symbol is exported, the export name for C/C++ symbols are the same as their C/C++ symbol names. This attribute can be used to override the default behavior, and request a specific string name be used instead.

make it sound like there's already a way to export the symbol, so it's not clear to me why this attribute is needed (unless this attribute is actually the one intended to provide that functionality!).

Also, the docs don't mention important things like that this attribute only works for emscripten.

clang/lib/Sema/SemaDeclAttr.cpp
7561–7568

These can both be dropped, they're handled automatically for you.

7572

Is this diagnostic actually correct? It's for use with the alias and ifunc attributes, so I'm surprised to see it here.

clang/test/CodeGen/WebAssembly/wasm-exported.c
12

This should be handled in a sema test along with the other sema testing, rather than squirreled away here in the codegen tests.

The reason __attribute__((export_name("foo"))) doesn't work in all use cases is that we have a lot of existing code that uses the EMSCRIPTEN_KEEPALIVE macro. We also have run into other folks who want to include this is some kind of FOO_API, or EXPORT_API type macros. Its not possible to have such a macro map to the existing export_name since they don't include the symbol name: e.g:

EMSCRIPTEN_KEEPALIVE int foo();`

JNI_EXPORT int myfunct();

In these cases we need something that uses the llvm symbol name for the export.

However, as I mention in my earlier comment I have since realized that these attributes cannot be applies the llvm GlobalValues in general only the Functions... and the idea behind EMSCRIPTEN_KEEPALIVE is that it can be used to tag both functions and data symbols (addresses).

Sadly I don't see any way to attach attributes to data symbols in llvm today.. we have visibility but not attribute bag :(

clang/lib/Sema/SemaDeclAttr.cpp
7572

It does look incorrect yes, this is copy-pasted from the exist ExportNameAttr so I guess that is wrong too.

The reason __attribute__((export_name("foo"))) doesn't work in all use cases is that we have a lot of existing code that uses the EMSCRIPTEN_KEEPALIVE macro. We also have run into other folks who want to include this is some kind of FOO_API, or EXPORT_API type macros. Its not possible to have such a macro map to the existing export_name since they don't include the symbol name: e.g:

EMSCRIPTEN_KEEPALIVE int foo();`

JNI_EXPORT int myfunct();

In these cases we need something that uses the llvm symbol name for the export.

I think there's two ways we could address this without adding a new attribute (maybe you've thought of this and have reasons for this to be a bad suggestion):

  • It seems that export_name doesn't care if you put in an empty string for the argument, so we could treat that case as meaning "export with the name of the symbol this attribute is attached to"
  • We could allow export_name to take zero or one argument. The one-argument form is the same as it is today, but the zero argument form exports with the name of the symbol the attribute is attached to.

Do you think either of those could work?

The reason __attribute__((export_name("foo"))) doesn't work in all use cases is that we have a lot of existing code that uses the EMSCRIPTEN_KEEPALIVE macro. We also have run into other folks who want to include this is some kind of FOO_API, or EXPORT_API type macros. Its not possible to have such a macro map to the existing export_name since they don't include the symbol name: e.g:

EMSCRIPTEN_KEEPALIVE int foo();`

JNI_EXPORT int myfunct();

In these cases we need something that uses the llvm symbol name for the export.

I think there's two ways we could address this without adding a new attribute (maybe you've thought of this and have reasons for this to be a bad suggestion):

  • It seems that export_name doesn't care if you put in an empty string for the argument, so we could treat that case as meaning "export with the name of the symbol this attribute is attached to"
  • We could allow export_name to take zero or one argument. The one-argument form is the same as it is today, but the zero argument form exports with the name of the symbol the attribute is attached to.

Do you think either of those could work?

Yes, I think the second one would be ideal. The first one is slightly less idea because it prevents something being exported with the empty string as its name (wasm allows such things).

Can an attribute take an optional argument? That would be great solution. For my initial version of this change I did look into making export_name(DEFAULT) work (note the lack of quotes around the word DEFAULT here), but I could not find way to make a single attribute take both a string *or* a constant.

The reason __attribute__((export_name("foo"))) doesn't work in all use cases is that we have a lot of existing code that uses the EMSCRIPTEN_KEEPALIVE macro. We also have run into other folks who want to include this is some kind of FOO_API, or EXPORT_API type macros. Its not possible to have such a macro map to the existing export_name since they don't include the symbol name: e.g:

EMSCRIPTEN_KEEPALIVE int foo();`

JNI_EXPORT int myfunct();

In these cases we need something that uses the llvm symbol name for the export.

I think there's two ways we could address this without adding a new attribute (maybe you've thought of this and have reasons for this to be a bad suggestion):

  • It seems that export_name doesn't care if you put in an empty string for the argument, so we could treat that case as meaning "export with the name of the symbol this attribute is attached to"
  • We could allow export_name to take zero or one argument. The one-argument form is the same as it is today, but the zero argument form exports with the name of the symbol the attribute is attached to.

Do you think either of those could work?

Yes, I think the second one would be ideal. The first one is slightly less idea because it prevents something being exported with the empty string as its name (wasm allows such things).

Ah, yeah, that's a good reason to avoid the first one.

Can an attribute take an optional argument? That would be great solution. For my initial version of this change I did look into making export_name(DEFAULT) work (note the lack of quotes around the word DEFAULT here), but I could not find way to make a single attribute take both a string *or* a constant.

Yup, it takes only a little bit of extra work to do right. Have the attribute's argument list take a VariadicStringArgument instead of StringArgument so you can pass zero or more arguments, then have the attribute handler in SemaDeclAttr.cpp diagnose if the attribute is given > 1 argument. The rest should be things like documentation or fall out somewhat naturally (there will be accessors added to the WebAssemblyExportNameAttr class that let you access the arguments with iterators, and a size accessor as well, so you can tell if the semantic attribute does/does not have an argument).

sbc100 abandoned this revision.Mar 29 2023, 11:52 AM

The reason __attribute__((export_name("foo"))) doesn't work in all use cases is that we have a lot of existing code that uses the EMSCRIPTEN_KEEPALIVE macro. We also have run into other folks who want to include this is some kind of FOO_API, or EXPORT_API type macros. Its not possible to have such a macro map to the existing export_name since they don't include the symbol name: e.g:

EMSCRIPTEN_KEEPALIVE int foo();`

JNI_EXPORT int myfunct();

In these cases we need something that uses the llvm symbol name for the export.

I think there's two ways we could address this without adding a new attribute (maybe you've thought of this and have reasons for this to be a bad suggestion):

  • It seems that export_name doesn't care if you put in an empty string for the argument, so we could treat that case as meaning "export with the name of the symbol this attribute is attached to"
  • We could allow export_name to take zero or one argument. The one-argument form is the same as it is today, but the zero argument form exports with the name of the symbol the attribute is attached to.

Do you think either of those could work?

Yes, I think the second one would be ideal. The first one is slightly less idea because it prevents something being exported with the empty string as its name (wasm allows such things).

Ah, yeah, that's a good reason to avoid the first one.

Can an attribute take an optional argument? That would be great solution. For my initial version of this change I did look into making export_name(DEFAULT) work (note the lack of quotes around the word DEFAULT here), but I could not find way to make a single attribute take both a string *or* a constant.

Yup, it takes only a little bit of extra work to do right. Have the attribute's argument list take a VariadicStringArgument instead of StringArgument so you can pass zero or more arguments, then have the attribute handler in SemaDeclAttr.cpp diagnose if the attribute is given > 1 argument. The rest should be things like documentation or fall out somewhat naturally (there will be accessors added to the WebAssemblyExportNameAttr class that let you access the arguments with iterators, and a size accessor as well, so you can tell if the semantic attribute does/does not have an argument).

Thanks! Closing this one for now then.