On 06/22/2016 10:38 AM, Matthias Pfaller wrote: > On 06/22/2016 10:21 AM, Sebastian Huber wrote: >> >> >> On 22/06/16 10:08, Matthias Pfaller wrote: >>> On 06/22/2016 09:48 AM, Sebastian Huber wrote: >>>> On 22/06/16 09:42, Mason wrote: >>>>> On 22/06/2016 09:00, Sebastian Huber wrote: >>>>> >>>>>> is there a way to tell GCC that a global variable is immutable after >>>>>> initialization? For example >>>>>> >>>>>> struct { >>>>>> int (*f)(void); >>>>>> } s; >>>>>> >>>>>> int f(void) >>>>>> { >>>>>> int a; >>>>>> int b; >>>>>> >>>>>> a = (*s.f)(); >>>>>> b = (*s.f)(); >>>>>> >>>>>> return a + b; >>>>>> } >>>>>> >>>>>> yields on ARMv8 for example >>>>>> >>>>>> f: >>>>>> push {r4, r5, r6, lr} >>>>>> movw r4, #:lower16:s >>>>>> movt r4, #:upper16:s >>>>>> ldr r3, [r4] >>>>>> blx r3 >>>>>> ldr r3, [r4] <- I would like to get rid of this load >>>>>> here >>>>>> mov r5, r0 >>>>>> blx r3 >>>>>> add r0, r5, r0 >>>>>> pop {r4, r5, r6, pc} >>>>>> >>>>>> The >>>>>> >>>>>> a = (*s.f)(); >>>>>> >>>>>> is a call to a global function, so GCC must assume that s might have >>>>>> changed afterwards. I would like to get rid of the second load of s.f. >>>>>> Is there a special attribute to tell GCC that s is essentially >>>>>> immutable? I cannot use the const qualifier, since the structure is >>>>>> initialized during system start. >>>>> A simple solution would be storing the function pointer in a local >>>>> variable. >>>>> Thus, the compiler "knows" you intended to call the same function >>>>> twice. >>>>> >>>>> typedef int func(void); >>>>> struct { func *f; } s; >>>>> int f(void) >>>>> { >>>>> func *g = s.f; >>>>> int a = g(); >>>>> int b = g(); >>>>> return a + b; >>>>> } >>>>> >>>>> push {r3, r4, r5, lr} >>>>> movw r3, #:lower16:s >>>>> movt r3, #:upper16:s >>>>> ldr r4, [r3] >>>>> blx r4 >>>>> mov r5, r0 >>>>> blx r4 >>>>> add r0, r0, r5 >>>>> pop {r3, r4, r5, pc} >>>>> >>>>> Regards. >>>> My problem is that the actual (*s.f)() call is an implementation detail. >>>> I have a function which returns a timestamp via an architecture specific >>>> way, e.g. on PowerPC this is something like this: >>>> >>>> static inline int timestamp(void) >>>> { >>>> int t; >>>> __asm__(... t ...). >>>> return t; >>>> } >>>> >>>> On SPARC this is something like this: >>>> >>>> static inline int timestamp(void) >>>> { >>>> return (*s.f)(); >>>> } >>>> >>>> So, I cannot use a local variable for this particular use case. >>> So you are saying that your code fragment with the two calls to s.f() is >>> actually the result of gcc inlining the call to timestamp? >> >> Yes. > > In that case your options are very limited :-( Its ugly, but the only > way I can see: > #if defined(PLATFORM_SPARC) > #define timestamp (*s.f) > #endif > > now you can use the suggested work around using a local variable: > func *g = timestamp; > > Be aware that in the powerpc case gcc will treat the __asm__ as > __attribute__((const)) when it has no inputs. Thus it will emit the code > in __asm__ only once and multiply by two... I just recognized (thank's to Sebastian) that this is no longer true. While gcc 4.8.3 will happily constant fold asm statements without input operands even in the presence of a memory clobber, gcc 5.3.0 will honor the memory clobber and doesn't do constant folding in that case. -- Matthias Pfaller Software Entwicklung marco Systemanalyse und Entwicklung GmbH Tel +49 8131 5161 41 Hans-Böckler-Str. 2, D 85221 Dachau Fax +49 8131 5161 66 http://www.marco.de/ Email leo@xxxxxxxx Geschäftsführer Martin Reuter HRB 171775 Amtsgericht München
Attachment:
smime.p7s
Description: S/MIME Cryptographic Signature