This crashes the backend of v2.102.1:
```
T clamp(T)(T x)
{
enum min = T(-1);
enum max = T(1);
const ltMask = x < min;
const gtMask = x > max;
version (none) // nice-to-have version
{
return (min & ltMask)
| (max & gtMask)
| (x & ~(ltMask | gtMask));
}
else // currently required ugly version
{
alias I = typeof(ltMask);
return cast(T) (
((cast(I) min) & ltMask)
| ((cast(I) max) & gtMask)
| ((cast(I) x) & ~(ltMask | gtMask)));
}
}
void main()
{
alias int4 = __vector(int[4]);
alias float4 = __vector(float[4]);
assert(clamp!int4([0, 1, -2, 3]).array == [0, 1, -1, 1]);
assert(clamp!float4([-0.25f, 0.5f, 1.5f, -2]).array == [-0.25f, 0.5f, 1, -1]);
}
```
Output on Linux x64:
```
el:0x556764d27e70 cnt=0 cs=0 > mTYconst|TYulong[4] 0x556764d275a0 0x556764d27480
el:0x556764d275a0 cnt=1 cs=255 var TYfloat4 x
el:0x556764d27480 cnt=0 cs=255 var mTYconst|TYfloat4 _TMP14
Illegal instruction
```
---
As shown in the example, working with vector masks is very cumbersome as of v2.102, requiring reinterpret-casts all over the place.
Comment #1 by ibuclaw — 2023-02-26T22:21:16Z
(In reply to kinke from comment #0)
> As shown in the example, working with vector masks is very cumbersome as of
> v2.102, requiring reinterpret-casts all over the place.
Only for vector floats though.
The result of a comparison is either all bits are zeros or ones. For floats, that's `0` or `nan`.
> return (min & ltMask)
You can't use bitwise operations on scalar floats, why would you expect it to be valid on vector floats?
Comment #2 by kinke — 2023-02-26T23:22:58Z
(In reply to Iain Buclaw from comment #1)
> The result of a comparison is either all bits are zeros or ones. For
> floats, that's `0` or `nan`.
The only usage of the new vector masks, at least that I can think of, are masking operations via bitwise ops. What the bit pattern represents for a specific vector element type plays no role whatsoever.
> > return (min & ltMask)
> You can't use bitwise operations on scalar floats, why would you expect it
> to be valid on vector floats?
Because then we don't need vector masks and elaborate vector comparisons in the first place, a library solution would do.
Comment #3 by kinke — 2023-02-27T00:46:06Z
Oh, I've just seen that `cast(int4) someFloat4` is a reinterpret cast with both LDC and GDC, but not with DMD (=> conversion). So would need to uglify further to please DMD, rendering vector masks with FP vectors next to useless.
That reinterpret-cast with LDC and GDC would be another difference from scalar vs. vector. While bitwise ops for a scalar FP type don't really make much sense, they are IMO key to making vector masks nice to work with in practice.
Oh and LDC is apparently the only compiler allowing the most trivial of comparisons - identity comparisons (yielding a scalar bool). So the other non-bitop use case for such vector masks, manually reducing to a scalar (e.g., `mask is 0`) currently only works with LDC, and needs a full array comparison and boilerplate syntax with the other compilers (`mask.array == [0, 0, 0, 0]`).
Comment #4 by robert.schadek — 2024-12-13T19:27:27Z