xref: /netbsd/external/bsd/pcc/dist/pcc/arch/m16c/local.c (revision 6550d01e)
1 /*	Id: local.c,v 1.15 2008/12/14 21:16:58 ragge Exp 	*/
2 /*	$NetBSD: local.c,v 1.1.1.3 2010/06/03 18:57:17 plunky 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  * 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 # include "pass1.h"
32 
33 /*	this file contains code which is dependent on the target machine */
34 
35 NODE *
36 clocal(NODE *p)
37 {
38 	/* this is called to do local transformations on
39 	   an expression tree preparitory to its being
40 	   written out in intermediate code.
41 	*/
42 
43 	/* the major essential job is rewriting the
44 	   automatic variables and arguments in terms of
45 	   REG and OREG nodes */
46 	/* conversion ops which are not necessary are also clobbered here */
47 	/* in addition, any special features (such as rewriting
48 	   exclusive or) are easily handled here as well */
49 
50 	struct symtab *q;
51 	NODE *l, *r;
52 	int o;
53 	TWORD ml;
54 
55 	switch( o = p->n_op ){
56 
57 	case NAME:
58 		if ((q = p->n_sp) == NULL)
59 			return p; /* Nothing to care about */
60 
61 		switch (q->sclass) {
62 
63 		case PARAM:
64 		case AUTO:
65 			/* fake up a structure reference */
66 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
67 			r->n_lval = 0;
68 			r->n_rval = FPREG;
69 			p = stref(block(STREF, r, p, 0, 0, 0));
70 			break;
71 
72 		case STATIC:
73 			if (q->slevel == 0)
74 				break;
75 			p->n_lval = 0;
76 			p->n_sp = q;
77 			break;
78 
79 		case REGISTER:
80 			p->n_op = REG;
81 			p->n_lval = 0;
82 			p->n_rval = q->soffset;
83 			break;
84 
85 			}
86 		break;
87 
88 	case PMCONV:
89 	case PVCONV:
90 		if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
91 		nfree(p);
92 		return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
93 
94 	case PCONV:
95 		ml = p->n_left->n_type;
96 		l = p->n_left;
97 		if ((ml == CHAR || ml == UCHAR) && l->n_op != ICON)
98 			break;
99 		l->n_type = p->n_type;
100 		l->n_qual = p->n_qual;
101 		l->n_df = p->n_df;
102 		l->n_sue = p->n_sue;
103 		nfree(p);
104 		p = l;
105 		break;
106 
107 	case SCONV:
108 		l = p->n_left;
109 		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) {
110 			nfree(p);
111 			return l;
112 		}
113 		if (l->n_op == ICON) {
114 			CONSZ val = l->n_lval;
115 			switch (p->n_type) {
116 			case CHAR:
117 				l->n_lval = (char)val;
118 				break;
119 			case UCHAR:
120 				l->n_lval = val & 0377;
121 				break;
122 			case SHORT:
123 			case INT:
124 				l->n_lval = (short)val;
125 				break;
126 			case USHORT:
127 			case UNSIGNED:
128 				l->n_lval = val & 0177777;
129 				break;
130 			case ULONG:
131 			case ULONGLONG:
132 				l->n_lval = val & 0xffffffff;
133 				break;
134 			case LONG:
135 			case LONGLONG:
136 				l->n_lval = (int)val;
137 				break;
138 			case VOID:
139 				break;
140 			case LDOUBLE:
141 			case DOUBLE:
142 			case FLOAT:
143 				l->n_op = FCON;
144 				l->n_dcon = val;
145 				break;
146 			default:
147 				cerror("unknown type %d", p->n_type);
148 			}
149 			l->n_type = p->n_type;
150 			nfree(p);
151 			return l;
152 		}
153 		break;
154 
155 
156 	}
157 
158 	return(p);
159 }
160 
161 /*ARGSUSED*/
162 int
163 andable(NODE *p)
164 {
165 	return(1);  /* all names can have & taken on them */
166 }
167 
168 /*
169  * at the end of the arguments of a ftn, set the automatic offset
170  */
171 void
172 cendarg()
173 {
174 	autooff = AUTOINIT;
175 }
176 
177 /*
178  * is an automatic variable of type t OK for a register variable
179  */
180 int
181 cisreg(TWORD t)
182 {
183 	if (t == INT || t == UNSIGNED || t == CHAR || t == UCHAR ||
184 		ISPTR(t))
185 		return(1);
186 	return 0; /* XXX - fix reg assignment in pftn.c */
187 }
188 
189 /*
190  * return a node, for structure references, which is suitable for
191  * being added to a pointer of type t, in order to be off bits offset
192  * into a structure
193  * t, d, and s are the type, dimension offset, and sizeoffset
194  * For pdp10, return the type-specific index number which calculation
195  * is based on its size. For example, short a[3] would return 3.
196  * Be careful about only handling first-level pointers, the following
197  * indirections must be fullword.
198  */
199 NODE *
200 offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
201 {
202 	register NODE *p;
203 
204 	if (xdebug)
205 		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
206 		    off, t, d, sue->suesize);
207 
208 	p = bcon(0);
209 	p->n_lval = off/SZCHAR; /* Default */
210 	return(p);
211 }
212 
213 /*
214  * Allocate off bits on the stack.  p is a tree that when evaluated
215  * is the multiply count for off, t is a NAME node where to write
216  * the allocated address.
217  */
218 void
219 spalloc(NODE *t, NODE *p, OFFSZ off)
220 {
221 	NODE *sp;
222 
223 	if ((off % SZINT) == 0)
224 		p =  buildtree(MUL, p, bcon(off/SZINT));
225 	else if ((off % SZSHORT) == 0) {
226 		p = buildtree(MUL, p, bcon(off/SZSHORT));
227 		p = buildtree(PLUS, p, bcon(1));
228 		p = buildtree(RS, p, bcon(1));
229 	} else if ((off % SZCHAR) == 0) {
230 		p = buildtree(MUL, p, bcon(off/SZCHAR));
231 		p = buildtree(PLUS, p, bcon(3));
232 		p = buildtree(RS, p, bcon(2));
233 	} else
234 		cerror("roundsp");
235 
236 	/* save the address of sp */
237 	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
238 	sp->n_lval = 0;
239 	sp->n_rval = STKREG;
240 	t->n_type = sp->n_type;
241 	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
242 
243 	/* add the size to sp */
244 	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
245 	sp->n_lval = 0;
246 	sp->n_rval = STKREG;
247 	ecomp(buildtree(PLUSEQ, sp, p));
248 }
249 
250 /*
251  * print out a constant node
252  * mat be associated with a label
253  */
254 void
255 ninval(NODE *p)
256 {
257 	struct symtab *q;
258 	TWORD t;
259 
260 	p = p->n_left;
261 	t = p->n_type;
262 	if (t > BTMASK)
263 		t = INT; /* pointer */
264 
265 	switch (t) {
266 	case LONGLONG:
267 	case ULONGLONG:
268 		inval(p->n_lval & 0xffffffff);
269 		inval(p->n_lval >> 32);
270 		break;
271 	case LONG:
272 	case ULONG:
273 	case INT:
274 	case UNSIGNED:
275 		printf("\t.long 0x%x", (int)p->n_lval);
276 		if ((q = p->n_sp) != NULL) {
277 			if ((q->sclass == STATIC && q->slevel > 0)) {
278 				printf("+" LABFMT, q->soffset);
279 			} else
280 				printf("+%s", exname(q->soname));
281 		}
282 		printf("\n");
283 		break;
284 	default:
285 		fwalk(p, eprint, 0);
286 		cerror("ninval");
287 	}
288 }
289 
290 /*
291  * print out an integer.
292  */
293 void
294 inval(CONSZ word)
295 {
296 	word &= 0xffffffff;
297 	printf("	.long 0x%llx\n", word);
298 }
299 
300 /* output code to initialize a floating point value */
301 /* the proper alignment has been obtained */
302 void
303 finval(NODE *p)
304 {
305 	switch (p->n_type) {
306 	case LDOUBLE:
307 		printf("\t.tfloat\t0t%.20Le\n", p->n_dcon);
308 		break;
309 	case DOUBLE:
310 		printf("\t.dfloat\t0d%.20e\n", (double)p->n_dcon);
311 		break;
312 	case FLOAT:
313 		printf("\t.ffloat\t0f%.20e\n", (float)p->n_dcon);
314 		break;
315 	}
316 }
317 
318 /* make a name look like an external name in the local machine */
319 char *
320 exname(char *p)
321 {
322 	if (p == NULL)
323 		return "";
324 	return p;
325 }
326 
327 /*
328  * map types which are not defined on the local machine
329  */
330 TWORD
331 ctype(TWORD type)
332 {
333 	switch (BTYPE(type)) {
334 	case SHORT:
335 		MODTYPE(type,INT);
336 		break;
337 
338 	case USHORT:
339 		MODTYPE(type,UNSIGNED);
340 		break;
341 
342 	case LONGLONG:
343 		MODTYPE(type,LONG);
344 		break;
345 
346 	case ULONGLONG:
347 		MODTYPE(type,ULONG);
348 		break;
349 
350 	case LDOUBLE:
351 		MODTYPE(type,DOUBLE);
352 		break;
353 	}
354 	return (type);
355 }
356 
357 /* curid is a variable which is defined but
358  * is not initialized (and not a function );
359  * This routine returns the storage class for an uninitialized declaration
360  */
361 int
362 noinit()
363 {
364 	return(EXTERN);
365 }
366 
367 /*
368  * Extern variable not necessary common.
369  */
370 void
371 extdec(struct symtab *q)
372 {
373 	extern void addsym(struct symtab *);
374 	addsym(q);
375 }
376 
377 /*
378  * Call to a function
379  */
380 void
381 calldec(NODE *p, NODE *r)
382 {
383 	struct symtab *q = p->n_sp;
384 	extern void addsym(struct symtab *);
385 	addsym(q);
386 }
387 
388 /* make a common declaration for id, if reasonable */
389 void
390 commdec(struct symtab *q)
391 {
392 	int off;
393 	char *c = q->soname;
394 
395 	off = tsize(q->stype, q->sdf, q->ssue);
396 	off = (off+(SZCHAR-1))/SZCHAR;
397 
398 	printf("	PUBLIC %s\n", c);
399 	/* XXX - NOROOT??? */
400 	printf("	RSEG DATA16_Z:NEARDATA:SORT:NOROOT(1)\n");
401 	printf("%s:\n", c);
402 	printf("	DS8 %d\n", off);
403 	printf("	REQUIRE __data16_zero\n");
404 }
405 
406 /* make a local common declaration for id, if reasonable */
407 void
408 lcommdec(struct symtab *q)
409 {
410 	int off;
411 
412 	off = tsize(q->stype, q->sdf, q->ssue);
413 	off = (off+(SZCHAR-1))/SZCHAR;
414 	if (q->slevel == 0)
415 		printf("	.lcomm %s,0%o\n", exname(q->soname), off);
416 	else
417 		printf("	.lcomm " LABFMT ",0%o\n", q->soffset, off);
418 }
419 
420 /*
421  * print a (non-prog) label.
422  */
423 void
424 deflab1(int label)
425 {
426 	printf(LABFMT ":\n", label);
427 }
428 
429 void
430 setloc1(int locc)
431 {
432 	if (locc == lastloc)
433 		return;
434 	lastloc = locc;
435 }
436 
437 /*
438  * special handling before tree is written out.
439  */
440 void
441 myp2tree(NODE *p)
442 {
443 	struct symtab *sp;
444 	union dimfun *df;
445 	union arglist *al;
446 	NODE *q;
447 	int i;
448 
449 	switch (p->n_op) {
450 	case MOD:
451 	case DIV:
452 		if (p->n_type == LONG || p->n_type == ULONG) {
453 			/* Swap arguments for hardops() later */
454 			q = p->n_left;
455 			p->n_left = p->n_right;
456 			p->n_right = q;
457 		}
458 		break;
459 
460 	case CALL:
461 	case STCALL:
462 		/*
463 		 * inform pass2 about varargs.
464 		 * store first variadic argument number in n_stalign
465 		 * in the CM node.
466 		 */
467 		if (p->n_right->n_op != CM)
468 			break; /* nothing to care about */
469 		df = p->n_left->n_df;
470 		if (df && (al = df->dfun)) {
471 			for (i = 0; i < 6; i++, al++) {
472 				if (al->type == TELLIPSIS || al->type == TNULL)
473 					break;
474 			}
475 			p->n_right->n_stalign = al->type == TELLIPSIS ? i : 0;
476 		} else
477 			p->n_right->n_stalign = 0;
478 		break;
479 
480 	case FCON:
481 		/* Write float constants to memory */
482 		sp = inlalloc(sizeof(struct symtab));
483 		sp->sclass = STATIC;
484 		sp->ssue = MKSUE(p->n_type);
485 		sp->slevel = 1; /* fake numeric label */
486 		sp->soffset = getlab();
487 		sp->sflags = 0;
488 		sp->stype = p->n_type;
489 		sp->squal = (CON >> TSHIFT);
490 
491 		defloc(sp);
492 		ninval(0, sp->ssue->suesize, p);
493 
494 		p->n_op = NAME;
495 		p->n_lval = 0;
496 		p->n_sp = sp;
497 		break;
498 	}
499 
500 }
501 /*
502  * Give target the opportunity of handling pragmas.
503  */
504 int
505 mypragma(char **ary)
506 {
507 	return 0; }
508 
509 /*
510  * Called when a identifier has been declared, to give target last word.
511  */
512 void
513 fixdef(struct symtab *sp)
514 {
515 }
516 
517 void
518 pass1_lastchance(struct interpass *ip)
519 {
520 }
521