1 /* $Id: builtins.c,v 1.18.2.2 2011/03/29 15:56:24 ragge Exp $ */
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
30 #define MIN(a,b) (((a)<(b))?(a):(b))
33 #define MAX(a,b) (((a)>(b))?(a):(b))
38 * replace an alloca function with direct allocation on stack.
39 * return a destination temp node.
42 builtin_alloca(NODE
*f
, NODE
*a
, TWORD rt
)
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
);
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
69 int o
= coptype(p
->n_op
);
76 return hasgoto(p
->n_left
);
77 if (hasgoto(p
->n_left
))
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
88 builtin_constant_p(NODE
*f
, NODE
*a
, TWORD rt
)
90 void putjops(NODE
*p
, void *arg
);
95 for (f
= a
; f
->n_op
== COMOP
; f
= f
->n_right
)
103 * Hint to the compiler whether this expression will evaluate true or false.
104 * Just ignored for now.
107 builtin_expect(NODE
*f
, NODE
*a
, TWORD rt
)
111 if (a
&& a
->n_op
== CM
) {
122 * Take integer absolute value.
123 * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1)))
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
)
136 if (a
->n_op
== ICON
) {
138 a
->n_lval
= -a
->n_lval
;
141 t
= tempnode(0, a
->n_type
, a
->n_df
, a
->n_ap
);
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
);
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
));
165 * Get size of object, if possible.
166 * Currently does nothing,
169 builtin_object_size(NODE
*f
, NODE
*a
, TWORD rt
)
171 int v
= icons(a
->n_right
);
173 uerror("arg2 must be between 0 and 3");
176 f
= buildtree(COMOP
, a
->n_left
, xbcon(v
< 2 ? -1 : 0, NULL
, rt
));
181 #ifndef TARGET_STDARGS
183 builtin_stdarg_start(NODE
*f
, NODE
*a
, TWORD rt
)
188 /* must first deal with argument size; use int size */
190 if (p
->n_type
< INT
) {
191 sz
= (int)(SZINT
/tsize(p
->n_type
, p
->n_df
, p
->n_ap
));
195 /* do the real job */
196 p
= buildtree(ADDROF
, p
, NIL
); /* address of last arg */
198 p
= optim(buildtree(PLUS
, p
, bcon(sz
))); /* add one to it (next arg) */
200 p
= optim(buildtree(MINUS
, p
, bcon(sz
))); /* add one to it (next arg) */
202 q
= block(NAME
, NIL
, NIL
, PTR
+VOID
, 0, 0); /* create cast node */
203 q
= buildtree(CAST
, q
, p
); /* cast to void * (for assignment) */
207 p
= buildtree(ASSIGN
, a
->n_left
, p
); /* assign to ap */
214 builtin_va_arg(NODE
*f
, NODE
*a
, TWORD rt
)
216 NODE
*p
, *q
, *r
, *rv
;
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
);
223 rv
= buildtree(ASSIGN
, q
, p
);
226 sz
= (int)tsize(r
->n_type
, r
->n_df
, r
->n_ap
)/SZCHAR
;
229 rv
= buildtree(COMOP
, rv
, buildtree(PLUSEQ
, a
->n_left
, bcon(sz
)));
231 #error fix wrong eval order in builtin_va_arg
232 ecomp(buildtree(MINUSEQ
, a
->n_left
, bcon(sz
)));
238 r
= tempnode(nodnum
, INCREF(r
->n_type
), r
->n_df
, r
->n_ap
);
239 return buildtree(COMOP
, rv
, buildtree(UMUL
, r
, NIL
));
244 builtin_va_end(NODE
*f
, NODE
*a
, TWORD rt
)
248 return bcon(0); /* nothing */
252 builtin_va_copy(NODE
*f
, NODE
*a
, TWORD rt
)
255 f
= buildtree(ASSIGN
, a
->n_left
, a
->n_right
);
259 #endif /* TARGET_STDARGS */
262 * For unimplemented "builtin" functions, try to invoke the
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
;
275 return buildtree(CALL
, f
, a
);
279 builtin_unimp(NODE
*f
, NODE
*a
, TWORD rt
)
281 char *n
= f
->n_sp
->sname
;
283 if (strncmp("__builtin_", n
, 10) == 0)
285 return binhelp(f
, a
, rt
, n
);
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.
304 NODE
*q
= block(NAME
, NIL
, NIL
, INT
, 0, MKAP(INT
));
306 return binhelp(q
, cast(ccopy(p
), DOUBLE
, 0), INT
, "isnan");
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
))
321 builtin_isunordered(NODE
*f
, NODE
*a
, TWORD rt
)
328 p
= buildtree(OROR
, mtisnan(a
->n_left
), mtisnan(a
->n_right
));
334 builtin_isany(NODE
*f
, NODE
*a
, TWORD rt
, int cmpt
)
339 if ((t
= mtcheck(a
)) == 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
);
351 builtin_isgreater(NODE
*f
, NODE
*a
, TWORD rt
)
353 return builtin_isany(f
, a
, rt
, GT
);
356 builtin_isgreaterequal(NODE
*f
, NODE
*a
, TWORD rt
)
358 return builtin_isany(f
, a
, rt
, GE
);
361 builtin_isless(NODE
*f
, NODE
*a
, TWORD rt
)
363 return builtin_isany(f
, a
, rt
, LT
);
366 builtin_islessequal(NODE
*f
, NODE
*a
, TWORD rt
)
368 return builtin_isany(f
, a
, rt
, LE
);
371 builtin_islessgreater(NODE
*f
, NODE
*a
, TWORD rt
)
376 if ((t
= mtcheck(a
)) == 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
);
393 * Math-specific builtins that expands to constants.
394 * Versins here is for IEEE FP, vax needs its own versions.
397 static char vFLOAT
[] = { 0, 0, 0x80, 0x7f };
398 static char vDOUBLE
[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
400 static char vLDOUBLE
[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
402 static char vLDOUBLE
[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
404 static char nFLOAT
[] = { 0, 0, 0xc0, 0x7f };
405 static char nDOUBLE
[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
407 static char nLDOUBLE
[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f };
409 static char nLDOUBLE
[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f, 0, 0 };
412 static char vFLOAT
[] = { 0x7f, 0x80, 0, 0 };
413 static char vDOUBLE
[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
415 static char vLDOUBLE
[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
417 static char vLDOUBLE
[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0 };
419 static char nFLOAT
[] = { 0x7f, 0xc0, 0, 0 };
420 static char nDOUBLE
[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
422 static char nLDOUBLE
[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
424 static char nLDOUBLE
[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0 };
428 #define VALX(typ,TYP) { \
431 x = MIN(sizeof(n ## TYP), sizeof(d)); \
432 memcpy(&d, v ## TYP, x); \
434 f = block(FCON, NIL, NIL, TYP, NULL, MKAP(TYP)); \
440 builtin_huge_valf(NODE
*f
, NODE
*a
, TWORD rt
) VALX(float,FLOAT
)
442 builtin_huge_val(NODE
*f
, NODE
*a
, TWORD rt
) VALX(double,DOUBLE
)
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) { \
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)); \
463 return buildtree(CALL, f, a); \
467 * Return NANs, if reasonable.
470 builtin_nanf(NODE
*f
, NODE
*a
, TWORD rt
) NANX(float,FLOAT
)
472 builtin_nan(NODE
*f
, NODE
*a
, TWORD rt
) NANX(double,DOUBLE
)
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
482 #ifndef TARGET_MEMCPY
483 #define builtin_memcpy builtin_unimp
485 #ifndef TARGET_MEMSET
486 #define builtin_memset builtin_unimp
489 /* Reasonable type of size_t */
492 #define SIZET UNSIGNED
496 #define SIZET UNSIGNED
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
{
516 NODE
*(*fun
)(NODE
*f
, NODE
*a
, TWORD
);
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 },
583 #ifdef TARGET_BUILTINS
589 * Check and cast arguments for builtins.
592 acnt(NODE
*a
, int narg
, TWORD
*tp
)
599 for (; a
->n_op
== CM
; a
= a
->n_left
, narg
--) {
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
) {
613 q
= ccast(q
, tp
[0], 0, NULL
, MKAP(BTYPE(tp
[0])));
621 builtin_check(NODE
*f
, NODE
*a
)
623 const struct bitable
*bt
;
626 for (i
= 0; i
< (int)(sizeof(bitable
)/sizeof(bitable
[0])); i
++) {
628 if (strcmp(bt
->name
, f
->n_sp
->sname
))
630 if (bt
->narg
>= 0 && acnt(a
, bt
->narg
, bt
->tp
)) {
631 uerror("wrong argument count to %s", bt
->name
);
634 return (*bt
->fun
)(f
, a
, bt
->rt
);