Bug 23746 – ICE with bit-wise binops with vector masks

Status
NEW
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2023-02-26T20:03:21Z
Last change time
2024-12-13T19:27:27Z
Assigned to
No Owner
Creator
kinke
Moved to GitHub: dmd#20238 →

Comments

Comment #0 by kinke — 2023-02-26T20:03:21Z
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
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/20238 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB