1 | /* Copyright (C) 2004-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library. If not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | /* Common bits for implementing software divide. */ |
19 | |
20 | #include <sysdep.h> |
21 | #ifdef __linux__ |
22 | # include <asm/gentrap.h> |
23 | # include <asm/pal.h> |
24 | #else |
25 | # include <machine/pal.h> |
26 | #endif |
27 | |
28 | /* These are not normal C functions. Argument registers are t10 and t11; |
29 | the result goes in t12; the return address is in t9. Only t12 and AT |
30 | may be clobbered. */ |
31 | #define X t10 |
32 | #define Y t11 |
33 | #define RV t12 |
34 | #define RA t9 |
35 | |
36 | /* The secureplt format does not allow the division routines to be called |
37 | via plt; there aren't enough registers free to be clobbered. Avoid |
38 | setting the symbol type to STT_FUNC, so that the linker won't be tempted |
39 | to create a plt entry. */ |
40 | #define funcnoplt notype |
41 | |
42 | /* None of these functions should use implicit anything. */ |
43 | .set nomacro |
44 | .set noat |
45 | |
46 | /* Code fragment to invoke _mcount for profiling. This should be invoked |
47 | directly after allocation of the stack frame. */ |
48 | .macro CALL_MCOUNT |
49 | #ifdef PROF |
50 | stq ra, 0(sp) |
51 | stq pv, 8(sp) |
52 | stq gp, 16(sp) |
53 | cfi_rel_offset (ra, 0) |
54 | cfi_rel_offset (pv, 8) |
55 | cfi_rel_offset (gp, 16) |
56 | br AT, 1f |
57 | .set macro |
58 | 1: ldgp gp, 0(AT) |
59 | mov RA, ra |
60 | lda AT, _mcount |
61 | jsr AT, (AT), _mcount |
62 | .set nomacro |
63 | ldq ra, 0(sp) |
64 | ldq pv, 8(sp) |
65 | ldq gp, 16(sp) |
66 | cfi_restore (ra) |
67 | cfi_restore (pv) |
68 | cfi_restore (gp) |
69 | /* Realign subsequent code with what we'd have without this |
70 | macro at all. This means aligned with one arithmetic insn |
71 | used within the bundle. */ |
72 | .align 4 |
73 | nop |
74 | #endif |
75 | .endm |
76 | |
77 | /* In order to make the below work, all top-level divide routines must |
78 | use the same frame size. */ |
79 | #define FRAME 64 |
80 | |
81 | /* Code fragment to generate an integer divide-by-zero fault. When |
82 | building libc.so, we arrange for there to be one copy of this code |
83 | placed late in the dso, such that all branches are forward. When |
84 | building libc.a, we use multiple copies to avoid having an out of |
85 | range branch. Users should jump to DIVBYZERO. */ |
86 | |
87 | .macro DO_DIVBYZERO |
88 | #ifdef PIC |
89 | #define DIVBYZERO __divbyzero |
90 | .section .gnu.linkonce.t.divbyzero, "ax" , @progbits |
91 | .globl __divbyzero |
92 | .type __divbyzero, @function |
93 | .usepv __divbyzero, no |
94 | .hidden __divbyzero |
95 | #else |
96 | #define DIVBYZERO $divbyzero |
97 | #endif |
98 | |
99 | .align 4 |
100 | DIVBYZERO: |
101 | cfi_startproc |
102 | cfi_return_column (RA) |
103 | cfi_def_cfa_offset (FRAME) |
104 | |
105 | mov a0, RV |
106 | unop |
107 | lda a0, GEN_INTDIV |
108 | call_pal PAL_gentrap |
109 | |
110 | mov RV, a0 |
111 | clr RV |
112 | lda sp, FRAME(sp) |
113 | cfi_def_cfa_offset (0) |
114 | ret $31, (RA), 1 |
115 | |
116 | cfi_endproc |
117 | .size DIVBYZERO, .-DIVBYZERO |
118 | .endm |
119 | |
120 | /* Like the ev6 instructions, but fall back to stack use on prior machines. */ |
121 | |
122 | .arch ev6 |
123 | |
124 | .macro _ITOFS gr, fr, slot |
125 | #ifdef __alpha_fix__ |
126 | itofs \gr, \fr |
127 | #else |
128 | stl \gr, \slot(sp) |
129 | lds \fr, \slot(sp) |
130 | #endif |
131 | .endm |
132 | |
133 | .macro _ITOFT gr, fr, slot |
134 | #ifdef __alpha_fix__ |
135 | itoft \gr, \fr |
136 | #else |
137 | stq \gr, \slot(sp) |
138 | ldt \fr, \slot(sp) |
139 | #endif |
140 | .endm |
141 | |
142 | .macro _FTOIT fr, gr, slot |
143 | #ifdef __alpha_fix__ |
144 | ftoit \fr, \gr |
145 | #else |
146 | stt \fr, \slot(sp) |
147 | ldq \gr, \slot(sp) |
148 | #endif |
149 | .endm |
150 | |
151 | /* Similarly, but move two registers. Schedules better for pre-ev6. */ |
152 | |
153 | .macro _ITOFT2 gr1, fr1, slot1, gr2, fr2, slot2 |
154 | #ifdef __alpha_fix__ |
155 | itoft \gr1, \fr1 |
156 | itoft \gr2, \fr2 |
157 | #else |
158 | stq \gr1, \slot1(sp) |
159 | stq \gr2, \slot2(sp) |
160 | ldt \fr1, \slot1(sp) |
161 | ldt \fr2, \slot2(sp) |
162 | #endif |
163 | .endm |
164 | |