Missing SIMD functions in Swift's standard library

On Apple platforms, we can import simd and gain SIMD functionality that isn't available in the Swift stdlib. This functionality is sometimes very basic and fundamental, but it is not available directly on other platforms due to this limitation.

Right now I'm thinking of simd_abs(mySIMD4) but there are others. Is the fact that this is missing an oversight, or is it due to a limitation I'm unaware of? For example, that simd_abs is not available on some platforms Swift supports, so there was an active decision not to support it.

It seems arbitrary that we have mySIMD4.clamped(lowerBound: ..., upperBound: ...), .min(), .max(), .sum(), etc. but not e.g. .magnitudes.


Specifically, I would like to use simd_abs in WebAssembly. The C instruction looks like this:

static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_abs(v128_t __a) {
  return (v128_t)__builtin_wasm_abs_f32x4((__f32x4)__a);
}

but it's unclear to me how to pass a SIMD4<Float> into that function. Would the suggestion be to "just do it" via unsafeBitCast and friends, or is there a Swiftier way?

2 Likes

I wonder if these would have to be exposed within the Builtin module, similarly to how it was done for shufflevector in Implement shufflevector builtin. by stephentyrone · Pull Request #36650 · apple/swift · GitHub by @scanon

There are a lot of things that I would like Swift's SIMD types to add. Scatter/gather instructions and horizontal reductions are probably top of my list, personally.

I think LLVM has intrinsics for those things, and plenty more besides.

1 Like

This is incorrect; it’s just that the simd module is part of Apple’s SDK, not Swift.

(It was introduced as a C and C++ header at the same time Swift was introduced, but Swift couldn't import the C header at that point. There was a partial reimplementation of the header as a Swift overlay for a few years, which was eventually folded back into the SDK project, just like all the other overlays.)

@scanon thanks, that's what I thought, but what do we do about it? And until there is an official solution for other platforms to catch up, how do we use e.g. the wasm_f32x4_abs function I shared above in combination with SIMD4<Float> (to avoid going "full C" on this problem)? Will unsafeBitCast work? Is there a better way?

I don't know how v128_t or __f32x4 are defined, but if they have the sensible memory layout, then yes you can just unsafeBitCast to shim it.

1 Like

At least according to LLVM (which ultimately is probably the source of truth here):

typedef int32_t v128_t __attribute__((__vector_size__(16), __aligned__(16)));

typedef float __f32x4 __attribute__((__vector_size__(16), __aligned__(16)));

I don't know how those __attribute__s work but it seems as sensible as one might expect.

Yeah, you can just unsafeBitCast those.

Thanks!

The next question is: how do we expose these LLVM builtins, and does it even make sense to do so? Or would the recommendation be to just define our own C module for now, based on snippets of the various target platforms' SIMD headers (like the ones I have pasted throughout this thread)?

I know I can proceed by essentially forward-declaring those bits by copy-pasting parts of the headers, but it seems pretty hacky and I'm always curious to find better ways to do things.