How do I tell GCC that a global variable is immutable after initialization?
Matthias Pfaller
leo@marco.de
Wed Jun 22 11:26:00 GMT 2016
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@marco.de
Geschäftsführer Martin Reuter HRB 171775 Amtsgericht München
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4349 bytes
Desc: S/MIME Cryptographic Signature
URL: <https://gcc.gnu.org/pipermail/gcc-help/attachments/20160622/bea56e7e/attachment-0001.p7s>
More information about the Gcc-help
mailing list