aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/xtensa/lib2funcs.S
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/xtensa/lib2funcs.S')
-rw-r--r--gcc/config/xtensa/lib2funcs.S214
1 files changed, 214 insertions, 0 deletions
diff --git a/gcc/config/xtensa/lib2funcs.S b/gcc/config/xtensa/lib2funcs.S
new file mode 100644
index 00000000000..f607e01f2ea
--- /dev/null
+++ b/gcc/config/xtensa/lib2funcs.S
@@ -0,0 +1,214 @@
+/* Assembly functions for libgcc2.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
+
+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 combine
+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, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "xtensa/xtensa-config.h"
+
+/* __xtensa_libgcc_window_spill: This function uses a series of nested
+ calls to flush out all but the current register window. This is
+ used to set up the stack so that arbitrary frames can be accessed.
+ The functions used for the nested calls are also reused by the
+ nonlocal goto function below. */
+
+ .align 4
+ .global __xtensa_libgcc_window_spill
+ .type __xtensa_libgcc_window_spill,@function
+__xtensa_libgcc_window_spill:
+ entry sp, 48
+ call4 .L__wdwspill_assist52 // called with call8, only need a call4
+ retw
+ .size __xtensa_libgcc_window_spill,.-__xtensa_libgcc_window_spill
+
+ .align 4
+.L__wdwspill_assist56:
+ entry sp, 16
+ call4 .L__wdwspill_assist52
+ retw
+ .align 4
+.L__wdwspill_assist52:
+ entry sp, 48
+ call12 .L__wdwspill_assist40
+ retw
+ .align 4
+.L__wdwspill_assist40:
+ entry sp, 48
+ call12 .L__wdwspill_assist28
+ retw
+ .align 4
+.L__wdwspill_assist28:
+ entry sp, 48
+ call12 .L__wdwspill_assist16
+ retw
+ .align 4
+.L__wdwspill_assist16:
+ entry sp, 16
+ movi a15, 0
+ retw
+
+
+/* __xtensa_nonlocal_goto: This code does all the hard work of a
+ nonlocal goto on Xtensa. It is here in the library to avoid the
+ code size bloat of generating it in-line. There are two
+ arguments:
+
+ a2 = frame pointer for the procedure containing the label
+ a3 = goto handler address
+
+ This function never returns to its caller but instead goes directly
+ to the address of the specified goto handler. */
+
+ .align 4
+ .global __xtensa_nonlocal_goto
+ .type __xtensa_nonlocal_goto,@function
+__xtensa_nonlocal_goto:
+ entry sp, 32
+
+ /* flush registers */
+ call8 .L__wdwspill_assist56
+
+ /* Because the save area for a0-a3 is stored one frame below
+ the one identified by a2, the only way to restore those
+ registers is to unwind the stack. If alloca() were never
+ called, we could just unwind until finding the sp value
+ matching a2. However, a2 is a frame pointer, not a stack
+ pointer, and may not be encountered during the unwinding.
+ The solution is to unwind until going _past_ the value
+ given by a2. This involves keeping three stack pointer
+ values during the unwinding:
+
+ next = sp of frame N-1
+ cur = sp of frame N
+ prev = sp of frame N+1
+
+ When next > a2, the desired save area is stored relative
+ to prev. At this point, cur will be the same as a2
+ except in the alloca() case.
+
+ Besides finding the values to be restored to a0-a3, we also
+ need to find the current window size for the target
+ function. This can be extracted from the high bits of the
+ return address, initially in a0. As the unwinding
+ proceeds, the window size is taken from the value of a0
+ saved _two_ frames below the current frame. */
+
+ addi a5, sp, -16 # a5 = prev - save area
+ l32i a6, a5, 4
+ addi a6, a6, -16 # a6 = cur - save area
+ mov a8, a0 # a8 = return address (for window size)
+ j .Lfirstframe
+
+.Lnextframe:
+ l32i a8, a5, 0 # next return address (for window size)
+ mov a5, a6 # advance prev
+ addi a6, a7, -16 # advance cur
+.Lfirstframe:
+ l32i a7, a6, 4 # a7 = next
+ bge a2, a7, .Lnextframe
+
+ /* At this point, prev (a5) points to the save area with the saved
+ values of a0-a3. Copy those values into the save area at the
+ current sp so they will be reloaded when the return from this
+ function underflows. We don't have to worry about exceptions
+ while updating the current save area, because the windows have
+ already been flushed. */
+
+ addi a4, sp, -16 # a4 = save area of this function
+ l32i a6, a5, 0
+ l32i a7, a5, 4
+ s32i a6, a4, 0
+ s32i a7, a4, 4
+ l32i a6, a5, 8
+ l32i a7, a5, 12
+ s32i a6, a4, 8
+ s32i a7, a4, 12
+
+ /* Set return address to goto handler. Use the window size bits
+ from the return address two frames below the target. */
+ extui a8, a8, 30, 2 # get window size from return addr.
+ slli a3, a3, 2 # get goto handler addr. << 2
+ ssai 2
+ src a0, a8, a3 # combine them with a funnel shift
+
+ retw
+ .size __xtensa_nonlocal_goto,.-__xtensa_nonlocal_goto
+
+
+/* __xtensa_sync_caches: This function is called after writing a trampoline
+ on the stack to force all the data writes to memory and invalidate the
+ instruction cache. a2 is the address of the new trampoline.
+
+ After the trampoline data is written out, it must be flushed out of
+ the data cache into memory. We use DHWB in case we have a writeback
+ cache. At least one DHWB instruction is needed for each data cache
+ line which may be touched by the trampoline. An ISYNC instruction
+ must follow the DHWBs.
+
+ We have to flush the i-cache to make sure that the new values get used.
+ At least one IHI instruction is needed for each i-cache line which may
+ be touched by the trampoline. An ISYNC instruction is also needed to
+ make sure that the modified instructions are loaded into the instruction
+ fetch buffer. */
+
+#define TRAMPOLINE_SIZE 49
+
+ .text
+ .align 4
+ .global __xtensa_sync_caches
+ .type __xtensa_sync_caches,@function
+__xtensa_sync_caches:
+ entry sp, 32
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
+ # Flush the trampoline from the data cache
+ extui a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
+ addi a4, a4, TRAMPOLINE_SIZE
+ addi a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1
+ srli a4, a4, XCHAL_DCACHE_LINEWIDTH
+ mov a3, a2
+.Ldcache_loop:
+ dhwb a3, 0
+ addi a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH)
+ addi a4, a4, -1
+ bnez a4, .Ldcache_loop
+ isync
+#endif
+#if XCHAL_ICACHE_SIZE > 0
+ # Invalidate the corresponding lines in the instruction cache
+ extui a4, a2, 0, XCHAL_ICACHE_LINEWIDTH
+ addi a4, a4, TRAMPOLINE_SIZE
+ addi a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1
+ srli a4, a4, XCHAL_ICACHE_LINEWIDTH
+.Licache_loop:
+ ihi a2, 0
+ addi a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH)
+ addi a4, a4, -1
+ bnez a4, .Licache_loop
+ isync
+#endif
+ retw
+ .size __xtensa_sync_caches,.-__xtensa_sync_caches