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.
This commit is contained in:
Max Filippov 2020-06-06 05:06:04 -07:00
parent df2c0060e5
commit 1d9921cbdc
3 changed files with 108 additions and 24 deletions

View File

@ -0,0 +1,43 @@
/* { dg-do run } */
extern "C" void abort(void);
extern "C" void __xtensa_libgcc_window_spill(void);
static int call;
static int cnt;
extern "C" void *memcpy(void *dst, const void *src, unsigned int sz)
{
char *a = (char *)dst;
const char *b = (const char *)src;
if (call++ == cnt)
__xtensa_libgcc_window_spill();
while (sz--)
*a++ = *b++;
return dst;
}
int main()
{
int i;
for (i = 0; i < 100; ++i)
{
call = 0;
cnt = i;
try
{
throw 1;
}
catch (int v)
{
if (v != 1)
abort ();
}
}
return 0;
}

View File

@ -0,0 +1,43 @@
# Specific regression driver for Xtensa.
# Copyright (C) 2020 Free Software Foundation, Inc.
#
# This file is part of GCC.
#
# GCC is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GCC is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>. */
# GCC testsuite that uses the `dg.exp' driver.
# Exit immediately if this isn't an Xtensa target.
if {![istarget xtensa*-*-*] } then {
return
}
# Load support procs.
load_lib g++-dg.exp
global DEFAULT_CXXFLAGS
if ![info exists DEFAULT_CXXFLAGS] then {
set DEFAULT_CXXFLAGS " -pedantic-errors"
}
# Initialize `dg'.
dg-init
# Main loop.
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] \
"" $DEFAULT_CXXFLAGS
# All done.
dg-finish

View File

@ -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)
{