diff options
author | Robie Basak <robie.basak@canonical.com> | 2014-10-14 13:16:22 +0100 |
---|---|---|
committer | Robie Basak <robie.basak@canonical.com> | 2014-10-14 17:44:34 +0100 |
commit | 505c91a68aaf5ab56325affd4d8581b32b649cf4 (patch) | |
tree | 577cfeda06cb3cb9c8948955d8b6f72b9dff1141 | |
parent | e31e76af477853d5e35418f60e2562ca94fdee0e (diff) | |
download | greenlet-505c91a68aaf5ab56325affd4d8581b32b649cf4.tar.gz |
arm32: force return value from asm
In my case, instead of a simple "mov r0, #0", the optimizer had done
this:
Between calls to slp_save_state and slp_restore_state, it saved the
value now guaranteed to be 0 using "str r0, [r7]".
Now, at the end, it restores that value into r0 using "ldr r3, [r7]"
and then "mov r0, r3".
It isn't clear to me that intermediate values managed by the compiler,
like this one at [r7], would be preserved in the stack this way,
especially as at this point we're in a "different" stack (unknown to the
optimizer).
Instead, prevent the optimizer from re-using a previous result like this
by forcing it to rely on the inline assembly to produce the result.
This fixes test failures on Ubuntu Utopic using gcc 4.9.1 (-5ubuntu1).
I think even this is still a hack though, and not guaranteed to work.
Ultimately, gcc can even re-order the "__asm__ volatile" functions at
will around the entire function, or just wrap each REGS_TO_SAVE
clobbering call with a simple push/pop, thus not preserving the
registers between stack switches.
The only way I can see of doing this without relying on undefined
compiler behaviour is to write the entire slp_switch function in
assembly for each architecture, instead of inlining it into a C function
for code reuse.
-rw-r--r-- | platform/switch_arm32_gcc.h | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/platform/switch_arm32_gcc.h b/platform/switch_arm32_gcc.h index c6e160d..e1cd797 100644 --- a/platform/switch_arm32_gcc.h +++ b/platform/switch_arm32_gcc.h @@ -54,6 +54,7 @@ slp_switch(void) { void *fp; register int *stackref, stsizediff; + int result; __asm__ volatile ("" : : : REGS_TO_SAVE); __asm__ volatile ("mov r0," REG_FP "\n\tstr r0,%0" : "=m" (fp) : : "r0"); __asm__ ("mov %0," REG_SP : "=r" (stackref)); @@ -67,9 +68,9 @@ slp_switch(void) ); SLP_RESTORE_STATE(); } - __asm__ volatile ("ldr r0,%0\n\tmov " REG_FP ",r0" : : "m" (fp) : "r0"); + __asm__ volatile ("ldr r0,%1\n\tmov " REG_FP ",r0\n\tmov %0, #0" : "=r" (result) : "m" (fp) : "r0"); __asm__ volatile ("" : : : REGS_TO_SAVE); - return 0; + return result; } #endif
\ No newline at end of file |