[gcc]
[official-gcc.git] / libgcc / config / xtensa / lib2funcs.S
blob686b43f9f551ab29a1cdf82e28c7ef099f232a32
1 /* Assembly functions for libgcc2.
2    Copyright (C) 2001-2018 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, 48
38 #if XCHAL_NUM_AREGS > 16
39         call12  1f
40         retw
41         .align  4
43         .rept   (XCHAL_NUM_AREGS - 24) / 12
44         _entry  sp, 48
45         mov     a12, a0
46         .endr
47         _entry  sp, 16
48 #if XCHAL_NUM_AREGS % 12 == 0
49         mov     a4, a4
50 #elif XCHAL_NUM_AREGS % 12 == 4
51         mov     a8, a8
52 #elif XCHAL_NUM_AREGS % 12 == 8
53         mov     a12, a12
54 #endif
55         retw
56 #else
57         mov     a8, a8
58         retw
59 #endif
60         .size   __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill
61 #endif
64 /* __xtensa_nonlocal_goto: This code does all the hard work of a
65    nonlocal goto on Xtensa.  It is here in the library to avoid the
66    code size bloat of generating it in-line.  There are two
67    arguments:
69         a2 = frame pointer for the procedure containing the label
70         a3 = goto handler address
72   This function never returns to its caller but instead goes directly
73   to the address of the specified goto handler.  */
75 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
76         .align  4
77         .global __xtensa_nonlocal_goto
78         .type   __xtensa_nonlocal_goto,@function
79 __xtensa_nonlocal_goto:
80         entry   sp, 32
82         /* Flush registers.  */
83         call8   __xtensa_libgcc_window_spill
85         /* Because the save area for a0-a3 is stored one frame below
86            the one identified by a2, the only way to restore those
87            registers is to unwind the stack.  If alloca() were never
88            called, we could just unwind until finding the sp value
89            matching a2.  However, a2 is a frame pointer, not a stack
90            pointer, and may not be encountered during the unwinding.
91            The solution is to unwind until going _past_ the value
92            given by a2.  This involves keeping three stack pointer
93            values during the unwinding:
95                 next = sp of frame N-1
96                 cur = sp of frame N
97                 prev = sp of frame N+1
99            When next > a2, the desired save area is stored relative
100            to prev.  At this point, cur will be the same as a2
101            except in the alloca() case.
103            Besides finding the values to be restored to a0-a3, we also
104            need to find the current window size for the target
105            function.  This can be extracted from the high bits of the
106            return address, initially in a0.  As the unwinding
107            proceeds, the window size is taken from the value of a0
108            saved _two_ frames below the current frame.  */
110         addi    a5, sp, -16     /* a5 = prev - save area */
111         l32i    a6, a5, 4
112         addi    a6, a6, -16     /* a6 = cur - save area */
113         mov     a8, a0          /* a8 = return address (for window size) */
114         j       .Lfirstframe
116 .Lnextframe:
117         l32i    a8, a5, 0       /* next return address (for window size) */
118         mov     a5, a6          /* advance prev */
119         addi    a6, a7, -16     /* advance cur */
120 .Lfirstframe:
121         l32i    a7, a6, 4       /* a7 = next */
122         bgeu    a2, a7, .Lnextframe
124         /* At this point, prev (a5) points to the save area with the saved
125            values of a0-a3.  Copy those values into the save area at the
126            current sp so they will be reloaded when the return from this
127            function underflows.  We don't have to worry about exceptions
128            while updating the current save area, because the windows have
129            already been flushed.  */
131         addi    a4, sp, -16     /* a4 = save area of this function */
132         l32i    a6, a5, 0
133         l32i    a7, a5, 4
134         s32i    a6, a4, 0
135         s32i    a7, a4, 4
136         l32i    a6, a5, 8
137         l32i    a7, a5, 12
138         s32i    a6, a4, 8
139         s32i    a7, a4, 12
141         /* Set return address to goto handler.  Use the window size bits
142            from the return address two frames below the target.  */
143         extui   a8, a8, 30, 2   /* get window size from return addr. */
144         slli    a3, a3, 2       /* get goto handler addr. << 2 */
145         ssai    2
146         src     a0, a8, a3      /* combine them with a funnel shift */
148         retw
149         .size   __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto
150 #endif
153 /* __xtensa_sync_caches: This function is called after writing a trampoline
154    on the stack to force all the data writes to memory and invalidate the
155    instruction cache. a2 is the address of the new trampoline.
157    After the trampoline data is written out, it must be flushed out of
158    the data cache into memory.  We use DHWB in case we have a writeback
159    cache.  At least one DHWB instruction is needed for each data cache
160    line which may be touched by the trampoline.  An ISYNC instruction
161    must follow the DHWBs.
163    We have to flush the i-cache to make sure that the new values get used.
164    At least one IHI instruction is needed for each i-cache line which may
165    be touched by the trampoline.  An ISYNC instruction is also needed to
166    make sure that the modified instructions are loaded into the instruction
167    fetch buffer.  */
169 /* Use the maximum trampoline size.  Flushing a bit extra is OK.  */
170 #define TRAMPOLINE_SIZE 60
172         .text
173         .align  4
174         .global __xtensa_sync_caches
175         .type   __xtensa_sync_caches,@function
176 __xtensa_sync_caches:
177 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
178         entry   sp, 32
179 #endif
180 #if XCHAL_DCACHE_SIZE > 0
181         /* Flush the trampoline from the data cache.  */
182         extui   a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
183         addi    a4, a4, TRAMPOLINE_SIZE
184         addi    a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1
185         srli    a4, a4, XCHAL_DCACHE_LINEWIDTH
186         mov     a3, a2
187 .Ldcache_loop:
188         dhwb    a3, 0
189         addi    a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH)
190         addi    a4, a4, -1
191         bnez    a4, .Ldcache_loop
192         isync
193 #endif
194 #if XCHAL_ICACHE_SIZE > 0
195         /* Invalidate the corresponding lines in the instruction cache.  */
196         extui   a4, a2, 0, XCHAL_ICACHE_LINEWIDTH
197         addi    a4, a4, TRAMPOLINE_SIZE
198         addi    a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1
199         srli    a4, a4, XCHAL_ICACHE_LINEWIDTH
200 .Licache_loop:
201         ihi     a2, 0
202         addi    a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH)
203         addi    a4, a4, -1
204         bnez    a4, .Licache_loop
205 #endif
206         isync
207 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
208         retw
209 #else
210         ret
211 #endif
212         .size   __xtensa_sync_caches, .-__xtensa_sync_caches