Re: How do I tell GCC that a global variable is immutable after initialization?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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...
-- 
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


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux