1/*	Id: local.c,v 1.12 2011/06/05 10:29:10 ragge Exp 	*/
2/*	$NetBSD$	*/
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
29#include "pass1.h"
30
31/*	this file contains code which is dependent on the target machine */
32
33/* clocal() is called to do local transformations on
34 * an expression tree preparitory to its being
35 * written out in intermediate code.
36 *
37 * the major essential job is rewriting the
38 * automatic variables and arguments in terms of
39 * REG and OREG nodes
40 * conversion ops which are not necessary are also clobbered here
41 * in addition, any special features (such as rewriting
42 * exclusive or) are easily handled here as well
43 */
44NODE *
45clocal(NODE *p)
46{
47
48	register struct symtab *q;
49	register NODE *r, *l;
50	register int o;
51	int m;
52
53#ifdef PCC_DEBUG
54	if (xdebug) {
55		printf("clocal: %p\n", p);
56		fwalk(p, eprint, 0);
57	}
58#endif
59	switch( o = p->n_op ){
60
61	case NAME:
62		if ((q = p->n_sp) == NULL)
63			return p; /* Nothing to care about */
64
65		switch (q->sclass) {
66
67		case PARAM:
68		case AUTO:
69			/* fake up a structure reference */
70			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
71			r->n_lval = 0;
72			r->n_rval = FPREG;
73			p = stref(block(STREF, r, p, 0, 0, 0));
74			break;
75
76		case STATIC:
77			if (q->slevel == 0)
78				break;
79			p->n_lval = 0;
80			break;
81
82		case REGISTER:
83			p->n_op = REG;
84			p->n_lval = 0;
85			p->n_rval = q->soffset;
86			break;
87
88		case EXTERN:
89		case EXTDEF:
90			break;
91		}
92		break;
93
94	case PCONV:
95		/* Remove redundant PCONV's. Be careful */
96		l = p->n_left;
97		if (l->n_op == ICON) {
98			l->n_lval = (unsigned)l->n_lval;
99			goto delp;
100		}
101		if (l->n_type < INT || l->n_type == LONGLONG ||
102		    l->n_type == ULONGLONG) {
103			/* float etc? */
104			p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
105			break;
106		}
107		/* if left is SCONV, cannot remove */
108		if (l->n_op == SCONV)
109			break;
110
111		/* avoid ADDROF TEMP */
112		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
113			break;
114
115		/* if conversion to another pointer type, just remove */
116		if (p->n_type > BTMASK && l->n_type > BTMASK)
117			goto delp;
118		break;
119
120	delp:	l->n_type = p->n_type;
121		l->n_qual = p->n_qual;
122		l->n_df = p->n_df;
123		l->n_sue = p->n_sue;
124		nfree(p);
125		p = l;
126		break;
127
128	case SCONV:
129		l = p->n_left;
130
131#if 0
132		if (p->n_type == l->n_type) {
133			nfree(p);
134			return l;
135		}
136
137		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
138		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
139			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
140			    l->n_type != FLOAT && l->n_type != DOUBLE &&
141			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
142				if (l->n_op == NAME || l->n_op == UMUL ||
143				    l->n_op == TEMP) {
144					l->n_type = p->n_type;
145					nfree(p);
146					return l;
147				}
148			}
149		}
150
151		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
152		    coptype(l->n_op) == BITYPE) {
153			l->n_type = p->n_type;
154			nfree(p);
155			return l;
156		}
157#endif
158		o = l->n_op;
159		m = p->n_type;
160
161		if (o == ICON) {
162			CONSZ val = l->n_lval;
163
164			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
165			    switch (m) {
166			case BOOL:
167				l->n_lval = l->n_lval != 0;
168				break;
169			case CHAR:
170				l->n_lval = (char)val;
171				break;
172			case UCHAR:
173				l->n_lval = val & 0377;
174				break;
175			case INT:
176				l->n_lval = (short)val;
177				break;
178			case UNSIGNED:
179				l->n_lval = val & 0177777;
180				break;
181			case ULONG:
182				l->n_lval = val & 0xffffffff;
183				break;
184			case LONG:
185				l->n_lval = (long)val;
186				break;
187			case LONGLONG:
188				l->n_lval = (long long)val;
189				break;
190			case ULONGLONG:
191				l->n_lval = val;
192				break;
193			case VOID:
194				break;
195			case LDOUBLE:
196			case DOUBLE:
197			case FLOAT:
198				l->n_op = FCON;
199				l->n_dcon = FLOAT_CAST(val, l->n_type);
200				break;
201			default:
202				cerror("unknown type %d", m);
203			}
204			l->n_type = m;
205			l->n_sue = 0;
206			nfree(p);
207			return l;
208		} else if (l->n_op == FCON) {
209			l->n_lval = FLOAT_VAL(l->n_dcon);
210			l->n_sp = NULL;
211			l->n_op = ICON;
212			l->n_type = m;
213			l->n_sue = 0;
214			nfree(p);
215			return clocal(l);
216		}
217		if (DEUNSIGN(p->n_type) == INT &&
218		    DEUNSIGN(l->n_type) == INT) {
219			nfree(p);
220			p = l;
221		}
222		break;
223
224	case CBRANCH:
225		l = p->n_left;
226		if (coptype(l->n_op) != BITYPE)
227			break;
228		if (l->n_left->n_op != SCONV || l->n_right->n_op != ICON)
229			break;
230		if ((r = l->n_left->n_left)->n_type > INT)
231			break;
232		/* compare with constant without casting */
233		nfree(l->n_left);
234		l->n_left = r;
235		l->n_right->n_type = l->n_left->n_type;
236		break;
237
238	case STASG: /* struct assignment, modify left */
239		l = p->n_left;
240		if (l->n_type == STRTY)
241			p->n_left = buildtree(ADDROF, l, NIL);
242		break;
243
244	case FORCE:
245		/* put return value in return reg */
246		p->n_op = ASSIGN;
247		p->n_right = p->n_left;
248		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
249		p->n_left->n_rval = p->n_left->n_type == BOOL ?
250		    RETREG(CHAR) : RETREG(p->n_type);
251		break;
252
253	}
254#ifdef PCC_DEBUG
255	if (xdebug) {
256		printf("clocal end: %p\n", p);
257		fwalk(p, eprint, 0);
258	}
259#endif
260	return(p);
261}
262
263void
264myp2tree(NODE *p)
265{
266	struct symtab *sp;
267
268	if (p->n_op != FCON)
269		return;
270
271	sp = inlalloc(sizeof(struct symtab));
272	sp->sclass = STATIC;
273	sp->ssue = 0;
274	sp->slevel = 1; /* fake numeric label */
275	sp->soffset = getlab();
276	sp->sflags = 0;
277	sp->stype = p->n_type;
278	sp->squal = (CON >> TSHIFT);
279
280	defloc(sp);
281	ninval(0, sp->ssue->suesize, p);
282
283	p->n_op = NAME;
284	p->n_lval = 0;
285	p->n_sp = sp;
286}
287
288/*ARGSUSED*/
289int
290andable(NODE *p)
291{
292	return(1);	/* all names can have & taken on them */
293}
294
295/*
296 * Return 1 if a variable of type type is OK to put in register.
297 */
298int
299cisreg(TWORD t)
300{
301	if (t == FLOAT || t == DOUBLE || t == LDOUBLE ||
302	    t == LONGLONG || t == ULONGLONG)
303		return 0; /* not yet */
304	return 1;
305}
306
307/*
308 * Allocate off bits on the stack.  p is a tree that when evaluated
309 * is the multiply count for off, t is a storeable node where to write
310 * the allocated address.
311 */
312void
313spalloc(NODE *t, NODE *p, OFFSZ off)
314{
315	NODE *sp;
316
317	p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
318
319	/* sub the size from sp */
320	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
321	sp->n_lval = 0;
322	sp->n_rval = STKREG;
323	ecomp(buildtree(MINUSEQ, sp, p));
324
325	/* save the address of sp */
326	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
327	sp->n_lval = 0;
328	sp->n_rval = STKREG;
329	t->n_type = sp->n_type;
330	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
331
332}
333
334/*
335 * Print out a string of characters.
336 * Assume that the assembler understands C-style escape
337 * sequences.
338 */
339void
340instring(struct symtab *sp)
341{
342	char *s;
343	int val, cnt;
344
345	defloc(sp);
346
347	for (cnt = 0, s = sp->sname; *s != 0; ) {
348		if (cnt++ == 0)
349			printf(".byte ");
350		if (*s++ == '\\')
351			val = esccon(&s);
352		else
353			val = s[-1];
354		printf("%o", val & 0377);
355		if (cnt > 15) {
356			cnt = 0;
357			printf("\n");
358		} else
359			printf(",");
360	}
361	printf("%s0\n", cnt ? "" : ".byte ");
362}
363
364static int inbits, xinval;
365
366/*
367 * set fsz bits in sequence to zero.
368 */
369void
370zbits(OFFSZ off, int fsz)
371{
372	int m;
373
374	if (idebug)
375		printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
376	if ((m = (inbits % SZCHAR))) {
377		m = SZCHAR - m;
378		if (fsz < m) {
379			inbits += fsz;
380			return;
381		} else {
382			fsz -= m;
383			printf("\t.byte %d\n", xinval);
384			xinval = inbits = 0;
385		}
386	}
387	if (fsz >= SZCHAR) {
388		printf(".=.+%o\n", fsz/SZCHAR);
389		fsz -= (fsz/SZCHAR) * SZCHAR;
390	}
391	if (fsz) {
392		xinval = 0;
393		inbits = fsz;
394	}
395}
396
397/*
398 * Initialize a bitfield.
399 */
400void
401infld(CONSZ off, int fsz, CONSZ val)
402{
403	if (idebug)
404		printf("infld off %lld, fsz %d, val %lld inbits %d\n",
405		    off, fsz, val, inbits);
406	val &= ((CONSZ)1 << fsz)-1;
407	while (fsz + inbits >= SZCHAR) {
408		xinval |= (val << inbits);
409		printf("\t.byte %d\n", xinval & 255);
410		fsz -= (SZCHAR - inbits);
411		val >>= (SZCHAR - inbits);
412		xinval = inbits = 0;
413	}
414	if (fsz) {
415		xinval |= (val << inbits);
416		inbits += fsz;
417	}
418}
419
420/*
421 * print out a constant node, may be associated with a label.
422 * Do not free the node after use.
423 * off is bit offset from the beginning of the aggregate
424 * fsz is the number of bits this is referring to
425 */
426int
427ninval(CONSZ off, int fsz, NODE *p)
428{
429#ifdef __pdp11__
430	union { float f; double d; short s[4]; int i[2]; } u;
431#endif
432	struct symtab *q;
433	TWORD t;
434	int i;
435
436	t = p->n_type;
437	if (t > BTMASK)
438		p->n_type = t = INT; /* pointer */
439
440	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
441		uerror("element not constant");
442
443	switch (t) {
444	case LONGLONG:
445	case ULONGLONG:
446		i = (p->n_lval >> 32);
447		p->n_lval &= 0xffffffff;
448		p->n_type = INT;
449		ninval(off, 32, p);
450		p->n_lval = i;
451		ninval(off+32, 32, p);
452		break;
453	case LONG:
454	case ULONG:
455		printf("%o ; %o\n", (int)((p->n_lval >> 16) & 0177777),
456		    (int)(p->n_lval & 0177777));
457		break;
458	case INT:
459	case UNSIGNED:
460		printf("%o", (int)(p->n_lval & 0177777));
461		if ((q = p->n_sp) != NULL) {
462			if ((q->sclass == STATIC && q->slevel > 0)) {
463				printf("+" LABFMT, q->soffset);
464			} else {
465				printf("+%s", q->soname ? q->soname : exname(q->sname));
466			}
467		}
468		printf("\n");
469		break;
470#ifdef __pdp11__
471	case FLOAT:
472		u.f = (float)p->n_dcon;
473		printf("%o ; %o\n", u.i[0], u.i[1]);
474		break;
475	case LDOUBLE:
476	case DOUBLE:
477		u.d = (double)p->n_dcon;
478		printf("%o ; %o ; %o ; %o\n", u.i[0], u.i[1], u.i[2], u.i[3]);
479		break;
480#else
481	/* cross-compiling */
482	case FLOAT:
483		printf("%o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2);
484		break;
485	case LDOUBLE:
486	case DOUBLE:
487		printf("%o ; %o ; %o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2,
488		    p->n_dcon.fd3, p->n_dcon.fd4);
489		break;
490#endif
491	default:
492		return 0;
493	}
494	return 1;
495}
496
497/* make a name look like an external name in the local machine */
498char *
499exname(char *p)
500{
501#define NCHNAM  256
502	static char text[NCHNAM+1];
503	int i;
504
505	if (p == NULL)
506		return "";
507
508	text[0] = '_';
509	for (i=1; *p && i<NCHNAM; ++i)
510		text[i] = *p++;
511
512	text[i] = '\0';
513	text[NCHNAM] = '\0';  /* truncate */
514
515	return (text);
516
517}
518
519/*
520 * map types which are not defined on the local machine
521 */
522TWORD
523ctype(TWORD type)
524{
525	switch (BTYPE(type)) {
526	case SHORT:
527		MODTYPE(type,INT);
528		break;
529
530	case USHORT:
531		MODTYPE(type,UNSIGNED);
532		break;
533
534	case LDOUBLE:
535		MODTYPE(type,DOUBLE);
536		break;
537
538	}
539	return (type);
540}
541
542void
543calldec(NODE *p, NODE *q)
544{
545}
546
547void
548extdec(struct symtab *q)
549{
550}
551
552/* make a common declaration for id, if reasonable */
553void
554defzero(struct symtab *sp)
555{
556	extern int lastloc;
557	char *n;
558	int off;
559
560	off = tsize(sp->stype, sp->sdf, sp->ssue);
561	off = (off+(SZCHAR-1))/SZCHAR;
562	n = sp->soname ? sp->soname : exname(sp->sname);
563	if (sp->sclass == STATIC) {
564		printf(".bss\n");
565		if (sp->slevel == 0)
566			printf("%s:", n);
567		else
568			printf(LABFMT ":", sp->soffset);
569		printf("	.=.+%o\n", off);
570		lastloc = -1;
571		return;
572	}
573	printf(".comm ");
574	if (sp->slevel == 0)
575		printf("%s,0%o\n", n, off);
576	else
577		printf(LABFMT ",0%o\n", sp->soffset, off);
578}
579
580/*
581 * Give target the opportunity of handling pragmas.
582 */
583int
584mypragma(char *str)
585{
586	return 0;
587}
588
589/*
590 * Called when a identifier has been declared.
591 */
592void
593fixdef(struct symtab *sp)
594{
595}
596
597void
598pass1_lastchance(struct interpass *ip)
599{
600}
601