source: mainline/uspace/app/pcc/arch/powerpc/code.c@ a7de7182

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

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

  • Property mode set to 100644
File size: 36.2 KB
Line 
1/* $Id: code.c,v 1.23 2010/11/26 17:06:31 ragge Exp $ */
2/*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <assert.h>
30#include <stdlib.h>
31
32#include "pass1.h"
33#include "pass2.h"
34
35static void genswitch_bintree(int num, TWORD ty, struct swents **p, int n);
36
37#if 0
38static void genswitch_table(int num, struct swents **p, int n);
39static void genswitch_mrst(int num, struct swents **p, int n);
40#endif
41
42int lastloc = -1;
43static int rvnr;
44
45/*
46 * Define everything needed to print out some data (or text).
47 * This means segment, alignment, visibility, etc.
48 */
49void
50defloc(struct symtab *sp)
51{
52#if defined(ELFABI)
53 static char *loctbl[] = { "text", "data", "rodata" };
54#elif defined(MACHOABI)
55 static char *loctbl[] = { "text", "data", "const_data" };
56#endif
57 TWORD t;
58 char *name;
59 int s, n;
60
61 if (sp == NULL) {
62 lastloc = -1;
63 return;
64 }
65 t = sp->stype;
66 s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
67 if (s != lastloc)
68 printf(" .%s\n", loctbl[s]);
69 lastloc = s;
70
71 if (s == PROG)
72 n = 2;
73 else if ((n = ispow2(talign(t, sp->sap) / SZCHAR)) == -1)
74 cerror("defalign: n != 2^i");
75 printf(" .p2align %d\n", n);
76
77 name = sp->soname ? sp->soname : exname(sp->sname);
78 if (sp->sclass == EXTDEF)
79 printf(" .globl %s\n", name);
80 if (sp->slevel == 0)
81 printf("%s:\n", name);
82 else
83 printf(LABFMT ":\n", sp->soffset);
84}
85
86/* Put a symbol in a temporary
87 * used by bfcode() and its helpers
88 */
89static void
90putintemp(struct symtab *sym)
91{
92 NODE *p;
93
94 p = tempnode(0, sym->stype, sym->sdf, sym->sap);
95 p = buildtree(ASSIGN, p, nametree(sym));
96 sym->soffset = regno(p->n_left);
97 sym->sflags |= STNODE;
98 ecomp(p);
99}
100
101/* setup a 64-bit parameter (double/ldouble/longlong)
102 * used by bfcode() */
103static void
104param_64bit(struct symtab *sym, int *argofsp, int dotemps)
105{
106 int argofs = *argofsp;
107 NODE *p, *q;
108 int navail;
109
110#if ALLONGLONG == 64
111 /* alignment */
112 ++argofs;
113 argofs &= ~1;
114#endif
115
116 navail = NARGREGS - argofs;
117
118 if (navail < 2) {
119 /* half in and half out of the registers */
120 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
121 regno(q) = R3 + argofs;
122 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
123 regno(p) = FPREG;
124 p = block(PLUS, p, bcon(sym->soffset/SZCHAR), PTR+INT, 0, MKAP(INT));
125 p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
126 } else {
127 q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
128 regno(q) = R3R4 + argofs;
129 if (dotemps) {
130 p = tempnode(0, sym->stype, sym->sdf, sym->sap);
131 sym->soffset = regno(p);
132 sym->sflags |= STNODE;
133 } else {
134 p = nametree(sym);
135 }
136 }
137 p = buildtree(ASSIGN, p, q);
138 ecomp(p);
139 *argofsp = argofs + 2;
140}
141
142/* setup a 32-bit param on the stack
143 * used by bfcode() */
144static void
145param_32bit(struct symtab *sym, int *argofsp, int dotemps)
146{
147 NODE *p, *q;
148
149 q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
150 regno(q) = R3 + (*argofsp)++;
151 if (dotemps) {
152 p = tempnode(0, sym->stype, sym->sdf, sym->sap);
153 sym->soffset = regno(p);
154 sym->sflags |= STNODE;
155 } else {
156 p = nametree(sym);
157 }
158 p = buildtree(ASSIGN, p, q);
159 ecomp(p);
160}
161
162/* setup a double param on the stack
163 * used by bfcode() */
164static void
165param_double(struct symtab *sym, int *argofsp, int dotemps)
166{
167 NODE *p, *q, *t;
168 int tmpnr;
169
170 /*
171 * we have to dump the double from the general register
172 * into a temp, since the register allocator doesn't like
173 * floats to be in CLASSA. This may not work for -xtemps.
174 */
175
176 if (xtemps) {
177 q = block(REG, NIL, NIL, ULONGLONG, 0, MKAP(ULONGLONG));
178 regno(q) = R3R4 + *argofsp;
179 p = block(REG, NIL, NIL, PTR+ULONGLONG, 0, MKAP(ULONGLONG));
180 regno(p) = SPREG;
181 p = block(PLUS, p, bcon(-8), INT, 0, MKAP(INT));
182 p = block(UMUL, p, NIL, ULONGLONG, 0, MKAP(ULONGLONG));
183 p = buildtree(ASSIGN, p, q);
184 ecomp(p);
185
186 t = tempnode(0, sym->stype, sym->sdf, sym->sap);
187 tmpnr = regno(t);
188 p = block(REG, NIL, NIL,
189 INCREF(sym->stype), sym->sdf, sym->sap);
190 regno(p) = SPREG;
191 p = block(PLUS, p, bcon(-8), INT, 0, MKAP(INT));
192 p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap);
193 p = buildtree(ASSIGN, t, p);
194 ecomp(p);
195 } else {
196 /* bounce straight into temp */
197 p = block(REG, NIL, NIL, ULONGLONG, 0, MKAP(ULONGLONG));
198 regno(p) = R3R4 + *argofsp;
199 t = tempnode(0, ULONGLONG, 0, MKAP(ULONGLONG));
200 tmpnr = regno(t);
201 p = buildtree(ASSIGN, t, p);
202 ecomp(p);
203 }
204
205 (*argofsp) += 2;
206
207 sym->soffset = tmpnr;
208 sym->sflags |= STNODE;
209}
210
211/* setup a float param on the stack
212 * used by bfcode() */
213static void
214param_float(struct symtab *sym, int *argofsp, int dotemps)
215{
216 NODE *p, *q, *t;
217 int tmpnr;
218
219 /*
220 * we have to dump the float from the general register
221 * into a temp, since the register allocator doesn't like
222 * floats to be in CLASSA. This may not work for -xtemps.
223 */
224
225 if (xtemps) {
226 /* bounce onto TOS */
227 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
228 regno(q) = R3 + (*argofsp);
229 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
230 regno(p) = SPREG;
231 p = block(PLUS, p, bcon(-4), INT, 0, MKAP(INT));
232 p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
233 p = buildtree(ASSIGN, p, q);
234 ecomp(p);
235
236 t = tempnode(0, sym->stype, sym->sdf, sym->sap);
237 tmpnr = regno(t);
238 p = block(REG, NIL, NIL, INCREF(sym->stype),
239 sym->sdf, sym->sap);
240 regno(p) = SPREG;
241 p = block(PLUS, p, bcon(-4), INT, 0, MKAP(INT));
242 p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap);
243 p = buildtree(ASSIGN, t, p);
244 ecomp(p);
245 } else {
246 /* bounce straight into temp */
247 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
248 regno(p) = R3 + (*argofsp);
249 t = tempnode(0, INT, 0, MKAP(INT));
250 tmpnr = regno(t);
251 p = buildtree(ASSIGN, t, p);
252 ecomp(p);
253 }
254
255 (*argofsp)++;
256
257 sym->soffset = tmpnr;
258 sym->sflags |= STNODE;
259}
260
261/* setup the hidden pointer to struct return parameter
262 * used by bfcode() */
263static void
264param_retstruct(void)
265{
266 NODE *p, *q;
267
268 p = tempnode(0, INCREF(cftnsp->stype), 0, cftnsp->sap);
269 rvnr = regno(p);
270 q = block(REG, NIL, NIL, INCREF(cftnsp->stype),
271 cftnsp->sdf, cftnsp->sap);
272 regno(q) = R3;
273 p = buildtree(ASSIGN, p, q);
274 ecomp(p);
275}
276
277
278/* setup struct parameter
279 * push the registers out to memory
280 * used by bfcode() */
281static void
282param_struct(struct symtab *sym, int *argofsp)
283{
284 int argofs = *argofsp;
285 NODE *p, *q;
286 int navail;
287 int sz;
288 int off;
289 int num;
290 int i;
291
292 navail = NARGREGS - argofs;
293 sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
294 off = ARGINIT/SZINT + argofs;
295 num = sz > navail ? navail : sz;
296 for (i = 0; i < num; i++) {
297 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
298 regno(q) = R3 + argofs++;
299 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
300 regno(p) = SPREG;
301 p = block(PLUS, p, bcon(4*off++), INT, 0, MKAP(INT));
302 p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
303 p = buildtree(ASSIGN, p, q);
304 ecomp(p);
305 }
306
307 *argofsp = argofs;
308}
309
310/*
311 * code for the beginning of a function
312 * sp is an array of indices in symtab for the arguments
313 * cnt is the number of arguments
314 */
315void
316bfcode(struct symtab **sp, int cnt)
317{
318#ifdef USE_GOTNR
319 extern int gotnr;
320#endif
321
322 struct symtab *sp2;
323 union arglist *usym;
324 int saveallargs = 0;
325 int i, argofs = 0;
326
327 /*
328 * Detect if this function has ellipses and save all
329 * argument registers onto stack.
330 */
331 usym = cftnsp->sdf->dfun;
332 while (usym && usym->type != TNULL) {
333 if (usym->type == TELLIPSIS) {
334 saveallargs = 1;
335 break;
336 }
337 ++usym;
338 }
339
340 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
341 param_retstruct();
342 ++argofs;
343 }
344
345#ifdef USE_GOTNR
346 if (kflag) {
347 /* put GOT register into temporary */
348 NODE *q, *p;
349 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
350 regno(q) = GOTREG;
351 p = tempnode(0, INT, 0, MKAP(INT));
352 gotnr = regno(p);
353 ecomp(buildtree(ASSIGN, p, q));
354 }
355#endif
356
357 /* recalculate the arg offset and create TEMP moves */
358 for (i = 0; i < cnt; i++) {
359
360 if (sp[i] == NULL)
361 continue;
362
363 if ((argofs >= NARGREGS) && !xtemps)
364 break;
365
366 if (argofs >= NARGREGS) {
367 putintemp(sp[i]);
368 } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
369 param_struct(sp[i], &argofs);
370 } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
371 param_64bit(sp[i], &argofs, xtemps && !saveallargs);
372 } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
373 if (features(FEATURE_HARDFLOAT))
374 param_double(sp[i], &argofs,
375 xtemps && !saveallargs);
376 else
377 param_64bit(sp[i], &argofs,
378 xtemps && !saveallargs);
379 } else if (sp[i]->stype == FLOAT) {
380 if (features(FEATURE_HARDFLOAT))
381 param_float(sp[i], &argofs,
382 xtemps && !saveallargs);
383 else
384 param_32bit(sp[i], &argofs,
385 xtemps && !saveallargs);
386 } else {
387 param_32bit(sp[i], &argofs, xtemps && !saveallargs);
388 }
389 }
390
391 /* if saveallargs, save the rest of the args onto the stack */
392 while (saveallargs && argofs < NARGREGS) {
393 NODE *p, *q;
394 /* int off = (ARGINIT+FIXEDSTACKSIZE*SZCHAR)/SZINT + argofs; */
395 int off = ARGINIT/SZINT + argofs;
396 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
397 regno(q) = R3 + argofs++;
398 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
399 regno(p) = FPREG;
400 p = block(PLUS, p, bcon(4*off), INT, 0, MKAP(INT));
401 p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
402 p = buildtree(ASSIGN, p, q);
403 ecomp(p);
404 }
405
406 /* profiling */
407 if (pflag) {
408 NODE *p;
409
410#if defined(ELFABI)
411
412 sp2 = lookup("_mcount", 0);
413 sp2->stype = EXTERN;
414 p = nametree(sp2);
415 p->n_sp->sclass = EXTERN;
416 p = clocal(p);
417 p = buildtree(ADDROF, p, NIL);
418 p = block(UCALL, p, NIL, INT, 0, MKAP(INT));
419 ecomp(funcode(p));
420
421
422#elif defined(MACHOABI)
423
424 NODE *q;
425 int tmpnr;
426
427 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
428 regno(q) = R0;
429 p = tempnode(0, INT, 0, MKAP(INT));
430 tmpnr = regno(p);
431 p = buildtree(ASSIGN, p, q);
432 ecomp(p);
433
434 q = tempnode(tmpnr, INT, 0, MKAP(INT));
435
436 sp2 = lookup("mcount", 0);
437 sp2->stype = EXTERN;
438 p = nametree(sp2);
439 p->n_sp->sclass = EXTERN;
440 p = clocal(p);
441 p = buildtree(ADDROF, p, NIL);
442 p = block(CALL, p, q, INT, 0, MKAP(INT));
443 ecomp(funcode(p));
444
445#endif
446 }
447}
448
449/*
450 * code for the end of a function
451 * deals with struct return here
452 */
453void
454efcode()
455{
456 NODE *p, *q;
457 int tempnr;
458 int ty;
459
460#ifdef USE_GOTNR
461 extern int gotnr;
462 gotnr = 0;
463#endif
464
465 if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
466 return;
467
468 ty = cftnsp->stype - FTN;
469
470 q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
471 regno(q) = R3;
472 p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
473 tempnr = regno(p);
474 p = buildtree(ASSIGN, p, q);
475 ecomp(p);
476
477 q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
478 q = buildtree(UMUL, q, NIL);
479
480 p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
481 p = buildtree(UMUL, p, NIL);
482
483 p = buildtree(ASSIGN, p, q);
484 ecomp(p);
485
486 q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
487 p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
488 regno(p) = R3;
489 p = buildtree(ASSIGN, p, q);
490 ecomp(p);
491}
492
493/*
494 * by now, the automatics and register variables are allocated
495 */
496void
497bccode()
498{
499 SETOFF(autooff, SZINT);
500}
501
502struct stub stublist;
503struct stub nlplist;
504
505/* called just before final exit */
506/* flag is 1 if errors, 0 if none */
507void
508ejobcode(int flag )
509{
510
511#if defined(MACHOABI)
512 /*
513 * iterate over the stublist and output the PIC stubs
514` */
515 if (kflag) {
516 struct stub *p;
517
518 DLIST_FOREACH(p, &stublist, link) {
519 printf("\t.section __TEXT, __picsymbolstub1,symbol_stubs,pure_instructions,32\n");
520 printf("\t.align 5\n");
521 printf("L%s$stub:\n", p->name);
522 if (strcmp(p->name, "mcount") == 0)
523 printf("\t.indirect_symbol %s\n", p->name);
524 else
525 printf("\t.indirect_symbol %s\n", p->name);
526 printf("\tmflr r0\n");
527 printf("\tbcl 20,31,L%s$spb\n", p->name);
528 printf("L%s$spb:\n", p->name);
529 printf("\tmflr r11\n");
530 printf("\taddis r11,r11,ha16(L%s$lazy_ptr-L%s$spb)\n",
531 p->name, p->name);
532 printf("\tmtlr r0\n");
533 printf("\tlwzu r12,lo16(L%s$lazy_ptr-L%s$spb)(r11)\n",
534 p->name, p->name);
535 printf("\tmtctr r12\n");
536 printf("\tbctr\n");
537 printf("\t.lazy_symbol_pointer\n");
538 printf("L%s$lazy_ptr:\n", p->name);
539 if (strcmp(p->name, "mcount") == 0)
540 printf("\t.indirect_symbol %s\n", p->name);
541 else
542 printf("\t.indirect_symbol %s\n", p->name);
543 printf("\t.long dyld_stub_binding_helper\n");
544 printf("\t.subsections_via_symbols\n");
545 }
546
547 printf("\t.non_lazy_symbol_pointer\n");
548 DLIST_FOREACH(p, &nlplist, link) {
549 printf("L%s$non_lazy_ptr:\n", p->name);
550 if (strcmp(p->name, "mcount") == 0)
551 printf("\t.indirect_symbol %s\n", p->name);
552 else
553 printf("\t.indirect_symbol %s\n", p->name);
554 printf("\t.long 0\n");
555 }
556
557 }
558#endif
559
560#ifndef os_darwin
561#define _MKSTR(x) #x
562#define MKSTR(x) _MKSTR(x)
563#define OS MKSTR(TARGOS)
564 printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
565#endif
566
567}
568
569void
570bjobcode()
571{
572 DLIST_INIT(&stublist, link);
573 DLIST_INIT(&nlplist, link);
574}
575
576#ifdef notdef
577/*
578 * Print character t at position i in one string, until t == -1.
579 * Locctr & label is already defined.
580 */
581void
582bycode(int t, int i)
583{
584 static int lastoctal = 0;
585
586 /* put byte i+1 in a string */
587
588 if (t < 0) {
589 if (i != 0)
590 puts("\"");
591 } else {
592 if (i == 0)
593 printf("\t.ascii \"");
594 if (t == '\\' || t == '"') {
595 lastoctal = 0;
596 putchar('\\');
597 putchar(t);
598 } else if (t < 040 || t >= 0177) {
599 lastoctal++;
600 printf("\\%o",t);
601 } else if (lastoctal && '0' <= t && t <= '9') {
602 lastoctal = 0;
603 printf("\"\n\t.ascii \"%c", t);
604 } else {
605 lastoctal = 0;
606 putchar(t);
607 }
608 }
609}
610#endif
611
612/*
613 * return the alignment of field of type t
614 */
615int
616fldal(unsigned int t)
617{
618 uerror("fldal: illegal field type");
619 return(ALINT);
620}
621
622/* fix up type of field p */
623void
624fldty(struct symtab *p)
625{
626}
627
628/*
629 * XXX - fix genswitch.
630 */
631int
632mygenswitch(int num, TWORD type, struct swents **p, int n)
633{
634 if (num < 0) {
635 genswitch_bintree(num, type, p, n);
636 return 1;
637 }
638
639 return 0;
640
641#if 0
642 if (0)
643 genswitch_table(num, p, n);
644 if (0)
645 genswitch_bintree(num, p, n);
646 genswitch_mrst(num, p, n);
647#endif
648}
649
650static void bintree_rec(TWORD ty, int num,
651 struct swents **p, int n, int s, int e);
652
653static void
654genswitch_bintree(int num, TWORD ty, struct swents **p, int n)
655{
656 int lab = getlab();
657
658 if (p[0]->slab == 0)
659 p[0]->slab = lab;
660
661 bintree_rec(ty, num, p, n, 1, n);
662
663 plabel(lab);
664}
665
666static void
667bintree_rec(TWORD ty, int num, struct swents **p, int n, int s, int e)
668{
669 NODE *r;
670 int rlabel;
671 int h;
672
673 if (s == e) {
674 r = tempnode(num, ty, 0, MKAP(ty));
675 r = buildtree(NE, r, bcon(p[s]->sval));
676 cbranch(buildtree(NOT, r, NIL), bcon(p[s]->slab));
677 branch(p[0]->slab);
678 return;
679 }
680
681 rlabel = getlab();
682
683 h = s + (e - s) / 2;
684
685 r = tempnode(num, ty, 0, MKAP(ty));
686 r = buildtree(GT, r, bcon(p[h]->sval));
687 cbranch(r, bcon(rlabel));
688 bintree_rec(ty, num, p, n, s, h);
689 plabel(rlabel);
690 bintree_rec(ty, num, p, n, h+1, e);
691}
692
693
694#if 0
695
696static void
697genswitch_table(int num, struct swents **p, int n)
698{
699 NODE *r, *t;
700 int tval;
701 int minval, maxval, range;
702 int deflabel, tbllabel;
703 int i, j;
704
705 minval = p[1]->sval;
706 maxval = p[n]->sval;
707
708 range = maxval - minval + 1;
709
710 if (n < 10 || range > 3 * n) {
711 /* too small or too sparse for jump table */
712 genswitch_simple(num, p, n);
713 return;
714 }
715
716 r = tempnode(num, UNSIGNED, 0, MKAP(UNSIGNED));
717 r = buildtree(MINUS, r, bcon(minval));
718 t = tempnode(0, UNSIGNED, 0, MKAP(UNSIGNED));
719 tval = regno(t);
720 r = buildtree(ASSIGN, t, r);
721 ecomp(r);
722
723 deflabel = p[0]->slab;
724 if (deflabel == 0)
725 deflabel = getlab();
726
727 t = tempnode(tval, UNSIGNED, 0, MKAP(UNSIGNED));
728 cbranch(buildtree(GT, t, bcon(maxval-minval)), bcon(deflabel));
729
730 tbllabel = getlab();
731 struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP);
732 strtbl->soffset = tbllabel;
733 strtbl->sclass = ILABEL;
734 strtbl->stype = INCREF(UCHAR);
735
736 t = block(NAME, NIL, NIL, UNSIGNED, 0, MKAP(UNSIGNED));
737 t->n_sp = strtbl;
738 t = buildtree(ADDROF, t, NIL);
739 r = tempnode(tval, UNSIGNED, 0, MKAP(INT));
740 r = buildtree(PLUS, t, r);
741 t = tempnode(0, INCREF(UNSIGNED), 0, MKAP(UNSIGNED));
742 r = buildtree(ASSIGN, t, r);
743 ecomp(r);
744
745 r = tempnode(regno(t), INCREF(UNSIGNED), 0, MKAP(UNSIGNED));
746 r = buildtree(UMUL, r, NIL);
747 t = block(NAME, NIL, NIL, UCHAR, 0, MKAP(UCHAR));
748 t->n_sp = strtbl;
749 t = buildtree(ADDROF, t, NIL);
750 r = buildtree(PLUS, t, r);
751 r = block(GOTO, r, NIL, 0, 0, 0);
752 ecomp(r);
753
754 plabel(tbllabel);
755 for (i = minval, j=1; i <= maxval; i++) {
756 char *entry = tmpalloc(20);
757 int lab = deflabel;
758 //printf("; minval=%d, maxval=%d, i=%d, j=%d p[j]=%lld\n", minval, maxval, i, j, p[j]->sval);
759 if (p[j]->sval == i) {
760 lab = p[j]->slab;
761 j++;
762 }
763 snprintf(entry, 20, ".long " LABFMT "-" LABFMT, lab, tbllabel);
764 send_passt(IP_ASM, entry);
765 }
766
767 if (p[0]->slab <= 0)
768 plabel(deflabel);
769}
770
771#define DPRINTF(x) if (xdebug) printf x
772//#define DPRINTF(x) do { } while(0)
773
774#define MIN_TABLE_SIZE 8
775
776/*
777 * Multi-way Radix Search Tree (MRST)
778 */
779
780static void mrst_rec(int num, struct swents **p, int n, int *state, int lab);
781static unsigned long mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit);
782void mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state, int tbllabel, int lab, unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit);
783
784static void
785genswitch_mrst(int num, struct swents **p, int n)
786{
787 int *state;
788 int i;
789 int putlabel = 0;
790
791 if (n < 10) {
792 /* too small for MRST */
793 genswitch_simple(num, p, n);
794 return;
795 }
796
797 state = tmpalloc((n+1)*sizeof(int));
798 for (i = 0; i <= n; i++)
799 state[i] = 0;
800
801 if (p[0]->slab == 0) {
802 p[0]->slab = getlab();
803 putlabel = 1;
804 }
805
806 mrst_rec(num, p, n, state, 0);
807
808 if (putlabel)
809 plabel(p[0]->slab);
810}
811
812
813/*
814 * Look through the cases and generate a table or
815 * list of simple comparisons. If generating a table,
816 * invoke mrst_put_entry_and_recurse() to put
817 * an entry in the table and recurse.
818 */
819static void
820mrst_rec(int num, struct swents **p, int n, int *state, int lab)
821{
822 int len, lowbit;
823 unsigned long Wmax;
824 unsigned int tblsize;
825 NODE *t;
826 NODE *r;
827 int tval;
828 int i;
829
830 DPRINTF(("mrst_rec: num=%d, n=%d, lab=%d\n", num, n, lab));
831
832 /* find best window to cover set*/
833 Wmax = mrst_find_window(p, n, state, lab, &len, &lowbit);
834 tblsize = (1 << len);
835 assert(len > 0 && tblsize > 0);
836
837 DPRINTF(("mrst_rec: Wmax=%lu, lowbit=%d, tblsize=%u\n",
838 Wmax, lowbit, tblsize));
839
840 if (lab)
841 plabel(lab);
842
843 if (tblsize <= MIN_TABLE_SIZE) {
844 DPRINTF(("msrt_rec: break the recursion\n"));
845 for (i = 1; i <= n; i++) {
846 if (state[i] == lab) {
847 t = tempnode(num, UNSIGNED, 0, MKAP(UNSIGNED));
848 cbranch(buildtree(EQ, t, bcon(p[i]->sval)),
849 bcon(p[i]->slab));
850 }
851 }
852 branch(p[0]->slab);
853 return;
854 }
855
856 DPRINTF(("generating table with %d elements\n", tblsize));
857
858 // AND with Wmax
859 t = tempnode(num, UNSIGNED, 0, MKAP(UNSIGNED));
860 r = buildtree(AND, t, bcon(Wmax));
861
862 // RS lowbits
863 r = buildtree(RS, r, bcon(lowbit));
864
865 t = tempnode(0, UNSIGNED, 0, MKAP(UNSIGNED));
866 tval = regno(t);
867 r = buildtree(ASSIGN, t, r);
868 ecomp(r);
869
870 int tbllabel = getlab();
871 struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP);
872 strtbl->sclass = STATIC;
873 strtbl->sap = MKAP(UCHAR);
874 strtbl->slevel = 1;
875 strtbl->soffset = tbllabel;
876 strtbl->stype = INCREF(UCHAR);
877 strtbl->squal = (CON >> TSHIFT);
878
879 t = block(NAME, NIL, NIL, UNSIGNED, 0, MKAP(UNSIGNED));
880 t->n_sp = strtbl;
881 t = buildtree(ADDROF, t, NIL);
882 r = tempnode(tval, UNSIGNED, 0, MKAP(INT));
883 r = buildtree(PLUS, t, r);
884 t = tempnode(0, INCREF(UNSIGNED), 0, MKAP(UNSIGNED));
885 r = buildtree(ASSIGN, t, r);
886 ecomp(r);
887
888 r = tempnode(regno(t), INCREF(UNSIGNED), 0, MKAP(UNSIGNED));
889 r = buildtree(UMUL, r, NIL);
890 t = block(NAME, NIL, NIL, UCHAR, 0, MKAP(UCHAR));
891 t->n_sp = strtbl;
892 t = buildtree(ADDROF, t, NIL);
893 r = buildtree(PLUS, t, r);
894 r = block(GOTO, r, NIL, 0, 0, 0);
895 ecomp(r);
896
897 plabel(tbllabel);
898
899 mrst_put_entry_and_recurse(num, p, n, state, tbllabel, lab,
900 0, tblsize, Wmax, lowbit);
901}
902
903
904/*
905 * Put an entry into the table and recurse to the next entry
906 * in the table. On the way back through the recursion, invoke
907 * mrst_rec() to check to see if we should generate another
908 * table.
909 */
910void
911mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state,
912 int tbllabel, int labval,
913 unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit)
914{
915 int i;
916 int found = 0;
917 int lab = getlab();
918
919 /*
920 * Look for labels which map to this table entry.
921 * Mark each one in "state" that they fall inside this table.
922 */
923 for (i = 1; i <= n; i++) {
924 unsigned int val = (p[i]->sval & Wmax) >> lowbit;
925 if (val == j && state[i] == labval) {
926 found = 1;
927 state[i] = lab;
928 }
929 }
930
931 /* couldn't find any labels? goto the default label */
932 if (!found)
933 lab = p[0]->slab;
934
935 /* generate the table entry */
936 char *entry = tmpalloc(20);
937 snprintf(entry, 20, ".long " LABFMT "-" LABFMT, lab, tbllabel);
938 send_passt(IP_ASM, entry);
939
940 DPRINTF(("mrst_put_entry: table=%d, pos=%lu/%lu, label=%d\n",
941 tbllabel, j, tblsize, lab));
942
943 /* go to the next table entry */
944 if (j+1 < tblsize) {
945 mrst_put_entry_and_recurse(num, p, n, state, tbllabel, labval,
946 j+1, tblsize, Wmax, lowbit);
947 }
948
949 /* if we are going to the default label, bail now */
950 if (!found)
951 return;
952
953#ifdef PCC_DEBUG
954 if (xdebug) {
955 printf("state: ");
956 for (i = 1; i <= n; i++)
957 printf("%d ", state[i]);
958 printf("\n");
959 }
960#endif
961
962 /* build another table */
963 mrst_rec(num, p, n, state, lab);
964}
965
966/*
967 * counts the number of entries in a table of size (1 << L) which would
968 * be used given the cases and the mask (W, lowbit).
969 */
970static unsigned int
971mrst_cardinality(struct swents **p, int n, int *state, int step, unsigned long W, int L, int lowbit)
972{
973 unsigned int count = 0;
974 int i;
975
976 if (W == 0)
977 return 0;
978
979 int *vals = (int *)calloc(1 << L, sizeof(int));
980 assert(vals);
981
982 DPRINTF(("mrst_cardinality: "));
983 for (i = 1; i <= n; i++) {
984 int idx;
985 if (state[i] != step)
986 continue;
987 idx = (p[i]->sval & W) >> lowbit;
988 DPRINTF(("%llu->%d, ", p[i]->sval, idx));
989 if (!vals[idx]) {
990 count++;
991 }
992 vals[idx] = 1;
993 }
994 DPRINTF((": found %d entries\n", count));
995 free(vals);
996
997 return count;
998}
999
1000/*
1001 * Find the maximum window (table size) which would best cover
1002 * the set of labels. Algorithm explained in:
1003 *
1004 * Ulfar Erlingsson, Mukkai Krishnamoorthy and T.V. Raman.
1005 * Efficient Multiway Radix Search Trees.
1006 * Information Processing Letters 60:3 115-120 (November 1996)
1007 */
1008
1009static unsigned long
1010mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit)
1011{
1012 unsigned int tblsize;
1013 unsigned long W = 0;
1014 unsigned long Wmax = 0;
1015 unsigned long Wleft = (1 << (SZLONG-1));
1016 unsigned int C = 0;
1017 unsigned int Cmax = 0;
1018 int L = 0;
1019 int Lmax = 0;
1020 int lowmax = 0;
1021 int no_b = SZLONG-1;
1022 unsigned long b = (1 << (SZLONG-1));
1023
1024 DPRINTF(("mrst_find_window: n=%d, lab=%d\n", n, lab));
1025
1026 for (; b > 0; b >>= 1, no_b--) {
1027
1028 // select the next bit
1029 W |= b;
1030 L += 1;
1031
1032 tblsize = 1 << L;
1033 assert(tblsize > 0);
1034
1035 DPRINTF(("no_b=%d, b=0x%lx, Wleft=0x%lx, W=0x%lx, Wmax=0x%lx, L=%d, Lmax=%d, Cmax=%u, lowmax=%d, tblsize=%u\n", no_b, b, Wleft, W, Wmax, L, Lmax, Cmax, lowmax, tblsize));
1036
1037 C = mrst_cardinality(p, n, state, lab, W, L, no_b);
1038 DPRINTF((" -> cardinality is %d\n", C));
1039
1040 if (2*C >= tblsize) {
1041 DPRINTF(("(found good match, keep adding to table)\n"));
1042 Wmax = W;
1043 Lmax = L;
1044 lowmax = no_b;
1045 Cmax = C;
1046 } else {
1047 DPRINTF(("(too sparse)\n"));
1048 assert((W & Wleft) != 0);
1049
1050 /* flip the MSB and see if we get a better match */
1051 W ^= Wleft;
1052 Wleft >>= 1;
1053 L -= 1;
1054
1055 DPRINTF((" --> trying W=0x%lx and L=%d and Cmax=%u\n", W, L, Cmax));
1056 C = mrst_cardinality(p, n, state, lab, W, L, no_b);
1057 DPRINTF((" --> C=%u\n", C));
1058 if (C > Cmax) {
1059 Wmax = W;
1060 Lmax = L;
1061 lowmax = no_b;
1062 Cmax = C;
1063 DPRINTF((" --> better!\n"));
1064 } else {
1065 DPRINTF((" --> no better\n"));
1066 }
1067 }
1068
1069 }
1070
1071#ifdef PCC_DEBUG
1072 if (xdebug) {
1073 int i;
1074 int hibit = lowmax + Lmax;
1075 printf("msrt_find_window: Wmax=0x%lx, lowbit=%d, result=", Wmax, lowmax);
1076 for (i = 31; i >= 0; i--) {
1077 int mask = (1 << i);
1078 if (i == hibit)
1079 printf("[");
1080 if (Wmax & mask)
1081 printf("1");
1082 else
1083 printf("0");
1084 if (i == lowmax)
1085 printf("]");
1086 }
1087 printf("\n");
1088 }
1089#endif
1090
1091 assert(Lmax > 0);
1092 *len = Lmax;
1093 *lowbit = lowmax;
1094
1095 DPRINTF(("msrt_find_window: returning Wmax=%lu, len=%d, lowbit=%d [tblsize=%u, entries=%u]\n", Wmax, Lmax, lowmax, tblsize, C));
1096
1097 return Wmax;
1098}
1099#endif
1100
1101/*
1102 * Straighten a chain of CM ops so that the CM nodes
1103 * only appear on the left node.
1104 *
1105 * CM CM
1106 * CM CM CM b
1107 * x y a b CM a
1108 * x y
1109 *
1110 * CM CM
1111 * CM CM CM c
1112 * CM z CM c CM b
1113 * x y a b CM a
1114 * CM z
1115 * x y
1116 */
1117static NODE *
1118straighten(NODE *p)
1119{
1120 NODE *r = p->n_right;
1121
1122 if (p->n_op != CM || r->n_op != CM)
1123 return p;
1124
1125 p->n_right = r->n_left;
1126 r->n_left = straighten(p);
1127
1128 return r;
1129}
1130
1131static NODE *
1132reverse1(NODE *p, NODE *a)
1133{
1134 NODE *l = p->n_left;
1135 NODE *r = p->n_right;
1136
1137 a->n_right = r;
1138 p->n_left = a;
1139
1140 if (l->n_op == CM) {
1141 return reverse1(l, p);
1142 } else {
1143 p->n_right = l;
1144 return p;
1145 }
1146}
1147
1148/*
1149 * Reverse a chain of CM ops
1150 */
1151static NODE *
1152reverse(NODE *p)
1153{
1154 NODE *l = p->n_left;
1155 NODE *r = p->n_right;
1156
1157 p->n_left = r;
1158
1159 if (l->n_op == CM)
1160 return reverse1(l, p);
1161
1162 p->n_right = l;
1163
1164 return p;
1165}
1166
1167/* push arg onto the stack */
1168/* called by moveargs() */
1169static NODE *
1170pusharg(NODE *p, int *regp)
1171{
1172 NODE *q;
1173 int sz;
1174 int off;
1175
1176 /* convert to register size, if smaller */
1177 sz = tsize(p->n_type, p->n_df, p->n_ap);
1178 if (sz < SZINT)
1179 p = block(SCONV, p, NIL, INT, 0, MKAP(INT));
1180
1181 q = block(REG, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap);
1182 regno(q) = SPREG;
1183
1184 off = ARGINIT/SZCHAR + 4 * (*regp - R3);
1185 q = block(PLUS, q, bcon(off), INT, 0, MKAP(INT));
1186 q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap);
1187 (*regp) += szty(p->n_type);
1188
1189 return buildtree(ASSIGN, q, p);
1190}
1191
1192/* setup call stack with 32-bit argument */
1193/* called from moveargs() */
1194static NODE *
1195movearg_32bit(NODE *p, int *regp)
1196{
1197 int reg = *regp;
1198 NODE *q;
1199
1200 q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
1201 regno(q) = reg++;
1202 q = buildtree(ASSIGN, q, p);
1203
1204 *regp = reg;
1205 return q;
1206}
1207
1208/* setup call stack with 64-bit argument */
1209/* called from moveargs() */
1210static NODE *
1211movearg_64bit(NODE *p, int *regp)
1212{
1213 int reg = *regp;
1214 NODE *q, *r;
1215
1216#if ALLONGLONG == 64
1217 /* alignment */
1218 ++reg;
1219 reg &= ~1;
1220#endif
1221
1222 if (reg > R10) {
1223 *regp = reg;
1224 q = pusharg(p, regp);
1225 } else if (reg == R10) {
1226 /* half in and half out of the registers */
1227 r = tcopy(p);
1228 if (!features(FEATURE_BIGENDIAN)) {
1229 q = block(SCONV, p, NIL, INT, 0, MKAP(INT));
1230 q = movearg_32bit(q, regp); /* little-endian */
1231 r = buildtree(RS, r, bcon(32));
1232 r = block(SCONV, r, NIL, INT, 0, MKAP(INT));
1233 r = pusharg(r, regp); /* little-endian */
1234 } else {
1235 q = buildtree(RS, p, bcon(32));
1236 q = block(SCONV, q, NIL, INT, 0, MKAP(INT));
1237 q = movearg_32bit(q, regp); /* big-endian */
1238 r = block(SCONV, r, NIL, INT, 0, MKAP(INT));
1239 r = pusharg(r, regp); /* big-endian */
1240 }
1241 q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap));
1242 } else {
1243 q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
1244 regno(q) = R3R4 + (reg - R3);
1245 q = buildtree(ASSIGN, q, p);
1246 *regp = reg + 2;
1247 }
1248
1249 return q;
1250}
1251
1252/* setup call stack with float argument */
1253/* called from moveargs() */
1254static NODE *
1255movearg_float(NODE *p, int *fregp, int *regp)
1256{
1257#if defined(MACHOABI)
1258 NODE *q, *r;
1259 TWORD ty = INCREF(p->n_type);
1260 int tmpnr;
1261#endif
1262
1263 p = movearg_32bit(p, fregp);
1264
1265 /*
1266 * On OS/X, floats are passed in the floating-point registers
1267 * and in the general registers for compatibily with libraries
1268 * compiled to handle soft-float.
1269 */
1270
1271#if defined(MACHOABI)
1272
1273 if (xtemps) {
1274 /* bounce into TOS */
1275 r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
1276 regno(r) = SPREG;
1277 r = block(PLUS, r, bcon(-4), INT, 0, MKAP(INT));
1278 r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
1279 r = buildtree(ASSIGN, r, p);
1280 ecomp(r);
1281
1282 /* bounce into temp */
1283 r = block(REG, NIL, NIL, PTR+INT, 0, MKAP(INT));
1284 regno(r) = SPREG;
1285 r = block(PLUS, r, bcon(-4), INT, 0, MKAP(INT));
1286 r = block(UMUL, r, NIL, INT, 0, MKAP(INT));
1287 q = tempnode(0, INT, 0, MKAP(INT));
1288 tmpnr = regno(q);
1289 r = buildtree(ASSIGN, q, r);
1290 ecomp(r);
1291 } else {
1292 /* copy directly into temp */
1293 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
1294 tmpnr = regno(q);
1295 r = buildtree(ASSIGN, q, p);
1296 ecomp(r);
1297 }
1298
1299 /* copy from temp to register parameter */
1300 r = tempnode(tmpnr, INT, 0, MKAP(INT));
1301 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
1302 regno(q) = (*regp)++;
1303 p = buildtree(ASSIGN, q, r);
1304
1305#endif
1306 return p;
1307
1308}
1309
1310/* setup call stack with float/double argument */
1311/* called from moveargs() */
1312static NODE *
1313movearg_double(NODE *p, int *fregp, int *regp)
1314{
1315#if defined(MACHOABI)
1316 NODE *q, *r;
1317 TWORD ty = INCREF(p->n_type);
1318 int tmpnr;
1319#endif
1320
1321 /* this does the move to a single register for us */
1322 p = movearg_32bit(p, fregp);
1323
1324 /*
1325 * On OS/X, doubles are passed in the floating-point registers
1326 * and in the general registers for compatibily with libraries
1327 * compiled to handle soft-float.
1328 */
1329
1330#if defined(MACHOABI)
1331
1332 if (xtemps) {
1333 /* bounce on TOS */
1334 r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
1335 regno(r) = SPREG;
1336 r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap);
1337 r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
1338 r = buildtree(ASSIGN, r, p);
1339 ecomp(r);
1340
1341 /* bounce into temp */
1342 r = block(REG, NIL, NIL, PTR+LONGLONG, 0, MKAP(LONGLONG));
1343 regno(r) = SPREG;
1344 r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, MKAP(LONGLONG));
1345 r = block(UMUL, r, NIL, LONGLONG, 0, MKAP(LONGLONG));
1346 q = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
1347 tmpnr = regno(q);
1348 r = buildtree(ASSIGN, q, r);
1349 ecomp(r);
1350 } else {
1351 /* copy directly into temp */
1352 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
1353 tmpnr = regno(q);
1354 r = buildtree(ASSIGN, q, p);
1355 ecomp(r);
1356 }
1357
1358 /* copy from temp to register parameter */
1359 r = tempnode(tmpnr, LONGLONG, 0, MKAP(LONGLONG));
1360 q = block(REG, NIL, NIL, LONGLONG, 0, MKAP(LONGLONG));
1361 regno(q) = R3R4 - R3 + (*regp);
1362 p = buildtree(ASSIGN, q, r);
1363
1364 (*regp) += 2;
1365
1366#endif
1367
1368 return p;
1369}
1370
1371/* setup call stack with a structure */
1372/* called from moveargs() */
1373static NODE *
1374movearg_struct(NODE *p, int *regp)
1375{
1376 int reg = *regp;
1377 NODE *l, *q, *t, *r;
1378 int tmpnr;
1379 int navail;
1380 int num;
1381 int sz;
1382 int ty;
1383 int i;
1384
1385 assert(p->n_op == STARG);
1386
1387 navail = NARGREGS - (reg - R3);
1388 navail = navail < 0 ? 0 : navail;
1389 sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
1390 num = sz > navail ? navail : sz;
1391
1392 /* remove STARG node */
1393 l = p->n_left;
1394 nfree(p);
1395 ty = l->n_type;
1396
1397 /*
1398 * put it into a TEMP, rather than tcopy(), since the tree
1399 * in p may have side-affects
1400 */
1401 t = tempnode(0, ty, l->n_df, l->n_ap);
1402 tmpnr = regno(t);
1403 q = buildtree(ASSIGN, t, l);
1404
1405 /* copy structure into registers */
1406 for (i = 0; i < num; i++) {
1407 t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
1408 t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
1409 t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
1410 t = buildtree(UMUL, t, NIL);
1411
1412 r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
1413 regno(r) = reg++;
1414 r = buildtree(ASSIGN, r, t);
1415
1416 q = block(CM, q, r, INT, 0, MKAP(INT));
1417 }
1418
1419 /* put the rest of the structure on the stack */
1420 for (i = num; i < sz; i++) {
1421 t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
1422 t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
1423 t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
1424 t = buildtree(UMUL, t, NIL);
1425 r = pusharg(t, &reg);
1426 q = block(CM, q, r, INT, 0, MKAP(INT));
1427 }
1428
1429 q = reverse(q);
1430
1431 *regp = reg;
1432 return q;
1433}
1434
1435
1436static NODE *
1437moveargs(NODE *p, int *regp, int *fregp)
1438{
1439 NODE *r, **rp;
1440 int reg, freg;
1441
1442 if (p->n_op == CM) {
1443 p->n_left = moveargs(p->n_left, regp, fregp);
1444 r = p->n_right;
1445 rp = &p->n_right;
1446 } else {
1447 r = p;
1448 rp = &p;
1449 }
1450
1451 reg = *regp;
1452 freg = *fregp;
1453
1454#define ISFLOAT(p) (p->n_type == FLOAT || \
1455 p->n_type == DOUBLE || \
1456 p->n_type == LDOUBLE)
1457
1458 if (reg > R10 && r->n_op != STARG) {
1459 *rp = pusharg(r, regp);
1460 } else if (r->n_op == STARG) {
1461 *rp = movearg_struct(r, regp);
1462 } else if (DEUNSIGN(r->n_type) == LONGLONG) {
1463 *rp = movearg_64bit(r, regp);
1464 } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
1465 if (features(FEATURE_HARDFLOAT))
1466 *rp = movearg_double(r, fregp, regp);
1467 else
1468 *rp = movearg_64bit(r, regp);
1469 } else if (r->n_type == FLOAT) {
1470 if (features(FEATURE_HARDFLOAT))
1471 *rp = movearg_float(r, fregp, regp);
1472 else
1473 *rp = movearg_32bit(r, regp);
1474 } else {
1475 *rp = movearg_32bit(r, regp);
1476 }
1477
1478 return straighten(p);
1479}
1480
1481/*
1482 * Fixup arguments to pass pointer-to-struct as first argument.
1483 *
1484 * called from funcode().
1485 */
1486static NODE *
1487retstruct(NODE *p)
1488{
1489 struct symtab s;
1490 NODE *l, *r, *t, *q;
1491 TWORD ty;
1492
1493 l = p->n_left;
1494 r = p->n_right;
1495
1496 ty = DECREF(l->n_type) - FTN;
1497
1498 s.sclass = AUTO;
1499 s.stype = ty;
1500 s.sdf = l->n_df;
1501 s.sap = l->n_ap;
1502 oalloc(&s, &autooff);
1503 q = block(REG, NIL, NIL, INCREF(ty), l->n_df, l->n_ap);
1504 regno(q) = FPREG;
1505 q = block(MINUS, q, bcon(autooff/SZCHAR), INCREF(ty),
1506 l->n_df, l->n_ap);
1507
1508 /* insert hidden assignment at beginning of list */
1509 if (r->n_op != CM) {
1510 p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap);
1511 } else {
1512 for (t = r; t->n_left->n_op == CM; t = t->n_left)
1513 ;
1514 t->n_left = block(CM, q, t->n_left, INCREF(ty),
1515 l->n_df, l->n_ap);
1516 }
1517
1518 return p;
1519}
1520
1521/*
1522 * Called with a function call with arguments as argument.
1523 * This is done early in buildtree() and only done once.
1524 */
1525NODE *
1526funcode(NODE *p)
1527{
1528 int regnum = R3;
1529 int fregnum = F1;
1530
1531 if (DECREF(p->n_left->n_type) == STRTY+FTN ||
1532 DECREF(p->n_left->n_type) == UNIONTY+FTN)
1533 p = retstruct(p);
1534
1535 p->n_right = moveargs(p->n_right, &regnum, &fregnum);
1536
1537 if (p->n_right == NULL)
1538 p->n_op += (UCALL - CALL);
1539
1540 return p;
1541}
Note: See TracBrowser for help on using the repository browser.