1/* Id: builtins.c,v 1.35 2012/03/22 18:04:41 plunky Exp */ 2/* $NetBSD: builtins.c,v 1.1.1.3.2.1 2012/04/03 16:36:21 riz Exp $ */ 3/* 4 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28# include "pass1.h" 29 30#ifndef MIN 31#define MIN(a,b) (((a)<(b))?(a):(b)) 32#endif 33#ifndef MAX 34#define MAX(a,b) (((a)>(b))?(a):(b)) 35#endif 36 37#ifndef NO_C_BUILTINS 38/* 39 * replace an alloca function with direct allocation on stack. 40 * return a destination temp node. 41 */ 42static NODE * 43builtin_alloca(NODE *f, NODE *a, TWORD rt) 44{ 45 NODE *t, *u; 46 47#ifdef notyet 48 if (xnobuiltins) 49 return NULL; 50#endif 51 52 t = tempnode(0, VOID|PTR, 0, 0); 53 u = tempnode(regno(t), VOID|PTR, 0, 0); 54 spalloc(t, a, SZCHAR); 55 tfree(f); 56 return u; 57} 58 59/* 60 * Determine if a value is known to be constant at compile-time and 61 * hence that PCC can perform constant-folding on expressions involving 62 * that value. 63 */ 64static NODE * 65builtin_constant_p(NODE *f, NODE *a, TWORD rt) 66{ 67 void putjops(NODE *p, void *arg); 68 int isconst; 69 70 tfree(f); 71 walkf(a, putjops, 0); 72 for (f = a; f->n_op == COMOP; f = f->n_right) 73 ; 74 isconst = nncon(f); 75 tfree(a); 76 return bcon(isconst); 77} 78 79/* 80 * Hint to the compiler whether this expression will evaluate true or false. 81 * Just ignored for now. 82 */ 83static NODE * 84builtin_expect(NODE *f, NODE *a, TWORD rt) 85{ 86 87 tfree(f); 88 if (a && a->n_op == CM) { 89 tfree(a->n_right); 90 f = a->n_left; 91 nfree(a); 92 a = f; 93 } 94 95 return a; 96} 97 98/* 99 * Take integer absolute value. 100 * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1))) 101 */ 102static NODE * 103builtin_abs(NODE *f, NODE *a, TWORD rt) 104{ 105 NODE *p, *q, *r, *t, *t2, *t3; 106 int tmp1, tmp2, shift; 107 108 if (a->n_type != INT) 109 a = cast(a, INT, 0); 110 111 tfree(f); 112 113 if (a->n_op == ICON) { 114 if (a->n_lval < 0) 115 a->n_lval = -a->n_lval; 116 p = a; 117 } else { 118 t = tempnode(0, a->n_type, a->n_df, a->n_ap); 119 tmp1 = regno(t); 120 p = buildtree(ASSIGN, t, a); 121 122 t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); 123 shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1; 124 q = buildtree(RS, t, bcon(shift)); 125 126 t2 = tempnode(0, a->n_type, a->n_df, a->n_ap); 127 tmp2 = regno(t2); 128 q = buildtree(ASSIGN, t2, q); 129 130 t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); 131 t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); 132 t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); 133 r = buildtree(MINUS, buildtree(ER, t, t2), t3); 134 135 p = buildtree(COMOP, p, buildtree(COMOP, q, r)); 136 } 137 138 return p; 139} 140 141#define cmop(x,y) buildtree(COMOP, x, y) 142#define lblnod(l) nlabel(l) 143 144#ifndef TARGET_CXZ 145/* 146 * Find number of beginning 0's in a word of type t. 147 * t should be deunsigned. 148 */ 149static NODE * 150builtin_cxz(NODE *f, NODE *a, TWORD t, int isclz) 151{ 152 NODE *t101, *t102; 153 NODE *rn, *p; 154 int l15, l16, l17; 155 int sz; 156 157 tfree(f); 158 t = ctype(t); 159 sz = (int)tsize(t, 0, 0); 160 161 t101 = tempnode(0, INT, 0, 0); 162 t102 = tempnode(0, t, 0, 0); 163 l15 = getlab(); 164 l16 = getlab(); 165 l17 = getlab(); 166 rn = buildtree(ASSIGN, ccopy(t102), a); 167 rn = cmop(rn, buildtree(ASSIGN, ccopy(t101), bcon(0))); 168 rn = cmop(rn, lblnod(l16)); 169 170 p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); 171 rn = cmop(rn, p); 172 if (isclz) { 173 p = buildtree(CBRANCH, 174 buildtree(GE, ccopy(t102), bcon(0)), bcon(l17)); 175 } else { 176 p = buildtree(CBRANCH, 177 buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), 178 bcon(0)), bcon(l17)); 179 } 180 rn = cmop(rn, p); 181 182 rn = cmop(rn, block(GOTO, bcon(l15), NIL, INT, 0, 0)); 183 184 rn = cmop(rn, lblnod(l17)); 185 rn = cmop(rn, buildtree(isclz ? LSEQ : RSEQ , t102, bcon(1))); 186 187 rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); 188 189 rn = cmop(rn, block(GOTO, bcon(l16), NIL, INT, 0, 0)); 190 rn = cmop(rn, lblnod(l15)); 191 return cmop(rn, t101); 192} 193 194static NODE * 195builtin_clz(NODE *f, NODE *a, TWORD rt) 196{ 197 return builtin_cxz(f, a, INT, 1); 198} 199 200static NODE * 201builtin_clzl(NODE *f, NODE *a, TWORD rt) 202{ 203 return builtin_cxz(f, a, LONG, 1); 204} 205 206static NODE * 207builtin_clzll(NODE *f, NODE *a, TWORD rt) 208{ 209 return builtin_cxz(f, a, LONGLONG, 1); 210} 211 212static NODE * 213builtin_ctz(NODE *f, NODE *a, TWORD rt) 214{ 215 return builtin_cxz(f, a, INT, 0); 216} 217 218static NODE * 219builtin_ctzl(NODE *f, NODE *a, TWORD rt) 220{ 221 return builtin_cxz(f, a, LONG, 0); 222} 223 224static NODE * 225builtin_ctzll(NODE *f, NODE *a, TWORD rt) 226{ 227 return builtin_cxz(f, a, LONGLONG, 0); 228} 229#endif 230 231#ifndef TARGET_FFS 232/* 233 * Find number of beginning 0's in a word of type t. 234 * t should be deunsigned. 235 */ 236static NODE * 237builtin_ff(NODE *f, NODE *a, TWORD t) 238{ 239 NODE *t101, *t102; 240 NODE *rn, *p; 241 int l15, l16, l17; 242 int sz; 243 244 tfree(f); 245 t = ctype(t); 246 sz = (int)tsize(t, 0, 0)+1; 247 248 t101 = tempnode(0, INT, 0, 0); 249 t102 = tempnode(0, t, 0, 0); 250 l15 = getlab(); 251 l16 = getlab(); 252 l17 = getlab(); 253 rn = buildtree(ASSIGN, ccopy(t101), bcon(0)); 254 rn = cmop(rn, buildtree(ASSIGN, ccopy(t102), a)); 255 256 p = buildtree(CBRANCH, buildtree(EQ, ccopy(t102), bcon(0)), bcon(l15)); 257 rn = cmop(rn, p); 258 259 rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); 260 261 rn = cmop(rn, lblnod(l16)); 262 263 p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); 264 rn = cmop(rn, p); 265 266 p = buildtree(CBRANCH, 267 buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), 268 bcon(0)), bcon(l17)); 269 rn = cmop(rn, p); 270 271 rn = cmop(rn, block(GOTO, bcon(l15), NIL, INT, 0, 0)); 272 273 rn = cmop(rn, lblnod(l17)); 274 rn = cmop(rn, buildtree(RSEQ, t102, bcon(1))); 275 276 rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); 277 278 rn = cmop(rn, block(GOTO, bcon(l16), NIL, INT, 0, 0)); 279 rn = cmop(rn, lblnod(l15)); 280 return cmop(rn, t101); 281} 282 283static NODE * 284builtin_ffs(NODE *f, NODE *a, TWORD rt) 285{ 286 return builtin_ff(f, a, INT); 287} 288 289static NODE * 290builtin_ffsl(NODE *f, NODE *a, TWORD rt) 291{ 292 return builtin_ff(f, a, LONG); 293} 294 295static NODE * 296builtin_ffsll(NODE *f, NODE *a, TWORD rt) 297{ 298 return builtin_ff(f, a, LONGLONG); 299} 300#endif 301 302/* 303 * Get size of object, if possible. 304 * Currently does nothing, 305 */ 306static NODE * 307builtin_object_size(NODE *f, NODE *a, TWORD rt) 308{ 309 CONSZ v = icons(a->n_right); 310 if (v < 0 || v > 3) 311 uerror("arg2 must be between 0 and 3"); 312 313 tfree(f); 314 f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, rt)); 315 nfree(a); 316 return f; 317} 318 319#ifndef TARGET_STDARGS 320static NODE * 321builtin_stdarg_start(NODE *f, NODE *a, TWORD rt) 322{ 323 NODE *p, *q; 324 int sz; 325 326 /* must first deal with argument size; use int size */ 327 p = a->n_right; 328 if (p->n_type < INT) { 329 sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap)); 330 } else 331 sz = 1; 332 333 /* do the real job */ 334 p = buildtree(ADDROF, p, NIL); /* address of last arg */ 335#ifdef BACKAUTO 336 p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */ 337#else 338 p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */ 339#endif 340 q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */ 341 q = buildtree(CAST, q, p); /* cast to void * (for assignment) */ 342 p = q->n_right; 343 nfree(q->n_left); 344 nfree(q); 345 p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */ 346 tfree(f); 347 nfree(a); 348 return p; 349} 350 351static NODE * 352builtin_va_arg(NODE *f, NODE *a, TWORD rt) 353{ 354 NODE *p, *q, *r, *rv; 355 int sz, nodnum; 356 357 /* create a copy to a temp node of current ap */ 358 p = ccopy(a->n_left); 359 q = tempnode(0, p->n_type, p->n_df, p->n_ap); 360 nodnum = regno(q); 361 rv = buildtree(ASSIGN, q, p); 362 363 r = a->n_right; 364 sz = (int)tsize(r->n_type, r->n_df, r->n_ap)/SZCHAR; 365 /* add one to ap */ 366#ifdef BACKAUTO 367 rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz))); 368#else 369#error fix wrong eval order in builtin_va_arg 370 ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz))); 371#endif 372 373 nfree(a->n_right); 374 nfree(a); 375 nfree(f); 376 r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap); 377 return buildtree(COMOP, rv, buildtree(UMUL, r, NIL)); 378 379} 380 381static NODE * 382builtin_va_end(NODE *f, NODE *a, TWORD rt) 383{ 384 tfree(f); 385 tfree(a); 386 return bcon(0); /* nothing */ 387} 388 389static NODE * 390builtin_va_copy(NODE *f, NODE *a, TWORD rt) 391{ 392 tfree(f); 393 f = buildtree(ASSIGN, a->n_left, a->n_right); 394 nfree(a); 395 return f; 396} 397#endif /* TARGET_STDARGS */ 398 399/* 400 * For unimplemented "builtin" functions, try to invoke the 401 * non-builtin name 402 */ 403static NODE * 404binhelp(NODE *f, NODE *a, TWORD rt, char *n) 405{ 406 f->n_sp = lookup(addname(n), SNORMAL); 407 if (f->n_sp->sclass == SNULL) { 408 f->n_sp->sclass = EXTERN; 409 f->n_sp->stype = INCREF(rt)+(FTN-PTR); 410 } 411 f->n_type = f->n_sp->stype; 412 f = clocal(f); 413 return buildtree(CALL, f, a); 414} 415 416static NODE * 417builtin_unimp(NODE *f, NODE *a, TWORD rt) 418{ 419 char *n = f->n_sp->sname; 420 421 if (strncmp("__builtin_", n, 10) == 0) 422 n += 10; 423 return binhelp(f, a, rt, n); 424} 425 426#if 0 427static NODE * 428builtin_unimp_f(NODE *f, NODE *a, TWORD rt) 429{ 430 return binhelp(f, a, rt, f->n_sp->sname); 431} 432#endif 433 434#ifndef TARGET_PREFETCH 435static NODE * 436builtin_prefetch(NODE *f, NODE *a, TWORD rt) 437{ 438 tfree(f); 439 tfree(a); 440 return bcon(0); 441} 442#endif 443 444#ifndef TARGET_ISMATH 445/* 446 * Handle the builtin macros for the math functions is* 447 * To get something that is be somewhat generic assume that 448 * isnan() is a real function and that cast of a NaN type 449 * to double will still be a NaN. 450 */ 451static NODE * 452mtisnan(NODE *p) 453{ 454 NODE *q = block(NAME, NIL, NIL, INT, 0, 0); 455 456 return binhelp(q, cast(ccopy(p), DOUBLE, 0), INT, "isnan"); 457} 458 459static TWORD 460mtcheck(NODE *p) 461{ 462 TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type; 463 464 if ((t1 >= FLOAT && t1 <= LDOUBLE) || 465 (t2 >= FLOAT && t2 <= LDOUBLE)) 466 return MAX(t1, t2); 467 return 0; 468} 469 470static NODE * 471builtin_isunordered(NODE *f, NODE *a, TWORD rt) 472{ 473 NODE *p; 474 475 if (mtcheck(a) == 0) 476 return bcon(0); 477 478 p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); 479 tfree(f); 480 tfree(a); 481 return p; 482} 483static NODE * 484builtin_isany(NODE *f, NODE *a, TWORD rt, int cmpt) 485{ 486 NODE *p, *q; 487 TWORD t; 488 489 if ((t = mtcheck(a)) == 0) 490 return bcon(0); 491 p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); 492 p = buildtree(NOT, p, NIL); 493 q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0), 494 cast(ccopy(a->n_right), t, 0)); 495 p = buildtree(ANDAND, p, q); 496 tfree(f); 497 tfree(a); 498 return p; 499} 500static NODE * 501builtin_isgreater(NODE *f, NODE *a, TWORD rt) 502{ 503 return builtin_isany(f, a, rt, GT); 504} 505static NODE * 506builtin_isgreaterequal(NODE *f, NODE *a, TWORD rt) 507{ 508 return builtin_isany(f, a, rt, GE); 509} 510static NODE * 511builtin_isless(NODE *f, NODE *a, TWORD rt) 512{ 513 return builtin_isany(f, a, rt, LT); 514} 515static NODE * 516builtin_islessequal(NODE *f, NODE *a, TWORD rt) 517{ 518 return builtin_isany(f, a, rt, LE); 519} 520static NODE * 521builtin_islessgreater(NODE *f, NODE *a, TWORD rt) 522{ 523 NODE *p, *q, *r; 524 TWORD t; 525 526 if ((t = mtcheck(a)) == 0) 527 return bcon(0); 528 p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); 529 p = buildtree(NOT, p, NIL); 530 q = buildtree(GT, cast(ccopy(a->n_left), t, 0), 531 cast(ccopy(a->n_right), t, 0)); 532 r = buildtree(LT, cast(ccopy(a->n_left), t, 0), 533 cast(ccopy(a->n_right), t, 0)); 534 q = buildtree(OROR, q, r); 535 p = buildtree(ANDAND, p, q); 536 tfree(f); 537 tfree(a); 538 return p; 539} 540#endif 541 542/* 543 * Math-specific builtins that expands to constants. 544 * Versins here is for IEEE FP, vax needs its own versions. 545 */ 546#if TARGET_ENDIAN == TARGET_LE 547static char vFLOAT[] = { 0, 0, 0x80, 0x7f }; 548static char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; 549#ifdef LDBL_128 550static char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f }; 551#else /* LDBL_80 */ 552static char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f }; 553#endif 554static char nFLOAT[] = { 0, 0, 0xc0, 0x7f }; 555static char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f }; 556#ifdef LDBL_128 557static char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f }; 558#else /* LDBL_80 */ 559static char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f, 0, 0 }; 560#endif 561#else 562static char vFLOAT[] = { 0x7f, 0x80, 0, 0 }; 563static char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; 564#ifdef LDBL_128 565static char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; 566#else /* LDBL_80 */ 567static char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0 }; 568#endif 569static char nFLOAT[] = { 0x7f, 0xc0, 0, 0 }; 570static char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }; 571#ifdef LDBL_128 572static char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; 573#else /* LDBL_80 */ 574static char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0 }; 575#endif 576#endif 577 578#define VALX(typ,TYP) { \ 579 typ d; \ 580 int x; \ 581 x = MIN(sizeof(n ## TYP), sizeof(d)); \ 582 memcpy(&d, v ## TYP, x); \ 583 nfree(f); \ 584 f = block(FCON, NIL, NIL, TYP, NULL, 0); \ 585 f->n_dcon = d; \ 586 return f; \ 587} 588 589static NODE * 590builtin_huge_valf(NODE *f, NODE *a, TWORD rt) VALX(float,FLOAT) 591static NODE * 592builtin_huge_val(NODE *f, NODE *a, TWORD rt) VALX(double,DOUBLE) 593static NODE * 594builtin_huge_vall(NODE *f, NODE *a, TWORD rt) VALX(long double,LDOUBLE) 595 596#define builtin_inff builtin_huge_valf 597#define builtin_inf builtin_huge_val 598#define builtin_infl builtin_huge_vall 599 600#define NANX(typ,TYP) { \ 601 typ d; \ 602 int x; \ 603 if ((a->n_op == ICON && a->n_sp && a->n_sp->sname[0] == '\0') ||\ 604 (a->n_op == ADDROF && a->n_left->n_op == NAME && \ 605 a->n_left->n_sp && a->n_left->n_sp->sname[0] == '\0')) { \ 606 x = MIN(sizeof(n ## TYP), sizeof(d)); \ 607 memcpy(&d, n ## TYP, x); \ 608 tfree(a); tfree(f); \ 609 f = block(FCON, NIL, NIL, TYP, NULL, 0); \ 610 f->n_dcon = d; \ 611 return f; \ 612 } \ 613 return buildtree(CALL, f, a); \ 614} 615 616/* 617 * Return NANs, if reasonable. 618 */ 619static NODE * 620builtin_nanf(NODE *f, NODE *a, TWORD rt) NANX(float,FLOAT) 621static NODE * 622builtin_nan(NODE *f, NODE *a, TWORD rt) NANX(double,DOUBLE) 623static NODE * 624builtin_nanl(NODE *f, NODE *a, TWORD rt) NANX(long double,LDOUBLE) 625 626/* 627 * Target defines, to implement target versions of the generic builtins 628 */ 629#ifndef TARGET_MEMCMP 630#define builtin_memcmp builtin_unimp 631#endif 632#ifndef TARGET_MEMCPY 633#define builtin_memcpy builtin_unimp 634#endif 635#ifndef TARGET_MEMPCPY 636#define builtin_mempcpy builtin_unimp 637#endif 638#ifndef TARGET_MEMSET 639#define builtin_memset builtin_unimp 640#endif 641 642/* Reasonable type of size_t */ 643#ifndef SIZET 644#if SZINT == SZSHORT 645#define SIZET UNSIGNED 646#elif SZLONG > SZINT 647#define SIZET ULONG 648#else 649#define SIZET UNSIGNED 650#endif 651#endif 652 653static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT }; 654static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT }; 655static TWORD allocat[] = { SIZET }; 656static TWORD expectt[] = { LONG, LONG }; 657static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR }; 658static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT }; 659static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT }; 660static TWORD strchrt[] = { CHAR|PTR, INT }; 661static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR }; 662static TWORD strspnt[] = { CHAR|PTR, CHAR|PTR }; 663static TWORD strpbrkt[] = { CHAR|PTR, CHAR|PTR }; 664static TWORD nant[] = { CHAR|PTR }; 665static TWORD bitt[] = { UNSIGNED }; 666static TWORD bitlt[] = { ULONG }; 667static TWORD bitllt[] = { ULONGLONG }; 668 669static const struct bitable { 670 char *name; 671 NODE *(*fun)(NODE *f, NODE *a, TWORD); 672 int narg; 673 TWORD *tp; 674 TWORD rt; 675} bitable[] = { 676 { "__builtin___memcpy_chk", builtin_unimp, 4, memcpyt, VOID|PTR }, 677 { "__builtin___mempcpy_chk", builtin_unimp, 4, memcpyt, VOID|PTR }, 678 { "__builtin___memmove_chk", builtin_unimp, 4, memcpyt, VOID|PTR }, 679 { "__builtin___memset_chk", builtin_unimp, 4, memsett, VOID|PTR }, 680 681 { "__builtin___strcat_chk", builtin_unimp, 3, strcpyt, CHAR|PTR }, 682 { "__builtin___strcpy_chk", builtin_unimp, 3, strcpyt, CHAR|PTR }, 683 { "__builtin___strncat_chk", builtin_unimp, 4, strncpyt,CHAR|PTR }, 684 { "__builtin___strncpy_chk", builtin_unimp, 4, strncpyt,CHAR|PTR }, 685 686 { "__builtin___printf_chk", builtin_unimp, -1, 0, INT }, 687 { "__builtin___fprintf_chk", builtin_unimp, -1, 0, INT }, 688 { "__builtin___sprintf_chk", builtin_unimp, -1, 0, INT }, 689 { "__builtin___snprintf_chk", builtin_unimp, -1, 0, INT }, 690 { "__builtin___vprintf_chk", builtin_unimp, -1, 0, INT }, 691 { "__builtin___vfprintf_chk", builtin_unimp, -1, 0, INT }, 692 { "__builtin___vsprintf_chk", builtin_unimp, -1, 0, INT }, 693 { "__builtin___vsnprintf_chk", builtin_unimp, -1, 0, INT }, 694 695 { "__builtin_alloca", builtin_alloca, 1, allocat }, 696 { "__builtin_abs", builtin_abs, 1 }, 697 { "__builtin_clz", builtin_clz, 1, bitt, INT }, 698 { "__builtin_clzl", builtin_clzl, 1, bitlt, INT }, 699 { "__builtin_clzll", builtin_clzll, 1, bitllt, INT }, 700 { "__builtin_ctz", builtin_ctz, 1, bitt, INT }, 701 { "__builtin_ctzl", builtin_ctzl, 1, bitlt, INT }, 702 { "__builtin_ctzll", builtin_ctzll, 1, bitllt, INT }, 703 { "__builtin_ffs", builtin_ffs, 1, bitt, INT }, 704 { "__builtin_ffsl", builtin_ffsl, 1, bitlt, INT }, 705 { "__builtin_ffsll", builtin_ffsll, 1, bitllt, INT }, 706 { "__builtin_popcount", builtin_unimp, 1, bitt, UNSIGNED }, 707 { "__builtin_popcountl", builtin_unimp, 1, bitlt, ULONG }, 708 { "__builtin_popcountll", builtin_unimp, 1, bitllt, ULONGLONG }, 709 710 { "__builtin_constant_p", builtin_constant_p, 1 }, 711 { "__builtin_expect", builtin_expect, 2, expectt }, 712 { "__builtin_memcmp", builtin_memcmp, 3, memcpyt, INT }, 713 { "__builtin_memcpy", builtin_memcpy, 3, memcpyt, VOID|PTR }, 714 { "__builtin_mempcpy", builtin_mempcpy, 3, memcpyt, VOID|PTR }, 715 { "__builtin_memset", builtin_memset, 3, memsett, VOID|PTR }, 716 { "__builtin_huge_valf", builtin_huge_valf, 0 }, 717 { "__builtin_huge_val", builtin_huge_val, 0 }, 718 { "__builtin_huge_vall", builtin_huge_vall, 0 }, 719 { "__builtin_inff", builtin_inff, 0 }, 720 { "__builtin_inf", builtin_inf, 0 }, 721 { "__builtin_infl", builtin_infl, 0 }, 722 { "__builtin_isgreater", builtin_isgreater, 2, NULL, INT }, 723 { "__builtin_isgreaterequal", builtin_isgreaterequal, 2, NULL, INT }, 724 { "__builtin_isless", builtin_isless, 2, NULL, INT }, 725 { "__builtin_islessequal", builtin_islessequal, 2, NULL, INT }, 726 { "__builtin_islessgreater", builtin_islessgreater, 2, NULL, INT }, 727 { "__builtin_isunordered", builtin_isunordered, 2, NULL, INT }, 728 { "__builtin_nanf", builtin_nanf, 1, nant, FLOAT }, 729 { "__builtin_nan", builtin_nan, 1, nant, DOUBLE }, 730 { "__builtin_nanl", builtin_nanl, 1, nant, LDOUBLE }, 731 { "__builtin_object_size", builtin_object_size, 2, memsett, SIZET }, 732 { "__builtin_prefetch", builtin_prefetch, 1, memsett, VOID }, 733 { "__builtin_strcmp", builtin_unimp, 2, strcmpt, INT }, 734 { "__builtin_strcpy", builtin_unimp, 2, strcpyt, CHAR|PTR }, 735 { "__builtin_stpcpy", builtin_unimp, 2, strcpyt, CHAR|PTR }, 736 { "__builtin_strchr", builtin_unimp, 2, strchrt, CHAR|PTR }, 737 { "__builtin_strlen", builtin_unimp, 1, strcmpt, SIZET }, 738 { "__builtin_strrchr", builtin_unimp, 2, strchrt, CHAR|PTR }, 739 { "__builtin_strncpy", builtin_unimp, 3, strncpyt, CHAR|PTR }, 740 { "__builtin_strncat", builtin_unimp, 3, strncpyt, CHAR|PTR }, 741 { "__builtin_strcspn", builtin_unimp, 2, strcspnt, SIZET }, 742 { "__builtin_strspn", builtin_unimp, 2, strspnt, SIZET }, 743 { "__builtin_strstr", builtin_unimp, 2, strcmpt, CHAR|PTR }, 744 { "__builtin_strpbrk", builtin_unimp, 2, strpbrkt, CHAR|PTR }, 745#ifndef TARGET_STDARGS 746 { "__builtin_stdarg_start", builtin_stdarg_start, 2 }, 747 { "__builtin_va_start", builtin_stdarg_start, 2 }, 748 { "__builtin_va_arg", builtin_va_arg, 2 }, 749 { "__builtin_va_end", builtin_va_end, 1 }, 750 { "__builtin_va_copy", builtin_va_copy, 2 }, 751#endif 752#ifdef TARGET_BUILTINS 753 TARGET_BUILTINS 754#endif 755}; 756 757/* 758 * Check and cast arguments for builtins. 759 */ 760static int 761acnt(NODE *a, int narg, TWORD *tp) 762{ 763 NODE *q; 764 TWORD t; 765 766 if (a == NIL) 767 return narg; 768 for (; a->n_op == CM; a = a->n_left, narg--) { 769 if (tp == NULL) 770 continue; 771 q = a->n_right; 772 t = ctype(tp[narg-1]); 773 if (q->n_type == t) 774 continue; 775 a->n_right = ccast(q, t, 0, NULL, 0); 776 } 777 778 /* Last arg is ugly to deal with */ 779 if (narg == 1 && tp != NULL) { 780 q = talloc(); 781 *q = *a; 782 q = ccast(q, ctype(tp[0]), 0, NULL, 0); 783 *a = *q; 784 nfree(q); 785 } 786 return narg != 1; 787} 788 789NODE * 790builtin_check(NODE *f, NODE *a) 791{ 792 const struct bitable *bt; 793 int i; 794 795 for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) { 796 bt = &bitable[i]; 797 if (strcmp(bt->name, f->n_sp->sname)) 798 continue; 799 if (bt->narg >= 0 && acnt(a, bt->narg, bt->tp)) { 800 uerror("wrong argument count to %s", bt->name); 801 return bcon(0); 802 } 803 return (*bt->fun)(f, a, bt->rt); 804 } 805 return NIL; 806} 807#endif 808