ecmascript_simd
ecmascript_simd copied to clipboard
Unsigned types don't have "neg"
The spec says that all integral types (signed and unsigned) should implement neg, although the polyfill doesn't have them. Is it that the polyfill is missing them, or is it that the spec shouldn't define them for unsigned types?
As noted by Jakob Olesen in https://bugzilla.mozilla.org/show_bug.cgi?id=1233111#c17 , they can be implemented with modulo arithmetic.
I would recommend keeping unsigned neg in the spec and adding it to the polyfill. It is the same for all integer types: neg(x) = sub(splat(0), x).
Let's get rid of neg from unsigned types. It was a typo on my part to include them; I don't think it was anyone's intention.
Currently, the signed and unsigned integer types support the same set of operations. This is a desirable property of a compilation target.
Would it make sense to remove neg from the signed integer types too? I don't think it provides any benefit. It is more important to have a floating point neg.
I did a quick survey of programming languages that provide fixed-size unsigned integer types:
- C/C++:
unsigned intandunsigned longsupport the unary-operator with modulo semantics. - Ada: Modular integer types support the unary
"-"operator. http://www.adaic.org/resources/add_content/standards/12rm/html/RM-4-5-4.html - D has unsigned types. The spec is not so clear about negation: http://dlang.org/spec/expression.html#UnaryExpression
- Haskell has a number of
Wordtypes which are all supported by thenegatefunction with modulo semantics. http://hackage.haskell.org/package/base-4.8.1.0/docs/Prelude.html#v:negate - Nim has unsigned integer types which do not support the unary
-operator. - Rust has unsigned types with a unary
-operator that currently generate an error: https://doc.rust-lang.org/stable/reference.html#unary-operator-expressions. Looks like it will be fixed in https://github.com/rust-lang/rust/pull/30538. - Swift has unsigned integer types which do not support the unary
-operator. They provide a binary&-operator with modulo semantics for both signed and unsigned types, but that doesn't come in a unary variant.
ARM Neon has a hardware negate instruction for the 64-bit types int8x8_t, int16x4_t, int32x2_t and float32x2_t, and the 128-bit types int8x16_t, int16x8_t, int32x4_t and float32x4_t. I'd favor keeping the negate instruction on signed and floating point types, since that can map directly to this ARM Neon instruction (even though x86 SSE doesn't have one) and be more expressive that way.
This is pretty much a continuation of #191: SIMD really expresses operations, some of which are signed / unsigned and some of which are sign-agnostic. The type system is expressed in terms of signed / unsigned, and it sometimes maps weirdly.
IMO in this case neg should either:
- Exist for both signed and unsigned. On unsigned should just do the same as neg does on the same bit-represented signed.
- As @stoklund suggested drop neg from signed and unsigned, keep it only for floating-point.
OK, I'm convinced, let's keep neg for unsigned and fix the polyfill and tests.
Rust has unsigned types with a unary - operator that currently generate an error: https://doc.rust-lang.org/stable/reference.html#unary-operator-expressions. Looks like it will be fixed in rust-lang/rust#30538.
I'm not fixing it. I'm making sure it errors always. We don't have unary negation. What we have is unary not, so we do !x + 1, which is equivalent to ~x + 1 in c/c++.
Ada's modular types are like Rust's Wrapping types, and those do support unary negation. Ada's Positive type does not support unary negation, it will raise an exception.
So if your types are wrapping (unsigned::MAX + 1 == unsigned::MIN) then it's probably correct to support them. If that's not happening, this might be very suprising in some situations that unary negation works.
Seems the consensus here is to have neg for both sign/unsigned ? Polyfill/tests still need to be fixed.
Yes, I believe that was the consensus on the last call where we discussed it.