WebAssembly / simd

Branch of the spec repo scoped to discussion of SIMD in WebAssembly
Other
530 stars 43 forks source link

WASM SIMD Intrinsics Added #31

Open rrwinterton opened 6 years ago

rrwinterton commented 6 years ago

There have been several request to look at including "WASM SIMD Intrinsics or Built-ins" to the LLVM Clang compiler for SIMD. The question is, "is there a proposal for an "instrinsic or built-in" naming convention to map the "intrinsic / built-in" syntax to WASM SIMD instruction? Should we create a pull request and add an agenda Item for WASM SIMD instrinsics? Or should we look at how to do direct WASM SIMD instructions with "inline WASM SIMD". I think this should be a topic at a future WASM WG meeting. Would be happy to help with the discussion.

sunfishcode commented 6 years ago

The clang and gcc convention for target-specific intrinsics is roughly __builtin_<arch>_<mnemonic>, for example __builtin_ia32_sqrtpd and __builtin_arm_ldrex and so on. We've already been following this for other intrinsics, such as __builtin_wasm_memory_size and __builtin_wasm_memory_grow, which map to memory.size and memory.grow, for example. So one option is to continue following this convention for wasm SIMD as well, taking whatever the spec ends up naming the operations, making a hopefully obvious translation into valid C identifier characters, and then prepending __builtin_wasm_.

lemaitre commented 6 years ago

To be noted that __builtin_* are not really intrinsics, but compilers builtins. The difference being a compiler builtin is provided by your compiler vendor, while intrinsics are defined but the architecture vendor.

In that respect, your example of __builtin_ia32_sqrtpd is bad: nobody writing SSE uses that kind of builtins. They all use _mm_rsqrt_pd which is the intrinsics provided by intel.

However, the question is still interesting: do we want to create intrinsics, and be able to write low level wasm code in C, or do we want to rely on compilers? My feeling is that we could start without intrinsics and let compiler vendors create their own builtins, and when we feel it's time, standardize some intrinsics.

If/when we want intrinsics, we need to standardize new data types for simd (instructions are not enough).

Here is a small table with syntax for writing SIMD depending on different architectures (simplified view):

gcc builtin intrinsics SSE intrinsics neon intrinsics SVE intrinsics altivec intrinsics wasm
float __attribute__((__vector_size__(16))) __m128 float32x4_t svfloat vector float wasm_f32x4
a + b _mm_add_ps(a, b) vaddq_f32(a, b) svadd_f32(a, b) vec_add(a, b) wasm_f32x4_add(a, b)
N/A _mm_load_ps(p) vld1q_f32(p) svld1_f32(p) vec_ld(0, p) wasm_f32x4_load(p)
__builtin_arch_instr _mm_instr_type suffix vinstrq_inner type svinstr_inner type vec_instr (no type) wasm_type_instr

The wasm column is what I would propose

penzn commented 6 years ago

The problem is that all current implementations of vector intrinsics (in C/C++ family) are platform-specific, while WASM is not, that's why it is an open question what syntax it should use.

On the other hand, the compiler builtins for WASM vector ops would be tied only to WASM, and it would be possible define them before worrying about the names visible to the user.

At least in theory, wasm builtins can map to multiple sets of intrinsics, that would help port the code written for various platforms.

lemaitre commented 6 years ago

As far as the compiler is concerned, WASM is the target platform and thus is no different from any actual platform/architecture. So if you need intrinsics for x86, you need intrinsics for WASM. The fact that WASM can be run on many platforms is completely independant from this compilation scheme.

Also, intrinsics are defined by the platform "vendor", and not by the compiler vendor (usually, there is some overlap though). After that, if a compiler wants to support the platform, it needs to support the intrinsics for this platform.

All in all, intrinsics are only about interface, and mostly about names.

penzn commented 6 years ago

I think you are probably right. The main question is who would be responsible from this header, since WASM does not have a vendor in the same sense as hardware operations do. It would probably make sense to supply the header as part of this proposal.

tlively commented 6 years ago

I think @rrwinterton has been working on a header to supply source-level intrinsics for the SIMD instructions. However, I don't think such a header file necessarily needs to be part of the WebAssembly spec since developers could easily choose to use a different interface or use the __builtin_wasm_* functions directly without having any effect on the generated WebAssembly code.

Once the groundwork for wasm SIMD has been laid in LLVM, I will start implementing clang's __builtin_wasm_* functions. Once those builtin functions are in, it will be straightforward to use them directly in your code or implement any other interface of your choosing in terms of them.

penzn commented 6 years ago

It just feels like the WebAssembly community is the right origin for this header, just like a hardware vendor is the right origin for corresponding hardware intrinsics header. At the least that would reduce the chance that using WASM intrinsics would not be portable across compilers.

Using __builtin_* directly or redefining interfaces to them is usually discouraged -- it can break if compiler changes, that's why we have those headers.