When defining a bitfield constant where multiple bitfields have initializing values, this constant is moved into .data in GCC 4.1. GCC 3.x could realize it can be written and assigned as a single integer number. GCC 4.x only realizes this situation as long as a single bitfield is initialized. Verified on i386 and avr targets, so this is apparently completely independent of the target CPU.
Created attachment 13982 [details] Test file Test case. Compile with -Os -S, and optionally -DONLY_ONE_BITFIELD to see the difference.
Created attachment 13983 [details] Result on i386 target from GCC 3.4.4
Created attachment 13984 [details] Result on i386 target from GCC 4.1.2
Created attachment 13985 [details] Result on avr target from GCC 4.1.2
Confirmed on the AVR target for 4.3.0 20070817 snapshot.
Ok, here's the deal. gimplify_init_constructor promotes the constructor to a static because it is a const aggregate variable, here: /* If a const aggregate variable is being initialized, then it should never be a lose to promote the variable to be static. */ if (valid_const_initializer ... This isn't a good idea if we are initializing bitfields from static numbers. If I keep the compiler from promoting to static in the above code, the gimplifier splits the constructor into independent assignments: init = {}; init.a1 = 1; init.a2 = 5; ...which later combine munges into the expected constant, thus fixing the problem reported. Perhaps we should keep the above code from executing if initializing a structure containing only bitfields that fit into a HOST_WIDE_INT, something we can do with one move? Or is there a better generalization we can code here? Any suggestions?
The problem is that we really don't have any optimization which would before expand merge all the sets to adjacent bitfield fields into one (or few) BITFIELD_REFs. If we are lucky and the RTL passes merge it together, initializing small structs containing bitfields this way will be a win, but it might be an pessimization as well. BTW, shouldn't TER try to merge several consecutive initializations of fields of one aggregate into a CONSTRUCTOR again, so that RTL expanders can do better job on it? This wouldn't be the only bug which could be helped by that.
E.g. for PR22141 it would help too (for PR32901 only if the constructor gimplification heuristics is also adjusted).
TER would never see the consecutive initializations because the code I pointed out in gimplify_init_constructor() keeps the gimplifier from splitting up the constructor into consecutive MODIFY_EXPRs. After gimplification we end up with: setup_foo () { static const struct foo init = {.a1=1, .a2=5}; thefoo = init; } So there's nothing to merge back. What I'm suggesting *is* splitting this up, so subsequent passes can take a stab at it. In this case, combine cleans it up.
(In reply to comment #8) > E.g. for PR22141 it would help too (for PR32901 only if the constructor > gimplification heuristics is also adjusted). > Ok, I see what you mean. We adjust the heuristic as I've suggested, and write some pass to merge consecutive bitfield stores. I wonder what pass we can hijack and add the smarts to, instead of writing a whole new pass...
testing a patch
http://gcc.gnu.org/ml/gcc-patches/2007-12/msg00525.html