xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/m68k/local.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
1 /*	Id: local.c,v 1.16 2016/01/30 17:26:19 ragge Exp 	*/
2 /*	$NetBSD: local.c,v 1.1.1.2 2016/02/09 20:28:34 plunky Exp $	*/
3 /*
4  * Copyright (c) 2014 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 
29 #include "pass1.h"
30 
31 #undef NIL
32 #define NIL NULL
33 
34 #ifdef LANG_CXX
35 #define P1ND NODE
36 #define p1nfree nfree
37 #define p1fwalk fwalk
38 #define p1tcopy tcopy
39 #define p1alloc talloc
40 #else
41 #define	NODE P1ND
42 #define	nfree p1nfree
43 #define	fwalk p1fwalk
44 #endif
45 
46 
47 /*	this file contains code which is dependent on the target machine */
48 
49 int gotnr;
50 
51 /*
52  * Make a symtab entry for PIC use.
53  */
54 static struct symtab *
picsymtab(char * p,char * s,char * s2)55 picsymtab(char *p, char *s, char *s2)
56 {
57 	struct symtab *sp = permalloc(sizeof(struct symtab));
58 	size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
59 
60 	sp->sname = permalloc(len);
61 	strlcpy(sp->sname, p, len);
62 	strlcat(sp->sname, s, len);
63 	strlcat(sp->sname, s2, len);
64 	sp->sap = attr_new(ATTR_SONAME, 1);
65 	sp->sap->sarg(0) = sp->sname;
66 	sp->sclass = EXTERN;
67 	sp->sflags = sp->slevel = 0;
68 	sp->stype = 0xdeadbeef;
69 	return sp;
70 }
71 
72 /*
73  * Create a reference for an extern variable.
74  */
75 static NODE *
picext(NODE * p)76 picext(NODE *p)
77 {
78 	NODE *q, *r;
79 	struct symtab *sp;
80 	char *name;
81 
82 	q = tempnode(gotnr, PTR|VOID, 0, 0);
83 	name = getexname(p->n_sp);
84 
85 #ifdef notdef
86 	struct attr *ga;
87 	if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) &&
88 	    strcmp(ga->sarg(0), "hidden") == 0) {
89 		/* For hidden vars use GOTOFF */
90 		sp = picsymtab("", name, "@GOTOFF");
91 		r = xbcon(0, sp, INT);
92 		q = buildtree(PLUS, q, r);
93 		q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
94 		q->n_sp = p->n_sp; /* for init */
95 		nfree(p);
96 		return q;
97 	}
98 #endif
99 
100 	sp = picsymtab("", name, "@GOT");
101 	r = xbcon(0, sp, INT);
102 	q = buildtree(PLUS, q, r);
103 	q = block(UMUL, q, 0, PTR|VOID, 0, 0);
104 	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
105 	q->n_sp = p->n_sp; /* for init */
106 	nfree(p);
107 	return q;
108 }
109 
110 static char *
getsoname(struct symtab * sp)111 getsoname(struct symtab *sp)
112 {
113 	struct attr *ap;
114 	return (ap = attr_find(sp->sap, ATTR_SONAME)) ?
115 	    ap->sarg(0) : sp->sname;
116 
117 }
118 
119 
120 static NODE *
picstatic(NODE * p)121 picstatic(NODE *p)
122 {
123 	NODE *q, *r;
124 	struct symtab *sp;
125 
126 	q = tempnode(gotnr, PTR|VOID, 0, 0);
127 	if (p->n_sp->slevel > 0) {
128 		char buf[32];
129 		if ((p->n_sp->sflags & SMASK) == SSTRING)
130 			p->n_sp->sflags |= SASG;
131 		snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset);
132 		sp = picsymtab("", buf, "@GOT");
133 	} else {
134 		sp = picsymtab("", getsoname(p->n_sp), "@GOT");
135 	}
136 
137 	sp->sclass = STATIC;
138 	sp->stype = p->n_sp->stype;
139 	r = xbcon(0, sp, INT);
140 	q = buildtree(PLUS, q, r);
141 	q = block(UMUL, q, 0, PTR|VOID, 0, 0);
142 	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
143 	q->n_sp = p->n_sp; /* for init */
144 	nfree(p);
145 	return q;
146 }
147 
148 /* clocal() is called to do local transformations on
149  * an expression tree preparitory to its being
150  * written out in intermediate code.
151  *
152  * the major essential job is rewriting the
153  * automatic variables and arguments in terms of
154  * REG and OREG nodes
155  * conversion ops which are not necessary are also clobbered here
156  * in addition, any special features (such as rewriting
157  * exclusive or) are easily handled here as well
158  */
159 NODE *
clocal(NODE * p)160 clocal(NODE *p)
161 {
162 
163 	register struct symtab *q;
164 	register NODE *r, *l;
165 	register int o;
166 	TWORD t;
167 
168 #ifdef PCC_DEBUG
169 	if (xdebug) {
170 		printf("clocal: %p\n", p);
171 		fwalk(p, eprint, 0);
172 	}
173 #endif
174 	switch( o = p->n_op ){
175 
176 	case NAME:
177 		if ((q = p->n_sp) == NULL)
178 			return p; /* Nothing to care about */
179 
180 		switch (q->sclass) {
181 
182 		case PARAM:
183 		case AUTO:
184 			/* fake up a structure reference */
185 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
186 			slval(r, 0);
187 			r->n_rval = FPREG;
188 			p = stref(block(STREF, r, p, 0, 0, 0));
189 			break;
190 
191 		case REGISTER:
192 			p->n_op = REG;
193 			slval(p, 0);
194 			p->n_rval = q->soffset;
195 			break;
196 
197 		case USTATIC:
198 		case STATIC:
199 			if (kflag == 0)
200 				break;
201 			if (blevel > 0 && !statinit)
202 				p = picstatic(p);
203 			break;
204 
205 		case EXTERN:
206 		case EXTDEF:
207 			if (kflag == 0)
208 				break;
209 			if (blevel > 0 && !statinit)
210 				p = picext(p);
211 			break;
212 		}
213 		break;
214 
215 	case ADDROF:
216 		if (kflag == 0 || blevel == 0 || statinit)
217 			break;
218 		/* char arrays may end up here */
219 		l = p->n_left;
220 		if (l->n_op != NAME ||
221 		    (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
222 			break;
223 		l = p;
224 		p = picstatic(p->n_left);
225 		nfree(l);
226 		if (p->n_op != UMUL)
227 			cerror("ADDROF error");
228 		l = p;
229 		p = p->n_left;
230 		nfree(l);
231 		break;
232 
233 	case STASG: /* convert struct assignment to call memcpy */
234 		l = p->n_left;
235 		if (l->n_op == NAME && ISFTN(l->n_sp->stype))
236 			break; /* struct return, do nothing */
237 		/* first construct arg list */
238 		p->n_left = buildtree(ADDROF, p->n_left, 0);
239 		r = bcon(tsize(STRTY, p->n_df, p->n_ap)/SZCHAR);
240 		p->n_left = buildtree(CM, p->n_left, p->n_right);
241 		p->n_right = r;
242 		p->n_op = CM;
243 		p->n_type = INT;
244 
245 		r = block(NAME, NIL, NIL, INT, 0, 0);
246 		r->n_sp = lookup(addname("memcpy"), SNORMAL);
247 		if (r->n_sp->sclass == SNULL) {
248 			r->n_sp->sclass = EXTERN;
249 			r->n_sp->stype = INCREF(VOID+PTR)+(FTN-PTR);
250 		}
251 		r->n_type = r->n_sp->stype;
252 		p = buildtree(CALL, r, p);
253 		break;
254 
255 	case SCONV:
256 		l = p->n_left;
257 		if (l->n_op == ICON && ISPTR(l->n_type)) {
258 			/* Do immediate cast here */
259 			/* Should be common code */
260 			q = l->n_sp;
261 			l->n_sp = NULL;
262 			l->n_type = UNSIGNED;
263 			if (concast(l, p->n_type) == 0)
264 				cerror("clocal");
265 			p = nfree(p);
266 			p->n_sp = q;
267 		}
268 		break;
269 
270 	case FORCE:
271 		/* put return value in return reg */
272 		p->n_op = ASSIGN;
273 		p->n_right = p->n_left;
274 		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
275 		t = p->n_type;
276 		if (ISITY(t))
277 			t = t - (FIMAG-FLOAT);
278 		p->n_left->n_rval = RETREG(t);
279 		break;
280 	}
281 #ifdef PCC_DEBUG
282 	if (xdebug) {
283 		printf("clocal end: %p\n", p);
284 		fwalk(p, eprint, 0);
285 	}
286 #endif
287 	return(p);
288 }
289 
290 #define IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
291 
292 void
myp2tree(NODE * p)293 myp2tree(NODE *p)
294 {
295 	struct symtab *sp;
296 	NODE *l;
297 
298 	if (cdope(p->n_op) & CALLFLG) {
299 		if (p->n_left->n_op == ADDROF &&
300 		    p->n_left->n_left->n_op == NAME) {
301 			p->n_left = nfree(p->n_left);
302 			l = p->n_left;
303 			l->n_op = ICON;
304 			if (l->n_sp->sclass != STATIC &&
305 			    l->n_sp->sclass != USTATIC)
306 				l->n_sp =
307 				    picsymtab(l->n_sp->sname, "@PLTPC", "");
308 		}
309 	}
310 
311 	if (p->n_op != FCON)
312 		return;
313 
314 	sp = IALLOC(sizeof(struct symtab));
315 	sp->sclass = STATIC;
316 	sp->sap = 0;
317 	sp->slevel = 1; /* fake numeric label */
318 	sp->soffset = getlab();
319 	sp->sflags = 0;
320 	sp->stype = p->n_type;
321 	sp->squal = (CON >> TSHIFT);
322 	sp->sname = NULL;
323 
324 	locctr(DATA, sp);
325 	defloc(sp);
326 	ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
327 
328 	p->n_op = NAME;
329 	slval(p, 0);
330 	p->n_sp = sp;
331 
332 }
333 
334 /*
335  * Convert ADDROF NAME to ICON?
336  */
337 int
andable(NODE * p)338 andable(NODE *p)
339 {
340 #ifdef notdef
341 	/* shared libraries cannot have direct referenced static syms */
342 	if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC)
343 		return 1;
344 #endif
345 	return 1;
346 }
347 
348 /*
349  * Return 1 if a variable of type type is OK to put in register.
350  */
351 int
cisreg(TWORD t)352 cisreg(TWORD t)
353 {
354 	return 1;
355 }
356 
357 /*
358  * Allocate off bits on the stack.  p is a tree that when evaluated
359  * is the multiply count for off, t is a storeable node where to write
360  * the allocated address.
361  */
362 void
spalloc(NODE * t,NODE * p,OFFSZ off)363 spalloc(NODE *t, NODE *p, OFFSZ off)
364 {
365 	NODE *sp;
366 
367 	p = buildtree(MUL, p, bcon(off/SZCHAR));
368 	p = buildtree(PLUS, p, bcon(30));
369 	p = buildtree(AND, p, xbcon(-16, NULL, UNSIGNED));
370 	p = cast(p, UNSIGNED, 0);
371 
372 	/* sub the size from sp */
373 	sp = block(REG, NIL, NIL, UNSIGNED+PTR, 0, 0);
374 	slval(sp, 0);
375 	sp->n_rval = STKREG;
376 	p = (buildtree(MINUSEQ, sp, p));
377 	ecomp(p);
378 
379 	/* save the address of sp */
380 	sp = block(REG, NIL, NIL, PTR+UNSIGNED, t->n_df, t->n_ap);
381 	slval(sp, 0);
382 	sp->n_rval = STKREG;
383 	t->n_type = sp->n_type;
384 	p = (buildtree(ASSIGN, t, sp)); /* Emit! */
385 	ecomp(p);
386 
387 }
388 
389 /*
390  * print out a constant node, may be associated with a label.
391  * Do not free the node after use.
392  * off is bit offset from the beginning of the aggregate
393  * fsz is the number of bits this is referring to
394  */
395 int
ninval(CONSZ off,int fsz,NODE * p)396 ninval(CONSZ off, int fsz, NODE *p)
397 {
398 	union { float f; double d; long double l; int i[3]; } u;
399 
400 	switch (p->n_type) {
401 	case LDOUBLE:
402 		u.i[2] = 0;
403 		u.l = (long double)((union flt *)p->n_dcon)->fp;
404 #if defined(HOST_LITTLE_ENDIAN)
405 		/* XXX probably broken on most hosts */
406 		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]);
407 #else
408 		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
409 #endif
410 		break;
411 	case DOUBLE:
412 		u.d = (double)((union flt *)p->n_dcon)->fp;
413 #if defined(HOST_LITTLE_ENDIAN)
414 		printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
415 #else
416 		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
417 #endif
418 		break;
419 	case FLOAT:
420 		u.f = (float)((union flt *)p->n_dcon)->fp;
421 		printf("\t.long\t0x%x\n", u.i[0]);
422 		break;
423 
424 	case LONGLONG:
425 	case ULONGLONG:
426 		printf("\t.long\t0x%x\n", (int)(off >> 32) & 0xffffffff);
427 		printf("\t.long\t0x%x\n", (int)(off) & 0xffffffff);
428 		break;
429 	default:
430 		return 0;
431 	}
432 	return 1;
433 }
434 
435 /* make a name look like an external name in the local machine */
436 char *
exname(char * p)437 exname(char *p)
438 {
439 	return (p == NULL ? "" : p);
440 }
441 
442 /*
443  * map types which are not defined on the local machine
444  */
445 TWORD
ctype(TWORD type)446 ctype(TWORD type)
447 {
448 	switch (BTYPE(type)) {
449 	case LONG:
450 		MODTYPE(type,INT);
451 		break;
452 
453 	case ULONG:
454 		MODTYPE(type,UNSIGNED);
455 
456 	}
457 	return (type);
458 }
459 
460 void
calldec(NODE * p,NODE * q)461 calldec(NODE *p, NODE *q)
462 {
463 }
464 
465 void
extdec(struct symtab * q)466 extdec(struct symtab *q)
467 {
468 }
469 
470 /* make a common declaration for id, if reasonable */
471 void
defzero(struct symtab * sp)472 defzero(struct symtab *sp)
473 {
474 	int off, al;
475 	char *name;
476 
477 	name = getexname(sp);
478 	off = tsize(sp->stype, sp->sdf, sp->sap);
479 	SETOFF(off,SZCHAR);
480 	off /= SZCHAR;
481 	al = talign(sp->stype, sp->sap)/SZCHAR;
482 
483 	if (sp->sclass == STATIC) {
484 		if (sp->slevel == 0) {
485 			printf("\t.local %s\n", name);
486 		} else
487 			printf("\t.local " LABFMT "\n", sp->soffset);
488 	}
489 	if (sp->slevel == 0) {
490 		printf("\t.comm %s,0%o,%d\n", name, off, al);
491 	} else
492 		printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al);
493 }
494 
495 char *nextsect;
496 static char *alias;
497 static int constructor;
498 static int destructor;
499 
500 /*
501  * Give target the opportunity of handling pragmas.
502  */
503 int
mypragma(char * str)504 mypragma(char *str)
505 {
506 	return 0;
507 }
508 
509 /*
510  * Called when a identifier has been declared.
511  */
512 void
fixdef(struct symtab * sp)513 fixdef(struct symtab *sp)
514 {
515 	struct attr *ga;
516 
517 #ifdef HAVE_WEAKREF
518 	/* not many as'es have this directive */
519 	if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) {
520 		char *wr = ga->sarg(0);
521 		char *sn = getsoname(sp);
522 		if (wr == NULL) {
523 			if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) {
524 				wr = ga->sarg(0);
525 			}
526 		}
527 		if (wr == NULL)
528 			printf("\t.weak %s\n", sn);
529 		else
530 			printf("\t.weakref %s,%s\n", sn, wr);
531 	} else
532 	       if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
533 		char *an = ga->sarg(0);
534 		char *sn = getsoname(sp);
535 		char *v;
536 
537 		v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
538 		printf("\t.%s %s\n", v, sn);
539 		printf("\t.set %s,%s\n", sn, an);
540 	}
541 	if (alias != NULL && (sp->sclass != PARAM)) {
542 		char *name = getexname(sp);
543 		printf("\t.globl %s\n", name);
544 		printf("%s = ", name);
545 		printf("%s\n", exname(alias));
546 		alias = NULL;
547 	}
548 	if ((constructor || destructor) && (sp->sclass != PARAM)) {
549 		NODE *p = p1alloc();
550 
551 		p->n_op = NAME;
552 		p->n_sp =
553 		  (struct symtab *)(constructor ? "constructor" : "destructor");
554 		sp->sap = attr_add(sp->sap, gcc_attr_parse(p));
555 		constructor = destructor = 0;
556 	}
557 #endif
558 }
559 
560 void
pass1_lastchance(struct interpass * ip)561 pass1_lastchance(struct interpass *ip)
562 {
563 }
564