source: mainline/uspace/app/pcc/arch/arm/code.c@ b670523

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b670523 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 15 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

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