This will always decrease performance and increase program size versus static
variables. Your question doesn't specifically ask what you are comparing to. I can see various alternatives,
- Versus static variables.
- Versus parameters passed by value.
- Versus values in a passed array or structure pointers.
The ARM blog gives specifics on how to load a constant to an arm register. This step must always be done to get the address of a global variable. The compiler will not know a prior how far away a global is. If you use gcc with -lto
or use something like whole-program, then better optimizations can be performed. Basically, these will transform the global to a static.
Here a compiler may keep a register with the address of a global base and then different variables are loaded with an offset; such as ldr rN, [rX, #offset]
. That is, if you are lucky.
The design of RISC CPUs, like ARM support a load/store unit which handles all memory accesses. Typically, the load/store instructions are capable of the [register + offset]
form. Also, all RISC registers are approximately symmetric. Meaning any register can be used for this offset access. Typically, if you pass a struct
or array pointer as a parameter, then it becomes the same thing. Ie, ldr rN, [rX, #offset]
.
Now, the advantage of the parameter is that eventually, your routines can support multiple arrays or structures by passing different pointers. Also, it gives you the advantage to group common data together which gives cache benefits.
I would argues that globals are detrimental on the ARM. You should only use global pointers, where your code needs a singleton. Or you have some sort of synchronization memory. Ie, globals should only be use for global functionality and not for data.
Passing all of the values via the stack is obviously in-efficient and misses the value of a memory reference or pointer.