[llvmlinux] Global vs. Local named registers

Renato Golin renato.golin at linaro.org
Wed May 21 10:58:15 UTC 2014


Clang now (as of r209149) has support for global named register variables.

The next step, now, is to make sure why the kernel uses *local* named
register variables for non-allocatable registers instead. Furthermore,
I just found out that GCC screws up the *local* variety, which makes
me wonder how it works at all.

Why Global?

Global named registers are useful for pinning a specific register
directly, and since it's not allocatable, all it is is a way to access
the value of the register specifically at the line it's being used.

Using allocatable (GPR) registers on that list would either force
their reservation throughout the compile unit, or mean nothing, since
that register could have any value after code movement, deletion and
inlining. That's why GCC reserves it, and that's an acceptable usage
in LLVM, but not implemented yet (and will take a while to get it
right, if ever).

Why local?

The local variety, however, has only one usage: to pin registers to
inline assembly snippets when marking variables to return. That's why
GCC doesn't reserve those registers if they're local.

Non-allocatable local named registers have absolutely no value, since
they can't be reserved anyway and the variable will never exist in the
compile unit, making local and global register variables functionally
equivalent. Since they're an extension, their linkage and behaviour
cannot be tied up back  to the standard.

We have seen problems with assuming registers in a local context
(http://llvm.org/bugs/show_bug.cgi?id=19317) and the way to "fix" this
is changing other constructs (in this case, __gnu_mcount_nc), which is

Current behaviour

So, ignoring all that, I went along and tried some example on both
Clang and GCC (source and asm files attached).

As you can see, both Clang and GCC produce the same result for the
global case (as expected), but the local behaviour is odd, even with
inline asm fixups. Clang doesn't do anything, as expected.

But GCC is doing something odd. It's returning the value of the stack
pointer on get_sp(), but it's not setting it on set_sp(). That tells
me that GCC has optimized the write away, since it has (in theory) no
effect on memory. I had this on my first implementation of the global
variable because I hadn't marked the intrinsic as having side effects.

This means that Rafael's fears were true, and GCC doesn't really
guarantee anything for local register variables, meaning it's not
really that safe to use them in the first place. At all.

What now?

My question is: what does GCC outputs on the kernel code? I tried to
compile that file but I'm getting tangled in headers, macros, etc. Are
we sure that GCC actually produces the expected moves between SP and
GPRs? I'm not so sure now...

Also, moving the SP cases top global variables shouldn't upset GCC,
and would start working on Clang. Is this something that the kernel
folks would accept?

-------------- next part --------------
A non-text attachment was scrubbed...
Name: named_reg.zip
Type: application/zip
Size: 3418 bytes
Desc: not available
URL: <http://lists.linuxfoundation.org/pipermail/llvmlinux/attachments/20140521/292116dc/attachment.zip>

More information about the LLVMLinux mailing list