* tree-ssa-loop-prefetch.c (determine_unroll_factor): Bound the unroll
[official-gcc.git] / gcc / config / arm / pr-support.c
blobb5592b192fcaeb8de14be7f1371af7ca999c88ea
1 /* ARM EABI compliant unwinding routines
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3 Contributed by Paul Brook
5 This file is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
8 later version.
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file. (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
17 executable.)
19 This file is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
27 Boston, MA 02110-1301, USA. */
28 #include "unwind.h"
30 /* We add a prototype for abort here to avoid creating a dependency on
31 target headers. */
32 extern void abort (void);
34 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
36 /* Misc constants. */
37 #define R_IP 12
38 #define R_SP 13
39 #define R_LR 14
40 #define R_PC 15
42 #define uint32_highbit (((_uw) 1) << 31)
44 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
46 /* Unwind descriptors. */
48 typedef struct
50 _uw16 length;
51 _uw16 offset;
52 } EHT16;
54 typedef struct
56 _uw length;
57 _uw offset;
58 } EHT32;
60 /* Calculate the address encoded by a 31-bit self-relative offset at address
61 P. Copy of routine in unwind-arm.c. */
63 static inline _uw
64 selfrel_offset31 (const _uw *p)
66 _uw offset;
68 offset = *p;
69 /* Sign extend to 32 bits. */
70 if (offset & (1 << 30))
71 offset |= 1u << 31;
73 return offset + (_uw) p;
77 /* Personality routine helper functions. */
79 #define CODE_FINISH (0xb0)
81 /* Return the next byte of unwinding information, or CODE_FINISH if there is
82 no data remaining. */
83 static inline _uw8
84 next_unwind_byte (__gnu_unwind_state * uws)
86 _uw8 b;
88 if (uws->bytes_left == 0)
90 /* Load another word */
91 if (uws->words_left == 0)
92 return CODE_FINISH; /* Nothing left. */
93 uws->words_left--;
94 uws->data = *(uws->next++);
95 uws->bytes_left = 3;
97 else
98 uws->bytes_left--;
100 /* Extract the most significant byte. */
101 b = (uws->data >> 24) & 0xff;
102 uws->data <<= 8;
103 return b;
106 /* Execute the unwinding instructions described by UWS. */
107 _Unwind_Reason_Code
108 __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
110 _uw op;
111 int set_pc;
112 _uw reg;
114 set_pc = 0;
115 for (;;)
117 op = next_unwind_byte (uws);
118 if (op == CODE_FINISH)
120 /* If we haven't already set pc then copy it from lr. */
121 if (!set_pc)
123 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
124 &reg);
125 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
126 &reg);
127 set_pc = 1;
129 /* Drop out of the loop. */
130 break;
132 if ((op & 0x80) == 0)
134 /* vsp = vsp +- (imm6 << 2 + 4). */
135 _uw offset;
137 offset = ((op & 0x3f) << 2) + 4;
138 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
139 if (op & 0x40)
140 reg -= offset;
141 else
142 reg += offset;
143 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
144 continue;
147 if ((op & 0xf0) == 0x80)
149 op = (op << 8) | next_unwind_byte (uws);
150 if (op == 0x8000)
152 /* Refuse to unwind. */
153 return _URC_FAILURE;
155 /* Pop r4-r15 under mask. */
156 op = (op << 4) & 0xfff0;
157 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
158 != _UVRSR_OK)
159 return _URC_FAILURE;
160 if (op & (1 << R_PC))
161 set_pc = 1;
162 continue;
164 if ((op & 0xf0) == 0x90)
166 op &= 0xf;
167 if (op == 13 || op == 15)
168 /* Reserved. */
169 return _URC_FAILURE;
170 /* vsp = r[nnnn]. */
171 _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
172 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
173 continue;
175 if ((op & 0xf0) == 0xa0)
177 /* Pop r4-r[4+nnn], [lr]. */
178 _uw mask;
180 mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
181 if (op & 8)
182 mask |= (1 << R_LR);
183 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
184 != _UVRSR_OK)
185 return _URC_FAILURE;
186 continue;
188 if ((op & 0xf0) == 0xb0)
190 /* op == 0xb0 already handled. */
191 if (op == 0xb1)
193 op = next_unwind_byte (uws);
194 if (op == 0 || ((op & 0xf0) != 0))
195 /* Spare. */
196 return _URC_FAILURE;
197 /* Pop r0-r4 under mask. */
198 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
199 != _UVRSR_OK)
200 return _URC_FAILURE;
201 continue;
203 if (op == 0xb2)
205 /* vsp = vsp + 0x204 + (uleb128 << 2). */
206 int shift;
208 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
209 &reg);
210 op = next_unwind_byte (uws);
211 shift = 2;
212 while (op & 0x80)
214 reg += ((op & 0x7f) << shift);
215 shift += 7;
216 op = next_unwind_byte (uws);
218 reg += ((op & 0x7f) << shift) + 0x204;
219 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
220 &reg);
221 continue;
223 if (op == 0xb3)
225 /* Pop VFP registers with fldmx. */
226 op = next_unwind_byte (uws);
227 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
228 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
229 != _UVRSR_OK)
230 return _URC_FAILURE;
231 continue;
233 if ((op & 0xfc) == 0xb4)
235 /* Pop FPA E[4]-E[4+nn]. */
236 op = 0x40000 | ((op & 3) + 1);
237 if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
238 != _UVRSR_OK)
239 return _URC_FAILURE;
240 continue;
242 /* op & 0xf8 == 0xb8. */
243 /* Pop VFP D[8]-D[8+nnn] with fldmx. */
244 op = 0x80000 | ((op & 7) + 1);
245 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
246 != _UVRSR_OK)
247 return _URC_FAILURE;
248 continue;
250 if ((op & 0xf0) == 0xc0)
252 if (op == 0xc6)
254 /* Pop iWMMXt D registers. */
255 op = next_unwind_byte (uws);
256 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
257 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
258 != _UVRSR_OK)
259 return _URC_FAILURE;
260 continue;
262 if (op == 0xc7)
264 op = next_unwind_byte (uws);
265 if (op == 0 || (op & 0xf0) != 0)
266 /* Spare. */
267 return _URC_FAILURE;
268 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
269 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
270 != _UVRSR_OK)
271 return _URC_FAILURE;
272 continue;
274 if ((op & 0xf8) == 0xc0)
276 /* Pop iWMMXt wR[10]-wR[10+nnn]. */
277 op = 0xa0000 | ((op & 0xf) + 1);
278 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
279 != _UVRSR_OK)
280 return _URC_FAILURE;
281 continue;
283 if (op == 0xc8)
285 #ifndef __VFP_FP__
286 /* Pop FPA registers. */
287 op = next_unwind_byte (uws);
288 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
289 if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
290 != _UVRSR_OK)
291 return _URC_FAILURE;
292 continue;
293 #else
294 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
295 op = next_unwind_byte (uws);
296 op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
297 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
298 != _UVRSR_OK)
299 return _URC_FAILURE;
300 continue;
301 #endif
303 if (op == 0xc9)
305 /* Pop VFP registers with fldmd. */
306 op = next_unwind_byte (uws);
307 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
308 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
309 != _UVRSR_OK)
310 return _URC_FAILURE;
311 continue;
313 /* Spare. */
314 return _URC_FAILURE;
316 if ((op & 0xf8) == 0xd0)
318 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
319 op = 0x80000 | ((op & 7) + 1);
320 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
321 != _UVRSR_OK)
322 return _URC_FAILURE;
323 continue;
325 /* Spare. */
326 return _URC_FAILURE;
328 return _URC_OK;
332 /* Execute the unwinding instructions associated with a frame. UCBP and
333 CONTEXT are the current exception object and virtual CPU state
334 respectively. */
336 _Unwind_Reason_Code
337 __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
339 _uw *ptr;
340 __gnu_unwind_state uws;
342 ptr = (_uw *) ucbp->pr_cache.ehtp;
343 /* Skip over the personality routine address. */
344 ptr++;
345 /* Setup the unwinder state. */
346 uws.data = (*ptr) << 8;
347 uws.next = ptr + 1;
348 uws.bytes_left = 3;
349 uws.words_left = ((*ptr) >> 24) & 0xff;
351 return __gnu_unwind_execute (context, &uws);
354 /* Get the _Unwind_Control_Block from an _Unwind_Context. */
356 static inline _Unwind_Control_Block *
357 unwind_UCB_from_context (_Unwind_Context * context)
359 return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
362 /* Get the start address of the function being unwound. */
364 _Unwind_Ptr
365 _Unwind_GetRegionStart (_Unwind_Context * context)
367 _Unwind_Control_Block *ucbp;
369 ucbp = unwind_UCB_from_context (context);
370 return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
373 /* Find the Language specific exception data. */
375 void *
376 _Unwind_GetLanguageSpecificData (_Unwind_Context * context)
378 _Unwind_Control_Block *ucbp;
379 _uw *ptr;
381 /* Get a pointer to the exception table entry. */
382 ucbp = unwind_UCB_from_context (context);
383 ptr = (_uw *) ucbp->pr_cache.ehtp;
384 /* Skip the personality routine address. */
385 ptr++;
386 /* Skip the unwind opcodes. */
387 ptr += (((*ptr) >> 24) & 0xff) + 1;
389 return ptr;
393 /* These two should never be used. */
395 _Unwind_Ptr
396 _Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
398 abort ();
401 _Unwind_Ptr
402 _Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
404 abort ();