Optimal stored property packing

I'm curious why Swift doesn't use optimal (from a size perspective) ordering of stored properties, for non-frozen structs (and similar)?

As far as I can tell there's nothing in the ABI that prevents it. You can already do this through manual re-ordering of the declarations, so why not have the compiler do it automatically?

For example, currently the following struct has an actual size (stride) of 24 bytes, but by simply ordering the stored properties better that can be reduced to the optimal 16.

struct SadPanda {
    let a: Int32
    let b: Int64
    let c: Int32
}

Is there a way to explicitly opt into this behaviour, at least? Some kind of @minimisePadding decorator or somesuch?

Note that I'm not talking about misaligning any of the fields (away from their natural alignment), as e.g. the packed attribute does in C. Merely reordering things. Though if anyone knows of an equivalent to __attribute__((packed)) for Swift, I'd like to know about that too.

3 Likes

Haven't gotten around to it yet.

3 Likes

Hah, fair enough, I guess. :slightly_smiling_face:

But just to confirm, then, this is something which Swift can be made to do in future?

It should be possible for any type that hasn't made itself @frozen in an ABI-stable context, yeah. It's one reason we try to discourage people from relying on in-memory layout to follow declaration order, or the specific order of fields in reflection, and so on.

3 Likes

If you (or someone else reading) is interested in exploring this, another form of layout optimization we'd like to do is to use spare bits to pack Bool and small enum fields, like we do with multi-payload enum tags already. This would allow something like struct Foo { var x: SomeClass; var y: Bool } to fit in a single word.

2 Likes

I remain unconvinced about doing this one by default because it makes assigning a new value to the base property much more expensive: read old value, extract bits, apply to new value, store new value. Reading likewise gets an extra masking step. Opt-in, sure, but it’s not free real estate like reordering is.

1 Like

Setting or clearing a single bit, at least, is one instruction for x86 or ARM. I agree the cost gets higher once you start talking about 2- or more-bit packing (though Intel has PDEP/PEXT to do that in one instruction too).

2 Likes

Even so there could still be an overall runtime win as more things will fit in cache.

3 Likes