WebAssembly / tool-conventions

Conventions supporting interoperatibility between tools working with WebAssembly.
Artistic License 2.0
297 stars 65 forks source link

Frontend predefines #36

Open dschuff opened 6 years ago

dschuff commented 6 years ago

I had a user ask about Emscripten's predefines (specifically it was surprising that __asmjs__ was predefined instead of __wasm__). For that particular case, since already Emscripten knows that we are compiling straight to wasm, it should probably also define __wasm__, and more generally we should probably make the defines match between asm and wasm just as we are doing with the rest of the ABI. I think we've discussed this before informally but probably worth getting down here and maybe putting something in the doc. Obviously Emscripten can still define extra things like __EMSCRIPTEN__ outside of the respective backends where it makes sense.

Poking through https://github.com/llvm-mirror/clang/blob/master/test/Preprocessor/init.c#L9063 I don't really see much interesting aside from __wasm__ that's not just a consequence of the other ABI stuff we've discussed separately. We did remove __unix__ previously. Are we missing anything?

dschuff commented 6 years ago

Oh also it probably makes sense for emscripten not to define __asmjs__ when compiling straight to wasm, (since there will never be any asmjs output) but removing that seems likely to break people who have used emscripten since before wasm (when they could just as easily have picked checking that vs __emscripten__). So the question there is to break those people during our other ABI churn, or let them be broken when we switch to the wasm backend, or keep defining asmjs in emscripten even though it will be even more of a lie then than it is now.

kripken commented 6 years ago

I wasn't even aware we defined __asmjs__ personally. @juj, do you think it's important?

juj commented 6 years ago

__asmjs__ is good to keep around. +1 for adding a new __wasm__ and +1 for not defining __asmjs__ when one is targeting __wasm__, but we should definitely retain __asmjs__ when targeting asm.js. We have sprinkled __asmjs__ checks in certain partner codebases in the past when migrating from non-asm.js a long ago, but I don't think there's any need to make __wasm__ be inclusive with __asmjs__ for backwards compatibility reasons, but it's nicer to have those be separate, largely because searching project trees for __asmjs case sensitive is really easy and not expected to run into any headscratchers.

Btw, I think the common form is to have both __wasm and __wasm__ appearances, although I don't know where that convention came from. Just follow suit for consistency?

dschuff commented 6 years ago

Yeah I think the particular clang APIs that we use to add those give you both the __wasm and __wasm__ forms automatically anyway. But yeah I'd be happy defining __asmjs__ or __wasm__ but not both together. I don't see that in the emscripten codebase anywhere so I'm guessing it's in fastcomp. So we could either move it out of there and make it one of the frontend flags that emscripten passes, or define a separate clang flag? edit: actually there's already a flag that means "i'm bypassing asmjs and going straight to wasm" right?

juj commented 6 years ago

We don't have a __wasm__ yet even in fastcomp. Adding it as a frontend flag sounds fine, although an important thing to note is that when Emscripten is compiling code that may end up generating either asm.js or wasm, then both __asmjs__ and __wasm__ will/should end up getting defined. This happens for example in -s WASM=1 -s BINARYEN_METHOD='asmjs,native-wasm' - in that mode, the same code files will end up being used for both asm.js and wasm.

Also I think up to this point .c -> .bc compilation stages have been agnostic as to whether the resulting .bc files will be later used to generate asm.js or wasm, since Binaryen pass is a final link step. This means that we will now want to pass -s WASM=1 also during compilation stage (as opposed to just at final link stage) to get the __wasm__ to show up. I think that's fine, we already have a precedent from that in other cases as well, for example in pthreads, where technically you only need -s USE_PTHREADS=1 at final link stage and not during compilation stage, but if you pass it also during compilation stage, you'll get the preprocessor define __EMSCRIPTEN_PTHREADS__ visible. We just want to document and instruct that -s WASM=1 is good to be defined already during compilation and not just during final link, like we do for the other flags.

kripken commented 6 years ago

This happens for example in -s WASM=1 -s BINARYEN_METHOD='asmjs,native-wasm' - in that mode, the same code files will end up being used for both asm.js and wasm.

That's a good point. Perhaps it isn't worth the complexity to keep supporting such mixed-mode outputs. They've been useful for debugging in the early days, but less now. However, I have heard of some users that emit such builds for simplicity, despite the decreased optimizations.

dschuff commented 6 years ago

Pretty soon we're going to run hard into the brick wall that is (the lack of) feature detection in wasm, and hopefully we can design some kind of mechanism or process or set of primitives to help our users deal with all the different possible combinations features that they might want to use and/or will appear in browsers at different times. Hopefully something better than "just build your app once for every possible combination of supported features". It's a much harder problem than it is with e.g. web APIs and it may not be that one size fits all. The problem of targeting asm vs wasm is sort of a subset of that so maybe we can work that into whatever we come up with.

dschuff commented 6 years ago

(oh but in general; yes, I don't think that the current way we do multiple binaryen methods will scale, and in any case it will break when we switch to the upstream backend).