1 /*      $Id: code.c,v 1.28 2014/04/19 07:47:51 ragge Exp $    */
2 /*
3  * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
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  *  Stuff for pass1.
32  */
33 
34 #include <assert.h>
35 
36 #include "pass1.h"
37 #include "pass2.h"
38 
39 static int rvnr;
40 
41 /*
42  * Print out assembler segment name.
43  */
44 void
setseg(int seg,char * name)45 setseg(int seg, char *name)
46 {
47 	switch (seg) {
48 	case PROG: name = ".text"; break;
49 	case DATA:
50 	case LDATA: name = ".data"; break;
51 	case UDATA: break;
52 	case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break;
53 	case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
54 	case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
55 	case STRNG:
56 	case RDATA: name = ".section .rodata"; break;
57 	case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
58 	case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
59 	case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
60 	case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
61 	case NMSEG:
62 		printf("\t.section %s,\"a%c\",@progbits\n", name,
63 		    cftnsp ? 'x' : 'w');
64 		return;
65 	}
66 	printf("\t%s\n", name);
67 }
68 
69 /*
70  * Define everything needed to print out some data (or text).
71  * This means segment, alignment, visibility, etc.
72  */
73 void
defloc(struct symtab * sp)74 defloc(struct symtab *sp)
75 {
76 	char *n;
77 
78 	n = sp->soname ? sp->soname : exname(sp->sname);
79 #ifdef USE_GAS
80 	if (ISFTN(t))
81 		printf("\t.type %s,%%function\n", n);
82 #endif
83 	if (sp->sclass == EXTDEF)
84 		printf("\t.global %s\n", n);
85 	if (sp->slevel == 0)
86 		printf("%s:\n", n);
87 	else
88 		printf(LABFMT ":\n", sp->soffset);
89 }
90 
91 /* Put a symbol in a temporary
92  * used by bfcode() and its helpers
93  */
94 static void
putintemp(struct symtab * sym)95 putintemp(struct symtab *sym)
96 {
97 	NODE *p;
98 
99 	p = tempnode(0, sym->stype, sym->sdf, sym->sap);
100 	p = buildtree(ASSIGN, p, nametree(sym));
101 	sym->soffset = regno(p->n_left);
102 	sym->sflags |= STNODE;
103 	ecomp(p);
104 }
105 
106 /* setup a 64-bit parameter (double/ldouble/longlong)
107  * used by bfcode() */
108 static void
param_64bit(struct symtab * sym,int * argofsp,int dotemps)109 param_64bit(struct symtab *sym, int *argofsp, int dotemps)
110 {
111 	int argofs = *argofsp;
112 	NODE *p, *q;
113 	int navail;
114 
115 #if ALLONGLONG == 64
116 	/* alignment */
117 	++argofs;
118 	argofs &= ~1;
119 	*argofsp = argofs;
120 #endif
121 
122 	navail = NARGREGS - argofs;
123 
124 	if (navail < 2) {
125 		/* half in and half out of the registers */
126 		if (features(FEATURE_BIGENDIAN)) {
127 			cerror("param_64bit");
128 			p = q = NULL;
129 		} else {
130 			q = block(REG, NIL, NIL, INT, 0, 0);
131 			regno(q) = R0 + argofs;
132 			if (dotemps) {
133 				q = block(SCONV, q, NIL,
134 				    ULONGLONG, 0, 0);
135 				p = nametree(sym);
136 				p->n_type = ULONGLONG;
137 				p->n_df = 0;
138 				p->n_ap = NULL;
139 				p = block(LS, p, bcon(32), ULONGLONG, 0, 0);
140 				q = block(PLUS, p, q, ULONGLONG, 0, 0);
141 				p = tempnode(0, ULONGLONG, 0, 0);
142 				sym->soffset = regno(p);
143 				sym->sflags |= STNODE;
144 			} else {
145 				p = nametree(sym);
146 				regno(p) = sym->soffset;
147 				p->n_type = INT;
148 				p->n_df = 0;
149 				p->n_ap = NULL;
150 			}
151 		}
152 		p = buildtree(ASSIGN, p, q);
153 		ecomp(p);
154 		*argofsp = argofs + 2;
155 		return;
156 	}
157 
158 	q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
159 	regno(q) = R0R1 + argofs;
160 	if (dotemps) {
161 		p = tempnode(0, sym->stype, sym->sdf, sym->sap);
162 		sym->soffset = regno(p);
163 		sym->sflags |= STNODE;
164 	} else {
165 		p = nametree(sym);
166 	}
167 	p = buildtree(ASSIGN, p, q);
168 	ecomp(p);
169 	*argofsp = argofs + 2;
170 }
171 
172 /* setup a 32-bit param on the stack
173  * used by bfcode() */
174 static void
param_32bit(struct symtab * sym,int * argofsp,int dotemps)175 param_32bit(struct symtab *sym, int *argofsp, int dotemps)
176 {
177 	NODE *p, *q;
178 
179 	q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
180 	regno(q) = R0 + (*argofsp)++;
181 	if (dotemps) {
182 		p = tempnode(0, sym->stype, sym->sdf, sym->sap);
183 		sym->soffset = regno(p);
184 		sym->sflags |= STNODE;
185 	} else {
186 		p = nametree(sym);
187 	}
188 	p = buildtree(ASSIGN, p, q);
189 	ecomp(p);
190 }
191 
192 /* setup a double param on the stack
193  * used by bfcode() */
194 static void
param_double(struct symtab * sym,int * argofsp,int dotemps)195 param_double(struct symtab *sym, int *argofsp, int dotemps)
196 {
197 	NODE *p, *q, *t;
198 	int tmpnr;
199 
200 	/*
201 	 * we have to dump the float from the general register
202 	 * into a temp, since the register allocator doesn't like
203 	 * floats to be in CLASSA.  This may not work for -xtemps.
204 	 */
205 
206 	t = tempnode(0, ULONGLONG, 0, 0);
207 	tmpnr = regno(t);
208 	q = block(REG, NIL, NIL, INT, 0, 0);
209 	q->n_rval = R0R1 + (*argofsp)++;
210 	p = buildtree(ASSIGN, t, q);
211 	ecomp(p);
212 
213 	if (dotemps) {
214 		sym->soffset = tmpnr;
215 		sym->sflags |= STNODE;
216 	} else {
217 		q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
218 		p = nametree(sym);
219 		p = buildtree(ASSIGN, p, q);
220 		ecomp(p);
221 	}
222 }
223 
224 /* setup a float param on the stack
225  * used by bfcode() */
226 static void
param_float(struct symtab * sym,int * argofsp,int dotemps)227 param_float(struct symtab *sym, int *argofsp, int dotemps)
228 {
229 	NODE *p, *q, *t;
230 	int tmpnr;
231 
232 	/*
233 	 * we have to dump the float from the general register
234 	 * into a temp, since the register allocator doesn't like
235 	 * floats to be in CLASSA.  This may not work for -xtemps.
236 	 */
237 
238 	t = tempnode(0, INT, 0, 0);
239 	tmpnr = regno(t);
240 	q = block(REG, NIL, NIL, INT, 0, 0);
241 	q->n_rval = R0 + (*argofsp)++;
242 	p = buildtree(ASSIGN, t, q);
243 	ecomp(p);
244 
245 	if (dotemps) {
246 		sym->soffset = tmpnr;
247 		sym->sflags |= STNODE;
248 	} else {
249 		q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
250 		p = nametree(sym);
251 		p = buildtree(ASSIGN, p, q);
252 		ecomp(p);
253 	}
254 }
255 
256 /* setup the hidden pointer to struct return parameter
257  * used by bfcode() */
258 static void
param_retstruct(void)259 param_retstruct(void)
260 {
261 	NODE *p, *q;
262 
263 	p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->sap);
264 	rvnr = regno(p);
265 	q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
266 	regno(q) = R0;
267 	p = buildtree(ASSIGN, p, q);
268 	ecomp(p);
269 }
270 
271 
272 /* setup struct parameter
273  * push the registers out to memory
274  * used by bfcode() */
275 static void
param_struct(struct symtab * sym,int * argofsp)276 param_struct(struct symtab *sym, int *argofsp)
277 {
278 	int argofs = *argofsp;
279 	NODE *p, *q;
280 	int navail;
281 	int sz;
282 	int off;
283 	int num;
284 	int i;
285 
286 	navail = NARGREGS - argofs;
287 	sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
288 	off = ARGINIT/SZINT + argofs;
289 	num = sz > navail ? navail : sz;
290 	for (i = 0; i < num; i++) {
291 		q = block(REG, NIL, NIL, INT, 0, 0);
292 		regno(q) = R0 + argofs++;
293 		p = block(REG, NIL, NIL, INT, 0, 0);
294 		regno(p) = SP;
295 		p = block(PLUS, p, bcon(4*off++), INT, 0, 0);
296 		p = block(UMUL, p, NIL, INT, 0, 0);
297 		p = buildtree(ASSIGN, p, q);
298 		ecomp(p);
299 	}
300 
301 	*argofsp = argofs;
302 }
303 
304 
305 /*
306  * Beginning-of-function code:
307  *
308  * 'sp' is an array of indices in symtab for the arguments
309  * 'cnt' is the number of arguments
310  */
311 void
bfcode(struct symtab ** sp,int cnt)312 bfcode(struct symtab **sp, int cnt)
313 {
314 	union arglist *usym;
315 	int saveallargs = 0;
316 	int i, argofs = 0;
317 
318 	/*
319 	 * Detect if this function has ellipses and save all
320 	 * argument registers onto stack.
321 	 */
322 	usym = cftnsp->sdf->dfun;
323 	while (usym && usym->type != TNULL) {
324 		if (usym->type == TELLIPSIS) {
325 			saveallargs = 1;
326 			break;
327 		}
328 		++usym;
329 	}
330 
331 	/* if returning a structure, move the hidden argument into a TEMP */
332 	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
333 		param_retstruct();
334 		++argofs;
335 	}
336 
337 	/* recalculate the arg offset and create TEMP moves */
338 	for (i = 0; i < cnt; i++) {
339 
340 		if (sp[i] == NULL)
341 			continue;
342 
343 		if ((argofs >= NARGREGS) && !xtemps)
344 			break;
345 
346 		if (argofs > NARGREGS) {
347 			putintemp(sp[i]);
348 		} else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
349 			param_struct(sp[i], &argofs);
350 		} else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
351 			param_64bit(sp[i], &argofs, xtemps && !saveallargs);
352 		} else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
353 			if (features(FEATURE_HARDFLOAT))
354 				param_double(sp[i], &argofs,
355 				    xtemps && !saveallargs);
356 			else
357 				param_64bit(sp[i], &argofs,
358 				    xtemps && !saveallargs);
359 		} else if (sp[i]->stype == FLOAT) {
360 			if (features(FEATURE_HARDFLOAT))
361 				param_float(sp[i], &argofs,
362 				    xtemps && !saveallargs);
363 			else
364 				param_32bit(sp[i], &argofs,
365 				    xtemps && !saveallargs);
366 		} else {
367 			param_32bit(sp[i], &argofs, xtemps && !saveallargs);
368 		}
369 	}
370 
371 	/* if saveallargs, save the rest of the args onto the stack */
372 	while (saveallargs && argofs < NARGREGS) {
373       		NODE *p, *q;
374 		int off = ARGINIT/SZINT + argofs;
375 		q = block(REG, NIL, NIL, INT, 0, 0);
376 		regno(q) = R0 + argofs++;
377 		p = block(REG, NIL, NIL, INT, 0, 0);
378 		regno(p) = FPREG;
379 		p = block(PLUS, p, bcon(4*off), INT, 0, 0);
380 		p = block(UMUL, p, NIL, INT, 0, 0);
381 		p = buildtree(ASSIGN, p, q);
382 		ecomp(p);
383 	}
384 
385 }
386 
387 /*
388  * End-of-Function code:
389  */
390 void
efcode(void)391 efcode(void)
392 {
393 	NODE *p, *q;
394 	int tempnr;
395 
396 	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
397 		return;
398 
399 	/*
400 	 * At this point, the address of the return structure on
401 	 * has been FORCEd to RETREG, which is R0.
402 	 * We want to copy the contents from there to the address
403 	 * we placed into the tempnode "rvnr".
404 	 */
405 
406 	/* move the pointer out of R0 to a tempnode */
407 	q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
408 	q->n_rval = R0;
409 	p = tempnode(0, PTR+STRTY, 0, cftnsp->sap);
410 	tempnr = regno(p);
411 	p = buildtree(ASSIGN, p, q);
412 	ecomp(p);
413 
414 	/* get the address from the tempnode */
415 	q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->sap);
416 	q = buildtree(UMUL, q, NIL);
417 
418 	/* now, get the structure destination */
419 	p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->sap);
420 	p = buildtree(UMUL, p, NIL);
421 
422 	/* struct assignment */
423 	p = buildtree(ASSIGN, p, q);
424 	ecomp(p);
425 }
426 
427 /*
428  * End-of-job: called just before final exit.
429  */
430 void
ejobcode(int flag)431 ejobcode(int flag)
432 {
433 	printf("\t.ident \"PCC: %s\"\n", VERSSTR);
434 }
435 
436 /*
437  * Beginning-of-job: called before compilation starts
438  *
439  * Initialise data structures specific for the local machine.
440  */
441 void
bjobcode(void)442 bjobcode(void)
443 {
444 }
445 
446 /*
447  * fix up type of field p
448  */
449 void
fldty(struct symtab * p)450 fldty(struct symtab *p)
451 {
452 }
453 
454 /*
455  * Build target-dependent switch tree/table.
456  *
457  * Return 1 if successfull, otherwise return 0 and the
458  * target-independent tree will be used.
459  */
460 int
mygenswitch(int num,TWORD type,struct swents ** p,int n)461 mygenswitch(int num, TWORD type, struct swents **p, int n)
462 {
463 	return 0;
464 }
465 
466 
467 /*
468  * Straighten a chain of CM ops so that the CM nodes
469  * only appear on the left node.
470  *
471  *	  CM	       CM
472  *	CM  CM	   CM  b
473  *       x y  a b	CM  a
474  *		      x  y
475  */
476 static NODE *
straighten(NODE * p)477 straighten(NODE *p)
478 {
479 	NODE *r = p->n_right;
480 
481 	if (p->n_op != CM || r->n_op != CM)
482 		return p;
483 
484 	p->n_right = r->n_left;
485 	r->n_left = p;
486 
487 	return r;
488 }
489 
490 static NODE *
reverse1(NODE * p,NODE * a)491 reverse1(NODE *p, NODE *a)
492 {
493 	NODE *l = p->n_left;
494 	NODE *r = p->n_right;
495 
496 	a->n_right = r;
497 	p->n_left = a;
498 
499 	if (l->n_op == CM) {
500 		return reverse1(l, p);
501 	} else {
502 		p->n_right = l;
503 		return p;
504 	}
505 }
506 
507 /*
508  * Reverse a chain of CM ops
509  */
510 static NODE *
reverse(NODE * p)511 reverse(NODE *p)
512 {
513 	NODE *l = p->n_left;
514 	NODE *r = p->n_right;
515 
516 	p->n_left = r;
517 
518 	if (l->n_op == CM)
519 		return reverse1(l, p);
520 
521 	p->n_right = l;
522 
523 	return p;
524 }
525 
526 
527 /* push arg onto the stack */
528 /* called by moveargs() */
529 static NODE *
pusharg(NODE * p,int * regp)530 pusharg(NODE *p, int *regp)
531 {
532 	NODE *q;
533 	int sz;
534 
535 	/* convert to register size, if smaller */
536 	sz = tsize(p->n_type, p->n_df, p->n_ap);
537 	if (sz < SZINT)
538 		p = block(SCONV, p, NIL, INT, 0, 0);
539 
540 	q = block(REG, NIL, NIL, INT, 0, 0);
541 	regno(q) = SP;
542 
543 	if (szty(p->n_type) == 1) {
544 		++(*regp);
545 		q = block(MINUSEQ, q, bcon(4), INT, 0, 0);
546 	} else {
547 		(*regp) += 2;
548 		q = block(MINUSEQ, q, bcon(8), INT, 0, 0);
549 	}
550 
551 	q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap);
552 
553 	return buildtree(ASSIGN, q, p);
554 }
555 
556 /* setup call stack with 32-bit argument */
557 /* called from moveargs() */
558 static NODE *
movearg_32bit(NODE * p,int * regp)559 movearg_32bit(NODE *p, int *regp)
560 {
561 	int reg = *regp;
562 	NODE *q;
563 
564 	q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
565 	regno(q) = reg++;
566 	q = buildtree(ASSIGN, q, p);
567 
568 	*regp = reg;
569 	return q;
570 }
571 
572 /* setup call stack with 64-bit argument */
573 /* called from moveargs() */
574 static NODE *
movearg_64bit(NODE * p,int * regp)575 movearg_64bit(NODE *p, int *regp)
576 {
577 	int reg = *regp;
578 	NODE *q, *r;
579 
580 #if ALLONGLONG == 64
581 	/* alignment */
582 	++reg;
583 	reg &= ~1;
584 	*regp = reg;
585 #endif
586 
587 	if (reg > R3) {
588 		q = pusharg(p, regp);
589 	} else if (reg == R3) {
590 		/* half in and half out of the registers */
591 		r = tcopy(p);
592 		if (!features(FEATURE_BIGENDIAN)) {
593 			q = block(SCONV, p, NIL, INT, 0, 0);
594 			q = movearg_32bit(q, regp);     /* little-endian */
595 			r = buildtree(RS, r, bcon(32));
596 			r = block(SCONV, r, NIL, INT, 0, 0);
597 			r = pusharg(r, regp); /* little-endian */
598 		} else {
599 			q = buildtree(RS, p, bcon(32));
600 			q = block(SCONV, q, NIL, INT, 0, 0);
601 			q = movearg_32bit(q, regp);     /* big-endian */
602 			r = block(SCONV, r, NIL, INT, 0, 0);
603 			r = pusharg(r, regp); /* big-endian */
604 		}
605 		q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap));
606 	} else {
607 		q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
608 		regno(q) = R0R1 + (reg - R0);
609 		q = buildtree(ASSIGN, q, p);
610 		*regp = reg + 2;
611 	}
612 
613 	return q;
614 }
615 
616 /* setup call stack with float/double argument */
617 /* called from moveargs() */
618 static NODE *
movearg_float(NODE * p,int * regp)619 movearg_float(NODE *p, int *regp)
620 {
621 	NODE *q, *r;
622 	TWORD ty = INCREF(p->n_type);
623 	int tmpnr;
624 
625 	/*
626 	 * Floats are passed in the general registers for
627 	 * compatibily with libraries compiled to handle soft-float.
628 	 */
629 
630 	if (xtemps) {
631 		/* bounce on TOS */
632 		r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
633 		regno(r) = SP;
634 		r = block(PLUS, r, bcon(-4), ty, p->n_df, p->n_ap);
635 		r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
636 		r = buildtree(ASSIGN, r, p);
637 		ecomp(r);
638 
639 		/* bounce into temp */
640 		r = block(REG, NIL, NIL, PTR+INT, 0, 0);
641 		regno(r) = SP;
642 		r = block(PLUS, r, bcon(-8), PTR+INT, 0, 0);
643 		r = block(UMUL, r, NIL, INT, 0, 0);
644 		q = tempnode(0, INT, 0, 0);
645 		tmpnr = regno(q);
646 		r = buildtree(ASSIGN, q, r);
647 		ecomp(r);
648 	} else {
649 		/* copy directly into temp */
650 		q = tempnode(0, p->n_type, p->n_df, p->n_ap);
651 		tmpnr = regno(q);
652 		r = buildtree(ASSIGN, q, p);
653 		ecomp(r);
654 	}
655 
656 	/* copy from temp to register parameter */
657 	r = tempnode(tmpnr, INT, 0, 0);
658 	q = block(REG, NIL, NIL, INT, 0, 0);
659 	regno(q) = (*regp)++;
660 	p = buildtree(ASSIGN, q, r);
661 
662 	return p;
663 }
664 
665 /* setup call stack with float/double argument */
666 /* called from moveargs() */
667 static NODE *
movearg_double(NODE * p,int * regp)668 movearg_double(NODE *p, int *regp)
669 {
670 	NODE *q, *r;
671 	TWORD ty = INCREF(p->n_type);
672 	int tmpnr;
673 
674 	if (xtemps) {
675 		/* bounce on TOS */
676 		r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
677 		regno(r) = SP;
678 		r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap);
679 		r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
680 		r = buildtree(ASSIGN, r, p);
681 		ecomp(r);
682 
683 		/* bounce into temp */
684 		r = block(REG, NIL, NIL, PTR+LONGLONG, 0, 0);
685 		regno(r) = SP;
686 		r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, 0);
687 		r = block(UMUL, r, NIL, LONGLONG, 0, 0);
688 		q = tempnode(0, LONGLONG, 0, 0);
689 		tmpnr = regno(q);
690 		r = buildtree(ASSIGN, q, r);
691 		ecomp(r);
692 	} else {
693 		/* copy directly into temp */
694 		q = tempnode(0, p->n_type, p->n_df, p->n_ap);
695 		tmpnr = regno(q);
696 		r = buildtree(ASSIGN, q, p);
697 		ecomp(r);
698 	}
699 
700 	/* copy from temp to register parameter */
701 	r = tempnode(tmpnr, LONGLONG, 0, 0);
702 	q = block(REG, NIL, NIL, LONGLONG, 0, 0);
703 	regno(q) = R0R1 - R0 + (*regp);
704 	p = buildtree(ASSIGN, q, r);
705 
706 	(*regp) += 2;
707 
708 	return p;
709 }
710 
711 
712 /* setup call stack with a structure */
713 /* called from moveargs() */
714 static NODE *
movearg_struct(NODE * p,int * regp)715 movearg_struct(NODE *p, int *regp)
716 {
717 	int reg = *regp;
718 	NODE *l, *q, *t, *r;
719 	int tmpnr;
720 	int navail;
721 	int num;
722 	int sz;
723 	int ty;
724 	int i;
725 
726 	assert(p->n_op == STARG);
727 
728 	navail = NARGREGS - (reg - R0);
729 	navail = navail < 0 ? 0 : navail;
730 	sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
731 	num = sz > navail ? navail : sz;
732 
733 	/* remove STARG node */
734 	l = p->n_left;
735 	nfree(p);
736 	ty = l->n_type;
737 
738 	/*
739 	 * put it into a TEMP, rather than tcopy(), since the tree
740 	 * in p may have side-affects
741 	 */
742 	t = tempnode(0, ty, l->n_df, l->n_ap);
743 	tmpnr = regno(t);
744 	q = buildtree(ASSIGN, t, l);
745 
746 	/* copy structure into registers */
747 	for (i = 0; i < num; i++) {
748 		t = tempnode(tmpnr, ty, 0, 0);
749 		t = block(SCONV, t, NIL, PTR+INT, 0, 0);
750 		t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0);
751 		t = buildtree(UMUL, t, NIL);
752 
753 		r = block(REG, NIL, NIL, INT, 0, 0);
754 		regno(r) = reg++;
755 		r = buildtree(ASSIGN, r, t);
756 
757 		q = block(CM, q, r, INT, 0, 0);
758 	}
759 
760 	/* put the rest of the structure on the stack */
761 	for (i = num; i < sz; i++) {
762 		t = tempnode(tmpnr, ty, 0, 0);
763 		t = block(SCONV, t, NIL, PTR+INT, 0, 0);
764 		t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0);
765 		t = buildtree(UMUL, t, NIL);
766 		r = pusharg(t, &reg);
767 		q = block(CM, q, r, INT, 0, 0);
768 	}
769 
770 	q = reverse(q);
771 
772 	*regp = reg;
773 	return q;
774 }
775 
776 
777 static NODE *
moveargs(NODE * p,int * regp)778 moveargs(NODE *p, int *regp)
779 {
780 	NODE *r, **rp;
781 	int reg;
782 
783 	if (p->n_op == CM) {
784 		p->n_left = moveargs(p->n_left, regp);
785 		r = p->n_right;
786 		rp = &p->n_right;
787 	} else {
788 		r = p;
789 		rp = &p;
790 	}
791 
792 	reg = *regp;
793 
794 	if (reg > R3 && r->n_op != STARG) {
795 		*rp = pusharg(r, regp);
796 	} else if (r->n_op == STARG) {
797 		*rp = movearg_struct(r, regp);
798 	} else if (DEUNSIGN(r->n_type) == LONGLONG) {
799 		*rp = movearg_64bit(r, regp);
800 	} else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
801 		*rp = movearg_double(r, regp);
802 	} else if (r->n_type == FLOAT) {
803 		*rp = movearg_float(r, regp);
804 	} else {
805 		*rp = movearg_32bit(r, regp);
806 	}
807 
808 	return straighten(p);
809 }
810 
811 /*
812  * Fixup arguments to pass pointer-to-struct as first argument.
813  *
814  * called from funcode().
815  */
816 static NODE *
retstruct(NODE * p)817 retstruct(NODE *p)
818 {
819 	NODE *l, *r, *t, *q;
820 	TWORD ty;
821 
822 	l = p->n_left;
823 	r = p->n_right;
824 
825 	ty = DECREF(l->n_type) - FTN;
826 
827 //      assert(tsize(ty, l->n_df, l->n_ap) == SZINT);
828 
829 	/* structure assign */
830 	q = tempnode(0, ty, l->n_df, l->n_ap);
831 	q = buildtree(ADDROF, q, NIL);
832 
833 	/* insert hidden assignment at beginning of list */
834 	if (r->n_op != CM) {
835 		p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap);
836 	} else {
837 		for (t = r; t->n_left->n_op == CM; t = t->n_left)
838 			;
839 		t->n_left = block(CM, q, t->n_left, INCREF(ty),
840 			    l->n_df, l->n_ap);
841 	}
842 
843 	return p;
844 }
845 
846 /*
847  * Called with a function call with arguments as argument.
848  * This is done early in buildtree() and only done once.
849  */
850 NODE *
funcode(NODE * p)851 funcode(NODE *p)
852 {
853 	int reg = R0;
854 
855 	if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) {
856 		p = retstruct(p);
857 		reg = R1;
858 	}
859 
860 	p->n_right = moveargs(p->n_right, &reg);
861 
862 	if (p->n_right == NULL)
863 		p->n_op += (UCALL - CALL);
864 
865 	return p;
866 }
867