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, ®);
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, ®);
861
862 if (p->n_right == NULL)
863 p->n_op += (UCALL - CALL);
864
865 return p;
866 }
867