1) unboxed floats
The double_array_tag saves a lot (50%) of ram because the floats are
not individually boxed. For mixed blocks a bitfield could also allow
unboxed floats.
Inspecting the contents of such a block would be more complex then
because, on 32bit, a is-float bit means the float is stored in 2
fields and the inspection has to combine the current field with the
next and skip over the next field.
You want to use a 16-bit bitfield to indicate which members are float.
This would work for record and constructors with up to 16 members. I
would modify this a bit. The lower 15 bit indicate which of the first
15 members are float while the 16th bit indicates if all remaining
members are floats. If you declare the 16-bit value as signed and use
arithmetic shift right to iterate through the bits you get this
naturally.
2) values the GC doesn't need to scan
This would probably be far more often usefull. There are tons of
tuples and records that contain only primitive types (int, bool, unit,
...). This is also true for a lot of variant types. So a simple
flat_tag would only cover half the cases. A flat bit would be better.
On the other hand a bitfield for values the GC doesn't have to inspect
seems pointless. Each value already has a bit for that.