Implementing a datastructure with two function pointers, key_eq and key_hash. When these function pointers are set only once and never modified, I’d like gcc to compile in the function address directly instead of loading the struct member, however a single puts("") call will break gcc’s constant propagation (correct term?).
Below is a short snippet of ppc asm. What is seen is that the field key_hash is stored, we call libc puts and then key_hash is loaded. If puts is removed, the constant is correctly propagated. Is this unavoidable?
lis 9,hasheq_string@ha # tmp174,
la 0,hasheq_string@l(9) # tmp173,, tmp174
stw 3,16(1) # h.flags,
lis 9,hashf_string@ha # tmp176,
lis 3,.LC0@ha # tmp178,
stw 0,36(1) # h.key_eq, tmp173
la 0,hashf_string@l(9) # tmp175,, tmp176
la 3,.LC0@l(3) #,, tmp178
stw 0,40(1) # h.key_hash, tmp175
bl puts #
lwz 0,40(1) # h.key_hash, h.key_hash
mr 3,31 #, tmp164
stw 31,32(1) # h._key, tmp164
mtctr 0 #, h.key_hash
bctrl #
I’m sorry for not having a C testcase to go with it, I have a hard time reproducing it, yet the short three-line “store, bl puts, load” sequence leads the question, is this impossible to work around?
It’s possible that GCC conservatively assumes that the call to
putsmay read/write memory, hence the value inkey_hashmay be needed by the called function and different before and after the call.This code:
produces the “signature” sequence:
However, with a small modification (manual Scalar Replacement of Aggregates?):
one gets the desired result: