diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2020-06-06 05:06:04 -0700 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2020-06-08 18:30:07 -0700 |
commit | 1d9921cbdc732e1a7fc66b9c24a6dfa9625bd4c0 (patch) | |
tree | 60b219c10241be1e2f0c7bc32e7154074cc2074a /libgcc | |
parent | df2c0060e5d1e0a37001b93f36e9245bb75ef33b (diff) | |
download | gcc-1d9921cbdc732e1a7fc66b9c24a6dfa9625bd4c0.zip gcc-1d9921cbdc732e1a7fc66b9c24a6dfa9625bd4c0.tar.gz gcc-1d9921cbdc732e1a7fc66b9c24a6dfa9625bd4c0.tar.bz2 |
xtensa: libgcc: fix PR target/95571
Rewrite uw_install_context without function calls to avoid register
spilling in _Unwind_RaiseException during return context installation.
2020-06-08 Max Filippov <jcmvbkbc@gmail.com>
gcc/testsuite/
* g++.target/xtensa/pr95571.C: New test.
* g++.target/xtensa/xtensa.exp: New testsuite.
libgcc/
* config/xtensa/unwind-dw2-xtensa.c (uw_install_context): Merge
with uw_install_context_1.
Diffstat (limited to 'libgcc')
-rw-r--r-- | libgcc/config/xtensa/unwind-dw2-xtensa.c | 46 |
1 files changed, 22 insertions, 24 deletions
diff --git a/libgcc/config/xtensa/unwind-dw2-xtensa.c b/libgcc/config/xtensa/unwind-dw2-xtensa.c index 056182a..8a6a44a 100644 --- a/libgcc/config/xtensa/unwind-dw2-xtensa.c +++ b/libgcc/config/xtensa/unwind-dw2-xtensa.c @@ -481,37 +481,35 @@ uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa, /* Install TARGET into CURRENT so that we can return to it. This is a macro because __builtin_eh_return must be invoked in the context of - our caller. */ + our caller, and also because spilling registers of the caller before + the context installation may result in reload of wrong register values + after the context installation due to the change of the stack pointer + in the base save area. This spilling may be caused by an interrupt + handler on baremetal host. */ -#define uw_install_context(CURRENT, TARGET, FRAMES) \ +#define uw_install_context(CURRENT, TARGET, FRAMES) \ do \ { \ - long offset = uw_install_context_1 ((CURRENT), (TARGET)); \ void *handler = __builtin_frob_return_addr ((TARGET)->ra); \ - __builtin_eh_return (offset, handler); \ + long i; \ + \ + /* The eh_return insn assumes a window size of 8, so don't bother \ + copying the save areas for registers a8-a15 since they won't be \ + reloaded. */ \ + for (i = 0; i < 2; ++i) \ + { \ + _Unwind_Word *c = (CURRENT)->reg[i]; \ + _Unwind_Word *t = (TARGET)->reg[i]; \ + int j; \ + \ + if (t && c && t != c) \ + for (j = 0; j < 4; ++j) \ + *c++ = *t++; \ + } \ + __builtin_eh_return (0, handler); \ } \ while (0) -static long -uw_install_context_1 (struct _Unwind_Context *current, - struct _Unwind_Context *target) -{ - long i; - - /* The eh_return insn assumes a window size of 8, so don't bother copying - the save areas for registers a8-a15 since they won't be reloaded. */ - for (i = 0; i < 2; ++i) - { - void *c = current->reg[i]; - void *t = target->reg[i]; - - if (t && c && t != c) - memcpy (c, t, 4 * sizeof (_Unwind_Word)); - } - - return 0; -} - static inline _Unwind_Ptr uw_identify_context (struct _Unwind_Context *context) { |