Updated to fedora-glibc-20090509T2200
[glibc/history.git] / fedora / power6emul.c
blobf1d0d20e0f6f378c415069bccb7fa35916c7f331
1 /* Emulate power6 mf[tf]gpr and fri[zpmn] instructions.
2 Copyright (C) 2006 Red Hat, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
5 This 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.
10 It 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.
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. */
20 #include <signal.h>
21 #include <stdio.h>
23 extern double frip (double), friz (double), frin (double), frim (double);
24 asm (".globl frip, friz, frin, frim\n.hidden frip, friz, frin, frim\n\t"
25 #ifdef __powerpc64__
26 ".section \".toc\",\"aw\"\n"
27 "8:" ".tc FD_43300000_0[TC],0x4330000000000000\n"
28 "9:" ".tc FD_3fe00000_0[TC],0x3fe0000000000000\n\t"
29 ".previous\n\t"
30 #else
31 ".rodata\n\t"
32 ".align 2\n"
33 "8:" ".long 0x59800000\n"
34 "9:" ".long 0x3f000000\n\t"
35 ".previous\n\t"
36 #endif
37 "# frip == ceil\n"
38 "frip:" "mffs 11\n\t"
39 #ifdef __powerpc64__
40 "lfd 13,8b@toc(2)\n\t"
41 #else
42 "mflr 11\n\t"
43 "bcl 20,31,1f\n"
44 "1:" "mflr 9\n\t"
45 "addis 9,9,8b-1b@ha\n\t"
46 "lfs 13,8b-1b@l(9)\n\t"
47 "mtlr 11\n\t"
48 #endif
49 "fabs 0,1\n\t"
50 "fsub 12,13,13\n\t"
51 "fcmpu 7,0,13\n\t"
52 "fcmpu 6,1,12\n\t"
53 "bnllr- 7\n\t"
54 "mtfsfi 7,2\n\t"
55 "ble- 6,2f\n\t"
56 "fadd 1,1,13\n\t"
57 "fsub 1,1,13\n\t"
58 "fabs 1,1\n\t"
59 "mtfsf 0x01,11\n\t"
60 "blr\n"
61 "2:" "bge- 6,3f\n\t"
62 "fsub 1,1,13\n\t"
63 "fadd 1,1,13\n\t"
64 "fnabs 1,1\n"
65 "3:" "mtfsf 0x01,11\n\t"
66 "blr\n\t"
67 "# friz == trunc\n"
68 "friz:" "mffs 11\n\t"
69 #ifdef __powerpc64__
70 "lfd 13,8b@toc(2)\n\t"
71 #else
72 "mflr 11\n\t"
73 "bcl 20,31,1f\n"
74 "1:" "mflr 9\n\t"
75 "addis 9,9,8b-1b@ha\n\t"
76 "lfs 13,8b-1b@l(9)\n\t"
77 "mtlr 11\n\t"
78 #endif
79 "fabs 0,1\n\t"
80 "fsub 12,13,13\n\t"
81 "fcmpu 7,0,13\n\t"
82 "fcmpu 6,1,12\n\t"
83 "bnllr- 7\n\t"
84 "mtfsfi 7,1\n\t"
85 "ble- 6,2f\n\t"
86 "fadd 1,1,13\n\t"
87 "fsub 1,1,13\n\t"
88 "fabs 1,1\n\t"
89 "mtfsf 0x01,11\n\t"
90 "blr\n"
91 "2:" "bge- 6,3f\n\t"
92 "fsub 1,1,13\n\t"
93 "fadd 1,1,13\n\t"
94 "fnabs 1,1\n"
95 "3:" "mtfsf 0x01,11\n\t"
96 "blr\n\t"
97 "# frin == round\n"
98 "frin:" "mffs 11\n\t"
99 #ifdef __powerpc64__
100 "lfd 13,8b@toc(2)\n\t"
101 #else
102 "mflr 11\n\t"
103 "bcl 20,31,1f\n"
104 "1:" "mflr 9\n\t"
105 "addis 9,9,8b-1b@ha\n\t"
106 "addi 9,9,8b-1b@l\n\t"
107 "mtlr 11\n\t"
108 "lfs 13,0(9)\n\t"
109 #endif
110 "fabs 0,1\n\t"
111 "fsub 12,13,13\n\t"
112 "fcmpu 7,0,13\n\t"
113 "fcmpu 6,1,12\n\t"
114 "bnllr- 7\n\t"
115 "mtfsfi 7,1\n\t"
116 #ifdef __powerpc64__
117 "lfd 10,9b@toc(2)\n\t"
118 #else
119 "lfs 10,9b-8b(9)\n\t"
120 #endif
121 "ble- 6,2f\n\t"
122 "fadd 1,1,10\n\t"
123 "fadd 1,1,13\n\t"
124 "fsub 1,1,13\n\t"
125 "fabs 1,1\n\t"
126 "mtfsf 0x01,11\n\t"
127 "blr\n"
128 "2:" "fsub 9,1,10\n\t"
129 "bge- 6,3f\n\t"
130 "fsub 1,9,13\n\t"
131 "fadd 1,1,13\n\t"
132 "fnabs 1,1\n"
133 "3:" "mtfsf 0x01,11\n\t"
134 "blr\n\t"
135 "# frim == floor\n"
136 "frim:" "mffs 11\n\t"
137 #ifdef __powerpc64__
138 "lfd 13,8b@toc(2)\n\t"
139 #else
140 "mflr 11\n\t"
141 "bcl 20,31,1f\n"
142 "1:" "mflr 9\n\t"
143 "addis 9,9,8b-1b@ha\n\t"
144 "lfs 13,8b-1b@l(9)\n\t"
145 "mtlr 11\n\t"
146 #endif
147 "fabs 0,1\n\t"
148 "fsub 12,13,13\n\t"
149 "fcmpu 7,0,13\n\t"
150 "fcmpu 6,1,12\n\t"
151 "bnllr- 7\n\t"
152 "mtfsfi 7,3\n\t"
153 "ble- 6,2f\n\t"
154 "fadd 1,1,13\n\t"
155 "fsub 1,1,13\n\t"
156 "fabs 1,1\n\t"
157 "mtfsf 0x01,11\n\t"
158 "blr\n"
159 "2:" "bge- 6,3f\n\t"
160 "fsub 1,1,13\n\t"
161 "fadd 1,1,13\n\t"
162 "fnabs 1,1\n"
163 "3:" "mtfsf 0x01,11\n\t"
164 "blr\n");
166 static void
167 catch_sigill (int signal, struct sigcontext *ctx)
169 unsigned int insn = *(unsigned int *) (ctx->regs->nip);
170 #ifdef __powerpc64__
171 if ((insn & 0xfc1f07ff) == 0x7c0005be) /* mftgpr */
173 unsigned long *regs = (unsigned long *) ctx->regs;
174 unsigned fpr = (insn >> 11) & 0x1f;
175 unsigned gpr = (insn >> 21) & 0x1f;
176 regs[gpr] = regs[fpr + 0x30];
177 ctx->regs->nip += 4;
178 return;
180 if ((insn & 0xfc1f07ff) == 0x7c0004be) /*mffgpr */
182 unsigned long *regs = (unsigned long *) ctx->regs;
183 unsigned fpr = (insn >> 21) & 0x1f;
184 unsigned gpr = (insn >> 11) & 0x1f;
185 regs[fpr + 0x30] = regs[gpr];
186 ctx->regs->nip += 4;
187 return;
189 #endif
190 if ((insn & 0xfc1f073f) == 0xfc000310) /* fri[pznm] */
192 #ifdef __powerpc64__
193 double *regs = (double *) (((char *) ctx->regs) + 0x30 * 8);
194 unsigned int *fpscr = (unsigned int *) (((char *) ctx->regs) + 0x50 * 8 + 4);
195 #else
196 double *regs = (double *) (((char *) ctx->regs) + 0x30 * 4);
197 unsigned int *fpscr = (unsigned int *) (((char *) ctx->regs) + 0x30 * 4 + 0x20 * 8 + 4);
198 #endif
199 unsigned dest = (insn >> 21) & 0x1f;
200 unsigned src = (insn >> 11) & 0x1f;
201 switch (insn & 0xc0)
203 case 0:
204 regs[dest] = frin (regs[src]);
205 break;
206 case 0x40:
207 regs[dest] = friz (regs[src]);
208 break;
209 case 0x80:
210 regs[dest] = frip (regs[src]);
211 break;
212 case 0xc0:
213 regs[dest] = frim (regs[src]);
214 break;
216 /* Update raised exceptions. */
217 union { unsigned int i[2]; double d; } u;
218 asm volatile ("mffs %0" : "=f" (u.d));
219 u.i[1] &= 0xfffe0000; /* Is this correct? */
220 *fpscr |= u.i[1];
221 ctx->regs->nip += 4;
222 return;
225 struct sigaction sa;
226 sa.sa_handler = SIG_DFL;
227 sigemptyset (&sa.sa_mask);
228 sa.sa_flags = 0;
229 sigaction (signal, &sa, NULL);
230 raise (signal);
233 static void
234 __attribute__ ((constructor))
235 install_handler (void)
237 struct sigaction sa;
238 sa.sa_handler = (void *) catch_sigill;
239 sigemptyset (&sa.sa_mask);
240 sa.sa_flags = SA_RESTART;
241 sigaction (SIGILL, &sa, NULL);