xref: /csrg-svn/old/pcc/ccom.vax/local.c (revision 32918)
1 #ifndef lint
2 static char *sccsid ="@(#)local.c	1.13 (Berkeley) 12/11/87";
3 #endif lint
4 
5 # include "pass1.h"
6 
7 /*	this file contains code which is dependent on the target machine */
8 
9 NODE *
10 clocal(p) register NODE *p; {
11 
12 	/* this is called to do local transformations on
13 	   an expression tree preparitory to its being
14 	   written out in intermediate code.
15 	*/
16 
17 	/* the major essential job is rewriting the
18 	   automatic variables and arguments in terms of
19 	   REG and OREG nodes */
20 	/* conversion ops which are not necessary are also clobbered here */
21 	/* in addition, any special features (such as rewriting
22 	   exclusive or) are easily handled here as well */
23 
24 	register struct symtab *q;
25 	register NODE *r;
26 	register int o;
27 	register int m, ml;
28 
29 	switch( o = p->in.op ){
30 
31 	case NAME:
32 		if( p->tn.rval < 0 ) { /* already processed; ignore... */
33 			return(p);
34 			}
35 		q = &stab[p->tn.rval];
36 		switch( q->sclass ){
37 
38 		case AUTO:
39 		case PARAM:
40 			/* fake up a structure reference */
41 			r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 );
42 			r->tn.lval = 0;
43 			r->tn.rval = (q->sclass==AUTO?STKREG:ARGREG);
44 			p = stref( block( STREF, r, p, 0, 0, 0 ) );
45 			break;
46 
47 		case ULABEL:
48 		case LABEL:
49 		case STATIC:
50 			if( q->slevel == 0 ) break;
51 			p->tn.lval = 0;
52 			p->tn.rval = -q->offset;
53 			break;
54 
55 		case REGISTER:
56 			p->in.op = REG;
57 			p->tn.lval = 0;
58 			p->tn.rval = q->offset;
59 			break;
60 
61 			}
62 		break;
63 
64 	case LT:
65 	case LE:
66 	case GT:
67 	case GE:
68 		if( ISPTR( p->in.left->in.type ) || ISPTR( p->in.right->in.type ) ){
69 			p->in.op += (ULT-LT);
70 			}
71 		break;
72 
73 	case PCONV:
74 		/* do pointer conversions for char and longs */
75 		ml = p->in.left->in.type;
76 		if( ( ml==CHAR || ml==UCHAR || ml==SHORT || ml==USHORT ) && p->in.left->in.op != ICON ) break;
77 
78 		/* pointers all have the same representation; the type is inherited */
79 
80 		p->in.left->in.type = p->in.type;
81 		p->in.left->fn.cdim = p->fn.cdim;
82 		p->in.left->fn.csiz = p->fn.csiz;
83 		p->in.op = FREE;
84 		return( p->in.left );
85 
86 	case SCONV:
87 		m = p->in.type;
88 		ml = p->in.left->in.type;
89 		if(m == ml)
90 			goto clobber;
91 		o = p->in.left->in.op;
92 		if(m == FLOAT || m == DOUBLE) {
93 			if(o==SCONV &&
94 			 ml == DOUBLE &&
95 			 p->in.left->in.left->in.type==m) {
96 				p->in.op = p->in.left->in.op = FREE;
97 				return(p->in.left->in.left);
98 				}
99 #ifndef SPRECC
100 			if(m == DOUBLE && ml == FLOAT)
101 				goto clobber;
102 #endif
103 			/* see makety() for constant conversions */
104 			break;
105 			}
106 		if(ml == FLOAT || ml == DOUBLE){
107 			if(o != FCON && o != DCON)
108 				break;
109 			ml = ISUNSIGNED(m) ? UNSIGNED : INT; /* LONG? */
110 			r = block( ICON, (NODE *)NULL, (NODE *)NULL, ml, 0, 0 );
111 			if( o == FCON )
112 				r->tn.lval = ml == INT ?
113 					(int) p->in.left->fpn.fval :
114 					(unsigned) p->in.left->fpn.fval;
115 			else
116 				r->tn.lval = ml == INT ?
117 					(int) p->in.left->dpn.dval :
118 					(unsigned) p->in.left->dpn.dval;
119 			r->tn.rval = NONAME;
120 			p->in.left->in.op = FREE;
121 			p->in.left = r;
122 			o = ICON;
123 			if( m == ml )
124 				goto clobber;
125 			}
126 		/* now, look for conversions downwards */
127 
128 		if( o == ICON ){ /* simulate the conversion here */
129 			CONSZ val;
130 			val = p->in.left->tn.lval;
131 			switch( m ){
132 			case CHAR:
133 				p->in.left->tn.lval = (char) val;
134 				break;
135 			case UCHAR:
136 				p->in.left->tn.lval = val & 0XFF;
137 				break;
138 			case USHORT:
139 				p->in.left->tn.lval = val & 0XFFFFL;
140 				break;
141 			case SHORT:
142 				p->in.left->tn.lval = (short)val;
143 				break;
144 			case UNSIGNED:
145 				p->in.left->tn.lval = val & 0xFFFFFFFFL;
146 				break;
147 			case INT:
148 				p->in.left->tn.lval = (int)val;
149 				break;
150 				}
151 			p->in.left->in.type = m;
152 			}
153 		else
154 			break;
155 
156 	clobber:
157 		p->in.op = FREE;
158 		return( p->in.left );  /* conversion gets clobbered */
159 
160 	case PVCONV:
161 	case PMCONV:
162 		if( p->in.right->in.op != ICON ) cerror( "bad conversion", 0);
163 		p->in.op = FREE;
164 		return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) );
165 
166 	case RS:
167 	case ASG RS:
168 		/* convert >> to << with negative shift count */
169 		/* only if type of left operand is not unsigned */
170 
171 		if( ISUNSIGNED(p->in.left->in.type) ) break;
172 		if( p->in.right->in.op != UNARY MINUS )
173 			p->in.right = buildtree( UNARY MINUS, p->in.right, NIL );
174 		else {
175 			r = p->in.right;
176 			p->in.right = p->in.right->in.left;
177 			r->in.op = FREE;
178 		}
179 		if( p->in.op == RS ) p->in.op = LS;
180 		else p->in.op = ASG LS;
181 		break;
182 
183 	case FLD:
184 		/* make sure that the second pass does not make the
185 		   descendant of a FLD operator into a doubly indexed OREG */
186 
187 		if( p->in.left->in.op == UNARY MUL
188 				&& (r=p->in.left->in.left)->in.op == PCONV)
189 			if( r->in.left->in.op == PLUS || r->in.left->in.op == MINUS )
190 				if( ISPTR(r->in.type) ) {
191 					if( ISUNSIGNED(p->in.left->in.type) )
192 						p->in.left->in.type = UNSIGNED;
193 					else
194 						p->in.left->in.type = INT;
195 				}
196 		break;
197 		}
198 
199 	return(p);
200 	}
201 
202 /*ARGSUSED*/
203 andable( p ) NODE *p; {
204 	return(1);  /* all names can have & taken on them */
205 	}
206 
207 cendarg(){ /* at the end of the arguments of a ftn, set the automatic offset */
208 	autooff = AUTOINIT;
209 	}
210 
211 cisreg( t ) TWORD t; { /* is an automatic variable of type t OK for a register variable */
212 
213 #ifdef TRUST_REG_CHAR_AND_REG_SHORT
214 	if( t==INT || t==UNSIGNED || t==LONG || t==ULONG	/* tbl */
215 		|| t==CHAR || t==UCHAR || t==SHORT 		/* tbl */
216 		|| t==USHORT || ISPTR(t)) return(1);		/* tbl */
217 #else
218 	if( t==INT || t==UNSIGNED || t==LONG || t==ULONG	/* wnj */
219 #ifdef SPRECC
220 		|| t==FLOAT
221 #endif
222 		|| ISPTR(t)) return (1);			/* wnj */
223 #endif
224 	return(0);
225 	}
226 
227 /*ARGSUSED*/
228 NODE *
229 offcon( off, t, d, s ) OFFSZ off; TWORD t; {
230 
231 	/* return a node, for structure references, which is suitable for
232 	   being added to a pointer of type t, in order to be off bits offset
233 	   into a structure */
234 
235 	register NODE *p;
236 
237 	/* t, d, and s are the type, dimension offset, and sizeoffset */
238 	/* in general they  are necessary for offcon, but not on VAX */
239 
240 	p = bcon(0);
241 	p->tn.lval = off/SZCHAR;
242 	return(p);
243 
244 	}
245 
246 
247 static inwd	/* current bit offsed in word */;
248 static CONSZ word	/* word being built from fields */;
249 
250 incode( p, sz ) register NODE *p; {
251 
252 	/* generate initialization code for assigning a constant c
253 		to a field of width sz */
254 	/* we assume that the proper alignment has been obtained */
255 	/* inoff is updated to have the proper final value */
256 	/* we also assume sz  < SZINT */
257 
258 	if(nerrors) return;
259 	if((sz+inwd) > SZINT) cerror("incode: field > int");
260 	word |= ((unsigned)(p->tn.lval<<(32-sz))) >> (32-sz-inwd);
261 	inwd += sz;
262 	inoff += sz;
263 	if(inoff%SZINT == 0) {
264 		printf( "	.long	0x%lx\n", word);
265 		word = inwd = 0;
266 		}
267 	}
268 
269 fincode( d, sz ) double d; {
270 	/* output code to initialize space of size sz to the value d */
271 	/* the proper alignment has been obtained */
272 	/* inoff is updated to have the proper final value */
273 	/* on the target machine, write it out in octal! */
274 
275 
276 	if (nerrors) return;
277 	printf("	%s	0%c%.20e\n", sz == SZDOUBLE ? ".double" : ".float",
278 		sz == SZDOUBLE ? 'd' : 'f', d);
279 	inoff += sz;
280 	}
281 
282 cinit( p, sz ) NODE *p; {
283 	NODE *l;
284 
285 	/*
286 	 * as a favor (?) to people who want to write
287 	 *     int i = 9600/134.5;
288 	 * we will, under the proper circumstances, do
289 	 * a coercion here.
290 	 */
291 	switch (p->in.type) {
292 	case INT:
293 	case UNSIGNED:
294 		l = p->in.left;
295 		if (l->in.op != SCONV ||
296 		    (l->in.left->tn.op != DCON && l->in.left->tn.op != FCON))
297 			break;
298 		l->in.op = FREE;
299 		l = l->in.left;
300 		l->tn.lval = l->tn.op == DCON ? (long)(l->dpn.dval) :
301 			(long)(l->fpn.fval);
302 		l->tn.rval = NONAME;
303 		l->tn.op = ICON;
304 		l->tn.type = INT;
305 		p->in.left = l;
306 		break;
307 	}
308 	/* arrange for the initialization of p into a space of size sz */
309 	/* the proper alignment has been opbtained */
310 	/* inoff is updated to have the proper final value */
311 	ecode( p );
312 	inoff += sz;
313 	}
314 
315 vfdzero( n ){ /* define n bits of zeros in a vfd */
316 
317 	if( n <= 0 ) return;
318 
319 	if (nerrors) return;
320 	inwd += n;
321 	inoff += n;
322 	if( inoff%ALINT ==0 ) {
323 		printf( "	.long	0x%lx\n", word );
324 		word = inwd = 0;
325 		}
326 	}
327 
328 char *
329 exname( p ) char *p; {
330 	/* make a name look like an external name in the local machine */
331 
332 #ifndef FLEXNAMES
333 	static char text[NCHNAM+1];
334 #else
335 	static char text[BUFSIZ+1];
336 #endif
337 
338 	register int i;
339 
340 	text[0] = '_';
341 #ifndef FLEXNAMES
342 	for( i=1; *p&&i<NCHNAM; ++i )
343 #else
344 	for( i=1; *p; ++i )
345 #endif
346 		text[i] = *p++;
347 
348 	text[i] = '\0';
349 #ifndef FLEXNAMES
350 	text[NCHNAM] = '\0';  /* truncate */
351 #endif
352 
353 	return( text );
354 	}
355 
356 ctype( type ) TWORD type;
357 	{ /* map types which are not defined on the local machine */
358 	switch( BTYPE(type) ){
359 
360 	case LONG:
361 		MODTYPE(type,INT);
362 		break;
363 
364 	case ULONG:
365 		MODTYPE(type,UNSIGNED);
366 		}
367 	return( type );
368 	}
369 
370 noinit() { /* curid is a variable which is defined but
371 	is not initialized (and not a function );
372 	This routine returns the stroage class for an uninitialized declaration */
373 
374 	return(EXTERN);
375 
376 	}
377 
378 commdec( id ){ /* make a common declaration for id, if reasonable */
379 	register struct symtab *q;
380 	OFFSZ off, tsize();
381 
382 	if (nerrors) return;
383 	q = &stab[id];
384 	printf( "	.comm	%s,", exname( q->sname ) );
385 	off = tsize( q->stype, q->dimoff, q->sizoff );
386 	printf( CONFMT, off/SZCHAR );
387 	putchar( '\n' );
388 	}
389 
390 prtdcon(p)
391 	register NODE *p;
392 {
393 	register int o = p->in.op;
394 	int i;
395 
396 	if (o != DCON && o != FCON)
397 		return;
398 	/*
399 	 * Clobber constants of value zero so
400 	 * we can generate more efficient code.
401 	 */
402 	if ((o == DCON && p->dpn.dval == 0) ||
403 	    (o == FCON && p->fpn.fval == 0)) {
404 		p->in.op = ICON;
405 		p->tn.rval = NONAME;
406 		return;
407 	}
408 	locctr(DATA);
409 	defalign(o == DCON ? ALDOUBLE : ALFLOAT);
410 	deflab(i = getlab());
411 	if (o == FCON)
412 		fincode(p->fpn.fval, SZFLOAT);
413 	else
414 		fincode(p->dpn.dval, SZDOUBLE);
415 	p->tn.lval = 0;
416 	p->tn.rval = -i;
417 	p->in.type = (o == DCON ? DOUBLE : FLOAT);
418 	p->in.op = NAME;
419 }
420 
421 isitfloat( s ) char *s; {
422 	union cvt {
423 		double	d;
424 		int	n[2];
425 	} cvt;
426 	double atof();
427 
428 	/* avoid floating point exception for double -> float conversions */
429 	dcon = cvt.d = atof(s);
430 	if( cvt.n[1] == 0 ){
431 		fcon = dcon;
432 		return( FCON );
433 		}
434 	return( DCON );
435 	}
436 
437 ecode( p ) NODE *p; {
438 
439 	/* walk the tree and write out the nodes.. */
440 
441 	if( nerrors ) return;
442 	p2tree( p );
443 	p2compile( p );
444 	}
445 
446 #ifndef ONEPASS
447 tlen(p) NODE *p;
448 {
449 	switch(p->in.type) {
450 		case CHAR:
451 		case UCHAR:
452 			return(1);
453 
454 		case SHORT:
455 		case USHORT:
456 			return(2);
457 
458 		case DOUBLE:
459 			return(8);
460 
461 		default:
462 			return(4);
463 		}
464 	}
465 #endif
466