* sysdeps/unix/alpha/sysdep.h (INLINE_SYSCALL1): Use __builtin_expect.
[kopensolaris-gnu/glibc.git] / sysdeps / unix / alpha / sysdep.h
1 /* Copyright (C) 1992, 1995, 1996, 2000, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Brendan Kehoe (brendan@zen.org).
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <sysdeps/unix/sysdep.h>
21
22 #ifdef __ASSEMBLER__
23
24 #ifdef __linux__
25 # include <alpha/regdef.h>
26 #else
27 # include <regdef.h>
28 #endif
29
30 #include <tls.h>                /* Defines USE___THREAD.  */
31
32 #ifdef IS_IN_rtld
33 # include <dl-sysdep.h>         /* Defines RTLD_PRIVATE_ERRNO.  */
34 #endif
35
36
37 #ifdef __STDC__
38 #define __LABEL(x)      x##:
39 #else
40 #define __LABEL(x)      x/**/:
41 #endif
42
43 #define LEAF(name, framesize)                   \
44   .globl name;                                  \
45   .align 3;                                     \
46   .ent name, 0;                                 \
47   __LABEL(name)                                 \
48   .frame sp, framesize, ra
49
50 #define ENTRY(name)                             \
51   .globl name;                                  \
52   .align 3;                                     \
53   .ent name, 0;                                 \
54   __LABEL(name)                                 \
55   .frame sp, 0, ra
56
57 /* Mark the end of function SYM.  */
58 #undef END
59 #define END(sym)        .end sym
60
61 #ifdef PROF
62 # define PSEUDO_PROLOGUE                        \
63         .frame sp, 0, ra;                       \
64         ldgp    gp,0(pv);                       \
65         .set noat;                              \
66         lda     AT,_mcount;                     \
67         jsr     AT,(AT),_mcount;                \
68         .set at;                                \
69         .prologue 1
70 #elif defined PIC
71 # define PSEUDO_PROLOGUE                        \
72         .frame sp, 0, ra;                       \
73         .prologue 0
74 #else
75 # define PSEUDO_PROLOGUE                        \
76         .frame sp, 0, ra;                       \
77         ldgp    gp,0(pv);                       \
78         .prologue 1
79 #endif /* PROF */
80
81 #if RTLD_PRIVATE_ERRNO
82 # define SYSCALL_ERROR_LABEL    $syscall_error
83 # define SYSCALL_ERROR_HANDLER                  \
84         stl     v0, errno(gp)   !gprel;         \
85         lda     v0, -1;                         \
86         ret
87 #elif defined(PIC)
88 # define SYSCALL_ERROR_LABEL    __syscall_error
89 # define SYSCALL_ERROR_HANDLER \
90         br      $31, __syscall_error !samegp
91 #else
92 # define SYSCALL_ERROR_LABEL    $syscall_error
93 # define SYSCALL_ERROR_HANDLER \
94         jmp     $31, __syscall_error
95 #endif /* RTLD_PRIVATE_ERRNO */
96
97 /* Overridden by specific syscalls.  */
98 #undef PSEUDO_PREPARE_ARGS
99 #define PSEUDO_PREPARE_ARGS     /* Nothing.  */
100
101 #define PSEUDO(name, syscall_name, args)        \
102         .globl name;                            \
103         .align 4;                               \
104         .ent name,0;                            \
105 __LABEL(name)                                   \
106         PSEUDO_PROLOGUE;                        \
107         PSEUDO_PREPARE_ARGS                     \
108         lda     v0, SYS_ify(syscall_name);      \
109         call_pal PAL_callsys;                   \
110         bne     a3, SYSCALL_ERROR_LABEL
111
112 #undef PSEUDO_END
113 #if defined(PIC) && !RTLD_PRIVATE_ERRNO
114 # define PSEUDO_END(sym)  END(sym)
115 #else
116 # define PSEUDO_END(sym)                        \
117 $syscall_error:                                 \
118         SYSCALL_ERROR_HANDLER;                  \
119         END(sym)
120 #endif
121
122 #define PSEUDO_NOERRNO(name, syscall_name, args)        \
123         .globl name;                                    \
124         .align 4;                                       \
125         .ent name,0;                                    \
126 __LABEL(name)                                           \
127         PSEUDO_PROLOGUE;                                \
128         PSEUDO_PREPARE_ARGS                             \
129         lda     v0, SYS_ify(syscall_name);              \
130         call_pal PAL_callsys;
131
132 #undef PSEUDO_END_NOERRNO
133 #define PSEUDO_END_NOERRNO(sym)  END(sym)
134
135 #define ret_NOERRNO ret
136
137 #define r0      v0
138 #define r1      a4
139
140 #define MOVE(x,y)       mov x,y
141
142 #else /* !ASSEMBLER */
143
144 /* ??? Linux needs to be able to override INLINE_SYSCALL for one
145    particular special case.  Make this easy.  */
146
147 #undef INLINE_SYSCALL
148 #define INLINE_SYSCALL(name, nr, args...) \
149         INLINE_SYSCALL1(name, nr, args)
150
151 #define INLINE_SYSCALL1(name, nr, args...)      \
152 ({                                              \
153         long _sc_ret, _sc_err;                  \
154         inline_syscall##nr(name, args);         \
155         if (__builtin_expect (_sc_err, 0))      \
156           {                                     \
157             __set_errno (_sc_ret);              \
158             _sc_ret = -1L;                      \
159           }                                     \
160         _sc_ret;                                \
161 })
162
163 #define INTERNAL_SYSCALL(name, err_out, nr, args...) \
164         INTERNAL_SYSCALL1(name, err_out, nr, args)
165
166 #define INTERNAL_SYSCALL1(name, err_out, nr, args...)   \
167 ({                                                      \
168         long _sc_ret, _sc_err;                          \
169         inline_syscall##nr(name, args);                 \
170         err_out = _sc_err;                              \
171         _sc_ret;                                        \
172 })
173
174 #define INTERNAL_SYSCALL_DECL(err)              long int err
175 #define INTERNAL_SYSCALL_ERROR_P(val, err)      err
176 #define INTERNAL_SYSCALL_ERRNO(val, err)        val
177
178 #define inline_syscall_clobbers                         \
179         "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", \
180         "$22", "$23", "$24", "$25", "$27", "$28", "memory"
181
182 /* If TLS is in use, we have a conflict between the PAL_rduniq primitive,
183    as modeled within GCC, and explicit use of the R0 register.  If we use
184    the register via the asm, the scheduler may place the PAL_rduniq insn
185    before we've copied the data from R0 into _sc_ret.  If this happens
186    we'll get a reload abort, since R0 is live at the same time it is
187    needed for the PAL_rduniq.
188
189    Solve this by using the "v" constraint instead of an asm for the syscall
190    output.  We don't do this unconditionally to allow compilation with
191    older compilers.  */
192
193 #ifdef USE_TLS
194 #define inline_syscall_r0_asm
195 #define inline_syscall_r0_out_constraint        "=v"
196 #else
197 #define inline_syscall_r0_asm                   __asm__("$0")
198 #define inline_syscall_r0_out_constraint        "=r"
199 #endif
200
201 /* It is moderately important optimization-wise to limit the lifetime
202    of the hard-register variables as much as possible.  Thus we copy
203    in/out as close to the asm as possible.  */
204
205 #define inline_syscall0(name, args...)                          \
206 {                                                               \
207         register long _sc_0 inline_syscall_r0_asm;              \
208         register long _sc_19 __asm__("$19");                    \
209                                                                 \
210         _sc_0 = __NR_##name;                                    \
211         __asm__ __volatile__                                    \
212           ("callsys # %0 %1 <= %2"                              \
213            : inline_syscall_r0_out_constraint (_sc_0),          \
214              "=r"(_sc_19)                                       \
215            : "0"(_sc_0)                                         \
216            : inline_syscall_clobbers,                           \
217              "$16", "$17", "$18", "$20", "$21");                \
218         _sc_ret = _sc_0, _sc_err = _sc_19;                      \
219 }
220
221 #define inline_syscall1(name,arg1)                              \
222 {                                                               \
223         register long _sc_0 inline_syscall_r0_asm;              \
224         register long _sc_16 __asm__("$16");                    \
225         register long _sc_19 __asm__("$19");                    \
226                                                                 \
227         _sc_0 = __NR_##name;                                    \
228         _sc_16 = (long) (arg1);                                 \
229         __asm__ __volatile__                                    \
230           ("callsys # %0 %1 <= %2 %3"                           \
231            : inline_syscall_r0_out_constraint (_sc_0),          \
232              "=r"(_sc_19), "=r"(_sc_16)                         \
233            : "0"(_sc_0), "2"(_sc_16)                            \
234            : inline_syscall_clobbers,                           \
235              "$17", "$18", "$20", "$21");                       \
236         _sc_ret = _sc_0, _sc_err = _sc_19;                      \
237 }
238
239 #define inline_syscall2(name,arg1,arg2)                         \
240 {                                                               \
241         register long _sc_0 inline_syscall_r0_asm;              \
242         register long _sc_16 __asm__("$16");                    \
243         register long _sc_17 __asm__("$17");                    \
244         register long _sc_19 __asm__("$19");                    \
245                                                                 \
246         _sc_0 = __NR_##name;                                    \
247         _sc_16 = (long) (arg1);                                 \
248         _sc_17 = (long) (arg2);                                 \
249         __asm__ __volatile__                                    \
250           ("callsys # %0 %1 <= %2 %3 %4"                        \
251            : inline_syscall_r0_out_constraint (_sc_0),          \
252              "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17)           \
253            : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17)               \
254            : inline_syscall_clobbers,                           \
255              "$18", "$20", "$21");                              \
256         _sc_ret = _sc_0, _sc_err = _sc_19;                      \
257 }
258
259 #define inline_syscall3(name,arg1,arg2,arg3)                    \
260 {                                                               \
261         register long _sc_0 inline_syscall_r0_asm;              \
262         register long _sc_16 __asm__("$16");                    \
263         register long _sc_17 __asm__("$17");                    \
264         register long _sc_18 __asm__("$18");                    \
265         register long _sc_19 __asm__("$19");                    \
266                                                                 \
267         _sc_0 = __NR_##name;                                    \
268         _sc_16 = (long) (arg1);                                 \
269         _sc_17 = (long) (arg2);                                 \
270         _sc_18 = (long) (arg3);                                 \
271         __asm__ __volatile__                                    \
272           ("callsys # %0 %1 <= %2 %3 %4 %5"                     \
273            : inline_syscall_r0_out_constraint (_sc_0),          \
274              "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17),          \
275              "=r"(_sc_18)                                       \
276            : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17),              \
277              "4"(_sc_18)                                        \
278            : inline_syscall_clobbers, "$20", "$21");            \
279         _sc_ret = _sc_0, _sc_err = _sc_19;                      \
280 }
281
282 #define inline_syscall4(name,arg1,arg2,arg3,arg4)               \
283 {                                                               \
284         register long _sc_0 inline_syscall_r0_asm;              \
285         register long _sc_16 __asm__("$16");                    \
286         register long _sc_17 __asm__("$17");                    \
287         register long _sc_18 __asm__("$18");                    \
288         register long _sc_19 __asm__("$19");                    \
289                                                                 \
290         _sc_0 = __NR_##name;                                    \
291         _sc_16 = (long) (arg1);                                 \
292         _sc_17 = (long) (arg2);                                 \
293         _sc_18 = (long) (arg3);                                 \
294         _sc_19 = (long) (arg4);                                 \
295         __asm__ __volatile__                                    \
296           ("callsys # %0 %1 <= %2 %3 %4 %5 %6"                  \
297            : inline_syscall_r0_out_constraint (_sc_0),          \
298              "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17),          \
299              "=r"(_sc_18)                                       \
300            : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17),              \
301              "4"(_sc_18), "1"(_sc_19)                           \
302            : inline_syscall_clobbers, "$20", "$21");            \
303         _sc_ret = _sc_0, _sc_err = _sc_19;                      \
304 }
305
306 #define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5)          \
307 {                                                               \
308         register long _sc_0 inline_syscall_r0_asm;              \
309         register long _sc_16 __asm__("$16");                    \
310         register long _sc_17 __asm__("$17");                    \
311         register long _sc_18 __asm__("$18");                    \
312         register long _sc_19 __asm__("$19");                    \
313         register long _sc_20 __asm__("$20");                    \
314                                                                 \
315         _sc_0 = __NR_##name;                                    \
316         _sc_16 = (long) (arg1);                                 \
317         _sc_17 = (long) (arg2);                                 \
318         _sc_18 = (long) (arg3);                                 \
319         _sc_19 = (long) (arg4);                                 \
320         _sc_20 = (long) (arg5);                                 \
321         __asm__ __volatile__                                    \
322           ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7"               \
323            : inline_syscall_r0_out_constraint (_sc_0),          \
324              "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17),          \
325              "=r"(_sc_18), "=r"(_sc_20)                         \
326            : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17),              \
327              "4"(_sc_18), "1"(_sc_19), "5"(_sc_20)              \
328            : inline_syscall_clobbers, "$21");                   \
329         _sc_ret = _sc_0, _sc_err = _sc_19;                      \
330 }
331
332 #define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6)     \
333 {                                                               \
334         register long _sc_0 inline_syscall_r0_asm;              \
335         register long _sc_16 __asm__("$16");                    \
336         register long _sc_17 __asm__("$17");                    \
337         register long _sc_18 __asm__("$18");                    \
338         register long _sc_19 __asm__("$19");                    \
339         register long _sc_20 __asm__("$20");                    \
340         register long _sc_21 __asm__("$21");                    \
341                                                                 \
342         _sc_0 = __NR_##name;                                    \
343         _sc_16 = (long) (arg1);                                 \
344         _sc_17 = (long) (arg2);                                 \
345         _sc_18 = (long) (arg3);                                 \
346         _sc_19 = (long) (arg4);                                 \
347         _sc_20 = (long) (arg5);                                 \
348         _sc_21 = (long) (arg6);                                 \
349         __asm__ __volatile__                                    \
350           ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7 %8"            \
351            : inline_syscall_r0_out_constraint (_sc_0),          \
352              "=r"(_sc_19) "=r"(_sc_16), "=r"(_sc_17),           \
353              "=r"(_sc_18), "=r"(_sc_20), "=r"(_sc_21)           \
354            : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17), "4"(_sc_18), \
355              "1"(_sc_19), "5"(_sc_20), "6"(_sc_21)              \
356            : inline_syscall_clobbers);                          \
357         _sc_ret = _sc_0, _sc_err = _sc_19;                      \
358 }
359
360 #endif /* ASSEMBLER */