reserved registers on inline asm clobber list silently ignored

Hi all,

I'm looking at an issue where when specifying a reserved register (fp, base pointer) on the clobber list of an asm() statement, we don't preserve the original value across the asm code. Practically the register in the clobber list is ignored in this case, so if we're overwriting it in our asm code, we have problems.

As the clobber list is a GCC extension, I looked at the GCC behaviour, and GCC is doing roughly the same thing. There is a GCC bug out on this (11807 – GCC should error out when clobbering the stack pointer and frame pointer), and the opinions are somewhat divided on how to proceed.

There's a few ways in which we think we'd like to resolve this:
1 - leave as is, and be in line with GCC
2 - error when we see the SP and PC on the clobber list, otherwise store and load around the assembly code
3 - error on any reserved register on the clobber list

Where option 1 doesn't sound like a very nice option to me as it's counter-intuitive, and seems quite shoot-in-the-foot-y.

Any opinions on this?

Best,
/Ties Stuij

Regardless of how much of a footgun this is, we'll get a ton of complaints if we print an error in any case where gcc doesn't, so any new diagnostics would need to be a warning, at least at first.

"otherwise store and load around the assembly code" makes sense for cases where the compiler is arbitrarily reserving registers, like fp/base ptr in a function that contains a VLA. In particular, the "base" register isn't really specified anywhere, so we can't expect users to consistently avoid it.

Printing a diagnostic for code that tries to clobber "sp" or "pc" makes sense; that can't do anything useful in any context. Probably also makes sense to print a diagnostic for other fundamentally reserved registers, like the frame pointer with -fno-omit-frame-pointer, or x18 on AArch64 targets where it's reserved, rather than try to do something which might have surprising results.

-Eli

Hi all,

I’m looking at an issue where when specifying a reserved register (fp, base pointer) on the clobber list of an asm() statement, we don’t preserve the original value across the asm code. Practically the register in the clobber list is ignored in this case, so if we’re overwriting it in our asm code, we have problems.

As the clobber list is a GCC extension, I looked at the GCC behaviour, and GCC is doing roughly the same thing. There is a GCC bug out on this (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807), and the opinions are somewhat divided on how to proceed.

There’s a few ways in which we think we’d like to resolve this:
1 - leave as is, and be in line with GCC
2 - error when we see the SP and PC on the clobber list, otherwise store and load around the assembly code
3 - error on any reserved register on the clobber list

Where option 1 doesn’t sound like a very nice option to me as it’s counter-intuitive, and seems quite shoot-in-the-foot-y.

Any opinions on this?

Would it be good enough if we changed LLVM to eliminate the need for the third reserved register, the so-called “base pointer” that Eli mentioned? This is usually what trips people up on X86 (RBX vs. cpuid: https://llvm.org/pr16830). Most users know they aren’t supposed to muck with SP or FP registers. You can imagine making the base pointer into a virtual register that could be spilled, reloaded, or rematerialized as needed.

Regardless of how much of a footgun this is, we’ll get a ton of
complaints if we print an error in any case where gcc doesn’t, so any
new diagnostics would need to be a warning, at least at first.

“otherwise store and load around the assembly code” makes sense for
cases where the compiler is arbitrarily reserving registers, like
fp/base ptr in a function that contains a VLA. In particular, the
“base” register isn’t really specified anywhere, so we can’t expect
users to consistently avoid it.

Printing a diagnostic for code that tries to clobber “sp” or “pc” makes
sense; that can’t do anything useful in any context. Probably also
makes sense to print a diagnostic for other fundamentally reserved
registers, like the frame pointer with -fno-omit-frame-pointer, or x18
on AArch64 targets where it’s reserved, rather than try to do something
which might have surprising results.

At some point when we were working on MS inline asm, we decided that inline asm clobbering SP should be treated as a dynamic alloca, i.e. a frame pointer should be used to address local variables.