xref: /netbsd/external/bsd/pcc/dist/pcc/arch/hppa/local.c (revision 6550d01e)
1 /*	$OpenBSD: local.c,v 1.2 2007/11/18 17:39:55 ragge Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Michael Shalayeff
5  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 #include "pass1.h"
33 #include "pass2.h"
34 
35 /*	this file contains code which is dependent on the target machine */
36 
37 #define	IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
38 
39 struct symtab *makememcpy(void);
40 char *section2string(char *, int);
41 
42 /* clocal() is called to do local transformations on
43  * an expression tree preparitory to its being
44  * written out in intermediate code.
45  *
46  * the major essential job is rewriting the
47  * automatic variables and arguments in terms of
48  * REG and OREG nodes
49  * conversion ops which are not necessary are also clobbered here
50  * in addition, any special features (such as rewriting
51  * exclusive or) are easily handled here as well
52  */
53 NODE *
54 clocal(NODE *p)
55 {
56 	register struct symtab *q, *sp;
57 	register NODE *r, *l, *s;
58 	register int o, m, rn;
59 	char *ch, name[16], *n;
60 	TWORD t;
61 
62 #ifdef PCC_DEBUG
63 	if (xdebug) {
64 		printf("clocal: %p\n", p);
65 		fwalk(p, eprint, 0);
66 	}
67 #endif
68 	switch (o = p->n_op) {
69 
70 	case NAME:
71 		if ((q = p->n_sp) == NULL)
72 			break;	/* Nothing to care about */
73 
74 		switch (q->sclass) {
75 
76 		case PARAM:
77 			/* first four integral args are in regs */
78 			rn = (q->soffset >> 5) - 8;
79 			if (rn < 4) {
80 				r = block(REG, NIL, NIL, p->n_type, 0, 0);
81 				r->n_lval = 0;
82 				switch (p->n_type) {
83 				case FLOAT:
84 					r->n_rval = FR7L - rn;
85 					break;
86 				case DOUBLE:
87 				case LDOUBLE:
88 					r->n_rval = FR6 - rn;
89 					break;
90 				case LONGLONG:
91 				case ULONGLONG:
92 					r->n_rval = AD1 - rn / 2;
93 					break;
94 				default:
95 					r->n_rval = ARG0 - rn;
96 				}
97 				r->n_sue = p->n_sue;
98 				p->n_sue = NULL;
99 				nfree(p);
100 				p = r;
101 				break;
102 			}
103 			/* FALLTHROUGH */
104 
105 		case AUTO:
106 			/* fake up a structure reference */
107 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
108 			r->n_lval = 0;
109 			r->n_rval = FPREG;
110 			p = stref(block(STREF, r, p, 0, 0, 0));
111 			break;
112 
113 		case REGISTER:
114 			p->n_op = REG;
115 			p->n_lval = 0;
116 			p->n_rval = q->soffset;
117 			break;
118 
119 		case STATIC:
120 		case EXTERN:
121 			if (p->n_sp->sflags & SSTRING)
122 				break;
123 
124 			n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
125 			if (strncmp(n, "__builtin", 9) == 0)
126 				break;
127 
128 			l = block(REG, NIL, NIL, INT, 0, 0);
129 			l->n_lval = 0;
130 			l->n_rval = R1;
131 			l = block(ASSIGN, l, p, INT, 0, 0);
132 			r = xbcon(0, p->n_sp, INT);
133 			p = block(UMUL,
134 			    block(PLUS, l, r, INT, 0, 0),
135 			    NIL, p->n_type, p->n_df, p->n_sue);
136 			break;
137 		}
138 		break;
139 
140 	case ADDROF:
141 		l = p->n_left;
142 		if (!l->n_sp)
143 			break;
144 
145 		if (l->n_sp->sclass != EXTERN &&
146 		    l->n_sp->sclass != STATIC &&
147 		    l->n_sp->sclass != USTATIC &&
148 		    l->n_sp->sclass != EXTDEF)
149 			break;
150 
151 		l = block(REG, NIL, NIL, INT, 0, 0);
152 		l->n_lval = 0;
153 		l->n_rval = R1;
154 		l = block(ASSIGN, l, p->n_left, INT, 0, 0);
155 		r = xbcon(0, p->n_left->n_sp, INT);
156 		l = block(PLUS, l, r, p->n_type, p->n_df, p->n_sue);
157 		nfree(p);
158 		p = l;
159 		break;
160 
161 	case CBRANCH:
162 		l = p->n_left;
163 
164 		/*
165 		 * Remove unnecessary conversion ops.
166 		 */
167 		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
168 			if (coptype(l->n_op) != BITYPE)
169 				break;
170 			if (l->n_right->n_op == ICON) {
171 				r = l->n_left->n_left;
172 				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
173 					break;
174 				/* Type must be correct */
175 				t = r->n_type;
176 				nfree(l->n_left);
177 				l->n_left = r;
178 				l->n_type = t;
179 				l->n_right->n_type = t;
180 			}
181 		}
182 		break;
183 
184 	case PCONV:
185 		/* Remove redundant PCONV's. Be careful */
186 		l = p->n_left;
187 		if (l->n_op == ICON) {
188 			l->n_lval = (unsigned)l->n_lval;
189 			goto delp;
190 		}
191 		if (l->n_type < INT || l->n_type == LONGLONG ||
192 		    l->n_type == ULONGLONG) {
193 			/* float etc? */
194 			p->n_left = block(SCONV, l, NIL,
195 			    UNSIGNED, 0, MKSUE(UNSIGNED));
196 			break;
197 		}
198 		/* if left is SCONV, cannot remove */
199 		if (l->n_op == SCONV)
200 			break;
201 
202 		/* avoid ADDROF TEMP */
203 		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
204 			break;
205 
206 		/* if conversion to another pointer type, just remove */
207 		if (p->n_type > BTMASK && l->n_type > BTMASK)
208 			goto delp;
209 		break;
210 
211 	delp:	l->n_type = p->n_type;
212 		l->n_qual = p->n_qual;
213 		l->n_df = p->n_df;
214 		l->n_sue = p->n_sue;
215 		nfree(p);
216 		p = l;
217 		break;
218 
219 	case SCONV:
220 		l = p->n_left;
221 
222 		if (p->n_type == l->n_type) {
223 			nfree(p);
224 			p = l;
225 			break;
226 		}
227 
228 		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
229 		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
230 			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
231 			    l->n_type != FLOAT && l->n_type != DOUBLE &&
232 			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
233 				if (l->n_op == UMUL || l->n_op == TEMP ||
234 				    l->n_op == NAME) {
235 					l->n_type = p->n_type;
236 					nfree(p);
237 					p = l;
238 					break;
239 				}
240 			}
241 		}
242 
243 		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
244 		    coptype(l->n_op) == BITYPE) {
245 			l->n_type = p->n_type;
246 			nfree(p);
247 			p = l;
248 			break;
249 		}
250 
251 		o = l->n_op;
252 		m = p->n_type;
253 
254 		if (o == ICON) {
255 			CONSZ val = l->n_lval;
256 
257 			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
258 			    switch (m) {
259 			case BOOL:
260 				l->n_lval = l->n_lval != 0;
261 				break;
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 = MKSUE(m);
301 			nfree(p);
302 			return l;
303                 } else if (l->n_op == FCON) {
304 			l->n_lval = l->n_dcon;
305 			l->n_sp = NULL;
306 			l->n_op = ICON;
307 			l->n_type = m;
308 			l->n_sue = MKSUE(m);
309 			nfree(p);
310 			return clocal(l);
311 		}
312 
313 		if (DEUNSIGN(p->n_type) == SHORT &&
314 		    DEUNSIGN(l->n_type) == SHORT) {
315 			nfree(p);
316 			p = l;
317 		}
318 		if ((p->n_type == CHAR || p->n_type == UCHAR ||
319 		    p->n_type == SHORT || p->n_type == USHORT) &&
320 		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
321 		    l->n_type == LDOUBLE)) {
322 			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
323 			p->n_left->n_type = INT;
324 			break;
325 		}
326 		break;
327 
328 	case MOD:
329 	case DIV:
330 		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
331 			break;
332 		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
333 			break;
334 		/* make it an int division by inserting conversions */
335 		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT));
336 		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT));
337 		p = block(SCONV, p, NIL, p->n_type, 0, MKSUE(p->n_type));
338 		p->n_left->n_type = INT;
339 		break;
340 
341 	case PMCONV:
342 	case PVCONV:
343                 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
344                 nfree(p);
345                 return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
346 
347 	case LS:
348 	case RS:
349 		/* shift count must be in an int */
350 		if (p->n_right->n_op == ICON || p->n_right->n_lval <= 32)
351 			break;	/* do not do anything */
352 		if (p->n_right->n_type != INT || p->n_right->n_lval > 32)
353 			p->n_right = block(SCONV, p->n_right, NIL,
354 			    INT, 0, MKSUE(INT));
355 		break;
356 
357 #if 0
358 	case FLD:
359 		/* already rewritten (in ASSIGN) */
360 		if (p->n_left->n_op == TEMP)
361 			break;
362 
363 		r = tempnode(0, p->n_type, p->n_df, p->n_sue);
364 		l = block(ASSIGN, r, p->n_left, p->n_type, p->n_df, p->n_sue);
365 		p->n_left = tcopy(r);
366 		p = block(COMOP, l, p, p->n_type, p->n_df, p->n_sue);
367 		break;
368 #endif
369 
370 	case FORCE:
371 		/* put return value in return reg */
372 		p->n_op = ASSIGN;
373 		p->n_right = p->n_left;
374 		p->n_left = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
375 		p->n_left->n_rval = p->n_left->n_type == BOOL ?
376 		    RETREG(CHAR) : RETREG(p->n_type);
377 		if (p->n_right->n_op != FLD)
378 			break;
379 		break;
380 
381 	case ASSIGN:
382 		r = p->n_right;
383 		l = p->n_left;
384 
385 		/* rewrite ICON#0 into %r0 */
386 		if (r->n_op == ICON && r->n_lval == 0 &&
387 		    (l->n_op == REG || l->n_op == OREG)) {
388 			r->n_op = REG;
389 			r->n_rval = R0;
390 		}
391 
392 		/* rewrite FCON#0 into %fr0 */
393 		if (r->n_op == FCON && r->n_lval == 0 && l->n_op == REG) {
394 			r->n_op = REG;
395 			r->n_rval = r->n_type == FLOAT? FR0L : FR0;
396 		}
397 
398 		if (p->n_left->n_op != FLD)
399 			break;
400 
401 		r = tempnode(0, l->n_type, l->n_df, l->n_sue);
402 		p = block(COMOP,
403 		    block(ASSIGN, r, l->n_left, l->n_type, l->n_df, l->n_sue),
404 		    p, p->n_type, p->n_df, p->n_sue);
405 		s = tcopy(l->n_left);
406 		p = block(COMOP, p,
407 		    block(ASSIGN, s, tcopy(r), l->n_type, l->n_df, l->n_sue),
408 		    p->n_type, p->n_df, p->n_sue);
409 		l->n_left = tcopy(r);
410 		break;
411 
412 	case STASG:
413 		/* memcpy(left, right, size) */
414 		sp = makememcpy();
415 		l = p->n_left;
416 		/* guess struct return */
417 		if (l->n_op == NAME && ISFTN(l->n_sp->stype)) {
418 			l = block(REG, NIL, NIL, VOID|PTR, 0, MKSUE(LONG));
419 			l->n_lval = 0;
420 			l->n_rval = RET0;
421 		} else if (l->n_op == UMUL)
422 			l = tcopy(l->n_left);
423 		else if (l->n_op == NAME)
424 			l = block(ADDROF,tcopy(l),NIL,PTR|STRTY,0,MKSUE(LONG));
425 		l = block(CALL, block(ADDROF,
426 		    (s = block(NAME, NIL, NIL, FTN, 0, MKSUE(LONG))),
427 		    NIL, PTR|FTN, 0, MKSUE(LONG)),
428 		    block(CM, block(CM, l, tcopy(p->n_right),
429 		    STRTY|PTR, 0, MKSUE(LONG)),
430 		    (r = block(ICON, NIL, NIL, INT, 0, MKSUE(LONG))), 0, 0, 0),
431 		    INT, 0, MKSUE(LONG));
432 		r->n_lval = p->n_sue->suesize/SZCHAR;
433 		s->n_sp = sp;
434 		s->n_df = s->n_sp->sdf;
435 		defid(s, EXTERN);
436 		tfree(p);
437 		p = l;
438 		p->n_left = clocal(p->n_left);
439 		p->n_right = clocal(p->n_right);
440 		calldec(p->n_left, p->n_right);
441 		funcode(p);
442 		break;
443 
444 	case STARG:
445 		/* arg = memcpy(argN-size, src, size) */
446 		sp = makememcpy();
447 		l = block(CALL, block(ADDROF,
448 		    (s = block(NAME, NIL, NIL, FTN, 0, MKSUE(LONG))),NIL,0,0,0),
449 		    block(CM, block(CM, tcopy(p), tcopy(p->n_left), 0, 0, 0),
450 		    (r = block(ICON, NIL, NIL, INT, 0, MKSUE(LONG))), 0, 0, 0),
451 		    INT, 0, MKSUE(LONG));
452 		r->n_lval = p->n_sue->suesize/SZCHAR;
453 		s->n_sp = sp;
454 		s->n_df = s->n_sp->sdf;
455 		defid(s, EXTERN);
456 		tfree(p);
457 		p = l;
458 		p->n_left = clocal(p->n_left);
459 		calldec(p->n_left, p->n_right);
460 		funcode(p);
461 		break;
462 
463 	case STCALL:
464 	case CALL:
465 		for (r = p->n_right; r->n_op == CM; r = r->n_left) {
466 			if (r->n_right->n_op == ASSIGN &&
467 			    r->n_right->n_right->n_op == CALL) {
468 				s = r->n_right->n_right;
469 				l = tempnode(0, s->n_type, s->n_df, s->n_sue);
470 				ecode(buildtree(ASSIGN, l, s));
471 				r->n_right->n_right = tcopy(l);
472 			}
473 			if (r->n_left->n_op == ASSIGN &&
474 			    r->n_left->n_right->n_op == CALL) {
475 				s = r->n_left->n_right;
476 				l = tempnode(0, s->n_type, s->n_df, s->n_sue);
477 				ecode(buildtree(ASSIGN, l, s));
478 				r->n_left->n_right = tcopy(l);
479 			}
480 		}
481 		break;
482 	}
483 
484 	/* second pass - rewrite long ops */
485 	switch (o) {
486 	case DIV:
487 	case MOD:
488 	case MUL:
489 	case RS:
490 	case LS:
491 		if (!(p->n_type == LONGLONG || p->n_type == ULONGLONG) ||
492 		    !((o == DIV || o == MOD || o == MUL) &&
493 		      p->n_type < FLOAT))
494 			break;
495 		if (o == DIV && p->n_type == ULONGLONG) ch = "udiv";
496 		else if (o == DIV) ch = "div";
497 		else if (o == MUL) ch = "mul";
498 		else if (o == MOD && p->n_type == ULONGLONG) ch = "umod";
499 		else if (o == MOD) ch = "mod";
500 		else if (o == RS && p->n_type == ULONGLONG) ch = "lshr";
501 		else if (o == RS) ch = "ashr";
502 		else if (o == LS) ch = "ashl";
503 		else break;
504 		snprintf(name, sizeof(name), "__%sdi3", ch);
505 		p->n_right = block(CM, p->n_left, p->n_right, 0, 0, 0);
506 		p->n_left = block(ADDROF,
507 		    block(NAME, NIL, NIL, FTN, 0, MKSUE(INT)), NIL,
508 		    PTR|FTN, 0, MKSUE(INT));
509 		p->n_left->n_left->n_sp = lookup(addname(name), 0);
510 		defid(p->n_left->n_left, EXTERN);
511 		p->n_left = clocal(p->n_left);
512 		calldec(p->n_left, p->n_right);
513 		p->n_op = CALL;
514 		funcode(p);
515 		break;
516 	}
517 
518 #ifdef PCC_DEBUG
519 	if (xdebug) {
520 		printf("clocal end: %p\n", p);
521 		fwalk(p, eprint, 0);
522 	}
523 #endif
524 	return(p);
525 }
526 
527 struct symtab *
528 makememcpy()
529 {
530 	NODE *memcpy, *args, *t, *u;
531 	struct symtab *sp;
532 
533 	/* TODO check that it's a func proto */
534 	if ((sp = lookup(addname("memcpy"), SNORMAL)))
535 		return sp;
536 
537 	memcpy = block(NAME, NIL, NIL, 0, 0, MKSUE(LONG));
538 	memcpy->n_sp = sp = lookup(addname("memcpy"), SNORMAL);
539 	defid(memcpy, EXTERN);
540 
541 	args = block(CM, block(CM,
542 	    block(NAME, NIL, NIL, VOID|PTR, 0, MKSUE(LONG)),
543 	    block(NAME, NIL, NIL, VOID|PTR, 0, MKSUE(LONG)), 0, 0, 0),
544 	    block(NAME, NIL, NIL, LONG, 0, MKSUE(LONG)), 0, 0, 0);
545 
546 	tymerge(t = block(TYPE, NIL, NIL, VOID|PTR, 0, 0),
547 	    (u = block(UMUL, block(CALL, memcpy, args, LONG, 0, 0),
548 	    NIL, LONG, 0, 0)));
549 	tfree(t);
550 	tfree(u);
551 
552 	return sp;
553 }
554 
555 void
556 myp2tree(NODE *p)
557 {
558 	struct symtab *sp;
559 	int o = p->n_op;
560 
561 	if (o != FCON)
562 		return;
563 
564 	/* Write float constants to memory */
565 	/* Should be volontary per architecture */
566 
567 #if 0
568 	setloc1(RDATA);
569 	defalign(p->n_type == FLOAT ? ALFLOAT : p->n_type == DOUBLE ?
570 	    ALDOUBLE : ALLDOUBLE );
571 	deflab1(i = getlab());
572 #endif
573 	sp = inlalloc(sizeof(struct symtab));
574 	sp->sclass = STATIC;
575 	sp->ssue = MKSUE(p->n_type);
576 	sp->slevel = 1; /* fake numeric label */
577 	sp->soffset = getlab();
578 	sp->sflags = 0;
579 	sp->stype = p->n_type;
580 	sp->squal = (CON >> TSHIFT);
581 
582 	defloc(sp);
583 	ninval(0, btdims[p->n_type].suesize, p);
584 
585 	p->n_op = NAME;
586 	p->n_lval = 0;
587 	p->n_sp = sp;
588 
589 }
590 
591 /*ARGSUSED*/
592 int
593 andable(NODE *p)
594 {
595 	return(1);  /* all names can have & taken on them */
596 }
597 
598 /*
599  * at the end of the arguments of a ftn, set the automatic offset
600  */
601 void
602 cendarg()
603 {
604 	/* TODO can use to generate sp/rp tree ops? */
605 	autooff = AUTOINIT;
606 }
607 
608 /*
609  * Return 1 if a variable of type "t" is OK to put in register.
610  */
611 int
612 cisreg(TWORD t)
613 {
614 	return 1;
615 }
616 
617 /*
618  * return a node, for structure references, which is suitable for
619  * being added to a pointer of type t, in order to be off bits offset
620  * into a structure
621  * t, d, and s are the type, dimension offset, and sizeoffset
622  * For pdp10, return the type-specific index number which calculation
623  * is based on its size. For example, short a[3] would return 3.
624  * Be careful about only handling first-level pointers, the following
625  * indirections must be fullword.
626  */
627 NODE *
628 offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
629 {
630 	register NODE *p;
631 
632 	if (xdebug)
633 		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
634 		    off, t, d, sue->suesize);
635 
636 	p = bcon(0);
637 	p->n_lval = off/SZCHAR;	/* Default */
638 	return(p);
639 }
640 
641 /*
642  * Allocate off bits on the stack.  p is a tree that when evaluated
643  * is the multiply count for off, t is a storeable node where to write
644  * the allocated address.
645  */
646 void
647 spalloc(NODE *t, NODE *p, OFFSZ off)
648 {
649 	NODE *sp;
650 
651 	p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
652 
653 	/* sub the size from sp */
654 	sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
655 	sp->n_lval = 0;
656 	sp->n_rval = STKREG;
657 	ecomp(buildtree(PLUSEQ, sp, p));
658 
659 	/* save the address of sp */
660 	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
661 	sp->n_lval = 0;
662 	sp->n_rval = STKREG;
663 	t->n_type = sp->n_type;
664 	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
665 
666 }
667 
668 #if 0
669 /*
670  * Print out an integer constant of size size.
671  * can only be sizes <= SZINT.
672  */
673 void
674 indata(CONSZ val, int size)
675 {
676 	switch (size) {
677 	case SZCHAR:
678 		printf("\t.byte %d\n", (int)val & 0xff);
679 		break;
680 	case SZSHORT:
681 		printf("\t.word %d\n", (int)val & 0xffff);
682 		break;
683 	case SZINT:
684 		printf("\t.long %d\n", (int)val & 0xffffffff);
685 		break;
686 	default:
687 		cerror("indata");
688 	}
689 }
690 #endif
691 
692 /*
693  * Print out a string of characters.
694  * Assume that the assembler understands C-style escape
695  * sequences.  Location is already set.
696  */
697 void
698 instring(struct symtab *sp)
699 {
700 	char *s, *str;
701 
702 	defloc(sp);
703 	str = sp->sname;
704 
705 	/* be kind to assemblers and avoid long strings */
706 	printf("\t.ascii\t\"");
707 	for (s = str; *s != 0; ) {
708 		if (*s++ == '\\') {
709 			(void)esccon(&s);
710 		}
711 		if (s - str > 64) {
712 			fwrite(str, 1, s - str, stdout);
713 			printf("\"\n\t.ascii\t\"");
714 			str = s;
715 		}
716 	}
717 	fwrite(str, 1, s - str, stdout);
718 	printf("\\0\"\n");
719 }
720 
721 static int inbits, inval;
722 
723 /*
724  * set fsz bits in sequence to zero.
725  */
726 void
727 zbits(OFFSZ off, int fsz)
728 {
729 	int m;
730 
731 	if (idebug)
732 		printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
733 	if ((m = (inbits % SZCHAR))) {
734 		m = SZCHAR - m;
735 		if (fsz < m) {
736 			inbits += fsz;
737 			return;
738 		} else {
739 			fsz -= m;
740 			printf("\t.byte %d\n", inval);
741 			inval = inbits = 0;
742 		}
743 	}
744 	if (fsz >= SZCHAR) {
745 		printf("\t.zero %d\n", fsz/SZCHAR);
746 		fsz -= (fsz/SZCHAR) * SZCHAR;
747 	}
748 	if (fsz) {
749 		inval = 0;
750 		inbits = fsz;
751 	}
752 }
753 
754 /*
755  * Initialize a bitfield.
756  */
757 void
758 infld(CONSZ off, int fsz, CONSZ val)
759 {
760 	if (idebug)
761 		printf("infld off %lld, fsz %d, val %lld inbits %d\n",
762 		    off, fsz, val, inbits);
763 	val &= (1 << fsz)-1;
764 	while (fsz + inbits >= SZCHAR) {
765 		inval |= (val << inbits);
766 		printf("\t.byte %d\n", inval & 255);
767 		fsz -= (SZCHAR - inbits);
768 		val >>= (SZCHAR - inbits);
769 		inval = inbits = 0;
770 	}
771 	if (fsz) {
772 		inval |= (val << inbits);
773 		inbits += fsz;
774 	}
775 }
776 
777 /*
778  * print out a constant node, may be associated with a label.
779  * Do not free the node after use.
780  * off is bit offset from the beginning of the aggregate
781  * fsz is the number of bits this is referring to
782  *
783  * XXX this relies on the host fp numbers representation
784  */
785 void
786 ninval(CONSZ off, int fsz, NODE *p)
787 {
788 	union { float f; double d; long double l; int i[3]; } u;
789 	struct symtab *q;
790 	TWORD t;
791 	int i;
792 
793 	t = p->n_type;
794 	if (t > BTMASK)
795 		t = INT; /* pointer */
796 
797 	if (p->n_op != ICON && p->n_op != FCON)
798 		cerror("ninval: init node not constant");
799 
800 	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
801 		uerror("element not constant");
802 
803 	switch (t) {
804 	case LONGLONG:
805 	case ULONGLONG:
806 		i = (p->n_lval >> 32);
807 		p->n_lval &= 0xffffffff;
808 		p->n_type = INT;
809 		ninval(off, 32, p);
810 		p->n_lval = i;
811 		ninval(off+32, 32, p);
812 		break;
813 	case INT:
814 	case UNSIGNED:
815 		printf("\t.long 0x%x", (int)p->n_lval);
816 		if ((q = p->n_sp) != NULL) {
817 			if ((q->sclass == STATIC && q->slevel > 0)) {
818 				printf("+" LABFMT, q->soffset);
819 			} else
820 				printf("+%s",
821 				    q->soname ? q->soname : exname(q->sname));
822 		}
823 		printf("\n");
824 		break;
825 	case SHORT:
826 	case USHORT:
827 		printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
828 		break;
829 	case BOOL:
830 		if (p->n_lval > 1)
831 			p->n_lval = p->n_lval != 0;
832 		/* FALLTHROUGH */
833 	case CHAR:
834 	case UCHAR:
835 		/* TODO make the upper layer give an .asciz */
836 		printf("\t.byte %d\n", (int)p->n_lval & 0xff);
837 		break;
838 	case LDOUBLE:
839 	case DOUBLE:
840 		u.d = (double)p->n_dcon;
841 		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
842 		break;
843 	case FLOAT:
844 		u.f = (float)p->n_dcon;
845 		printf("\t.long\t0x%x\n", u.i[0]);
846 		break;
847 	default:
848 		cerror("ninval");
849 	}
850 }
851 
852 /* make a name look like an external name in the local machine */
853 char *
854 exname(char *p)
855 {
856 	if (p == NULL)
857 		return "";
858 	return p;
859 }
860 
861 /*
862  * map types which are not defined on the local machine
863  */
864 TWORD
865 ctype(TWORD type)
866 {
867 	switch (BTYPE(type)) {
868 	case LONG:
869 		MODTYPE(type,INT);
870 		break;
871 
872 	case ULONG:
873 		MODTYPE(type,UNSIGNED);
874 	}
875 
876 	return (type);
877 }
878 
879 void
880 calldec(NODE *f, NODE *a)
881 {
882 	struct symtab *q;
883 	if (f->n_op == UMUL && f->n_left->n_op == PLUS &&
884 	    f->n_left->n_right->n_op == ICON)
885 		q = f->n_left->n_right->n_sp;
886 	else if (f->n_op == PLUS && f->n_right->n_op == ICON)
887 		q = f->n_right->n_sp;
888 	else {
889 		fwalk(f, eprint, 0);
890 		cerror("unknown function");
891 		return;
892 	}
893 
894 	printf("\t.import\t%s,code\n", q->soname ? q->soname : exname(q->sname));
895 }
896 
897 void
898 extdec(struct symtab *q)
899 {
900 	printf("\t.import\t%s,data\n", q->soname ? q->soname : exname(q->sname));
901 }
902 
903 /* make a common declaration for id, if reasonable */
904 void
905 defzero(struct symtab *sp)
906 {
907 	int off;
908 
909 	off = tsize(sp->stype, sp->sdf, sp->ssue);
910 	off = (off + (SZCHAR - 1)) / SZCHAR;
911 	printf("\t.%scomm\t", sp->sclass == STATIC ? "l" : "");
912 	if (sp->slevel == 0)
913 		printf("%s,0%o\n", sp->soname ? sp->soname : exname(sp->sname), off);
914 	else
915 		printf(LABFMT ",0%o\n", sp->soffset, off);
916 }
917 
918 char *
919 section2string(char *name, int len)
920 {
921 	char *s;
922 	int n;
923 
924 	if (strncmp(name, "link_set", 8) == 0) {
925 		const char *postfix = ",\"aw\",@progbits";
926 		n = len + strlen(postfix) + 1;
927 		s = IALLOC(n);
928 		strlcpy(s, name, n);
929 		strlcat(s, postfix, n);
930 		return s;
931 	}
932 
933 	return newstring(name, len);
934 }
935 
936 char *nextsect;
937 char *alias;
938 int constructor;
939 int destructor;
940 
941 #define	SSECTION	010000
942 
943 /*
944  * Give target the opportunity of handling pragmas.
945  */
946 int
947 mypragma(char **ary)
948 {
949 	if (strcmp(ary[1], "constructor") == 0 || strcmp(ary[1], "init") == 0) {
950 		constructor = 1;
951 		return 1;
952 	}
953 	if (strcmp(ary[1], "destructor") == 0 || strcmp(ary[1], "fini") == 0) {
954 		destructor = 1;
955 		return 1;
956 	}
957 	if (strcmp(ary[1], "section") == 0 && ary[2] != NULL) {
958 		nextsect = section2string(ary[2], strlen(ary[2]));
959 		return 1;
960 	}
961 	if (strcmp(ary[1], "alias") == 0 && ary[2] != NULL) {
962 		alias = tmpstrdup(ary[2]);
963 		return 1;
964 	}
965 	if (strcmp(ary[1], "ident") == 0)
966 		return 1; /* Just ignore */
967 	return 0;
968 }
969 
970 /*
971  * Called when a identifier has been declared, to give target last word.
972  */
973 void
974 fixdef(struct symtab *sp)
975 {
976 	if (alias != NULL && (sp->sclass != PARAM)) {
977 		printf("\t.globl %s\n%s = %s\n", exname(sp->soname),
978 		    exname(sp->soname), exname(alias));
979 		alias = NULL;
980 	}
981 	if ((constructor || destructor) && (sp->sclass != PARAM)) {
982 		printf("\t.section .%ctors,\"aw\",@progbits\n"
983 		    "\t.p2align 2\n\t.long %s\n\t.previous\n",
984 		    constructor ? 'c' : 'd', exname(sp->sname));
985 		constructor = destructor = 0;
986 	}
987 }
988 
989 void
990 pass1_lastchance(struct interpass *ip)
991 {
992 }
993