From 6eb065e62cab6df886f8e0192f8cd3153772642a Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Tue, 13 Nov 2007 22:41:50 +0000 Subject: [PATCH] unwind-dw2-xtensa.c: New. * config/xtensa/unwind-dw2-xtensa.c: New. * config/xtensa/unwind-dw2-xtensa.h: New. * config/xtensa/xtensa.h (MUST_USE_SJLJ_EXCEPTIONS): Remove. (DWARF2_UNWIND_INFO): Remove. (DWARF_FRAME_REGISTERS): Define. (EH_RETURN_DATA_REGNO): Define. * config/xtensa/xtensa.md (UNSPECV_EH_RETURN): Define. (eh_return): New. * config/xtensa/t-xtensa (LIB2ADDEH): Define. Co-Authored-By: Bob Wilson From-SVN: r130160 --- gcc/ChangeLog | 13 + gcc/config/xtensa/t-xtensa | 2 + gcc/config/xtensa/unwind-dw2-xtensa.c | 546 ++++++++++++++++++++++++++ gcc/config/xtensa/unwind-dw2-xtensa.h | 57 +++ gcc/config/xtensa/xtensa.h | 11 +- gcc/config/xtensa/xtensa.md | 21 + 6 files changed, 646 insertions(+), 4 deletions(-) create mode 100644 gcc/config/xtensa/unwind-dw2-xtensa.c create mode 100644 gcc/config/xtensa/unwind-dw2-xtensa.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b3bac1f53af..d4517ad5646 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2007-11-13 Sterling Augustine + Bob Wilson + + * config/xtensa/unwind-dw2-xtensa.c: New. + * config/xtensa/unwind-dw2-xtensa.h: New. + * config/xtensa/xtensa.h (MUST_USE_SJLJ_EXCEPTIONS): Remove. + (DWARF2_UNWIND_INFO): Remove. + (DWARF_FRAME_REGISTERS): Define. + (EH_RETURN_DATA_REGNO): Define. + * config/xtensa/xtensa.md (UNSPECV_EH_RETURN): Define. + (eh_return): New. + * config/xtensa/t-xtensa (LIB2ADDEH): Define. + 2007-11-13 Jakub Jelinek * doc/invoke.texi: Fix description of -fsched-stalled-insns=0, diff --git a/gcc/config/xtensa/t-xtensa b/gcc/config/xtensa/t-xtensa index 5db4f7c66ce..b0a7e8115e4 100644 --- a/gcc/config/xtensa/t-xtensa +++ b/gcc/config/xtensa/t-xtensa @@ -11,6 +11,8 @@ LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3 _udivsi3 _umodsi3 \ _truncdfsf2 _extendsfdf2 LIB2FUNCS_EXTRA = $(srcdir)/config/xtensa/lib2funcs.S +LIB2ADDEH = $(srcdir)/config/xtensa/unwind-dw2-xtensa.c \ + $(srcdir)/unwind-dw2-fde.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c $(T)crti.o: $(srcdir)/config/xtensa/crti.asm $(GCC_PASSES) $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ diff --git a/gcc/config/xtensa/unwind-dw2-xtensa.c b/gcc/config/xtensa/unwind-dw2-xtensa.c new file mode 100644 index 00000000000..1dd4f9dee3f --- /dev/null +++ b/gcc/config/xtensa/unwind-dw2-xtensa.c @@ -0,0 +1,546 @@ +/* DWARF2 exception handling and frame unwinding for Xtensa. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007 + 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 2, or (at your option) + any later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + 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 COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "dwarf2.h" +#include "unwind.h" +#ifdef __USING_SJLJ_EXCEPTIONS__ +# define NO_SIZE_OF_ENCODED_VALUE +#endif +#include "unwind-pe.h" +#include "unwind-dw2-fde.h" +#include "unwind-dw2-xtensa.h" + +#ifndef __USING_SJLJ_EXCEPTIONS__ + +/* The standard CIE and FDE structures work fine for Xtensa but the + variable-size register window save areas are not a good fit for the rest + of the standard DWARF unwinding mechanism. Nor is that mechanism + necessary, since the register save areas are always in fixed locations + in each stack frame. This file is a stripped down and customized version + of the standard DWARF unwinding code. It needs to be customized to have + builtin logic for finding the save areas and also to track the stack + pointer value (besides the CFA) while unwinding since the primary save + area is located below the stack pointer. It is stripped down to reduce + code size and ease the maintenance burden of tracking changes in the + standard version of the code. */ + +#ifndef DWARF_REG_TO_UNWIND_COLUMN +#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO) +#endif + +#define XTENSA_RA_FIELD_MASK 0x3FFFFFFF + +/* This is the register and unwind state for a particular frame. This + provides the information necessary to unwind up past a frame and return + to its caller. */ +struct _Unwind_Context +{ + /* Track register window save areas of 4 registers each, instead of + keeping separate addresses for the individual registers. */ + _Unwind_Word *reg[4]; + + void *cfa; + void *sp; + void *ra; + + /* Cache the 2 high bits to replace the window size in return addresses. */ + _Unwind_Word ra_high_bits; + + void *lsda; + struct dwarf_eh_bases bases; + /* Signal frame context. */ +#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1) + _Unwind_Word flags; + /* 0 for now, can be increased when further fields are added to + struct _Unwind_Context. */ + _Unwind_Word version; +}; + + +/* Read unaligned data from the instruction buffer. */ + +union unaligned +{ + void *p; +} __attribute__ ((packed)); + +static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *); +static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *, + _Unwind_FrameState *); + +static inline void * +read_pointer (const void *p) { const union unaligned *up = p; return up->p; } + +static inline _Unwind_Word +_Unwind_IsSignalFrame (struct _Unwind_Context *context) +{ + return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0; +} + +static inline void +_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val) +{ + if (val) + context->flags |= SIGNAL_FRAME_BIT; + else + context->flags &= ~SIGNAL_FRAME_BIT; +} + +/* Get the value of register INDEX as saved in CONTEXT. */ + +inline _Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *context, int index) +{ + _Unwind_Word *ptr; + + index = DWARF_REG_TO_UNWIND_COLUMN (index); + ptr = context->reg[index >> 2] + (index & 3); + + return *ptr; +} + +/* Get the value of the CFA as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->cfa; +} + +/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ + +inline void +_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) +{ + _Unwind_Word *ptr; + + index = DWARF_REG_TO_UNWIND_COLUMN (index); + ptr = context->reg[index >> 2] + (index & 3); + + *ptr = val; +} + +/* Retrieve the return address for CONTEXT. */ + +inline _Unwind_Ptr +_Unwind_GetIP (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->ra; +} + +/* Retrieve the return address and flag whether that IP is before + or after first not yet fully executed instruction. */ + +inline _Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = _Unwind_IsSignalFrame (context); + return (_Unwind_Ptr) context->ra; +} + +/* Overwrite the return address for CONTEXT with VAL. */ + +inline void +_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) +{ + context->ra = (void *) val; +} + +void * +_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) +{ + return context->lsda; +} + +_Unwind_Ptr +_Unwind_GetRegionStart (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->bases.func; +} + +void * +_Unwind_FindEnclosingFunction (void *pc) +{ + struct dwarf_eh_bases bases; + const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); + if (fde) + return bases.func; + else + return NULL; +} + +_Unwind_Ptr +_Unwind_GetDataRelBase (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->bases.dbase; +} + +_Unwind_Ptr +_Unwind_GetTextRelBase (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->bases.tbase; +} + +#ifdef MD_UNWIND_SUPPORT +#include MD_UNWIND_SUPPORT +#endif + +/* Extract any interesting information from the CIE for the translation + unit F belongs to. Return a pointer to the byte after the augmentation, + or NULL if we encountered an undecipherable augmentation. */ + +static const unsigned char * +extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + const unsigned char *aug = cie->augmentation; + const unsigned char *p = aug + strlen ((const char *)aug) + 1; + const unsigned char *ret = NULL; + _uleb128_t utmp; + _sleb128_t stmp; + + /* g++ v2 "eh" has pointer immediately following augmentation string, + so it must be handled first. */ + if (aug[0] == 'e' && aug[1] == 'h') + { + fs->eh_ptr = read_pointer (p); + p += sizeof (void *); + aug += 2; + } + + /* Immediately following the augmentation are the code and + data alignment and return address column. */ + p = read_uleb128 (p, &utmp); + p = read_sleb128 (p, &stmp); + if (cie->version == 1) + fs->retaddr_column = *p++; + else + { + p = read_uleb128 (p, &utmp); + fs->retaddr_column = (_Unwind_Word)utmp; + } + fs->lsda_encoding = DW_EH_PE_omit; + + /* If the augmentation starts with 'z', then a uleb128 immediately + follows containing the length of the augmentation field following + the size. */ + if (*aug == 'z') + { + p = read_uleb128 (p, &utmp); + ret = p + utmp; + + fs->saw_z = 1; + ++aug; + } + + /* Iterate over recognized augmentation subsequences. */ + while (*aug != '\0') + { + /* "L" indicates a byte showing how the LSDA pointer is encoded. */ + if (aug[0] == 'L') + { + fs->lsda_encoding = *p++; + aug += 1; + } + + /* "R" indicates a byte indicating how FDE addresses are encoded. */ + else if (aug[0] == 'R') + { + fs->fde_encoding = *p++; + aug += 1; + } + + /* "P" indicates a personality routine in the CIE augmentation. */ + else if (aug[0] == 'P') + { + _Unwind_Ptr personality; + + p = read_encoded_value (context, *p, p + 1, &personality); + fs->personality = (_Unwind_Personality_Fn) personality; + aug += 1; + } + + /* "S" indicates a signal frame. */ + else if (aug[0] == 'S') + { + fs->signal_frame = 1; + aug += 1; + } + + /* Otherwise we have an unknown augmentation string. + Bail unless we saw a 'z' prefix. */ + else + return ret; + } + + return ret ? ret : p; +} + +/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for + its caller and decode it into FS. This function also sets the + lsda member of CONTEXT, as it is really information + about the caller's frame. */ + +static _Unwind_Reason_Code +uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + const struct dwarf_fde *fde; + const struct dwarf_cie *cie; + const unsigned char *aug; + int window_size; + _Unwind_Word *ra_ptr; + + memset (fs, 0, sizeof (*fs)); + context->lsda = 0; + + ra_ptr = context->reg[0]; + if (ra_ptr && *ra_ptr == 0) + return _URC_END_OF_STACK; + + fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1, + &context->bases); + if (fde == NULL) + { +#ifdef MD_FALLBACK_FRAME_STATE_FOR + _Unwind_Reason_Code reason; + /* Couldn't find frame unwind info for this function. Try a + target-specific fallback mechanism. This will necessarily + not provide a personality routine or LSDA. */ + reason = MD_FALLBACK_FRAME_STATE_FOR (context, fs); + if (reason != _URC_END_OF_STACK) + return reason; + /* The frame was not recognized and handled by the fallback function, + but it is not really the end of the stack. Fall through here and + unwind it anyway. */ +#endif + fs->pc = context->ra; + } + else + { + fs->pc = context->bases.func; + + cie = get_cie (fde); + if (extract_cie_info (cie, context, fs) == NULL) + /* CIE contained unknown augmentation. */ + return _URC_FATAL_PHASE1_ERROR; + + /* Locate augmentation for the fde. */ + aug = (const unsigned char *) fde + sizeof (*fde); + aug += 2 * size_of_encoded_value (fs->fde_encoding); + if (fs->saw_z) + { + _uleb128_t i; + aug = read_uleb128 (aug, &i); + } + if (fs->lsda_encoding != DW_EH_PE_omit) + { + _Unwind_Ptr lsda; + + aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda); + context->lsda = (void *) lsda; + } + } + + /* Find the window size from the high bits of the return address. */ + if (ra_ptr) + window_size = (*ra_ptr >> 30) * 4; + else + window_size = 8; + + fs->retaddr_column = window_size; + + return _URC_NO_REASON; +} + +static void +uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + struct _Unwind_Context orig_context = *context; + _Unwind_Word *sp, *cfa, *next_cfa; + int i; + + if (fs->signal_frame) + { + cfa = (_Unwind_Word *) fs->signal_regs[1]; + next_cfa = (_Unwind_Word *) cfa[-3]; + + for (i = 0; i < 4; i++) + context->reg[i] = fs->signal_regs + (i << 2); + } + else + { + int window_size = fs->retaddr_column >> 2; + + sp = (_Unwind_Word *) orig_context.sp; + cfa = (_Unwind_Word *) orig_context.cfa; + next_cfa = (_Unwind_Word *) cfa[-3]; + + /* Registers a0-a3 are in the save area below sp. */ + context->reg[0] = sp - 4; + + /* Find the extra save area below next_cfa. */ + for (i = 1; i < window_size; i++) + context->reg[i] = next_cfa - 4 * (1 + window_size - i); + + /* Remaining registers rotate from previous save areas. */ + for (i = window_size; i < 4; i++) + context->reg[i] = orig_context.reg[i - window_size]; + } + + context->sp = cfa; + context->cfa = next_cfa; + + _Unwind_SetSignalFrame (context, fs->signal_frame); +} + +/* CONTEXT describes the unwind state for a frame, and FS describes the FDE + of its caller. Update CONTEXT to refer to the caller as well. Note + that the lsda member is not updated here, but later in + uw_frame_state_for. */ + +static void +uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + uw_update_context_1 (context, fs); + + /* Compute the return address now, since the return address column + can change from frame to frame. */ + context->ra = (void *) ((_Unwind_GetGR (context, fs->retaddr_column) + & XTENSA_RA_FIELD_MASK) | context->ra_high_bits); +} + +static void +uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + uw_update_context (context, fs); +} + +/* Fill in CONTEXT for top-of-stack. The only valid registers at this + level will be the return address and the CFA. */ + +#define uw_init_context(CONTEXT) \ + do \ + { \ + __builtin_unwind_init (); \ + uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \ + __builtin_return_address (0)); \ + } \ + while (0) + +static void +uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa, + void *outer_ra) +{ + void *ra = __builtin_return_address (0); + void *cfa = __builtin_dwarf_cfa (); + _Unwind_FrameState fs; + + memset (context, 0, sizeof (struct _Unwind_Context)); + context->ra = ra; + + memset (&fs, 0, sizeof (fs)); + fs.retaddr_column = 8; + context->sp = cfa; + context->cfa = outer_cfa; + context->ra_high_bits = + ((_Unwind_Word) uw_init_context_1) & ~XTENSA_RA_FIELD_MASK; + uw_update_context_1 (context, &fs); + + context->ra = outer_ra; +} + + +/* 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. */ + +#define uw_install_context(CURRENT, TARGET) \ + do \ + { \ + long offset = uw_install_context_1 ((CURRENT), (TARGET)); \ + void *handler = __builtin_frob_return_addr ((TARGET)->ra); \ + __builtin_eh_return (offset, 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) +{ + return _Unwind_GetCFA (context); +} + + +#include "unwind.inc" + +#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) +alias (_Unwind_Backtrace); +alias (_Unwind_DeleteException); +alias (_Unwind_FindEnclosingFunction); +alias (_Unwind_ForcedUnwind); +alias (_Unwind_GetDataRelBase); +alias (_Unwind_GetTextRelBase); +alias (_Unwind_GetCFA); +alias (_Unwind_GetGR); +alias (_Unwind_GetIP); +alias (_Unwind_GetLanguageSpecificData); +alias (_Unwind_GetRegionStart); +alias (_Unwind_RaiseException); +alias (_Unwind_Resume); +alias (_Unwind_Resume_or_Rethrow); +alias (_Unwind_SetGR); +alias (_Unwind_SetIP); +#endif + +#endif /* !USING_SJLJ_EXCEPTIONS */ diff --git a/gcc/config/xtensa/unwind-dw2-xtensa.h b/gcc/config/xtensa/unwind-dw2-xtensa.h new file mode 100644 index 00000000000..99341172eac --- /dev/null +++ b/gcc/config/xtensa/unwind-dw2-xtensa.h @@ -0,0 +1,57 @@ +/* DWARF2 frame unwind data structure for Xtensa. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2007 + 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 2, or (at your option) + any later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + 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 COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* A target can override (perhaps for backward compatibility) how + many dwarf2 columns are unwound. */ +#ifndef DWARF_FRAME_REGISTERS +#define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER +#endif + +/* Xtensa's variable-size register window save areas can be unwound without + any unwind info. This is a stripped down version of the standard DWARF + _Unwind_FrameState. */ +typedef struct +{ + /* The PC described by the current frame state. */ + void *pc; + + /* The information we care about from the CIE/FDE. */ + _Unwind_Personality_Fn personality; + _Unwind_Word retaddr_column; + unsigned char fde_encoding; + unsigned char lsda_encoding; + unsigned char saw_z; + unsigned char signal_frame; + void *eh_ptr; + + /* Saved registers for a signal frame. */ + _Unwind_Word *signal_regs; +} _Unwind_FrameState; + diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h index 4b9e58335de..7887345f9f5 100644 --- a/gcc/config/xtensa/xtensa.h +++ b/gcc/config/xtensa/xtensa.h @@ -1062,12 +1062,15 @@ typedef struct xtensa_args /* How to start an assembler comment. */ #define ASM_COMMENT_START "#" -/* Generate DWARF2 unwind info to get the DW_AT_frame_base set correctly, - even though we don't yet use it for unwinding. */ -#define MUST_USE_SJLJ_EXCEPTIONS 1 -#define DWARF2_UNWIND_INFO 1 +/* Exception handling. Xtensa uses much of the standard DWARF2 unwinding + machinery, but the variable size register window save areas are too + complicated to efficiently describe with CFI entries. The CFA must + still be specified in DWARF so that DW_AT_frame_base is set correctly + for debugging. */ #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, 0) #define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (0) +#define DWARF_FRAME_REGISTERS 16 +#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) + 2 : INVALID_REGNUM) /* Xtensa constant pool breaks the devices in crtstuff.c to control section in where code resides. We have to write it as asm code. Use diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 98ebb09d46e..37e29e70039 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -35,6 +35,7 @@ (UNSPECV_MEMW 3) (UNSPECV_S32RI 4) (UNSPECV_S32C1I 5) + (UNSPECV_EH_RETURN 6) ]) ;; This code iterator allows signed and unsigned widening multiplications @@ -1600,6 +1601,26 @@ DONE; }) +;; Stuff an address into the return address register along with the window +;; size in the high bits. Because we don't have the window size of the +;; previous frame, assume the function called out with a CALL8 since that +;; is what compilers always use. Note: __builtin_frob_return_addr has +;; already been applied to the handler, but the generic version doesn't +;; allow us to frob it quite enough, so we just frob here. + +(define_insn_and_split "eh_return" + [(set (reg:SI A0_REG) + (unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPECV_EH_RETURN)) + (clobber (match_scratch:SI 1 "=r"))] + "" + "#" + "reload_completed" + [(set (match_dup 1) (ashift:SI (match_dup 0) (const_int 2))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 2))) + (set (reg:SI A0_REG) (rotatert:SI (match_dup 1) (const_int 2)))] + "") + ;; Setting up a frame pointer is tricky for Xtensa because GCC doesn't ;; know if a frame pointer is required until the reload pass, and ;; because there may be an incoming argument value in the hard frame -- 2.30.2