gcc/
[official-gcc.git] / libgcc / config / xtensa / lib2funcs.S
blob4d451c8c71c8952e54baa0107a77252e5a18ac4a
1 /* Assembly functions for libgcc2.
2    Copyright (C) 2001-2015 Free Software Foundation, Inc.
3    Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 <http://www.gnu.org/licenses/>.  */
26 #include "xtensa-config.h"
28 /* __xtensa_libgcc_window_spill: This function flushes out all but the
29    current register window.  This is used to set up the stack so that
30    arbitrary frames can be accessed.  */
32 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
33         .align  4
34         .global __xtensa_libgcc_window_spill
35         .type   __xtensa_libgcc_window_spill,@function
36 __xtensa_libgcc_window_spill:
37         entry   sp, 32
38         movi    a2, 0
39         syscall
40         retw
41         .size   __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill
42 #endif
45 /* __xtensa_nonlocal_goto: This code does all the hard work of a
46    nonlocal goto on Xtensa.  It is here in the library to avoid the
47    code size bloat of generating it in-line.  There are two
48    arguments:
50         a2 = frame pointer for the procedure containing the label
51         a3 = goto handler address
53   This function never returns to its caller but instead goes directly
54   to the address of the specified goto handler.  */
56 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
57         .align  4
58         .global __xtensa_nonlocal_goto
59         .type   __xtensa_nonlocal_goto,@function
60 __xtensa_nonlocal_goto:
61         entry   sp, 32
63         /* Flush registers.  */
64         mov     a5, a2
65         movi    a2, 0
66         syscall
67         mov     a2, a5
69         /* Because the save area for a0-a3 is stored one frame below
70            the one identified by a2, the only way to restore those
71            registers is to unwind the stack.  If alloca() were never
72            called, we could just unwind until finding the sp value
73            matching a2.  However, a2 is a frame pointer, not a stack
74            pointer, and may not be encountered during the unwinding.
75            The solution is to unwind until going _past_ the value
76            given by a2.  This involves keeping three stack pointer
77            values during the unwinding:
79                 next = sp of frame N-1
80                 cur = sp of frame N
81                 prev = sp of frame N+1
83            When next > a2, the desired save area is stored relative
84            to prev.  At this point, cur will be the same as a2
85            except in the alloca() case.
87            Besides finding the values to be restored to a0-a3, we also
88            need to find the current window size for the target
89            function.  This can be extracted from the high bits of the
90            return address, initially in a0.  As the unwinding
91            proceeds, the window size is taken from the value of a0
92            saved _two_ frames below the current frame.  */
94         addi    a5, sp, -16     /* a5 = prev - save area */
95         l32i    a6, a5, 4
96         addi    a6, a6, -16     /* a6 = cur - save area */
97         mov     a8, a0          /* a8 = return address (for window size) */
98         j       .Lfirstframe
100 .Lnextframe:
101         l32i    a8, a5, 0       /* next return address (for window size) */
102         mov     a5, a6          /* advance prev */
103         addi    a6, a7, -16     /* advance cur */
104 .Lfirstframe:
105         l32i    a7, a6, 4       /* a7 = next */
106         bgeu    a2, a7, .Lnextframe
108         /* At this point, prev (a5) points to the save area with the saved
109            values of a0-a3.  Copy those values into the save area at the
110            current sp so they will be reloaded when the return from this
111            function underflows.  We don't have to worry about exceptions
112            while updating the current save area, because the windows have
113            already been flushed.  */
115         addi    a4, sp, -16     /* a4 = save area of this function */
116         l32i    a6, a5, 0
117         l32i    a7, a5, 4
118         s32i    a6, a4, 0
119         s32i    a7, a4, 4
120         l32i    a6, a5, 8
121         l32i    a7, a5, 12
122         s32i    a6, a4, 8
123         s32i    a7, a4, 12
125         /* Set return address to goto handler.  Use the window size bits
126            from the return address two frames below the target.  */
127         extui   a8, a8, 30, 2   /* get window size from return addr. */
128         slli    a3, a3, 2       /* get goto handler addr. << 2 */
129         ssai    2
130         src     a0, a8, a3      /* combine them with a funnel shift */
132         retw
133         .size   __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto
134 #endif
137 /* __xtensa_sync_caches: This function is called after writing a trampoline
138    on the stack to force all the data writes to memory and invalidate the
139    instruction cache. a2 is the address of the new trampoline.
141    After the trampoline data is written out, it must be flushed out of
142    the data cache into memory.  We use DHWB in case we have a writeback
143    cache.  At least one DHWB instruction is needed for each data cache
144    line which may be touched by the trampoline.  An ISYNC instruction
145    must follow the DHWBs.
147    We have to flush the i-cache to make sure that the new values get used.
148    At least one IHI instruction is needed for each i-cache line which may
149    be touched by the trampoline.  An ISYNC instruction is also needed to
150    make sure that the modified instructions are loaded into the instruction
151    fetch buffer.  */
153 /* Use the maximum trampoline size.  Flushing a bit extra is OK.  */
154 #define TRAMPOLINE_SIZE 60
156         .text
157         .align  4
158         .global __xtensa_sync_caches
159         .type   __xtensa_sync_caches,@function
160 __xtensa_sync_caches:
161 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
162         entry   sp, 32
163 #endif
164 #if XCHAL_DCACHE_SIZE > 0
165         /* Flush the trampoline from the data cache.  */
166         extui   a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
167         addi    a4, a4, TRAMPOLINE_SIZE
168         addi    a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1
169         srli    a4, a4, XCHAL_DCACHE_LINEWIDTH
170         mov     a3, a2
171 .Ldcache_loop:
172         dhwb    a3, 0
173         addi    a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH)
174         addi    a4, a4, -1
175         bnez    a4, .Ldcache_loop
176         isync
177 #endif
178 #if XCHAL_ICACHE_SIZE > 0
179         /* Invalidate the corresponding lines in the instruction cache.  */
180         extui   a4, a2, 0, XCHAL_ICACHE_LINEWIDTH
181         addi    a4, a4, TRAMPOLINE_SIZE
182         addi    a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1
183         srli    a4, a4, XCHAL_ICACHE_LINEWIDTH
184 .Licache_loop:
185         ihi     a2, 0
186         addi    a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH)
187         addi    a4, a4, -1
188         bnez    a4, .Licache_loop
189 #endif
190         isync
191 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
192         retw
193 #else
194         ret
195 #endif
196         .size   __xtensa_sync_caches, .-__xtensa_sync_caches