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