xref: /netbsd/external/bsd/pcc/dist/pcc/cc/ccom/gcc_compat.c (revision 6550d01e)
1 /*      Id: gcc_compat.c,v 1.52 2010/05/15 15:58:33 ragge Exp      */
2 /*      $NetBSD: gcc_compat.c,v 1.1.1.3 2010/06/03 18:57:39 plunky Exp $     */
3 /*
4  * Copyright (c) 2004 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  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * Routines to support some of the gcc extensions to C.
32  */
33 #ifdef GCC_COMPAT
34 
35 #include "pass1.h"
36 #include "cgram.h"
37 
38 #include <string.h>
39 
40 static struct kw {
41 	char *name, *ptr;
42 	int rv;
43 } kw[] = {
44 /*
45  * Do NOT change the order of these entries unless you know
46  * what you're doing!
47  */
48 /* 0 */	{ "__asm", NULL, C_ASM },
49 /* 1 */	{ "__signed", NULL, 0 },
50 /* 2 */	{ "__inline", NULL, C_FUNSPEC },
51 /* 3 */	{ "__const", NULL, 0 },
52 /* 4 */	{ "__asm__", NULL, C_ASM },
53 /* 5 */	{ "__inline__", NULL, C_FUNSPEC },
54 /* 6 */	{ "__thread", NULL, 0 },
55 /* 7 */	{ "__FUNCTION__", NULL, 0 },
56 /* 8 */	{ "__volatile", NULL, 0 },
57 /* 9 */	{ "__volatile__", NULL, 0 },
58 /* 10 */{ "__restrict", NULL, -1 },
59 /* 11 */{ "__typeof__", NULL, C_TYPEOF },
60 /* 12 */{ "typeof", NULL, C_TYPEOF },
61 /* 13 */{ "__extension__", NULL, -1 },
62 /* 14 */{ "__signed__", NULL, 0 },
63 /* 15 */{ "__attribute__", NULL, 0 },
64 /* 16 */{ "__attribute", NULL, 0 },
65 /* 17 */{ "__real__", NULL, 0 },
66 /* 18 */{ "__imag__", NULL, 0 },
67 /* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF },
68 	{ NULL, NULL, 0 },
69 };
70 
71 /* g77 stuff */
72 #if SZFLOAT == SZLONG
73 #define G77_INTEGER LONG
74 #define G77_UINTEGER ULONG
75 #elif SZFLOAT == SZINT
76 #define G77_INTEGER INT
77 #define G77_UINTEGER UNSIGNED
78 #else
79 #error fix g77 stuff
80 #endif
81 #if SZFLOAT*2 == SZLONG
82 #define G77_LONGINT LONG
83 #define G77_ULONGINT ULONG
84 #elif SZFLOAT*2 == SZLONGLONG
85 #define G77_LONGINT LONGLONG
86 #define G77_ULONGINT ULONGLONG
87 #else
88 #error fix g77 long stuff
89 #endif
90 
91 static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT };
92 static char *g77n[] = { "__g77_integer", "__g77_uinteger",
93 	"__g77_longint", "__g77_ulongint" };
94 
95 void
96 gcc_init()
97 {
98 	struct kw *kwp;
99 	NODE *p;
100 	TWORD t;
101 	int i;
102 
103 	for (kwp = kw; kwp->name; kwp++)
104 		kwp->ptr = addname(kwp->name);
105 
106 	for (i = 0; i < 4; i++) {
107 		struct symtab *sp;
108 		t = ctype(g77t[i]);
109 		p = block(NAME, NIL, NIL, t, NULL, MKSUE(t));
110 		sp = lookup(addname(g77n[i]), 0);
111 		p->n_sp = sp;
112 		defid(p, TYPEDEF);
113 		nfree(p);
114 	}
115 
116 }
117 
118 #define	TS	"\n#pragma tls\n# %d\n"
119 #define	TLLEN	sizeof(TS)+10
120 /*
121  * See if a string matches a gcc keyword.
122  */
123 int
124 gcc_keyword(char *str, NODE **n)
125 {
126 	extern int inattr, parlvl, parbal;
127 	YYSTYPE *yyl = (YYSTYPE *)n; /* XXX should pass yylval */
128 	char tlbuf[TLLEN], *tw;
129 	struct kw *kwp;
130 	int i;
131 
132 	for (i = 0, kwp = kw; kwp->name; kwp++, i++)
133 		if (str == kwp->ptr)
134 			break;
135 	if (kwp->name == NULL)
136 		return 0;
137 	if (kwp->rv)
138 		return kwp->rv;
139 	switch (i) {
140 	case 1:  /* __signed */
141 	case 14: /* __signed__ */
142 		*n = mkty((TWORD)SIGNED, 0, MKSUE(SIGNED));
143 		return C_TYPE;
144 	case 3: /* __const */
145 		*n = block(QUALIFIER, NIL, NIL, CON, 0, 0);
146 		return C_QUALIFIER;
147 	case 6: /* __thread */
148 		snprintf(tlbuf, TLLEN, TS, lineno);
149 		tw = &tlbuf[strlen(tlbuf)];
150 		while (tw > tlbuf)
151 			cunput(*--tw);
152 		return -1;
153 	case 7: /* __FUNCTION__ */
154 		if (cftnsp == NULL) {
155 			uerror("__FUNCTION__ outside function");
156 			yylval.strp = "";
157 		} else
158 			yylval.strp = cftnsp->sname; /* XXX - not C99 */
159 		return C_STRING;
160 	case 8: /* __volatile */
161 	case 9: /* __volatile__ */
162 		*n = block(QUALIFIER, NIL, NIL, VOL, 0, 0);
163 		return C_QUALIFIER;
164 	case 15: /* __attribute__ */
165 	case 16: /* __attribute */
166 		inattr = 1;
167 		parlvl = parbal;
168 		return C_ATTRIBUTE;
169 	case 17: /* __real__ */
170 		yyl->intval = XREAL;
171 		return C_UNOP;
172 	case 18: /* __imag__ */
173 		yyl->intval = XIMAG;
174 		return C_UNOP;
175 	}
176 	cerror("gcc_keyword");
177 	return 0;
178 }
179 
180 #ifndef TARGET_ATTR
181 #define	TARGET_ATTR(p, sue)		0
182 #endif
183 #ifndef	ALMAX
184 #define	ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG)
185 #endif
186 
187 /* allowed number of args */
188 #define	A_0ARG	0x01
189 #define	A_1ARG	0x02
190 #define	A_2ARG	0x04
191 #define	A_3ARG	0x08
192 /* arg # is a name */
193 #define	A1_NAME	0x10
194 #define	A2_NAME	0x20
195 #define	A3_NAME	0x40
196 #define	A_MANY	0x80
197 /* arg # is "string" */
198 #define	A1_STR	0x100
199 #define	A2_STR	0x200
200 #define	A3_STR	0x400
201 
202 struct atax {
203 	int typ;
204 	char *name;
205 } atax[GCC_ATYP_MAX] = {
206 #ifndef __MSC__
207 	[GCC_ATYP_ALIGNED] =	{ A_0ARG|A_1ARG, "aligned" },
208 	[GCC_ATYP_PACKED] =	{ A_0ARG|A_1ARG, "packed" },
209 	[GCC_ATYP_SECTION] = 	{ A_1ARG|A1_STR, "section" },
210 	[GCC_ATYP_UNUSED] =	{ A_0ARG, "unused" },
211 	[GCC_ATYP_DEPRECATED] =	{ A_0ARG, "deprecated" },
212 	[GCC_ATYP_NORETURN] =	{ A_0ARG, "noreturn" },
213 	[GCC_ATYP_FORMAT] =	{ A_3ARG|A1_NAME, "format" },
214 	[GCC_ATYP_BOUNDED] =	{ A_3ARG|A_MANY|A1_NAME, "bounded" },
215 	[GCC_ATYP_NONNULL] =	{ A_MANY, "nonnull" },
216 	[GCC_ATYP_SENTINEL] =	{ A_0ARG|A_1ARG, "sentinel" },
217 	[GCC_ATYP_WEAK] =	{ A_0ARG, "weak" },
218 	[GCC_ATYP_FORMATARG] =	{ A_1ARG, "format_arg" },
219 	[GCC_ATYP_GNU_INLINE] =	{ A_0ARG, "gnu_inline" },
220 	[GCC_ATYP_MALLOC] =	{ A_0ARG, "malloc" },
221 	[GCC_ATYP_NOTHROW] =	{ A_0ARG, "nothrow" },
222 	[GCC_ATYP_MODE] =	{ A_1ARG|A1_NAME, "mode" },
223 	[GCC_ATYP_CONST] =	{ A_0ARG, "const" },
224 	[GCC_ATYP_PURE] =	{ A_0ARG, "pure" },
225 	[GCC_ATYP_CONSTRUCTOR] ={ A_0ARG, "constructor" },
226 	[GCC_ATYP_DESTRUCTOR] =	{ A_0ARG, "destructor" },
227 	[GCC_ATYP_VISIBILITY] =	{ A_1ARG|A1_STR, "visibility" },
228 	[GCC_ATYP_STDCALL] =	{ A_0ARG, "stdcall" },
229 	[GCC_ATYP_CDECL] =	{ A_0ARG, "cdecl" },
230 	[GCC_ATYP_WARN_UNUSED_RESULT] = { A_0ARG, "warn_unused_result" },
231 	[GCC_ATYP_USED] =	{ A_0ARG, "used" },
232 #else
233 	{ 0, NULL },
234 	{ A_0ARG|A_1ARG, "aligned" },
235 	{ A_0ARG, "packed" },
236 	{ A_1ARG|A1_STR, "section" },
237 	{ 0, NULL }, 	/* GCC_ATYP_TRANSP_UNION */
238 	{ A_0ARG, "unused" },
239 	{ A_0ARG, "deprecated" },
240 	{ 0, NULL }, 	/* GCC_ATYP_MAYALIAS */
241 	{ A_1ARG|A1_NAME, "mode" },
242 	{ A_0ARG, "noreturn" },
243 	{ A_3ARG|A1_STR, "format" },
244 	{ A_MANY, "nonnull" },
245 	{ A_0ARG|A_1ARG, "sentinel" },
246 	{ A_0ARG, "weak" },
247 	{ A_1ARG, "format_arg" },
248 	{ A_0ARG, "gnu_inline" },
249 	{ A_0ARG, "malloc" },
250 	{ A_0ARG, "nothrow" },
251 	{ A_0ARG, "const" },
252 	{ A_0ARG, "pure" },
253 	{ A_0ARG, "constructor" },
254 	{ A_0ARG, "destructor" },
255 	{ A_1ARG|A1_STR, "visibility" },
256 	{ A_0ARG, "stdcall" },
257 	{ A_0ARG, "cdecl" },
258 	{ A_0ARG, "warn_unused_result" },
259 	{ A_0ARG, "used" },
260 	{ A_3ARG|A_MANY|A1_STR, "bounded" },
261 	{ 0, NULL },	/* ATTR_COMPLEX */
262 #endif
263 };
264 #if SZPOINT(CHAR) == SZLONGLONG
265 #define	GPT	LONGLONG
266 #else
267 #define	GPT	INT
268 #endif
269 
270 struct atax mods[] = {
271 	{ 0, NULL },
272 	{ INT, "SI" },
273 	{ INT, "word" },
274 	{ GPT, "pointer" },
275 	{ CHAR, "byte" },
276 	{ CHAR, "QI" },
277 	{ SHORT, "HI" },
278 	{ LONGLONG, "DI" },
279 	{ FLOAT, "SF" },
280 	{ DOUBLE, "DF" },
281 };
282 #define	ATSZ	(sizeof(mods)/sizeof(mods[0]))
283 
284 static int
285 amatch(char *s, struct atax *at, int mx)
286 {
287 	int i, len;
288 
289 	if (s[0] == '_' && s[1] == '_')
290 		s += 2;
291 	len = strlen(s);
292 	if (len > 2 && s[len-1] == '_' && s[len-2] == '_')
293 		len -= 2;
294 	for (i = 0; i < mx; i++) {
295 		char *t = at[i].name;
296 		if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0)
297 			return i;
298 	}
299 	return 0;
300 }
301 
302 static void
303 setaarg(int str, union gcc_aarg *aa, NODE *p)
304 {
305 	if (str) {
306 		if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) ||
307 		    ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME))
308 			uerror("bad arg to attribute");
309 		aa->sarg = p->n_op == STRING ? p->n_name : (char *)p->n_sp;
310 		nfree(p);
311 	} else
312 		aa->iarg = (int)icons(eve(p));
313 }
314 
315 /*
316  * Parse attributes from an argument list.
317  */
318 static void
319 gcc_attribs(NODE *p, void *arg)
320 {
321 	NODE *q, *r;
322 	gcc_ap_t *gap = arg;
323 	char *name = NULL, *c;
324 	int num, cw, attr, narg, i;
325 
326 	if (p->n_op == NAME) {
327 		name = (char *)p->n_sp;
328 	} else if (p->n_op == CALL || p->n_op == UCALL) {
329 		name = (char *)p->n_left->n_sp;
330 	} else
331 		cerror("bad variable attribute");
332 
333 	if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) {
334 		werror("unsupported attribute '%s'", name);
335 		goto out;
336 	}
337 	narg = 0;
338 	if (p->n_op == CALL)
339 		for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left)
340 			narg++;
341 
342 	cw = atax[attr].typ;
343 	if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) {
344 		uerror("wrong attribute arg count");
345 		return;
346 	}
347 	num = gap->num;
348 	gap->ga[num].atype = attr;
349 	q = p->n_right;
350 
351 	switch (narg) {
352 	default:
353 		/* XXX */
354 		while (narg-- > 3) {
355 			r = q;
356 			q = q->n_left;
357 			tfree(r->n_right);
358 			nfree(r);
359 		}
360 		/* FALLTHROUGH */
361 	case 3:
362 		setaarg(cw & (A3_NAME|A3_STR), &gap->ga[num].a3, q->n_right);
363 		r = q;
364 		q = q->n_left;
365 		nfree(r);
366 		/* FALLTHROUGH */
367 	case 2:
368 		setaarg(cw & (A2_NAME|A2_STR), &gap->ga[num].a2, q->n_right);
369 		r = q;
370 		q = q->n_left;
371 		nfree(r);
372 		/* FALLTHROUGH */
373 	case 1:
374 		setaarg(cw & (A1_NAME|A1_STR), &gap->ga[num].a1, q);
375 		p->n_op = UCALL;
376 		/* FALLTHROUGH */
377 	case 0:
378 		break;
379 	}
380 
381 	/* some attributes must be massaged special */
382 	switch (attr) {
383 	case GCC_ATYP_ALIGNED:
384 		if (narg == 0)
385 			gap->ga[num].a1.iarg = ALMAX;
386 		else
387 			gap->ga[num].a1.iarg *= SZCHAR;
388 		break;
389 	case GCC_ATYP_PACKED:
390 		if (narg == 0)
391 			gap->ga[num].a1.iarg = 1; /* bitwise align */
392 		else
393 			gap->ga[num].a1.iarg *= SZCHAR;
394 		break;
395 
396 	case GCC_ATYP_MODE:
397 		if ((i = amatch(gap->ga[num].a1.sarg, mods, ATSZ)) == 0)
398 			werror("unknown mode arg %s", gap->ga[num].a1.sarg);
399 		gap->ga[num].a1.iarg = mods[i].typ;
400 		break;
401 
402 	case GCC_ATYP_VISIBILITY:
403 		c = gap->ga[num].a1.sarg;
404 		if (strcmp(c, "default") && strcmp(c, "hidden") &&
405 		    strcmp(c, "internal") && strcmp(c, "protected"))
406 			werror("unknown visibility %s", c);
407 		break;
408 
409 	default:
410 		break;
411 	}
412 out:
413 	gap->num++;
414 }
415 
416 /*
417  * Extract type attributes from a node tree and create a gcc_attr_pack
418  * struct based on its contents.
419  */
420 gcc_ap_t *
421 gcc_attr_parse(NODE *p)
422 {
423 	gcc_ap_t *gap;
424 	NODE *q, *r;
425 	int i, sz;
426 
427 	/* count number of elems and build tower to the left */
428 	for (q = p, i = 1; q->n_op == CM; q = q->n_left, i++)
429 		if (q->n_right->n_op == CM)
430 			r = q->n_right, q->n_right = q->n_left, q->n_left = r;
431 
432 	/* get memory for struct */
433 	sz = sizeof(struct gcc_attr_pack) + sizeof(struct gcc_attrib) * i;
434 	if (blevel == 0)
435 		gap = memset(permalloc(sz), 0, sz);
436 	else
437 		gap = tmpcalloc(sz);
438 
439 	flist(p, gcc_attribs, gap);
440 	if (gap->num != i)
441 		cerror("attribute sync error");
442 
443 	tfree(p);
444 	return gap;
445 }
446 
447 /*
448  * Fixup struct/unions depending on attributes.
449  */
450 void
451 gcc_tcattrfix(NODE *p, NODE *q)
452 {
453 	struct symtab *sp;
454 	struct suedef *sue;
455 	gcc_ap_t *gap;
456 	int align = 0;
457 	int i, sz, coff, csz;
458 
459 	gap = gcc_attr_parse(q);
460 	sue = p->n_sue;
461 	if (sue->suega) {
462 		if (p->n_sp == NULL)
463 			cerror("gcc_tcattrfix");
464 	}
465 
466 	/* must know about align first */
467 	for (i = 0; i < gap->num; i++)
468 		if (gap->ga[i].atype == GCC_ATYP_ALIGNED)
469 			align = gap->ga[i].a1.iarg;
470 
471 	/* Check following attributes */
472 	for (i = 0; i < gap->num; i++) {
473 		switch (gap->ga[i].atype) {
474 		case GCC_ATYP_PACKED:
475 			/* Must repack struct */
476 			/* XXX - aligned types inside? */
477 			coff = csz = 0;
478 			for (sp = sue->suem; sp; sp = sp->snext) {
479 				if (sp->sclass & FIELD)
480 					sz = sp->sclass&FLDSIZ;
481 				else
482 					sz = (int)tsize(sp->stype, sp->sdf, sp->ssue);
483 				SETOFF(sz, gap->ga[i].a1.iarg);
484 				sp->soffset = coff;
485 				coff += sz;
486 				if (coff > csz)
487 					csz = coff;
488 				if (p->n_type == UNIONTY)
489 					coff = 0;
490 			}
491 			SETOFF(csz, SZCHAR);
492 			sue->suesize = csz;
493 			sue->suealign = gap->ga[i].a1.iarg;
494 			break;
495 
496 		case GCC_ATYP_ALIGNED:
497 			break;
498 
499 		default:
500 			werror("unsupported attribute %d", gap->ga[i].atype);
501 		}
502 	}
503 	if (align) {
504 		sue->suealign = align;
505 		SETOFF(sue->suesize, sue->suealign);
506 	}
507 	sue->suega = gap;
508 }
509 
510 /*
511  * Search for a specific attribute type.
512  */
513 struct gcc_attrib *
514 gcc_get_attr(struct suedef *sue, int typ)
515 {
516 	gcc_ap_t *gap;
517 	int i;
518 
519 	if (sue == NULL)
520 		return NULL;
521 
522 	if ((gap = sue->suega) == NULL)
523 		return NULL;
524 
525 	for (i = 0; i < gap->num; i++)
526 		if (gap->ga[i].atype == typ)
527 			return &gap->ga[i];
528 	if (sue->suep)
529 		return gcc_get_attr(sue->suep, typ);
530 	return NULL;
531 }
532 
533 #ifdef PCC_DEBUG
534 void
535 dump_attr(gcc_ap_t *gap)
536 {
537 	int i;
538 
539 	printf("GCC attributes\n");
540 	if (gap == NULL)
541 		return;
542 	for (i = 0; i < gap->num; i++) {
543 		printf("%d: ", gap->ga[i].atype);
544 		printf("%d %d %d", gap->ga[i].a1.iarg,
545 		    gap->ga[i].a2.iarg, gap->ga[i].a3.iarg);
546 		printf("\n");
547 	}
548 }
549 #endif
550 #endif
551