relaxed-simd
relaxed-simd copied to clipboard
Add new instructions: min / max
- What are the instructions being proposed?
- relaxed f32x4.min
- relaxed f32x4.max
- relaxed f64x2.min
- relaxed f64x2.max
- What are the semantics of these instructions?
Return the lane-wise minimum or maximum of two values. If either is NaN, or the values are -0.0 and +0.0, then which value will be returned is implementation-defined.
- How will these instructions be implemented? Give examples for at least x86-64 and ARM64. Also provide reference implementation in terms of 128-bit Wasm SIMD.
Pretty much all architectures which support SIMD have min / max instructions. On those platforms, these would be mapped to those instructions.
relaxed f32x4.min:
- x86 + SSE:
minps - armv7 + NEON:
vmin.f32 - AArch64:
fminorfminnm - POWER6 + AltiVec:
vminfp - POWER7 + VSX:
xvminsp - MIPS + MSA:
fmin.w
relaxed f32x4.max:
- x86 + SSE:
maxps - armv7 + NEON:
vmax.f32 - AArch64:
fmaxorfmaxnm - POWER6 + AltiVec:
vmaxfp - POWER7 + VSX:
xvmaxsp - MIPS + MSA:
fmax.w
relaxed f64x2.min:
- x86 + SSE2:
minpd - AArch64:
fminorfminnm - POWER7 + VSX:
xvmindp - MIPS + MSA:
fmin.d
relaxed f64x2.max:
- x86 + SSE2:
maxpd - AArch64:
fmaxorfmaxnm - POWER7 + VSX:
xvmaxdp - MIPS + MSA:
fmax.d
On platforms where no hardware support is available, implementations could use the same code they use for the pmin / pmax instructions (or min/max if they prefer, or some other sequence).
- How does behavior differ across processors? What new fingerprinting surfaces will be exposed?
Different processors will return different results if one of the inputs is NaN.
- If using
fmin/fmax, Arm will always return NaN if either input is NaN - POWER (and I think MIPS) will return the number, as will Arm if using
fminnm/fmaxnm. - On x86, the result depends on the argument order.
- What use cases are there?
Whenever you want the minimum or maximum of two values and don't have NaNs in your data. Currently the programmer must choose between instructions which will perform sub-optimally on Arm (pmin/pmax) or x86 (min/max); with these instructions the fastest implementation will be selected automatically.
There is another case where the underlying instruction differ: when one input is +0.0 and the other is -0.0
Thanks for pointing that out, I hadn't considered it ☹. I updated the description to make that implementation-defined as well.
For RISC-V V extension, vector float min/max follows scalar semantics, copied the relevant paragraph:
Floating-point minimum-number and maximum-number instructions FMIN.S and FMAX.S write, respectively, the smaller or larger of rs1 and rs2 to rd. For the purposes of these instructions only, the value −0.0 is considered to be less than the value +0.0. If both inputs are NaNs, the result is the canonical NaN. If only one operand is a NaN, the result is the non-NaN operand. Signaling NaN inputs set the invalid operation exception flag, even when the result is not NaN
Note that this is different from x86/arm for relaxed_min(1.0f, NaN):
- x86 and ARM:
NaN - RISC V:
1.0f
Lookingat PowerISA V2.07B has vminfp, vmaxfp, where:
- max of +0 and -0 is +0
- min of +0 and -0 is -0.
- max of x and NaN is QNaN
- min of x and NaN is QNaN