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