mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
SVE unwinding
This patch adds support for unwinding frames that use the SVE pseudo VG register. We want this register to act like a normal register if the CFI explicitly sets it, but want to provide a default value otherwise. Computing the default value requires an SVE target, so we only want to compute it on demand. aarch64_vg uses a hard-coded .inst in order to avoid a build dependency on binutils 2.28 or later. 2018-01-13 Richard Sandiford <richard.sandiford@linaro.org> gcc/ * doc/tm.texi.in (DWARF_LAZY_REGISTER_VALUE): Document. * doc/tm.texi: Regenerate. libgcc/ * config/aarch64/value-unwind.h (aarch64_vg): New function. (DWARF_LAZY_REGISTER_VALUE): Define. * unwind-dw2.c (_Unwind_GetGR): Use DWARF_LAZY_REGISTER_VALUE to provide a fallback register value. gcc/testsuite/ * g++.target/aarch64/sve/aarch64-sve.exp: New harness. * g++.target/aarch64/sve/catch_1.C: New test. * g++.target/aarch64/sve/catch_2.C: Likewise. * g++.target/aarch64/sve/catch_3.C: Likewise. * g++.target/aarch64/sve/catch_4.C: Likewise. * g++.target/aarch64/sve/catch_5.C: Likewise. * g++.target/aarch64/sve/catch_6.C: Likewise. Reviewed-by: James Greenhalgh <james.greenhalgh@arm.com> From-SVN: r256615
This commit is contained in:
parent
825b856cd0
commit
dbc3af4fc6
@ -1,3 +1,8 @@
|
||||
2018-01-13 Richard Sandiford <richard.sandiford@linaro.org>
|
||||
|
||||
* doc/tm.texi.in (DWARF_LAZY_REGISTER_VALUE): Document.
|
||||
* doc/tm.texi: Regenerate.
|
||||
|
||||
2018-01-13 Richard Sandiford <richard.sandiford@linaro.org>
|
||||
Alan Hayward <alan.hayward@arm.com>
|
||||
David Sherwood <david.sherwood@arm.com>
|
||||
|
@ -3621,6 +3621,13 @@ defined and 0 otherwise.
|
||||
|
||||
@end defmac
|
||||
|
||||
@defmac DWARF_LAZY_REGISTER_VALUE (@var{regno}, @var{value})
|
||||
Define this macro if the target has pseudo DWARF registers whose
|
||||
values need to be computed lazily on demand by the unwinder (such as when
|
||||
referenced in a CFA expression). The macro returns true if @var{regno}
|
||||
is such a register and stores its value in @samp{*@var{value}} if so.
|
||||
@end defmac
|
||||
|
||||
@node Elimination
|
||||
@subsection Eliminating Frame Pointer and Arg Pointer
|
||||
|
||||
|
@ -3002,6 +3002,13 @@ defined and 0 otherwise.
|
||||
|
||||
@end defmac
|
||||
|
||||
@defmac DWARF_LAZY_REGISTER_VALUE (@var{regno}, @var{value})
|
||||
Define this macro if the target has pseudo DWARF registers whose
|
||||
values need to be computed lazily on demand by the unwinder (such as when
|
||||
referenced in a CFA expression). The macro returns true if @var{regno}
|
||||
is such a register and stores its value in @samp{*@var{value}} if so.
|
||||
@end defmac
|
||||
|
||||
@node Elimination
|
||||
@subsection Eliminating Frame Pointer and Arg Pointer
|
||||
|
||||
|
@ -1,3 +1,13 @@
|
||||
2018-01-13 Richard Sandiford <richard.sandiford@linaro.org>
|
||||
|
||||
* g++.target/aarch64/sve/aarch64-sve.exp: New harness.
|
||||
* g++.target/aarch64/sve/catch_1.C: New test.
|
||||
* g++.target/aarch64/sve/catch_2.C: Likewise.
|
||||
* g++.target/aarch64/sve/catch_3.C: Likewise.
|
||||
* g++.target/aarch64/sve/catch_4.C: Likewise.
|
||||
* g++.target/aarch64/sve/catch_5.C: Likewise.
|
||||
* g++.target/aarch64/sve/catch_6.C: Likewise.
|
||||
|
||||
2018-01-13 Richard Sandiford <richard.sandiford@linaro.org>
|
||||
Alan Hayward <alan.hayward@arm.com>
|
||||
David Sherwood <david.sherwood@arm.com>
|
||||
|
45
gcc/testsuite/g++.target/aarch64/sve/aarch64-sve.exp
Normal file
45
gcc/testsuite/g++.target/aarch64/sve/aarch64-sve.exp
Normal file
@ -0,0 +1,45 @@
|
||||
# Specific regression driver for AArch64.
|
||||
# Copyright (C) 2009-2017 Free Software Foundation, Inc.
|
||||
# Contributed by ARM Ltd.
|
||||
#
|
||||
# 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 AArch64 target.
|
||||
if {![istarget aarch64*-*-*] } then {
|
||||
return
|
||||
}
|
||||
|
||||
# Load support procs.
|
||||
load_lib g++-dg.exp
|
||||
|
||||
# Initialize `dg'.
|
||||
dg-init
|
||||
|
||||
# Force SVE if we're not testing it already.
|
||||
if { [check_effective_target_aarch64_sve] } {
|
||||
set sve_flags ""
|
||||
} else {
|
||||
set sve_flags "-march=armv8.2-a+sve"
|
||||
}
|
||||
|
||||
# Main loop.
|
||||
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] $sve_flags ""
|
||||
|
||||
# All done.
|
||||
dg-finish
|
69
gcc/testsuite/g++.target/aarch64/sve/catch_1.C
Normal file
69
gcc/testsuite/g++.target/aarch64/sve/catch_1.C
Normal file
@ -0,0 +1,69 @@
|
||||
/* { dg-do run { target aarch64_sve_hw } } */
|
||||
/* { dg-options "-O3 -fopenmp-simd -fno-omit-frame-pointer" } */
|
||||
|
||||
/* Invoke X (P##n) for n in [0, 7]. */
|
||||
#define REPEAT8(X, P) \
|
||||
X (P##0) X (P##1) X (P##2) X (P##3) X (P##4) X (P##5) X (P##6) X (P##7)
|
||||
|
||||
/* Invoke X (n) for all octal n in [0, 39]. */
|
||||
#define REPEAT40(X) \
|
||||
REPEAT8 (X, 0) REPEAT8 (X, 1) REPEAT8 (X, 2) REPEAT8 (X, 3) REPEAT8 (X, 4)
|
||||
|
||||
volatile int testi;
|
||||
|
||||
/* Throw to f3. */
|
||||
void __attribute__ ((weak))
|
||||
f1 (int x[40][100], int *y)
|
||||
{
|
||||
/* A wild write to x and y. */
|
||||
asm volatile ("" ::: "memory");
|
||||
if (y[testi] == x[testi][testi])
|
||||
throw 100;
|
||||
}
|
||||
|
||||
/* Expect vector work to be done, with spilling of vector registers. */
|
||||
void __attribute__ ((weak))
|
||||
f2 (int x[40][100], int *y)
|
||||
{
|
||||
/* Try to force some spilling. */
|
||||
#define DECLARE(N) int y##N = y[N];
|
||||
REPEAT40 (DECLARE);
|
||||
for (int j = 0; j < 20; ++j)
|
||||
{
|
||||
f1 (x, y);
|
||||
#pragma omp simd
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
#define INC(N) x[N][i] += y##N;
|
||||
REPEAT40 (INC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Catch an exception thrown from f1, via f2. */
|
||||
void __attribute__ ((weak))
|
||||
f3 (int x[40][100], int *y, int *z)
|
||||
{
|
||||
volatile int extra = 111;
|
||||
try
|
||||
{
|
||||
f2 (x, y);
|
||||
}
|
||||
catch (int val)
|
||||
{
|
||||
*z = val + extra;
|
||||
}
|
||||
}
|
||||
|
||||
static int x[40][100];
|
||||
static int y[40];
|
||||
static int z;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f3 (x, y, &z);
|
||||
if (z != 211)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
4
gcc/testsuite/g++.target/aarch64/sve/catch_2.C
Normal file
4
gcc/testsuite/g++.target/aarch64/sve/catch_2.C
Normal file
@ -0,0 +1,4 @@
|
||||
/* { dg-do run { target aarch64_sve_hw } } */
|
||||
/* { dg-options "-O3 -fopenmp-simd -fomit-frame-pointer" } */
|
||||
|
||||
#include "catch_1.C"
|
78
gcc/testsuite/g++.target/aarch64/sve/catch_3.C
Normal file
78
gcc/testsuite/g++.target/aarch64/sve/catch_3.C
Normal file
@ -0,0 +1,78 @@
|
||||
/* { dg-do run { target aarch64_sve_hw } } */
|
||||
/* { dg-options "-O3 -fopenmp-simd -fno-omit-frame-pointer" } */
|
||||
|
||||
/* Invoke X (P##n) for n in [0, 7]. */
|
||||
#define REPEAT8(X, P) \
|
||||
X (P##0) X (P##1) X (P##2) X (P##3) X (P##4) X (P##5) X (P##6) X (P##7)
|
||||
|
||||
/* Invoke X (n) for all octal n in [0, 39]. */
|
||||
#define REPEAT40(X) \
|
||||
REPEAT8 (X, 0) REPEAT8 (X, 1) REPEAT8 (X, 2) REPEAT8 (X, 3) REPEAT8 (X, 4)
|
||||
|
||||
volatile int testi, sink;
|
||||
|
||||
/* Take 2 stack arguments and throw to f3. */
|
||||
void __attribute__ ((weak))
|
||||
f1 (int x[40][100], int *y, int z1, int z2, int z3, int z4,
|
||||
int z5, int z6, int z7, int z8)
|
||||
{
|
||||
/* A wild write to x and y. */
|
||||
sink = z1;
|
||||
sink = z2;
|
||||
sink = z3;
|
||||
sink = z4;
|
||||
sink = z5;
|
||||
sink = z6;
|
||||
sink = z7;
|
||||
sink = z8;
|
||||
asm volatile ("" ::: "memory");
|
||||
if (y[testi] == x[testi][testi])
|
||||
throw 100;
|
||||
}
|
||||
|
||||
/* Expect vector work to be done, with spilling of vector registers. */
|
||||
void __attribute__ ((weak))
|
||||
f2 (int x[40][100], int *y)
|
||||
{
|
||||
/* Try to force some spilling. */
|
||||
#define DECLARE(N) int y##N = y[N];
|
||||
REPEAT40 (DECLARE);
|
||||
for (int j = 0; j < 20; ++j)
|
||||
{
|
||||
f1 (x, y, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
#pragma omp simd
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
#define INC(N) x[N][i] += y##N;
|
||||
REPEAT40 (INC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Catch an exception thrown from f1, via f2. */
|
||||
void __attribute__ ((weak))
|
||||
f3 (int x[40][100], int *y, int *z)
|
||||
{
|
||||
volatile int extra = 111;
|
||||
try
|
||||
{
|
||||
f2 (x, y);
|
||||
}
|
||||
catch (int val)
|
||||
{
|
||||
*z = val + extra;
|
||||
}
|
||||
}
|
||||
|
||||
static int x[40][100];
|
||||
static int y[40];
|
||||
static int z;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f3 (x, y, &z);
|
||||
if (z != 211)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
4
gcc/testsuite/g++.target/aarch64/sve/catch_4.C
Normal file
4
gcc/testsuite/g++.target/aarch64/sve/catch_4.C
Normal file
@ -0,0 +1,4 @@
|
||||
/* { dg-do run { target aarch64_sve_hw } } */
|
||||
/* { dg-options "-O3 -fopenmp-simd -fomit-frame-pointer" } */
|
||||
|
||||
#include "catch_3.C"
|
81
gcc/testsuite/g++.target/aarch64/sve/catch_5.C
Normal file
81
gcc/testsuite/g++.target/aarch64/sve/catch_5.C
Normal file
@ -0,0 +1,81 @@
|
||||
/* { dg-do run { target aarch64_sve_hw } } */
|
||||
/* { dg-options "-O3 -fopenmp-simd -fno-omit-frame-pointer" } */
|
||||
|
||||
/* Invoke X (P##n) for n in [0, 7]. */
|
||||
#define REPEAT8(X, P) \
|
||||
X (P##0) X (P##1) X (P##2) X (P##3) X (P##4) X (P##5) X (P##6) X (P##7)
|
||||
|
||||
/* Invoke X (n) for all octal n in [0, 39]. */
|
||||
#define REPEAT40(X) \
|
||||
REPEAT8 (X, 0) REPEAT8 (X, 1) REPEAT8 (X, 2) REPEAT8 (X, 3) REPEAT8 (X, 4)
|
||||
|
||||
volatile int testi, sink;
|
||||
volatile void *ptr;
|
||||
|
||||
/* Take 2 stack arguments and throw to f3. */
|
||||
void __attribute__ ((weak))
|
||||
f1 (int x[40][100], int *y, int z1, int z2, int z3, int z4,
|
||||
int z5, int z6, int z7, int z8)
|
||||
{
|
||||
/* A wild write to x and y. */
|
||||
sink = z1;
|
||||
sink = z2;
|
||||
sink = z3;
|
||||
sink = z4;
|
||||
sink = z5;
|
||||
sink = z6;
|
||||
sink = z7;
|
||||
sink = z8;
|
||||
asm volatile ("" ::: "memory");
|
||||
if (y[testi] == x[testi][testi])
|
||||
throw 100;
|
||||
}
|
||||
|
||||
/* Expect vector work to be done, with spilling of vector registers. */
|
||||
void __attribute__ ((weak))
|
||||
f2 (int x[40][100], int *y)
|
||||
{
|
||||
/* Create a true variable-sized frame. */
|
||||
ptr = __builtin_alloca (testi + 40);
|
||||
/* Try to force some spilling. */
|
||||
#define DECLARE(N) int y##N = y[N];
|
||||
REPEAT40 (DECLARE);
|
||||
for (int j = 0; j < 20; ++j)
|
||||
{
|
||||
f1 (x, y, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
#pragma omp simd
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
#define INC(N) x[N][i] += y##N;
|
||||
REPEAT40 (INC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Catch an exception thrown from f1, via f2. */
|
||||
void __attribute__ ((weak))
|
||||
f3 (int x[40][100], int *y, int *z)
|
||||
{
|
||||
volatile int extra = 111;
|
||||
try
|
||||
{
|
||||
f2 (x, y);
|
||||
}
|
||||
catch (int val)
|
||||
{
|
||||
*z = val + extra;
|
||||
}
|
||||
}
|
||||
|
||||
static int x[40][100];
|
||||
static int y[40];
|
||||
static int z;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f3 (x, y, &z);
|
||||
if (z != 211)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
4
gcc/testsuite/g++.target/aarch64/sve/catch_6.C
Normal file
4
gcc/testsuite/g++.target/aarch64/sve/catch_6.C
Normal file
@ -0,0 +1,4 @@
|
||||
/* { dg-do run { target aarch64_sve_hw } } */
|
||||
/* { dg-options "-O3 -fopenmp-simd -fomit-frame-pointer" } */
|
||||
|
||||
#include "catch_5.C"
|
@ -1,3 +1,10 @@
|
||||
2018-01-13 Richard Sandiford <richard.sandiford@linaro.org>
|
||||
|
||||
* config/aarch64/value-unwind.h (aarch64_vg): New function.
|
||||
(DWARF_LAZY_REGISTER_VALUE): Define.
|
||||
* unwind-dw2.c (_Unwind_GetGR): Use DWARF_LAZY_REGISTER_VALUE
|
||||
to provide a fallback register value.
|
||||
|
||||
2018-01-08 Michael Meissner <meissner@linux.vnet.ibm.com>
|
||||
|
||||
* config/rs6000/quad-float128.h (IBM128_TYPE): Explicitly use
|
||||
|
@ -23,3 +23,19 @@
|
||||
#if defined __aarch64__ && !defined __LP64__
|
||||
# define REG_VALUE_IN_UNWIND_CONTEXT
|
||||
#endif
|
||||
|
||||
/* Return the value of the pseudo VG register. This should only be
|
||||
called if we know this is an SVE host. */
|
||||
static inline int
|
||||
aarch64_vg (void)
|
||||
{
|
||||
register int vg asm ("x0");
|
||||
/* CNTD X0. */
|
||||
asm (".inst 0x04e0e3e0" : "=r" (vg));
|
||||
return vg;
|
||||
}
|
||||
|
||||
/* Lazily provide a value for VG, so that we don't try to execute SVE
|
||||
instructions unless we know they're needed. */
|
||||
#define DWARF_LAZY_REGISTER_VALUE(REGNO, VALUE) \
|
||||
((REGNO) == AARCH64_DWARF_VG && ((*VALUE) = aarch64_vg (), 1))
|
||||
|
@ -216,12 +216,12 @@ _Unwind_IsExtendedContext (struct _Unwind_Context *context)
|
||||
|| (context->flags & EXTENDED_CONTEXT_BIT));
|
||||
}
|
||||
|
||||
/* Get the value of register INDEX as saved in CONTEXT. */
|
||||
/* Get the value of register REGNO as saved in CONTEXT. */
|
||||
|
||||
inline _Unwind_Word
|
||||
_Unwind_GetGR (struct _Unwind_Context *context, int index)
|
||||
_Unwind_GetGR (struct _Unwind_Context *context, int regno)
|
||||
{
|
||||
int size;
|
||||
int size, index;
|
||||
_Unwind_Context_Reg_Val val;
|
||||
|
||||
#ifdef DWARF_ZERO_REG
|
||||
@ -229,7 +229,7 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
index = DWARF_REG_TO_UNWIND_COLUMN (index);
|
||||
index = DWARF_REG_TO_UNWIND_COLUMN (regno);
|
||||
gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
|
||||
size = dwarf_reg_size_table[index];
|
||||
val = context->reg[index];
|
||||
@ -237,6 +237,14 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index)
|
||||
if (_Unwind_IsExtendedContext (context) && context->by_value[index])
|
||||
return _Unwind_Get_Unwind_Word (val);
|
||||
|
||||
#ifdef DWARF_LAZY_REGISTER_VALUE
|
||||
{
|
||||
_Unwind_Word value;
|
||||
if (DWARF_LAZY_REGISTER_VALUE (regno, &value))
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This will segfault if the register hasn't been saved. */
|
||||
if (size == sizeof(_Unwind_Ptr))
|
||||
return * (_Unwind_Ptr *) (_Unwind_Internal_Ptr) val;
|
||||
|
Loading…
Reference in New Issue
Block a user