1 /*	$Id: local.c,v 1.16 2014/06/03 20:19:50 ragge Exp $	*/
2 /*
3  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4  * All rights reserved.
5  *
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.
14  *
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.
25  */
26 
27 
28 # include "pass1.h"
29 
30 /*	this file contains code which is dependent on the target machine */
31 
32 NODE *
clocal(NODE * p)33 clocal(NODE *p)
34 {
35 	struct symtab *q;
36 	NODE *r, *l;
37 	TWORD t;
38 	int o;
39 
40 #ifdef PCC_DEBUG
41 	if (xdebug) {
42 		printf("clocal\n");
43 		fwalk(p, eprint, 0);
44 	}
45 #endif
46 
47 	switch( o = p->n_op ){
48 	case NAME:
49 		/* handle variables */
50 		if ((q = p->n_sp) == NULL)
51 			return p; /* Nothing to care about */
52 		switch (q->sclass) {
53 		case PARAM:
54 		case AUTO:
55 			if (0 && q->soffset < MAXZP * SZINT &&
56 			    q->sclass != PARAM) {
57 				p->n_lval = -(q->soffset/SZCHAR) + ZPOFF*2;
58 				p->n_sp = NULL;
59 			} else {
60 				/* fake up a structure reference */
61 				r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
62 				r->n_lval = 0;
63 				r->n_rval = FPREG;
64 				p = stref(block(STREF, r, p, 0, 0, 0));
65 			}
66 			break;
67 		default:
68 			break;
69 		}
70 		break;
71 
72 	case PMCONV:
73 	case PVCONV:
74                 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
75                 nfree(p);
76                 p = (buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
77 		break;
78 
79 	case PCONV:
80 		t = p->n_type;
81 		if (t == INCREF(CHAR) || t == INCREF(UCHAR) ||
82 		    t == INCREF(BOOL) || t == INCREF(VOID))
83 			break;
84 		l = p->n_left;
85 		t = l->n_type;
86 		if (t == INCREF(CHAR) || t == INCREF(UCHAR) ||
87 		    t == INCREF(BOOL) || t == INCREF(VOID))
88 			break;
89 		if (p->n_type <= UCHAR || l->n_type <= UCHAR)
90 			break; /* must do runtime ptr conv */
91 		/* if conversion to another pointer type, just remove */
92 		if (p->n_type > BTMASK && l->n_type > BTMASK)
93 			goto delp;
94 		if (l->n_op == ICON && l->n_sp == NULL)
95 			goto delp;
96 		break;
97 
98 	delp:	l->n_type = p->n_type;
99 		l->n_qual = p->n_qual;
100 		l->n_df = p->n_df;
101 		l->n_ap = p->n_ap;
102 		p = nfree(p);
103 		break;
104 	}
105 
106 #ifdef PCC_DEBUG
107 	if (xdebug) {
108 		printf("clocal end\n");
109 		fwalk(p, eprint, 0);
110 	}
111 #endif
112 
113 #if 0
114 	register struct symtab *q;
115 	register NODE *r, *l;
116 	register int o;
117 	register int m;
118 	TWORD t;
119 
120 //printf("in:\n");
121 //fwalk(p, eprint, 0);
122 	switch( o = p->n_op ){
123 
124 	case NAME:
125 		if ((q = p->n_sp) == NULL)
126 			return p; /* Nothing to care about */
127 
128 		switch (q->sclass) {
129 
130 		case PARAM:
131 		case AUTO:
132 			/* fake up a structure reference */
133 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
134 			r->n_lval = 0;
135 			r->n_rval = FPREG;
136 			p = stref(block(STREF, r, p, 0, 0, 0));
137 			break;
138 
139 		case STATIC:
140 			if (q->slevel == 0)
141 				break;
142 			p->n_lval = 0;
143 			p->n_sp = q;
144 			break;
145 
146 		case REGISTER:
147 			p->n_op = REG;
148 			p->n_lval = 0;
149 			p->n_rval = q->soffset;
150 			break;
151 
152 			}
153 		break;
154 
155 	case STCALL:
156 	case CALL:
157 		/* Fix function call arguments. On x86, just add funarg */
158 		for (r = p->n_right; r->n_op == CM; r = r->n_left) {
159 			if (r->n_right->n_op != STARG &&
160 			    r->n_right->n_op != FUNARG)
161 				r->n_right = block(FUNARG, r->n_right, NIL,
162 				    r->n_right->n_type, r->n_right->n_df,
163 				    r->n_right->n_sue);
164 		}
165 		if (r->n_op != STARG && r->n_op != FUNARG) {
166 			l = talloc();
167 			*l = *r;
168 			r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
169 		}
170 		break;
171 
172 	case CBRANCH:
173 		l = p->n_left;
174 
175 		/*
176 		 * Remove unnecessary conversion ops.
177 		 */
178 		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
179 			if (coptype(l->n_op) != BITYPE)
180 				break;
181 			if (l->n_right->n_op == ICON) {
182 				r = l->n_left->n_left;
183 				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
184 					break;
185 				/* Type must be correct */
186 				t = r->n_type;
187 				nfree(l->n_left);
188 				l->n_left = r;
189 				l->n_type = t;
190 				l->n_right->n_type = t;
191 			}
192 		}
193 		break;
194 
195 	case PCONV:
196 		/* Remove redundant PCONV's. Be careful */
197 		l = p->n_left;
198 		if (l->n_op == ICON) {
199 			l->n_lval = (unsigned)l->n_lval;
200 			goto delp;
201 		}
202 		if (l->n_type < INT || l->n_type == LONGLONG ||
203 		    l->n_type == ULONGLONG) {
204 			/* float etc? */
205 			p->n_left = block(SCONV, l, NIL,
206 			    UNSIGNED, 0, 0);
207 			break;
208 		}
209 		/* if left is SCONV, cannot remove */
210 		if (l->n_op == SCONV)
211 			break;
212 		/* if conversion to another pointer type, just remove */
213 		if (p->n_type > BTMASK && l->n_type > BTMASK)
214 			goto delp;
215 		break;
216 
217 	delp:	l->n_type = p->n_type;
218 		l->n_qual = p->n_qual;
219 		l->n_df = p->n_df;
220 		l->n_sue = p->n_sue;
221 		nfree(p);
222 		p = l;
223 		break;
224 
225 	case SCONV:
226 		l = p->n_left;
227 
228 		if (p->n_type == l->n_type) {
229 			nfree(p);
230 			return l;
231 		}
232 
233 		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
234 		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
235 			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
236 			    l->n_type != FLOAT && l->n_type != DOUBLE &&
237 			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
238 				if (l->n_op == NAME || l->n_op == UMUL ||
239 				    l->n_op == TEMP) {
240 					l->n_type = p->n_type;
241 					nfree(p);
242 					return l;
243 				}
244 			}
245 		}
246 
247 		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
248 		    coptype(l->n_op) == BITYPE) {
249 			l->n_type = p->n_type;
250 			nfree(p);
251 			return l;
252 		}
253 
254 		o = l->n_op;
255 		m = p->n_type;
256 
257 		if (o == ICON) {
258 			CONSZ val = l->n_lval;
259 
260 			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
261 			    switch (m) {
262 			case CHAR:
263 				l->n_lval = (char)val;
264 				break;
265 			case UCHAR:
266 				l->n_lval = val & 0377;
267 				break;
268 			case SHORT:
269 				l->n_lval = (short)val;
270 				break;
271 			case USHORT:
272 				l->n_lval = val & 0177777;
273 				break;
274 			case ULONG:
275 			case UNSIGNED:
276 				l->n_lval = val & 0xffffffff;
277 				break;
278 			case LONG:
279 			case INT:
280 				l->n_lval = (int)val;
281 				break;
282 			case LONGLONG:
283 				l->n_lval = (long long)val;
284 				break;
285 			case ULONGLONG:
286 				l->n_lval = val;
287 				break;
288 			case VOID:
289 				break;
290 			case LDOUBLE:
291 			case DOUBLE:
292 			case FLOAT:
293 				l->n_op = FCON;
294 				l->n_dcon = val;
295 				break;
296 			default:
297 				cerror("unknown type %d", m);
298 			}
299 			l->n_type = m;
300 			l->n_sue = 0;
301 			nfree(p);
302 			return l;
303 		}
304 		if (DEUNSIGN(p->n_type) == SHORT &&
305 		    DEUNSIGN(l->n_type) == SHORT) {
306 			nfree(p);
307 			p = l;
308 		}
309 		if ((p->n_type == CHAR || p->n_type == UCHAR ||
310 		    p->n_type == SHORT || p->n_type == USHORT) &&
311 		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
312 		    l->n_type == LDOUBLE)) {
313 			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
314 			p->n_left->n_type = INT;
315 			return p;
316 		}
317 		break;
318 
319 	case MOD:
320 	case DIV:
321 		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
322 			break;
323 		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
324 			break;
325 		/* make it an int division by inserting conversions */
326 		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
327 		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
328 		p = block(SCONV, p, NIL, p->n_type, 0, 0);
329 		p->n_left->n_type = INT;
330 		break;
331 
332 	case PMCONV:
333 	case PVCONV:
334                 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
335                 nfree(p);
336                 return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
337 
338 	case FORCE:
339 		/* put return value in return reg */
340 		p->n_op = ASSIGN;
341 		p->n_right = p->n_left;
342 		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
343 		p->n_left->n_rval = RETREG(p->n_type);
344 		break;
345 
346 	case LS:
347 	case RS:
348 		/* shift count must be in a char
349 		 * unless longlong, where it must be int */
350 		if (p->n_right->n_op == ICON)
351 			break; /* do not do anything */
352 		if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
353 			if (p->n_right->n_type != INT)
354 				p->n_right = block(SCONV, p->n_right, NIL,
355 				    INT, 0, 0);
356 			break;
357 		}
358 		if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
359 			break;
360 		p->n_right = block(SCONV, p->n_right, NIL,
361 		    CHAR, 0, 0);
362 		break;
363 	}
364 //printf("ut:\n");
365 //fwalk(p, eprint, 0);
366 
367 #endif
368 
369 	return(p);
370 }
371 
372 void
myp2tree(NODE * p)373 myp2tree(NODE *p)
374 {
375 	struct symtab *sp;
376 	NODE *l, *r;
377 	int o = p->n_op;
378 
379 	switch (o) {
380 	case NAME: /* reading from a name must be done with a subroutine */
381 		if (p->n_type != CHAR && p->n_type != UCHAR)
382 			break;
383 		l = buildtree(ADDROF, ccopy(p), NIL);
384 		r = block(NAME, NIL, NIL, INT, 0, 0);
385 
386 		r->n_sp = lookup(addname("__nova_rbyte"), SNORMAL);
387 		if (r->n_sp->sclass == SNULL) {
388 			r->n_sp->sclass = EXTERN;
389 			r->n_sp->stype = INCREF(p->n_type)+(FTN-PTR);
390 		}
391 		r->n_type = r->n_sp->stype;
392 		r = clocal(r);
393 		r = optim(buildtree(CALL, r, l));
394 		*p = *r;
395 		nfree(r);
396 		break;
397 
398 	case FCON:
399 		sp = inlalloc(sizeof(struct symtab));
400 		sp->sclass = STATIC;
401 		sp->sap = 0;
402 		sp->slevel = 1; /* fake numeric label */
403 		sp->soffset = getlab();
404 		sp->sflags = 0;
405 		sp->stype = p->n_type;
406 		sp->squal = (CON >> TSHIFT);
407 
408 		defloc(sp);
409 		ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
410 
411 		p->n_op = NAME;
412 		p->n_lval = 0;
413 		p->n_sp = sp;
414 	}
415 }
416 
417 /*ARGSUSED*/
418 int
andable(NODE * p)419 andable(NODE *p)
420 {
421 	return(1);  /* all names can have & taken on them */
422 }
423 
424 /*
425  * Return 1 if a variable of type type is OK to put in register.
426  */
427 int
cisreg(TWORD t)428 cisreg(TWORD t)
429 {
430 	return 1; /* try to put anything in a register */
431 }
432 
433 /*
434  * return a node, for structure references, which is suitable for
435  * being added to a pointer of type t, in order to be off bits offset
436  * into a structure
437  * t, d, and s are the type, dimension offset, and sizeoffset
438  * For nova, return the type-specific index number which calculation
439  * is based on its size. For example, char a[3] would return 3.
440  * Be careful about only handling first-level pointers, the following
441  * indirections must be fullword.
442  */
443 NODE *
offcon(OFFSZ off,TWORD t,union dimfun * d,struct attr * ap)444 offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap)
445 {
446 	register NODE *p;
447 
448 	if (xdebug)
449 		printf("offcon: OFFSZ %ld type %x dim %p siz %ld\n",
450 		    off, t, d, tsize(t, d, ap));
451 
452 	p = bcon(off/SZINT);
453 	if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(VOID))
454 		p->n_lval = off/SZCHAR; /* pointer to char */
455 	return(p);
456 }
457 
458 /*
459  * Allocate off bits on the stack.  p is a tree that when evaluated
460  * is the multiply count for off, t is a NAME node where to write
461  * the allocated address.
462  */
463 void
spalloc(NODE * t,NODE * p,OFFSZ off)464 spalloc(NODE *t, NODE *p, OFFSZ off)
465 {
466 	NODE *sp;
467 
468 cerror("spalloc");
469 	if ((off % SZINT) == 0)
470 		p =  buildtree(MUL, p, bcon(off/SZINT));
471 	else if ((off % SZSHORT) == 0) {
472 		p = buildtree(MUL, p, bcon(off/SZSHORT));
473 		p = buildtree(PLUS, p, bcon(1));
474 		p = buildtree(RS, p, bcon(1));
475 	} else if ((off % SZCHAR) == 0) {
476 		p = buildtree(MUL, p, bcon(off/SZCHAR));
477 		p = buildtree(PLUS, p, bcon(3));
478 		p = buildtree(RS, p, bcon(2));
479 	} else
480 		cerror("roundsp");
481 
482 	/* save the address of sp */
483 	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
484 	sp->n_lval = 0;
485 	sp->n_rval = STKREG;
486 	t->n_type = sp->n_type;
487 	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
488 
489 	/* add the size to sp */
490 	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
491 	sp->n_lval = 0;
492 	sp->n_rval = STKREG;
493 	ecomp(buildtree(PLUSEQ, sp, p));
494 }
495 
496 /*
497  * print out a constant node
498  * mat be associated with a label
499  */
500 int
ninval(CONSZ off,int fsz,NODE * p)501 ninval(CONSZ off, int fsz, NODE *p)
502 {
503 	switch (p->n_type) {
504 	case FLOAT:
505 	case DOUBLE:
506 	case LDOUBLE:
507 		cerror("ninval");
508 	}
509 	return 1;
510 }
511 
512 /* make a name look like an external name in the local machine */
513 char *
exname(char * p)514 exname(char *p)
515 {
516 	if (p == NULL)
517 		return "";
518 	return p;
519 }
520 
521 /*
522  * map types which are not defined on the local machine
523  */
524 TWORD
ctype(TWORD type)525 ctype(TWORD type)
526 {
527 	switch (BTYPE(type)) {
528 	case LONGLONG:
529 		MODTYPE(type,LONG);
530 		break;
531 
532 	case ULONGLONG:
533 		MODTYPE(type,ULONG);
534 		break;
535 	case SHORT:
536 		MODTYPE(type,INT);
537 		break;
538 	case USHORT:
539 		MODTYPE(type,UNSIGNED);
540 		break;
541 	}
542 	return (type);
543 }
544 
545 #if 0
546 /* curid is a variable which is defined but
547  * is not initialized (and not a function );
548  * This routine returns the storage class for an uninitialized declaration
549  */
550 int
551 noinit()
552 {
553 	return(EXTERN);
554 }
555 #endif
556 
557 void
calldec(NODE * p,NODE * q)558 calldec(NODE *p, NODE *q)
559 {
560 }
561 
562 void
extdec(struct symtab * q)563 extdec(struct symtab *q)
564 {
565 }
566 
567 #if 0
568 /* make a common declaration for id, if reasonable */
569 void
570 commdec(struct symtab *q)
571 {
572 	int off;
573 
574 	off = tsize(q->stype, q->sdf, q->ssue);
575 	off = (off+(SZCHAR-1))/SZCHAR;
576 	printf("	.comm %s,0%o\n", exname(q->soname), off);
577 }
578 
579 /* make a local common declaration for id, if reasonable */
580 void
581 lcommdec(struct symtab *q)
582 {
583 	int off;
584 
585 	off = tsize(q->stype, q->sdf, q->ssue);
586 	off = (off+(SZCHAR-1))/SZCHAR;
587 	if (q->slevel == 0)
588 		printf("	.lcomm %s,0%o\n", exname(q->soname), off);
589 	else
590 		printf("	.lcomm " LABFMT ",0%o\n", q->soffset, off);
591 }
592 
593 /*
594  * print a (non-prog) label.
595  */
596 void
597 deflab1(int label)
598 {
599 	printf(LABFMT ":\n", label);
600 }
601 
602 static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" };
603 
604 void
605 setloc1(int locc)
606 {
607 	if (locc == lastloc)
608 		return;
609 	lastloc = locc;
610 	printf("	.%s\n", loctbl[locc]);
611 }
612 #endif
613 
614 /*
615  * Give target the opportunity of handling pragmas.
616  */
617 int
mypragma(char * str)618 mypragma(char *str)
619 {
620 	return 0;
621 }
622 
623 /*
624  * Called when a identifier has been declared, to give target last word.
625  * On Nova we put symbols over the size of an int above 24 bytes in
626  * offset and leave zeropage for small vars.
627  */
628 void
fixdef(struct symtab * sp)629 fixdef(struct symtab *sp)
630 {
631 #if 0
632 	if (sp->sclass != AUTO)
633 		return; /* not our business */
634 	if (ISPTR(sp->stype) || sp->stype < LONG)
635 		return;
636 	if (sp->soffset >= (MAXZP * SZINT))
637 		return; /* already above */
638 	/* have to move */
639 	/* XXX remember old autooff for reorg of smaller vars */
640 	if (autooff < MAXZP * SZINT)
641 		autooff = MAXZP * SZINT;
642 	oalloc(sp, &autooff);
643 #endif
644 }
645 
646 void
pass1_lastchance(struct interpass * ip)647 pass1_lastchance(struct interpass *ip)
648 {
649 }
650