I might be biased because I'm currently working on this same optimization but for GCC. I think that it is more complicated than it seems. Defining the layout of a structure is normally done during parse time (at least in GCC). And one cannot know if it is safe to reorder fields all the way up until link time.
This means that a lot of optimizations and assumptions that were made might not longer be valid. For example, in GCC the results of the sizeof operator are evaluated at parse time. One might need to change these values link time. Otherwise statements like:
memset(&astruct, 0, sizeof(astruct));
will overwrite memory that is no longer part of the struct.
Furthermore, constant propagation might have propagated the value of a sizeof operator and it might have been folded into different arithmetic operations. This can be solved in different ways, but if the compiler was not built this way, it might take some time to implement. Also, all pointer arithmetic will need to be changed...
In my time in the embedded world we would reorder fields to deal with issues like alignment in MIPS. If you wanted to avoid this you would have to use a directive like __attribute__((packed)). Does go allow you do do the same?
So I used to do things like this (hopefully the formatting is correct):
I first ran into this the other way around: misaligned 64 bit values on 64 bit MIPS (and PPC) hardware.
But it's the sort of thread that once you pull on it, you just keep pulling. Getting the alignment made the data bigger, then we had to shrink it back, and while you're in there you might as well keep looking around...
Mmm... I might be able to provide some insight... For the C language it is not possible to reorder fields generally at compile time. This is because if a user defines a struct and the struct is passed to a library that was pre-compiled, then the library and your application hold a different representation for the struct.
You can at link-time be able to change some structure definitions if you know the structure definition is not escaping your application (i.e. it is not passed to a library). There are possibly other things that might hinder the reordering of the fields, for example casting or placing a structure in a union. If you are casting a structure to another, you might be expecting that the underlying memory to be represented in a specific way in order for the cast to make sense. The same thing happens when you place a struct in a union.
That go enforces alignment by padding structs is full of sad and fail. Since what's important with modern processors is cache line alignment not word alignment. All they get for that optimization is more memory usage and cache pressure.
Not the same language but this is still an important read http://www.catb.org/esr/structure-packing/ although its not quite a lost art as it is made out to be. A developer is expected to know this.
I know the person who is working on an implementation of this in GCC. However, it is still early days and the implementation is not ready for public consumption. Other than that, I've only seen this transformation on academic papers.
11 comments
[ 2.9 ms ] story [ 40.2 ms ] threadThis means that a lot of optimizations and assumptions that were made might not longer be valid. For example, in GCC the results of the sizeof operator are evaluated at parse time. One might need to change these values link time. Otherwise statements like:
memset(&astruct, 0, sizeof(astruct));
will overwrite memory that is no longer part of the struct.
Furthermore, constant propagation might have propagated the value of a sizeof operator and it might have been folded into different arithmetic operations. This can be solved in different ways, but if the compiler was not built this way, it might take some time to implement. Also, all pointer arithmetic will need to be changed...
So I used to do things like this (hopefully the formatting is correct):
But it's the sort of thread that once you pull on it, you just keep pulling. Getting the alignment made the data bigger, then we had to shrink it back, and while you're in there you might as well keep looking around...
You can at link-time be able to change some structure definitions if you know the structure definition is not escaping your application (i.e. it is not passed to a library). There are possibly other things that might hinder the reordering of the fields, for example casting or placing a structure in a union. If you are casting a structure to another, you might be expecting that the underlying memory to be represented in a specific way in order for the cast to make sense. The same thing happens when you place a struct in a union.