MATCH: Improve `A CMP 0 ? A : -A` set of patterns to use bitwise_equal_p.
[official-gcc.git] / gcc / ada / sigtramp-ios.c
blob3d9d139c30df57dea6eb18edee76787fedfee4ec
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * S I G T R A M P *
6 * *
7 * Asm Implementation File *
8 * *
9 * Copyright (C) 2015-2023, Free Software Foundation, Inc. *
10 * *
11 * GNAT is free software; you can redistribute it and/or modify it under *
12 * terms of the GNU General Public License as published by the Free Soft- *
13 * ware Foundation; either version 3, or (at your option) any later ver- *
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
16 * or FITNESS FOR A PARTICULAR PURPOSE. *
17 * *
18 * As a special exception under Section 7 of GPL version 3, you are granted *
19 * additional permissions described in the GCC Runtime Library Exception, *
20 * version 3.1, as published by the Free Software Foundation. *
21 * *
22 * In particular, you can freely distribute your programs built with the *
23 * GNAT Pro compiler, including any required library run-time units, using *
24 * any licensing terms of your choosing. See the AdaCore Software License *
25 * for full details. *
26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
29 * *
30 ****************************************************************************/
32 /****************************************************
33 * ARM64/IOS version of the __gnat_sigtramp service *
34 ****************************************************/
36 #include <sys/ucontext.h>
38 #include "sigtramp.h"
39 /* See sigtramp.h for a general explanation of functionality. */
41 /* ----------------------
42 -- General comments --
43 ----------------------
45 Unfortunately the libunwind library used on this platform comes with severe
46 limitations that make the implementation convoluted:
48 1. At each step, the stack pointer register SP is restored with the CFA.
49 This makes it impossible to set the CFA to an arbitrary value, for
50 example to the address of the context saved on the stack, which means
51 that the simple CFI directives cannot be used for the registers.
53 2. For the ARM64 architecture (and only it), DWARF expressions are not
54 supported to compute the CFA. Only DW_CFA_def_cfa is supported, which
55 means that the CFA (modulo offset) must be loaded into a register.
57 3. The return column cannot be changed (30 for the ARM64 architecture).
58 Since column 30 is that of the LR register, this makes it impossible
59 to restore both the LR register and the PC.
61 Therefore we need 2 distinct call-saved registers in the trampoline and
62 we resort to manual encoding of CFI byte sequences. */
64 /* -----------------------------------------
65 -- Protypes for our internal asm stubs --
66 -----------------------------------------
68 Even though our symbols will remain local, the prototype claims "extern"
69 and not "static" to prevent compiler complaints about a symbol used but
70 never defined. */
72 /* sigtramp stub providing unwind info for common registers. */
74 #if defined(__cplusplus)
75 extern "C" {
76 #endif
78 extern void __gnat_sigtramp_common
79 (int signo, void *siginfo, void *sigcontext,
80 __sigtramphandler_t * handler);
82 void __gnat_sigtramp (int signo, void *si, void *ucontext,
83 __sigtramphandler_t * handler)
84 __attribute__((optimize(2)));
86 void __gnat_sigtramp (int signo, void *si, void *ucontext,
87 __sigtramphandler_t * handler)
89 mcontext_t mcontext = ((ucontext_t *) ucontext)->uc_mcontext;
91 __gnat_sigtramp_common (signo, si, mcontext, handler);
94 #if defined(__cplusplus)
96 #endif
98 /* asm string construction helpers. */
100 #define STR(TEXT) #TEXT
101 /* stringify expanded TEXT, surrounding it with double quotes. */
103 #define S(E) STR(E)
104 /* stringify E, which will resolve as text but may contain macros
105 still to be expanded. */
107 /* asm (TEXT) outputs <tab>TEXT. These facilitate the output of
108 multiline contents: */
109 #define TAB(S) "\t" S
110 #define CR(S) S "\n"
112 #undef TCR
113 #define TCR(S) TAB(CR(S))
115 /* Offset in uc_mcontext of the __ss structure containing the registers. */
116 #define UC_MCONTEXT_SS 16
118 #define CFA_REG 19
119 #define BASE_REG 20
121 #define DW_CFA_def_cfa 0x0c
122 #define DW_CFA_expression 0x10
124 #define DW_OP_breg(n) 0x70+(n)
126 #define REG_REGNO_GR(n) n
127 #define REG_REGNO_PC 30
129 /* The first byte of the SLEB128 value of the offset. */
130 #define REG_OFFSET_GR(n) (UC_MCONTEXT_SS + n * 8)
131 #define REG_OFFSET_LONG_GR(n) (UC_MCONTEXT_SS + n * 8 + 128)
132 #define REG_OFFSET_LONG128_GR(n) (UC_MCONTEXT_SS + (n - 16) * 8 + 128)
133 #define REG_OFFSET_LONG256_GR(n) (UC_MCONTEXT_SS + (n - 32) * 8 + 128)
135 #define REG_OFFSET_LONG256_PC REG_OFFSET_LONG256_GR(32)
137 #define CFI_DEF_CFA \
138 TCR(".cfi_def_cfa " S(CFA_REG) ", 0")
140 /* We need 4 variants depending on the offset: 0+, 64+, 128+, 256+. */
141 #define COMMON_CFI(REG) \
142 ".cfi_escape " S(DW_CFA_expression) "," S(REG_REGNO_##REG) ",2," \
143 S(DW_OP_breg(BASE_REG)) "," S(REG_OFFSET_##REG)
145 #define COMMON_LONG_CFI(REG) \
146 ".cfi_escape " S(DW_CFA_expression) "," S(REG_REGNO_##REG) ",3," \
147 S(DW_OP_breg(BASE_REG)) "," S(REG_OFFSET_LONG_##REG) ",0"
149 #define COMMON_LONG128_CFI(REG) \
150 ".cfi_escape " S(DW_CFA_expression) "," S(REG_REGNO_##REG) ",3," \
151 S(DW_OP_breg(BASE_REG)) "," S(REG_OFFSET_LONG128_##REG) ",1"
153 #define COMMON_LONG256_CFI(REG) \
154 ".cfi_escape " S(DW_CFA_expression) "," S(REG_REGNO_##REG) ",3," \
155 S(DW_OP_breg(BASE_REG)) "," S(REG_OFFSET_LONG256_##REG) ",2"
157 #define CFI_COMMON_REGS \
158 CR("# CFI for common registers\n") \
159 TCR(COMMON_CFI(GR(0))) \
160 TCR(COMMON_CFI(GR(1))) \
161 TCR(COMMON_CFI(GR(2))) \
162 TCR(COMMON_CFI(GR(3))) \
163 TCR(COMMON_CFI(GR(4))) \
164 TCR(COMMON_CFI(GR(5))) \
165 TCR(COMMON_LONG_CFI(GR(6))) \
166 TCR(COMMON_LONG_CFI(GR(7))) \
167 TCR(COMMON_LONG_CFI(GR(8))) \
168 TCR(COMMON_LONG_CFI(GR(9))) \
169 TCR(COMMON_LONG_CFI(GR(10))) \
170 TCR(COMMON_LONG_CFI(GR(11))) \
171 TCR(COMMON_LONG_CFI(GR(12))) \
172 TCR(COMMON_LONG_CFI(GR(13))) \
173 TCR(COMMON_LONG128_CFI(GR(14))) \
174 TCR(COMMON_LONG128_CFI(GR(15))) \
175 TCR(COMMON_LONG128_CFI(GR(16))) \
176 TCR(COMMON_LONG128_CFI(GR(17))) \
177 TCR(COMMON_LONG128_CFI(GR(18))) \
178 TCR(COMMON_LONG128_CFI(GR(19))) \
179 TCR(COMMON_LONG128_CFI(GR(20))) \
180 TCR(COMMON_LONG128_CFI(GR(21))) \
181 TCR(COMMON_LONG128_CFI(GR(22))) \
182 TCR(COMMON_LONG128_CFI(GR(23))) \
183 TCR(COMMON_LONG128_CFI(GR(24))) \
184 TCR(COMMON_LONG128_CFI(GR(25))) \
185 TCR(COMMON_LONG128_CFI(GR(26))) \
186 TCR(COMMON_LONG128_CFI(GR(27))) \
187 TCR(COMMON_LONG128_CFI(GR(28))) \
188 TCR(COMMON_LONG128_CFI(GR(29))) \
189 TCR(COMMON_LONG256_CFI(PC))
191 /* Trampoline body block
192 --------------------- */
194 #define SIGTRAMP_BODY \
195 TCR("stp fp, lr, [sp, #-32]!") \
196 TCR("stp x" S(CFA_REG) ", x" S(BASE_REG) ", [sp, #16]") \
197 TCR("mov fp, sp") \
198 TCR("# Load the saved value of the stack pointer as CFA") \
199 TCR("ldr x" S(CFA_REG) ", [x2, #" S(REG_OFFSET_GR(31)) "]") \
200 TCR("# Use x" S(BASE_REG) " as base register for the CFI") \
201 TCR("mov x" S(BASE_REG) ", x2") \
202 TCR("# Call the handler") \
203 TCR("blr x3") \
204 TCR("# Release our frame and return (should never get here!).") \
205 TCR("ldp x" S(CFA_REG) ", x" S(BASE_REG)" , [sp, #16]") \
206 TCR("ldp fp, lr, [sp], 32") \
207 TCR("ret")
209 /* -----------------------------
210 -- Symbol definition block --
211 ----------------------------- */
213 #define SIGTRAMP_START(SYM) \
214 CR("# " S(SYM) " signal trampoline") \
215 CR(S(SYM) ":") \
216 TCR(".cfi_startproc") \
217 TCR(".cfi_signal_frame")
219 /* ------------------------------
220 -- Symbol termination block --
221 ------------------------------ */
223 #define SIGTRAMP_END(SYM) \
224 TCR(".cfi_endproc")
226 /*----------------------------
227 -- And now, the real code --
228 ---------------------------- */
230 asm(".text\n"
231 TCR(".align 2"));
233 /* sigtramp stub for common registers. */
235 #define TRAMP_COMMON ___gnat_sigtramp_common
237 asm (SIGTRAMP_START(TRAMP_COMMON));
238 asm (CFI_DEF_CFA);
239 asm (CFI_COMMON_REGS);
240 asm (SIGTRAMP_BODY);
241 asm (SIGTRAMP_END(TRAMP_COMMON));