[gforth] / gforth / engine / support.c  

gforth: gforth/engine/support.c


1 : anton 1.1 /* Gforth support functions
2 :    
3 : anton 1.46 Copyright (C) 1995,1996,1997,1998,2000,2003,2004,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc.
4 : anton 1.1
5 :     This file is part of Gforth.
6 :    
7 :     Gforth is free software; you can redistribute it and/or
8 :     modify it under the terms of the GNU General Public License
9 : anton 1.31 as published by the Free Software Foundation, either version 3
10 : anton 1.1 of the License, or (at your option) any later version.
11 :    
12 :     This program is distributed in the hope that it will be useful,
13 :     but WITHOUT ANY WARRANTY; without even the implied warranty of
14 :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 :     GNU General Public License for more details.
16 :    
17 :     You should have received a copy of the GNU General Public License
18 : anton 1.31 along with this program; if not, see http://www.gnu.org/licenses/.
19 : anton 1.1 */
20 :    
21 :     #include "config.h"
22 :     #include "forth.h"
23 : anton 1.10 #include "io.h"
24 : anton 1.1 #include <stdlib.h>
25 :     #include <string.h>
26 :     #include <sys/time.h>
27 :     #include <unistd.h>
28 :     #include <pwd.h>
29 : anton 1.28 #include <assert.h>
30 : pazsan 1.23 #ifndef STANDALONE
31 : anton 1.1 #include <dirent.h>
32 : anton 1.2 #include <math.h>
33 : anton 1.5 #include <ctype.h>
34 :     #include <errno.h>
35 : anton 1.32 #include <sys/types.h>
36 :     #include <sys/stat.h>
37 :     #include <fcntl.h>
38 :     #include <time.h>
39 : pazsan 1.23 #endif
40 : pazsan 1.34 #if defined(HAVE_LIBDL) || defined(HAVE_DLOPEN) /* what else? */
41 :     #include <dlfcn.h>
42 :     #endif
43 : anton 1.1
44 :     #ifdef HAS_FILE
45 : pazsan 1.47 char *cstr(Char *from, UCell size)
46 : anton 1.1 /* return a C-string corresponding to the Forth string ( FROM SIZE ).
47 : pazsan 1.47 the C-string lives until free */
48 : anton 1.1 {
49 : pazsan 1.47 char * string = malloc(size+1);
50 :     memcpy(string,from,size);
51 :     string[size]='\0';
52 :     return string;
53 : anton 1.1 }
54 :    
55 : pazsan 1.47 char *tilde_cstr(Char *from, UCell size)
56 : anton 1.1 /* like cstr(), but perform tilde expansion on the string */
57 :     {
58 :     char *s1,*s2;
59 :     int s1_len, s2_len;
60 :     struct passwd *getpwnam (), *user_entry;
61 :    
62 :     if (size<1 || from[0]!='~')
63 : pazsan 1.47 return cstr(from, size);
64 : anton 1.1 if (size<2 || from[1]=='/') {
65 :     s1 = (char *)getenv ("HOME");
66 :     if(s1 == NULL)
67 : pazsan 1.8 #if defined(_WIN32) || defined (MSDOS)
68 :     s1 = (char *)getenv ("TEMP");
69 :     if(s1 == NULL)
70 :     s1 = (char *)getenv ("TMP");
71 :     if(s1 == NULL)
72 :     #endif
73 : anton 1.1 s1 = "";
74 : pazsan 1.15 s2 = (char *)from+1;
75 : anton 1.1 s2_len = size-1;
76 :     } else {
77 :     UCell i;
78 :     for (i=1; i<size && from[i]!='/'; i++)
79 :     ;
80 :     if (i==2 && from[1]=='+') /* deal with "~+", i.e., the wd */
81 : pazsan 1.47 return cstr(from+3, size<3?0:size-3);
82 : anton 1.1 {
83 :     char user[i];
84 :     memcpy(user,from+1,i-1);
85 :     user[i-1]='\0';
86 :     user_entry=getpwnam(user);
87 :     }
88 :     if (user_entry==NULL)
89 : pazsan 1.47 return cstr(from, size);
90 : anton 1.1 s1 = user_entry->pw_dir;
91 : pazsan 1.15 s2 = (char *)from+i;
92 : anton 1.1 s2_len = size-i;
93 :     }
94 :     s1_len = strlen(s1);
95 :     if (s1_len>1 && s1[s1_len-1]=='/')
96 :     s1_len--;
97 :     {
98 :     char path[s1_len+s2_len];
99 :     memcpy(path,s1,s1_len);
100 :     memcpy(path+s1_len,s2,s2_len);
101 : pazsan 1.47 return cstr((Char *)path,s1_len+s2_len);
102 : anton 1.1 }
103 :     }
104 : anton 1.29
105 :     Cell opencreate_file(char *s, Cell wfam, int flags, Cell *wiorp)
106 :     {
107 :     Cell fd;
108 :     Cell wfileid;
109 :     fd = open(s, flags|ufileattr[wfam], 0666);
110 :     if (fd != -1) {
111 :     wfileid = (Cell)fdopen(fd, fileattr[wfam]);
112 :     *wiorp = IOR(wfileid == 0);
113 :     } else {
114 :     wfileid = 0;
115 :     *wiorp = IOR(1);
116 :     }
117 :     return wfileid;
118 :     }
119 :     #endif /* defined(HAS_FILE) */
120 : anton 1.1
121 :     DCell timeval2us(struct timeval *tvp)
122 :     {
123 :     #ifndef BUGGY_LONG_LONG
124 :     return (tvp->tv_sec*(DCell)1000000)+tvp->tv_usec;
125 :     #else
126 :     DCell d2;
127 :     DCell d1=mmul(tvp->tv_sec,1000000);
128 :     d2.lo = d1.lo+tvp->tv_usec;
129 :     d2.hi = d1.hi + (d2.lo<d1.lo);
130 :     return d2;
131 :     #endif
132 :     }
133 :    
134 : pazsan 1.44 DCell timespec2ns(struct timespec *tvp)
135 :     {
136 :     #ifndef BUGGY_LONG_LONG
137 : pazsan 1.45 return (tvp->tv_sec*(DCell)1000000000LL)+tvp->tv_nsec;
138 : pazsan 1.44 #else
139 :     DCell d2;
140 :     DCell d1=mmul(tvp->tv_sec,1000000000);
141 :     d2.lo = d1.lo+tvp->tv_nsec;
142 :     d2.hi = d1.hi + (d2.lo<d1.lo);
143 :     return d2;
144 :     #endif
145 :     }
146 :    
147 : anton 1.2 DCell double2ll(Float r)
148 :     {
149 :     #ifndef BUGGY_LONG_LONG
150 :     return (DCell)(r);
151 :     #else
152 :     double ldexp(double x, int exp);
153 :     DCell d;
154 :     if (r<0) {
155 :     d.hi = ldexp(-r,-(int)(CELL_BITS));
156 :     d.lo = (-r)-ldexp((Float)d.hi,CELL_BITS);
157 :     return dnegate(d);
158 :     }
159 :     d.hi = ldexp(r,-(int)(CELL_BITS));
160 :     d.lo = r-ldexp((Float)d.hi,CELL_BITS);
161 :     return d;
162 :     #endif
163 : anton 1.5 }
164 :    
165 :     void cmove(Char *c_from, Char *c_to, UCell u)
166 :     {
167 :     while (u-- > 0)
168 :     *c_to++ = *c_from++;
169 :     }
170 :    
171 :     void cmove_up(Char *c_from, Char *c_to, UCell u)
172 :     {
173 :     while (u-- > 0)
174 :     c_to[u] = c_from[u];
175 :     }
176 :    
177 :     Cell compare(Char *c_addr1, UCell u1, Char *c_addr2, UCell u2)
178 :     {
179 :     Cell n;
180 :    
181 :     n = memcmp(c_addr1, c_addr2, u1<u2 ? u1 : u2);
182 :     if (n==0)
183 :     n = u1-u2;
184 :     if (n<0)
185 :     n = -1;
186 :     else if (n>0)
187 :     n = 1;
188 :     return n;
189 :     }
190 :    
191 :     Cell memcasecmp(const Char *s1, const Char *s2, Cell n)
192 :     {
193 :     Cell i;
194 :    
195 :     for (i=0; i<n; i++) {
196 :     Char c1=toupper(s1[i]);
197 :     Char c2=toupper(s2[i]);
198 :     if (c1 != c2) {
199 :     if (c1 < c2)
200 :     return -1;
201 :     else
202 :     return 1;
203 :     }
204 :     }
205 :     return 0;
206 :     }
207 :    
208 : pazsan 1.14 Cell capscompare(Char *c_addr1, UCell u1, Char *c_addr2, UCell u2)
209 :     {
210 :     Cell n;
211 :    
212 :     n = memcasecmp(c_addr1, c_addr2, u1<u2 ? u1 : u2);
213 :     if (n==0)
214 :     n = u1-u2;
215 :     if (n<0)
216 :     n = -1;
217 :     else if (n>0)
218 :     n = 1;
219 :     return n;
220 :     }
221 :    
222 : anton 1.5 struct Longname *listlfind(Char *c_addr, UCell u, struct Longname *longname1)
223 :     {
224 :     for (; longname1 != NULL; longname1 = (struct Longname *)(longname1->next))
225 :     if ((UCell)LONGNAME_COUNT(longname1)==u &&
226 : pazsan 1.15 memcasecmp(c_addr, (Char *)(longname1->name), u)== 0 /* or inline? */)
227 : anton 1.5 break;
228 :     return longname1;
229 :     }
230 :    
231 :     struct Longname *hashlfind(Char *c_addr, UCell u, Cell *a_addr)
232 :     {
233 :     struct Longname *longname1;
234 :    
235 :     while(a_addr != NULL) {
236 :     longname1=(struct Longname *)(a_addr[1]);
237 :     a_addr=(Cell *)(a_addr[0]);
238 :     if ((UCell)LONGNAME_COUNT(longname1)==u &&
239 : pazsan 1.15 memcasecmp(c_addr, (Char *)(longname1->name), u)== 0 /* or inline? */) {
240 : anton 1.5 return longname1;
241 :     }
242 :     }
243 :     return NULL;
244 :     }
245 :    
246 :     struct Longname *tablelfind(Char *c_addr, UCell u, Cell *a_addr)
247 :     {
248 :     struct Longname *longname1;
249 :     while(a_addr != NULL) {
250 :     longname1=(struct Longname *)(a_addr[1]);
251 :     a_addr=(Cell *)(a_addr[0]);
252 :     if ((UCell)LONGNAME_COUNT(longname1)==u &&
253 :     memcmp(c_addr, longname1->name, u)== 0 /* or inline? */) {
254 :     return longname1;
255 :     }
256 :     }
257 :     return NULL;
258 :     }
259 :    
260 :     UCell hashkey1(Char *c_addr, UCell u, UCell ubits)
261 :     /* this hash function rotates the key at every step by rot bits within
262 :     ubits bits and xors it with the character. This function does ok in
263 :     the chi-sqare-test. Rot should be <=7 (preferably <=5) for
264 :     ASCII strings (larger if ubits is large), and should share no
265 :     divisors with ubits.
266 :     */
267 :     {
268 :     static char rot_values[] = {5,0,1,2,3,4,5,5,5,5,3,5,5,5,5,7,5,5,5,5,7,5,5,5,5,6,5,5,5,5,7,5,5};
269 :     unsigned rot = rot_values[ubits];
270 :     Char *cp = c_addr;
271 :     UCell ukey;
272 :    
273 :     for (ukey=0; cp<c_addr+u; cp++)
274 :     ukey = ((((ukey<<rot) | (ukey>>(ubits-rot)))
275 :     ^ toupper(*cp))
276 :     & ((1<<ubits)-1));
277 :     return ukey;
278 :     }
279 :    
280 :     struct Cellpair parse_white(Char *c_addr1, UCell u1)
281 :     {
282 :     /* use !isgraph instead of isspace? */
283 :     struct Cellpair result;
284 :     Char *c_addr2;
285 :     Char *endp = c_addr1+u1;
286 :     while (c_addr1<endp && isspace(*c_addr1))
287 :     c_addr1++;
288 :     if (c_addr1<endp) {
289 :     for (c_addr2 = c_addr1; c_addr1<endp && !isspace(*c_addr1); c_addr1++)
290 :     ;
291 : anton 1.6 result.n1 = (Cell)c_addr2;
292 : anton 1.5 result.n2 = c_addr1-c_addr2;
293 :     } else {
294 : anton 1.6 result.n1 = (Cell)c_addr1;
295 : anton 1.5 result.n2 = 0;
296 :     }
297 :     return result;
298 :     }
299 :    
300 : pazsan 1.22 #ifdef HAS_FILE
301 : anton 1.5 Cell rename_file(Char *c_addr1, UCell u1, Char *c_addr2, UCell u2)
302 :     {
303 : pazsan 1.47 char *s1=tilde_cstr(c_addr2, u2);
304 :     char *s2=tilde_cstr(c_addr1, u1);
305 :     return IOR(rename(s2, s1)==-1);
306 :     free(s1);
307 :     free(s2);
308 : anton 1.5 }
309 :    
310 : anton 1.40 struct Cellquad read_line(Char *c_addr, UCell u1, FILE *wfileid)
311 : anton 1.5 {
312 :     UCell u2, u3;
313 :     Cell flag, wior;
314 :     Cell c;
315 :     struct Cellquad r;
316 :    
317 :     flag=-1;
318 :     u3=0;
319 : anton 1.40 if (u1>0)
320 :     gf_regetc(wfileid);
321 : anton 1.5 for(u2=0; u2<u1; u2++) {
322 : anton 1.40 c = getc(wfileid);
323 : anton 1.5 u3++;
324 :     if (c=='\n') break;
325 :     if (c=='\r') {
326 : anton 1.40 if ((c = getc(wfileid))!='\n')
327 :     gf_ungetc(c,wfileid);
328 : anton 1.5 else
329 :     u3++;
330 :     break;
331 :     }
332 :     if (c==EOF) {
333 :     flag=FLAG(u2!=0);
334 :     break;
335 :     }
336 :     c_addr[u2] = (Char)c;
337 :     }
338 : anton 1.40 wior=FILEIO(ferror(wfileid));
339 : anton 1.5 r.n1 = u2;
340 :     r.n2 = flag;
341 :     r.n3 = u3;
342 :     r.n4 = wior;
343 :     return r;
344 :     }
345 :    
346 :     struct Cellpair file_status(Char *c_addr, UCell u)
347 :     {
348 :     struct Cellpair r;
349 :     Cell wfam;
350 :     Cell wior;
351 : pazsan 1.47 char *filename=tilde_cstr(c_addr, u);
352 : anton 1.5
353 :     if (access (filename, F_OK) != 0) {
354 :     wfam=0;
355 :     wior=IOR(1);
356 :     }
357 :     else if (access (filename, R_OK | W_OK) == 0) {
358 :     wfam=2; /* r/w */
359 :     wior=0;
360 :     }
361 :     else if (access (filename, R_OK) == 0) {
362 :     wfam=0; /* r/o */
363 :     wior=0;
364 :     }
365 :     else if (access (filename, W_OK) == 0) {
366 :     wfam=4; /* w/o */
367 :     wior=0;
368 :     }
369 :     else {
370 :     wfam=1; /* well, we cannot access the file, but better deliver a
371 :     legal access mode (r/o bin), so we get a decent error
372 :     later upon open. */
373 :     wior=0;
374 :     }
375 :     r.n1 = wfam;
376 :     r.n2 = wior;
377 : pazsan 1.47 free(filename);
378 : anton 1.6 return r;
379 : anton 1.5 }
380 :    
381 : pazsan 1.49 Cell to_float(Char *c_addr, UCell u, Float *rp, Char dot)
382 : anton 1.5 {
383 : anton 1.28 /* convertible string := <significand>[<exponent>]
384 :     <significand> := [<sign>]{<digits>[.<digits0>] | .<digits> }
385 :     <exponent> := <marker><digits0>
386 :     <marker> := {<e-form> | <sign-form>}
387 :     <e-form> := <e-char>[<sign-form>]
388 :     <sign-form> := { + | - }
389 :     <e-char> := { D | d | E | e }
390 :     */
391 :     Char *s = c_addr;
392 :     Char c;
393 :     Char *send = c_addr+u;
394 :     UCell ndigits = 0;
395 :     UCell ndots = 0;
396 :     UCell edigits = 0;
397 :     char cnum[u+3]; /* append at most "e0\0" */
398 :     char *t=cnum;
399 :     char *endconv;
400 : anton 1.5 Float r;
401 : anton 1.28
402 :     if (s >= send) /* treat empty string as 0e */
403 :     goto return0;
404 :     switch ((c=*s)) {
405 :     case ' ':
406 :     /* "A string of blanks should be treated as a special case
407 :     representing zero."*/
408 :     for (s++; s<send; )
409 :     if (*s++ != ' ')
410 :     goto error;
411 :     goto return0;
412 :     case '-':
413 :     case '+': *t++ = c; s++; goto aftersign;
414 :     }
415 :     aftersign:
416 :     if (s >= send)
417 :     goto exponent;
418 : pazsan 1.49 if((c=*s)==dot) { *t++ = '.'; ndots++; s++; goto aftersign; }
419 :     switch (c) {
420 : anton 1.28 case '0' ... '9': *t++ = c; ndigits++; s++; goto aftersign;
421 :     default: goto exponent;
422 :     }
423 :     exponent:
424 :     if (ndigits < 1 || ndots > 1)
425 :     goto error;
426 :     *t++ = 'E';
427 :     if (s >= send)
428 :     goto done;
429 :     switch (c=*s) {
430 :     case 'D':
431 : anton 1.5 case 'd':
432 : anton 1.28 case 'E':
433 :     case 'e': s++; break;
434 : anton 1.5 }
435 : anton 1.28 if (s >= send)
436 :     goto done;
437 :     switch (c=*s) {
438 :     case '+':
439 :     case '-': *t++ = c; s++; break;
440 :     }
441 :     edigits0:
442 :     if (s >= send)
443 :     goto done;
444 :     switch (c=*s) {
445 :     case '0' ... '9': *t++ = c; s++; edigits++; goto edigits0;
446 :     default: goto error;
447 :     }
448 :     done:
449 :     if (edigits == 0)
450 :     *t++ = '0';
451 :     *t++ = '\0';
452 :     assert(t-cnum <= u+3);
453 :     r = strtod(cnum, &endconv);
454 :     assert(*endconv == '\0');
455 : anton 1.5 *rp = r;
456 : anton 1.28 return -1;
457 :     return0:
458 :     *rp = 0.0;
459 :     return -1;
460 :     error:
461 :     *rp = 0.0;
462 :     return 0;
463 : anton 1.5 }
464 : pazsan 1.22 #endif
465 : anton 1.5
466 : pazsan 1.25 #ifdef HAS_FLOATING
467 : anton 1.5 Float v_star(Float *f_addr1, Cell nstride1, Float *f_addr2, Cell nstride2, UCell ucount)
468 :     {
469 :     Float r;
470 :    
471 :     for (r=0.; ucount>0; ucount--) {
472 :     r += *f_addr1 * *f_addr2;
473 :     f_addr1 = (Float *)(((Address)f_addr1)+nstride1);
474 :     f_addr2 = (Float *)(((Address)f_addr2)+nstride2);
475 :     }
476 :     return r;
477 :     }
478 :    
479 :     void faxpy(Float ra, Float *f_x, Cell nstridex, Float *f_y, Cell nstridey, UCell ucount)
480 :     {
481 :     for (; ucount>0; ucount--) {
482 :     *f_y += ra * *f_x;
483 :     f_x = (Float *)(((Address)f_x)+nstridex);
484 :     f_y = (Float *)(((Address)f_y)+nstridey);
485 :     }
486 : anton 1.1 }
487 : pazsan 1.24 #endif
488 : pazsan 1.9
489 :     UCell lshift(UCell u1, UCell n)
490 :     {
491 :     return u1 << n;
492 :     }
493 :    
494 :     UCell rshift(UCell u1, UCell n)
495 :     {
496 :     return u1 >> n;
497 : anton 1.10 }
498 :    
499 : pazsan 1.24 #ifndef STANDALONE
500 : anton 1.10 int gforth_system(Char *c_addr, UCell u)
501 :     {
502 :     int retval;
503 :     char *prefix = getenv("GFORTHSYSTEMPREFIX") ? : DEFAULTSYSTEMPREFIX;
504 :     size_t prefixlen = strlen(prefix);
505 :     char buffer[prefixlen+u+1];
506 : anton 1.42 int MAYBE_UNUSED old_tp;
507 : anton 1.39 fflush(stdout);
508 : anton 1.10 #ifndef MSDOS
509 : anton 1.42 old_tp=terminal_prepped;
510 : anton 1.10 deprep_terminal();
511 :     #endif
512 :     memcpy(buffer,prefix,prefixlen);
513 :     memcpy(buffer+prefixlen,c_addr,u);
514 :     buffer[prefixlen+u]='\0';
515 :     retval=system(buffer); /* ~ expansion on first part of string? */
516 :     #ifndef MSDOS
517 :     if (old_tp)
518 :     prep_terminal();
519 :     #endif
520 :     return retval;
521 : pazsan 1.9 }
522 : anton 1.26
523 :     void gforth_ms(UCell u)
524 :     {
525 :     #ifdef HAVE_NANOSLEEP
526 :     struct timespec time_req;
527 :     time_req.tv_sec=u/1000;
528 :     time_req.tv_nsec=1000000*(u%1000);
529 :     while(nanosleep(&time_req, &time_req));
530 :     #else /* !defined(HAVE_NANOSLEEP) */
531 :     struct timeval timeout;
532 :     timeout.tv_sec=u/1000;
533 :     timeout.tv_usec=1000*(u%1000);
534 :     (void)select(0,0,0,0,&timeout);
535 :     #endif /* !defined(HAVE_NANOSLEEP) */
536 :     }
537 : pazsan 1.33
538 :     UCell gforth_dlopen(Char *c_addr, UCell u)
539 :     {
540 : pazsan 1.47 char * file=tilde_cstr(c_addr, u);
541 : pazsan 1.36 UCell lib;
542 : pazsan 1.34 #if defined(HAVE_LIBLTDL)
543 :     lib = (UCell)lt_dlopen(file);
544 : pazsan 1.47 free(file);
545 : pazsan 1.34 if(lib) return lib;
546 : pazsan 1.33 #elif defined(HAVE_LIBDL) || defined(HAVE_DLOPEN)
547 :     #ifndef RTLD_GLOBAL
548 :     #define RTLD_GLOBAL 0
549 :     #endif
550 : pazsan 1.48 lib = (UCell)dlopen(file, RTLD_GLOBAL);
551 : pazsan 1.47 free(file);
552 : pazsan 1.34 if(lib) return lib;
553 : pazsan 1.50 fprintf(stderr, "%s\n", dlerror());
554 : pazsan 1.34 #elif defined(_WIN32)
555 :     lib = (UCell) GetModuleHandle(file);
556 : pazsan 1.47 free(file);
557 : pazsan 1.34 if(lib) return lib;
558 :     #endif
559 : pazsan 1.33 return 0;
560 :     }
561 :    
562 : anton 1.26 #endif /* !defined(STANDALONE) */
563 :    
564 : anton 1.16
565 : anton 1.17 /* mixed division support; should usually be faster than gcc's
566 : anton 1.16 double-by-double division (and gcc typically does not generate
567 :     double-by-single division because of exception handling issues. If
568 :     the architecture has double-by-single division, you should define
569 : anton 1.17 ASM_SM_SLASH_REM and ASM_UM_SLASH_MOD appropriately. */
570 : anton 1.16
571 : anton 1.17 /* Type definitions for longlong.h (according to the comments at the start):
572 :     declarations taken from libgcc2.h */
573 :    
574 :     typedef unsigned int UQItype __attribute__ ((mode (QI)));
575 :     typedef int SItype __attribute__ ((mode (SI)));
576 :     typedef unsigned int USItype __attribute__ ((mode (SI)));
577 :     typedef int DItype __attribute__ ((mode (DI)));
578 :     typedef unsigned int UDItype __attribute__ ((mode (DI)));
579 :     typedef UCell UWtype;
580 :     #if (SIZEOF_CHAR_P == 4)
581 :     typedef unsigned int UHWtype __attribute__ ((mode (HI)));
582 :     #endif
583 :     #if (SIZEOF_CHAR_P == 8)
584 :     typedef USItype UHWtype;
585 :     #endif
586 :     #ifndef BUGGY_LONG_LONG
587 :     typedef UDCell UDWtype;
588 :     #endif
589 :     #define W_TYPE_SIZE (SIZEOF_CHAR_P * 8)
590 :    
591 :     #include "longlong.h"
592 :    
593 : anton 1.37
594 : anton 1.27 #if defined(udiv_qrnnd) && !defined(__alpha) && UDIV_NEEDS_NORMALIZATION
595 : anton 1.37
596 :     #if defined(count_leading_zeros)
597 :     const UQItype __clz_tab[256] =
598 :     {
599 :     0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
600 :     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
601 :     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
602 :     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
603 :     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
604 :     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
605 :     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
606 :     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
607 :     };
608 :     #endif
609 :    
610 : anton 1.17 static Cell MAYBE_UNUSED nlz(UCell x)
611 : anton 1.16 /* number of leading zeros, adapted from "Hacker's Delight" */
612 :     {
613 :     Cell n;
614 :    
615 : anton 1.17 #if !defined(COUNT_LEADING_ZEROS_0)
616 : anton 1.16 if (x == 0) return(CELL_BITS);
617 : anton 1.17 #endif
618 :     #if defined(count_leading_zeros)
619 :     count_leading_zeros(n,x);
620 :     #else
621 : anton 1.16 n = 0;
622 :     #if (SIZEOF_CHAR_P > 4)
623 : anton 1.27 if (x <= 0xffffffff)
624 :     n+=32;
625 :     else
626 :     x >>= 32;
627 : anton 1.16 #endif
628 :     if (x <= 0x0000FFFF) {n = n +16; x = x <<16;}
629 :     if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;}
630 :     if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
631 :     if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
632 :     if (x <= 0x7FFFFFFF) {n = n + 1;}
633 : anton 1.17 #endif
634 : anton 1.16 return n;
635 :     }
636 : anton 1.27 #endif /*defined(udiv_qrnnd) && !defined(__alpha) && UDIV_NEEDS_NORMALIZATION*/
637 : anton 1.16
638 : anton 1.17 #if !defined(ASM_UM_SLASH_MOD)
639 : anton 1.16 UDCell umdiv (UDCell u, UCell v)
640 :     /* Divide unsigned double by single precision using shifts and subtracts.
641 :     Return quotient in lo, remainder in hi. */
642 :     {
643 : anton 1.17 UDCell res;
644 : anton 1.27 #if defined(udiv_qrnnd) && !defined(__alpha)
645 :     #if 0
646 :     This code is slower on an Alpha (timings with gcc-3.3.5):
647 :     other this
648 :     */ 5205 ms 5741 ms
649 :     */mod 5167 ms 5717 ms
650 :     fm/mod 5467 ms 5312 ms
651 :     sm/rem 4734 ms 5278 ms
652 :     um/mod 4490 ms 5020 ms
653 :     m*/ 15557 ms 17151 ms
654 :     #endif /* 0 */
655 : anton 1.17 UCell q,r,u0,u1;
656 :     UCell MAYBE_UNUSED lz;
657 :    
658 :     vm_ud2twoCell(u,u0,u1);
659 :     if (v==0)
660 :     throw(BALL_DIVZERO);
661 :     if (u1>=v)
662 :     throw(BALL_RESULTRANGE);
663 :     #if UDIV_NEEDS_NORMALIZATION
664 :     lz = nlz(v);
665 :     v <<= lz;
666 : anton 1.19 u = UDLSHIFT(u,lz);
667 : anton 1.17 vm_ud2twoCell(u,u0,u1);
668 :     #endif
669 :     udiv_qrnnd(q,r,u1,u0,v);
670 :     #if UDIV_NEEDS_NORMALIZATION
671 :     r >>= lz;
672 :     #endif
673 :     vm_twoCell2ud(q,r,res);
674 : anton 1.27 #else /* !(defined(udiv_qrnnd) && !defined(__alpha)) */
675 : anton 1.16 /* simple restoring subtract-and-shift algorithm, might be faster on Alpha */
676 :     int i = CELL_BITS, c = 0;
677 :     UCell q = 0;
678 : anton 1.27 UCell h, l;
679 : anton 1.16
680 :     vm_ud2twoCell(u,l,h);
681 :     if (v==0)
682 :     throw(BALL_DIVZERO);
683 :     if (h>=v)
684 :     throw(BALL_RESULTRANGE);
685 :     for (;;)
686 :     {
687 :     if (c || h >= v)
688 :     {
689 :     q++;
690 :     h -= v;
691 :     }
692 :     if (--i < 0)
693 :     break;
694 :     c = HIGHBIT (h);
695 :     h <<= 1;
696 :     h += HIGHBIT (l);
697 :     l <<= 1;
698 :     q <<= 1;
699 :     }
700 :     vm_twoCell2ud(q,h,res);
701 : anton 1.27 #endif /* !(defined(udiv_qrnnd) && !defined(__alpha)) */
702 : anton 1.16 return res;
703 :     }
704 :     #endif
705 :    
706 :     #if !defined(ASM_SM_SLASH_REM)
707 :     #if defined(ASM_UM_SLASH_MOD)
708 :     /* define it if it is not defined above */
709 : anton 1.17 static UDCell MAYBE_UNUSED umdiv (UDCell u, UCell v)
710 : anton 1.16 {
711 :     UDCell res;
712 :     UCell u0,u1;
713 :     vm_ud2twoCell(u,u0,u1);
714 :     ASM_UM_SLASH_MOD(u0,u1,v,r,q);
715 :     vm_twoCell2ud(q,r,res);
716 :     return res;
717 :     }
718 :     #endif /* defined(ASM_UM_SLASH_MOD) */
719 :    
720 :     #ifndef BUGGY_LONG_LONG
721 :     #define dnegate(x) (-(x))
722 :     #endif
723 :    
724 : anton 1.17 DCell smdiv (DCell num, Cell denom)
725 :     /* symmetric divide procedure, mixed prec */
726 : anton 1.16 {
727 :     DCell res;
728 : anton 1.17 #if defined(sdiv_qrnnd)
729 : anton 1.32 /* #warning "using sdiv_qrnnd" */
730 : anton 1.17 Cell u1,q,r
731 :     UCell u0;
732 :     UCell MAYBE_UNUSED lz;
733 :    
734 :     vm_d2twoCell(u,u0,u1);
735 :     if (v==0)
736 :     throw(BALL_DIVZERO);
737 :     if (u1>=v)
738 :     throw(BALL_RESULTRANGE);
739 :     sdiv_qrnnd(q,r,u1,u0,v);
740 :     vm_twoCell2d(q,r,res);
741 :     #else
742 : anton 1.16 UDCell ures;
743 :     UCell l, q, r;
744 :     Cell h;
745 :     Cell denomsign=denom;
746 :    
747 :     vm_d2twoCell(num,l,h);
748 :     if (h < 0)
749 :     num = dnegate (num);
750 :     if (denomsign < 0)
751 :     denom = -denom;
752 :     ures = umdiv(D2UD(num), denom);
753 :     vm_ud2twoCell(ures,q,r);
754 :     if ((h^denomsign)<0) {
755 :     q = -q;
756 :     if (((Cell)q) > 0) /* note: == 0 is possible */
757 :     throw(BALL_RESULTRANGE);
758 :     } else {
759 :     if (((Cell)q) < 0)
760 :     throw(BALL_RESULTRANGE);
761 :     }
762 :     if (h<0)
763 :     r = -r;
764 :     vm_twoCell2d(q,r,res);
765 : anton 1.17 #endif
766 : anton 1.16 return res;
767 :     }
768 :    
769 : anton 1.17 DCell fmdiv (DCell num, Cell denom)
770 :     /* floored divide procedure, mixed prec */
771 : anton 1.16 {
772 :     /* I have this technique from Andrew Haley */
773 :     DCell res;
774 :     UDCell ures;
775 :     Cell denomsign=denom;
776 :     Cell numsign;
777 :     UCell q,r;
778 :    
779 :     if (denom < 0) {
780 :     denom = -denom;
781 :     num = dnegate(num);
782 :     }
783 :     numsign = DHI(num);
784 :     if (numsign < 0)
785 :     DHI_IS(num,DHI(num)+denom);
786 :     ures = umdiv(D2UD(num),denom);
787 :     vm_ud2twoCell(ures,q,r);
788 :     if ((numsign^((Cell)q)) < 0)
789 :     throw(BALL_RESULTRANGE);
790 :     if (denomsign<0)
791 :     r = -r;
792 :     vm_twoCell2d(q,r,res);
793 :     return res;
794 :     }
795 :     #endif

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help