* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / cc / ccom / builtins.c
blob192cfbe996d530389882ef31dd47fd7a87d87f23
1 /* $Id: builtins.c,v 1.18.2.2 2011/03/29 15:56:24 ragge Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # include "pass1.h"
29 #ifndef MIN
30 #define MIN(a,b) (((a)<(b))?(a):(b))
31 #endif
32 #ifndef MAX
33 #define MAX(a,b) (((a)>(b))?(a):(b))
34 #endif
36 #ifndef NO_C_BUILTINS
38 * replace an alloca function with direct allocation on stack.
39 * return a destination temp node.
41 static NODE *
42 builtin_alloca(NODE *f, NODE *a, TWORD rt)
44 struct symtab *sp;
45 NODE *t, *u;
47 #ifdef notyet
48 if (xnobuiltins)
49 return NULL;
50 #endif
51 sp = f->n_sp;
53 t = tempnode(0, VOID|PTR, 0, MKAP(INT) /* XXX */);
54 u = tempnode(regno(t), VOID|PTR, 0, MKAP(INT) /* XXX */);
55 spalloc(t, a, SZCHAR);
56 tfree(f);
57 return u;
61 * See if there is a goto in the tree.
62 * XXX this function is a hack for a flaw in handling of
63 * compound expressions and inline functions and should not be
64 * needed.
66 static int
67 hasgoto(NODE *p)
69 int o = coptype(p->n_op);
71 if (o == LTYPE)
72 return 0;
73 if (p->n_op == GOTO)
74 return 1;
75 if (o == UTYPE)
76 return hasgoto(p->n_left);
77 if (hasgoto(p->n_left))
78 return 1;
79 return hasgoto(p->n_right);
83 * Determine if a value is known to be constant at compile-time and
84 * hence that PCC can perform constant-folding on expressions involving
85 * that value.
87 static NODE *
88 builtin_constant_p(NODE *f, NODE *a, TWORD rt)
90 void putjops(NODE *p, void *arg);
91 int isconst;
93 tfree(f);
94 walkf(a, putjops, 0);
95 for (f = a; f->n_op == COMOP; f = f->n_right)
97 isconst = nncon(f);
98 tfree(a);
99 return bcon(isconst);
103 * Hint to the compiler whether this expression will evaluate true or false.
104 * Just ignored for now.
106 static NODE *
107 builtin_expect(NODE *f, NODE *a, TWORD rt)
110 tfree(f);
111 if (a && a->n_op == CM) {
112 tfree(a->n_right);
113 f = a->n_left;
114 nfree(a);
115 a = f;
118 return a;
122 * Take integer absolute value.
123 * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1)))
125 static NODE *
126 builtin_abs(NODE *f, NODE *a, TWORD rt)
128 NODE *p, *q, *r, *t, *t2, *t3;
129 int tmp1, tmp2, shift;
131 if (a->n_type != INT)
132 a = cast(a, INT, 0);
134 tfree(f);
136 if (a->n_op == ICON) {
137 if (a->n_lval < 0)
138 a->n_lval = -a->n_lval;
139 p = a;
140 } else {
141 t = tempnode(0, a->n_type, a->n_df, a->n_ap);
142 tmp1 = regno(t);
143 p = buildtree(ASSIGN, t, a);
145 t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
146 shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1;
147 q = buildtree(RS, t, bcon(shift));
149 t2 = tempnode(0, a->n_type, a->n_df, a->n_ap);
150 tmp2 = regno(t2);
151 q = buildtree(ASSIGN, t2, q);
153 t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
154 t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
155 t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
156 r = buildtree(MINUS, buildtree(ER, t, t2), t3);
158 p = buildtree(COMOP, p, buildtree(COMOP, q, r));
161 return p;
165 * Get size of object, if possible.
166 * Currently does nothing,
168 static NODE *
169 builtin_object_size(NODE *f, NODE *a, TWORD rt)
171 int v = icons(a->n_right);
172 if (v < 0 || v > 3)
173 uerror("arg2 must be between 0 and 3");
175 tfree(f);
176 f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, rt));
177 nfree(a);
178 return f;
181 #ifndef TARGET_STDARGS
182 static NODE *
183 builtin_stdarg_start(NODE *f, NODE *a, TWORD rt)
185 NODE *p, *q;
186 int sz;
188 /* must first deal with argument size; use int size */
189 p = a->n_right;
190 if (p->n_type < INT) {
191 sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap));
192 } else
193 sz = 1;
195 /* do the real job */
196 p = buildtree(ADDROF, p, NIL); /* address of last arg */
197 #ifdef BACKAUTO
198 p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */
199 #else
200 p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */
201 #endif
202 q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */
203 q = buildtree(CAST, q, p); /* cast to void * (for assignment) */
204 p = q->n_right;
205 nfree(q->n_left);
206 nfree(q);
207 p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */
208 tfree(f);
209 nfree(a);
210 return p;
213 static NODE *
214 builtin_va_arg(NODE *f, NODE *a, TWORD rt)
216 NODE *p, *q, *r, *rv;
217 int sz, nodnum;
219 /* create a copy to a temp node of current ap */
220 p = ccopy(a->n_left);
221 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
222 nodnum = regno(q);
223 rv = buildtree(ASSIGN, q, p);
225 r = a->n_right;
226 sz = (int)tsize(r->n_type, r->n_df, r->n_ap)/SZCHAR;
227 /* add one to ap */
228 #ifdef BACKAUTO
229 rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz)));
230 #else
231 #error fix wrong eval order in builtin_va_arg
232 ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz)));
233 #endif
235 nfree(a->n_right);
236 nfree(a);
237 nfree(f);
238 r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap);
239 return buildtree(COMOP, rv, buildtree(UMUL, r, NIL));
243 static NODE *
244 builtin_va_end(NODE *f, NODE *a, TWORD rt)
246 tfree(f);
247 tfree(a);
248 return bcon(0); /* nothing */
251 static NODE *
252 builtin_va_copy(NODE *f, NODE *a, TWORD rt)
254 tfree(f);
255 f = buildtree(ASSIGN, a->n_left, a->n_right);
256 nfree(a);
257 return f;
259 #endif /* TARGET_STDARGS */
262 * For unimplemented "builtin" functions, try to invoke the
263 * non-builtin name
265 static NODE *
266 binhelp(NODE *f, NODE *a, TWORD rt, char *n)
268 f->n_sp = lookup(addname(n), SNORMAL);
269 if (f->n_sp->sclass == SNULL) {
270 f->n_sp->sclass = EXTERN;
271 f->n_sp->stype = INCREF(rt)+(FTN-PTR);
273 f->n_type = f->n_sp->stype;
274 f = clocal(f);
275 return buildtree(CALL, f, a);
278 static NODE *
279 builtin_unimp(NODE *f, NODE *a, TWORD rt)
281 char *n = f->n_sp->sname;
283 if (strncmp("__builtin_", n, 10) == 0)
284 n += 10;
285 return binhelp(f, a, rt, n);
288 static NODE *
289 builtin_unimp_f(NODE *f, NODE *a, TWORD rt)
291 return binhelp(f, a, rt, f->n_sp->sname);
294 #ifndef TARGET_ISMATH
296 * Handle the builtin macros for the math functions is*
297 * To get something that is be somewhat generic assume that
298 * isnan() is a real function and that cast of a NaN type
299 * to double will still be a NaN.
301 static NODE *
302 mtisnan(NODE *p)
304 NODE *q = block(NAME, NIL, NIL, INT, 0, MKAP(INT));
306 return binhelp(q, cast(ccopy(p), DOUBLE, 0), INT, "isnan");
309 static TWORD
310 mtcheck(NODE *p)
312 TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type;
314 if ((t1 >= FLOAT && t1 <= LDOUBLE) ||
315 (t2 >= FLOAT && t2 <= LDOUBLE))
316 return MAX(t1, t2);
317 return 0;
320 static NODE *
321 builtin_isunordered(NODE *f, NODE *a, TWORD rt)
323 NODE *p;
325 if (mtcheck(a) == 0)
326 return bcon(0);
328 p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
329 tfree(f);
330 tfree(a);
331 return p;
333 static NODE *
334 builtin_isany(NODE *f, NODE *a, TWORD rt, int cmpt)
336 NODE *p, *q;
337 TWORD t;
339 if ((t = mtcheck(a)) == 0)
340 return bcon(0);
341 p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
342 p = buildtree(NOT, p, NIL);
343 q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0),
344 cast(ccopy(a->n_right), t, 0));
345 p = buildtree(ANDAND, p, q);
346 tfree(f);
347 tfree(a);
348 return p;
350 static NODE *
351 builtin_isgreater(NODE *f, NODE *a, TWORD rt)
353 return builtin_isany(f, a, rt, GT);
355 static NODE *
356 builtin_isgreaterequal(NODE *f, NODE *a, TWORD rt)
358 return builtin_isany(f, a, rt, GE);
360 static NODE *
361 builtin_isless(NODE *f, NODE *a, TWORD rt)
363 return builtin_isany(f, a, rt, LT);
365 static NODE *
366 builtin_islessequal(NODE *f, NODE *a, TWORD rt)
368 return builtin_isany(f, a, rt, LE);
370 static NODE *
371 builtin_islessgreater(NODE *f, NODE *a, TWORD rt)
373 NODE *p, *q, *r;
374 TWORD t;
376 if ((t = mtcheck(a)) == 0)
377 return bcon(0);
378 p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
379 p = buildtree(NOT, p, NIL);
380 q = buildtree(GT, cast(ccopy(a->n_left), t, 0),
381 cast(ccopy(a->n_right), t, 0));
382 r = buildtree(LT, cast(ccopy(a->n_left), t, 0),
383 cast(ccopy(a->n_right), t, 0));
384 q = buildtree(OROR, q, r);
385 p = buildtree(ANDAND, p, q);
386 tfree(f);
387 tfree(a);
388 return p;
390 #endif
393 * Math-specific builtins that expands to constants.
394 * Versins here is for IEEE FP, vax needs its own versions.
396 #ifdef RTOLBYTES
397 static char vFLOAT[] = { 0, 0, 0x80, 0x7f };
398 static char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
399 #ifdef LDBL_128
400 static char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
401 #else /* LDBL_80 */
402 static char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
403 #endif
404 static char nFLOAT[] = { 0, 0, 0xc0, 0x7f };
405 static char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
406 #ifdef LDBL_128
407 static char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f };
408 #else /* LDBL_80 */
409 static char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f, 0, 0 };
410 #endif
411 #else
412 static char vFLOAT[] = { 0x7f, 0x80, 0, 0 };
413 static char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
414 #ifdef LDBL_128
415 static char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
416 #else /* LDBL_80 */
417 static char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0 };
418 #endif
419 static char nFLOAT[] = { 0x7f, 0xc0, 0, 0 };
420 static char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
421 #ifdef LDBL_128
422 static char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
423 #else /* LDBL_80 */
424 static char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0 };
425 #endif
426 #endif
428 #define VALX(typ,TYP) { \
429 typ d; \
430 int x; \
431 x = MIN(sizeof(n ## TYP), sizeof(d)); \
432 memcpy(&d, v ## TYP, x); \
433 nfree(f); \
434 f = block(FCON, NIL, NIL, TYP, NULL, MKAP(TYP)); \
435 f->n_dcon = d; \
436 return f; \
439 static NODE *
440 builtin_huge_valf(NODE *f, NODE *a, TWORD rt) VALX(float,FLOAT)
441 static NODE *
442 builtin_huge_val(NODE *f, NODE *a, TWORD rt) VALX(double,DOUBLE)
443 static NODE *
444 builtin_huge_vall(NODE *f, NODE *a, TWORD rt) VALX(long double,LDOUBLE)
446 #define builtin_inff builtin_huge_valf
447 #define builtin_inf builtin_huge_val
448 #define builtin_infl builtin_huge_vall
450 #define NANX(typ,TYP) { \
451 typ d; \
452 int x; \
453 if ((a->n_op == ICON && a->n_sp && a->n_sp->sname[0] == '\0') ||\
454 (a->n_op == ADDROF && a->n_left->n_op == NAME && \
455 a->n_left->n_sp && a->n_left->n_sp->sname[0] == '\0')) { \
456 x = MIN(sizeof(n ## TYP), sizeof(d)); \
457 memcpy(&d, n ## TYP, x); \
458 tfree(a); tfree(f); \
459 f = block(FCON, NIL, NIL, TYP, NULL, MKAP(TYP)); \
460 f->n_dcon = d; \
461 return f; \
463 return buildtree(CALL, f, a); \
467 * Return NANs, if reasonable.
469 static NODE *
470 builtin_nanf(NODE *f, NODE *a, TWORD rt) NANX(float,FLOAT)
471 static NODE *
472 builtin_nan(NODE *f, NODE *a, TWORD rt) NANX(double,DOUBLE)
473 static NODE *
474 builtin_nanl(NODE *f, NODE *a, TWORD rt) NANX(long double,LDOUBLE)
477 * Target defines, to implement target versions of the generic builtins
479 #ifndef TARGET_MEMCMP
480 #define builtin_memcmp builtin_unimp
481 #endif
482 #ifndef TARGET_MEMCPY
483 #define builtin_memcpy builtin_unimp
484 #endif
485 #ifndef TARGET_MEMSET
486 #define builtin_memset builtin_unimp
487 #endif
489 /* Reasonable type of size_t */
490 #ifndef SIZET
491 #if SZINT == SZSHORT
492 #define SIZET UNSIGNED
493 #elif SZLONG > SZINT
494 #define SIZET ULONG
495 #else
496 #define SIZET UNSIGNED
497 #endif
498 #endif
500 static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT };
501 static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT };
502 static TWORD allocat[] = { SIZET };
503 static TWORD expectt[] = { LONG, LONG };
504 static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR };
505 static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT };
506 static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT };
507 static TWORD strchrt[] = { CHAR|PTR, INT };
508 static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR };
509 static TWORD nant[] = { CHAR|PTR };
510 static TWORD bitt[] = { UNSIGNED };
511 static TWORD bitlt[] = { ULONG };
512 static TWORD ffst[] = { INT };
514 static const struct bitable {
515 char *name;
516 NODE *(*fun)(NODE *f, NODE *a, TWORD);
517 int narg;
518 TWORD *tp;
519 TWORD rt;
520 } bitable[] = {
521 { "__builtin___memcpy_chk", builtin_unimp, 4, memcpyt, VOID|PTR },
522 { "__builtin___memmove_chk", builtin_unimp, 4, memcpyt, VOID|PTR },
523 { "__builtin___memset_chk", builtin_unimp, 4, memsett, VOID|PTR },
525 { "__builtin___strcat_chk", builtin_unimp, 3, strcpyt, CHAR|PTR },
526 { "__builtin___strcpy_chk", builtin_unimp, 3, strcpyt, CHAR|PTR },
527 { "__builtin___strncat_chk", builtin_unimp, 4, strncpyt,CHAR|PTR },
528 { "__builtin___strncpy_chk", builtin_unimp, 4, strncpyt,CHAR|PTR },
530 { "__builtin___printf_chk", builtin_unimp, -1, 0, INT },
531 { "__builtin___fprintf_chk", builtin_unimp, -1, 0, INT },
532 { "__builtin___sprintf_chk", builtin_unimp, -1, 0, INT },
533 { "__builtin___snprintf_chk", builtin_unimp, -1, 0, INT },
534 { "__builtin___vprintf_chk", builtin_unimp, -1, 0, INT },
535 { "__builtin___vfprintf_chk", builtin_unimp, -1, 0, INT },
536 { "__builtin___vsprintf_chk", builtin_unimp, -1, 0, INT },
537 { "__builtin___vsnprintf_chk", builtin_unimp, -1, 0, INT },
539 { "__builtin_alloca", builtin_alloca, 1, allocat },
540 { "__builtin_abs", builtin_abs, 1 },
541 { "__builtin_clz", builtin_unimp_f, 1, bitt, INT },
542 { "__builtin_ctz", builtin_unimp_f, 1, bitt, INT },
543 { "__builtin_clzl", builtin_unimp_f, 1, bitlt, INT },
544 { "__builtin_ctzl", builtin_unimp_f, 1, bitlt, INT },
545 { "__builtin_ffs", builtin_unimp, 1, ffst, INT },
547 { "__builtin_constant_p", builtin_constant_p, 1 },
548 { "__builtin_expect", builtin_expect, 2, expectt },
549 { "__builtin_memcmp", builtin_memcmp, 3, memcpyt, INT },
550 { "__builtin_memcpy", builtin_memcpy, 3, memcpyt, VOID|PTR },
551 { "__builtin_memset", builtin_memset, 3, memsett, VOID|PTR },
552 { "__builtin_huge_valf", builtin_huge_valf, 0 },
553 { "__builtin_huge_val", builtin_huge_val, 0 },
554 { "__builtin_huge_vall", builtin_huge_vall, 0 },
555 { "__builtin_inff", builtin_inff, 0 },
556 { "__builtin_inf", builtin_inf, 0 },
557 { "__builtin_infl", builtin_infl, 0 },
558 { "__builtin_isgreater", builtin_isgreater, 2, NULL, INT },
559 { "__builtin_isgreaterequal", builtin_isgreaterequal, 2, NULL, INT },
560 { "__builtin_isless", builtin_isless, 2, NULL, INT },
561 { "__builtin_islessequal", builtin_islessequal, 2, NULL, INT },
562 { "__builtin_islessgreater", builtin_islessgreater, 2, NULL, INT },
563 { "__builtin_isunordered", builtin_isunordered, 2, NULL, INT },
564 { "__builtin_nanf", builtin_nanf, 1, nant, FLOAT },
565 { "__builtin_nan", builtin_nan, 1, nant, DOUBLE },
566 { "__builtin_nanl", builtin_nanl, 1, nant, LDOUBLE },
567 { "__builtin_object_size", builtin_object_size, 2, memsett, SIZET },
568 { "__builtin_strcmp", builtin_unimp, 2, strcmpt, INT },
569 { "__builtin_strcpy", builtin_unimp, 2, strcmpt, CHAR|PTR },
570 { "__builtin_strchr", builtin_unimp, 2, strchrt, CHAR|PTR },
571 { "__builtin_strlen", builtin_unimp, 1, strcmpt, SIZET },
572 { "__builtin_strrchr", builtin_unimp, 2, strchrt, CHAR|PTR },
573 { "__builtin_strncpy", builtin_unimp, 3, strncpyt, CHAR|PTR },
574 { "__builtin_strncat", builtin_unimp, 3, strncpyt, CHAR|PTR },
575 { "__builtin_strcspn", builtin_unimp, 2, strcspnt, SIZET },
576 #ifndef TARGET_STDARGS
577 { "__builtin_stdarg_start", builtin_stdarg_start, 2 },
578 { "__builtin_va_start", builtin_stdarg_start, 2 },
579 { "__builtin_va_arg", builtin_va_arg, 2 },
580 { "__builtin_va_end", builtin_va_end, 1 },
581 { "__builtin_va_copy", builtin_va_copy, 2 },
582 #endif
583 #ifdef TARGET_BUILTINS
584 TARGET_BUILTINS
585 #endif
589 * Check and cast arguments for builtins.
591 static int
592 acnt(NODE *a, int narg, TWORD *tp)
594 NODE *q;
595 TWORD t;
597 if (a == NIL)
598 return narg;
599 for (; a->n_op == CM; a = a->n_left, narg--) {
600 if (tp == NULL)
601 continue;
602 q = a->n_right;
603 t = tp[narg-1];
604 if (q->n_type == t)
605 continue;
606 a->n_right = ccast(q, t, 0, NULL, MKAP(BTYPE(t)));
609 /* Last arg is ugly to deal with */
610 if (narg == 1 && tp != NULL) {
611 q = talloc();
612 *q = *a;
613 q = ccast(q, tp[0], 0, NULL, MKAP(BTYPE(tp[0])));
614 *a = *q;
615 nfree(q);
617 return narg != 1;
620 NODE *
621 builtin_check(NODE *f, NODE *a)
623 const struct bitable *bt;
624 int i;
626 for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) {
627 bt = &bitable[i];
628 if (strcmp(bt->name, f->n_sp->sname))
629 continue;
630 if (bt->narg >= 0 && acnt(a, bt->narg, bt->tp)) {
631 uerror("wrong argument count to %s", bt->name);
632 return bcon(0);
634 return (*bt->fun)(f, a, bt->rt);
636 return NIL;
638 #endif