~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to uspace/app/pcc/arch/mips/code.c

  • Committer: Jakub Jermar
  • Date: 2011-09-07 22:19:24 UTC
  • mfrom: (1113.1.41 devel)
  • Revision ID: jakub@jermar.eu-20110907221924-cfgktigu4e8l0uyv
Merge from lp:~helenos-posix/helenos/devel.

* Petr Koupy's port of binutils.
* Jiri Zarevucky's port of pcc.
* Petr and Jiri's libposix library.
* Changes needed to make it all work together.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $Id: code.c,v 1.17 2010/09/19 14:01:35 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
 
 
30
/*
 
31
 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
 
32
 * Simon Olsson (simols-1@student.ltu.se) 2005.
 
33
 */
 
34
 
 
35
#include <assert.h>
 
36
#include "pass1.h"
 
37
 
 
38
/*
 
39
 * Define everything needed to print out some data (or text).
 
40
 * This means segment, alignment, visibility, etc.
 
41
 */
 
42
void
 
43
defloc(struct symtab *sp)
 
44
{
 
45
        static char *loctbl[] = { "text", "data", "section .rodata" };
 
46
        static int lastloc = -1;
 
47
        TWORD t;
 
48
        char *n;
 
49
        int s;
 
50
 
 
51
        if (sp == NULL) {
 
52
                lastloc = -1;
 
53
                return;
 
54
        }
 
55
        t = sp->stype;
 
56
        s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
 
57
        lastloc = s;
 
58
        if (s == PROG)
 
59
                return; /* text is written in prologue() */
 
60
        if (s != lastloc)
 
61
                printf("        .%s\n", loctbl[s]);
 
62
        printf("        .p2align %d\n", ispow2(talign(t, sp->sap)));
 
63
        n = sp->soname ? sp->soname : sp->sname;
 
64
        if (sp->sclass == EXTDEF)
 
65
                printf("        .globl %s\n", n);
 
66
        if (sp->slevel == 0) {
 
67
#ifdef USE_GAS
 
68
                printf("\t.type %s,@object\n", n);
 
69
                printf("\t.size %s," CONFMT "\n", n,
 
70
                    tsize(sp->stype, sp->sdf, sp->sap));
 
71
#endif
 
72
                printf("%s:\n", n);
 
73
        } else
 
74
                printf(LABFMT ":\n", sp->soffset);
 
75
}
 
76
 
 
77
 
 
78
#ifdef notdef
 
79
/*
 
80
 * cause the alignment to become a multiple of n
 
81
 * never called for text segment.
 
82
 */
 
83
void
 
84
defalign(int n)
 
85
{
 
86
        n = ispow2(n / SZCHAR);
 
87
        if (n == -1)
 
88
                cerror("defalign: n != 2^i");
 
89
        printf("\t.p2align %d\n", n);
 
90
}
 
91
 
 
92
/*
 
93
 * define the current location as the name p->sname
 
94
 * never called for text segment.
 
95
 */
 
96
void
 
97
defnam(struct symtab *p)
 
98
{
 
99
        char *c = p->soname;
 
100
 
 
101
        if (p->sclass == EXTDEF)
 
102
                printf("\t.globl %s\n", c);
 
103
#ifdef USE_GAS
 
104
        printf("\t.type %s,@object\n", c);
 
105
        printf("\t.size %s," CONFMT "\n", c, tsize(p->stype, p->sdf, p->sap));
 
106
#endif
 
107
        printf("%s:\n", c);
 
108
}
 
109
#endif
 
110
 
 
111
static int rvnr;
 
112
 
 
113
/*
 
114
 * code for the end of a function
 
115
 * deals with struct return here
 
116
 */
 
117
void
 
118
efcode()
 
119
{
 
120
        NODE *p, *q;
 
121
        int tempnr;
 
122
        int ty;
 
123
 
 
124
        if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
 
125
                return;
 
126
 
 
127
        ty = cftnsp->stype - FTN;
 
128
 
 
129
        q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
 
130
        q->n_rval = V0;
 
131
        p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
 
132
        tempnr = regno(p);
 
133
        p = buildtree(ASSIGN, p, q);
 
134
        ecomp(p);
 
135
 
 
136
        q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
 
137
        q = buildtree(UMUL, q, NIL);
 
138
 
 
139
        p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
 
140
        p = buildtree(UMUL, p, NIL);
 
141
 
 
142
        p = buildtree(ASSIGN, p, q);
 
143
        ecomp(p);
 
144
 
 
145
        q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
 
146
        p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
 
147
        p->n_rval = V0;
 
148
        p = buildtree(ASSIGN, p, q);
 
149
        ecomp(p);
 
150
}
 
151
 
 
152
/* Put a symbol in a temporary
 
153
 * used by bfcode() and its helpers */
 
154
static void
 
155
putintemp(struct symtab *sym)
 
156
{
 
157
        NODE *p;
 
158
        p = tempnode(0, sym->stype, sym->sdf, sym->sap);
 
159
        p = buildtree(ASSIGN, p, nametree(sym));
 
160
        sym->soffset = regno(p->n_left);
 
161
        sym->sflags |= STNODE;
 
162
        ecomp(p);
 
163
}
 
164
 
 
165
/* setup the hidden pointer to struct return parameter
 
166
 * used by bfcode() */
 
167
static void
 
168
param_retptr(void)
 
169
{
 
170
        NODE *p, *q;
 
171
 
 
172
        p = tempnode(0, PTR+STRTY, 0, cftnsp->sap);
 
173
        rvnr = regno(p);
 
174
        q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
 
175
        q->n_rval = A0;
 
176
        p = buildtree(ASSIGN, p, q);
 
177
        ecomp(p);
 
178
}
 
179
 
 
180
/* setup struct parameter
 
181
 * push the registers out to memory
 
182
 * used by bfcode() */
 
183
static void
 
184
param_struct(struct symtab *sym, int *regp)
 
185
{
 
186
        int reg = *regp;
 
187
        NODE *p, *q;
 
188
        int navail;
 
189
        int sz;
 
190
        int off;
 
191
        int num;
 
192
        int i;
 
193
 
 
194
        navail = nargregs - (reg - A0);
 
195
        sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
 
196
        off = ARGINIT/SZINT + (reg - A0);
 
197
        num = sz > navail ? navail : sz;
 
198
        for (i = 0; i < num; i++) {
 
199
                q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
 
200
                q->n_rval = reg++;
 
201
                p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
 
202
                p->n_rval = FP;
 
203
                p = block(PLUS, p, bcon(4*off++), INT, 0, MKAP(INT));
 
204
                p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
 
205
                p = buildtree(ASSIGN, p, q);
 
206
                ecomp(p);
 
207
        }
 
208
 
 
209
        *regp = reg;
 
210
}
 
211
 
 
212
/* setup a 64-bit parameter (double/ldouble/longlong)
 
213
 * used by bfcode() */
 
214
static void
 
215
param_64bit(struct symtab *sym, int *regp, int dotemps)
 
216
{
 
217
        int reg = *regp;
 
218
        NODE *p, *q;
 
219
        int navail;
 
220
 
 
221
        /* alignment */
 
222
        ++reg;
 
223
        reg &= ~1;
 
224
 
 
225
        navail = nargregs - (reg - A0);
 
226
 
 
227
        if (navail < 2) {
 
228
                /* would have appeared half in registers/half
 
229
                 * on the stack, but alignment ensures it
 
230
                 * appears on the stack */
 
231
                if (dotemps)
 
232
                        putintemp(sym);
 
233
                *regp = reg;
 
234
                return;
 
235
        }
 
236
 
 
237
        q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
 
238
        q->n_rval = A0A1 + (reg - A0);
 
239
        if (dotemps) {
 
240
                p = tempnode(0, sym->stype, sym->sdf, sym->sap);
 
241
                sym->soffset = regno(p);
 
242
                sym->sflags |= STNODE;
 
243
        } else {
 
244
                p = nametree(sym);
 
245
        }
 
246
        p = buildtree(ASSIGN, p, q);
 
247
        ecomp(p);
 
248
        *regp = reg + 2;
 
249
}
 
250
 
 
251
/* setup a 32-bit param on the stack
 
252
 * used by bfcode() */
 
253
static void
 
254
param_32bit(struct symtab *sym, int *regp, int dotemps)
 
255
{
 
256
        NODE *p, *q;
 
257
 
 
258
        q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
 
259
        q->n_rval = (*regp)++;
 
260
        if (dotemps) {
 
261
                p = tempnode(0, sym->stype, sym->sdf, sym->sap);
 
262
                sym->soffset = regno(p);
 
263
                sym->sflags |= STNODE;
 
264
        } else {
 
265
                p = nametree(sym);
 
266
        }
 
267
        p = buildtree(ASSIGN, p, q);
 
268
        ecomp(p);
 
269
}
 
270
 
 
271
/*
 
272
 * XXX This is a hack.  We cannot have (l)doubles in more than one
 
273
 * register class.  So we bounce them in and out of temps to
 
274
 * move them in and out of the right registers.
 
275
 */
 
276
static void
 
277
param_double(struct symtab *sym, int *regp, int dotemps)
 
278
{
 
279
        int reg = *regp;
 
280
        NODE *p, *q, *t;
 
281
        int navail;
 
282
        int tmpnr;
 
283
 
 
284
        /* alignment */
 
285
        ++reg;
 
286
        reg &= ~1;
 
287
 
 
288
        navail = nargregs - (reg - A0);
 
289
 
 
290
        if (navail < 2) {
 
291
                /* would have appeared half in registers/half
 
292
                 * on the stack, but alignment ensures it
 
293
                 * appears on the stack */
 
294
                if (dotemps)
 
295
                        putintemp(sym);
 
296
                *regp = reg;
 
297
                return;
 
298
        }
 
299
 
 
300
        t = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
 
301
        tmpnr = regno(t);
 
302
        q = block(REG, NIL, NIL, LONGLONG, 0, MKAP(LONGLONG));
 
303
        q->n_rval = A0A1 + (reg - A0);
 
304
        p = buildtree(ASSIGN, t, q);
 
305
        ecomp(p);
 
306
 
 
307
        if (dotemps) {
 
308
                sym->soffset = tmpnr;
 
309
                sym->sflags |= STNODE;
 
310
        } else {
 
311
                q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
 
312
                p = nametree(sym);
 
313
                p = buildtree(ASSIGN, p, q);
 
314
                ecomp(p);
 
315
        }
 
316
        *regp = reg + 2;
 
317
}
 
318
 
 
319
/*
 
320
 * XXX This is a hack.  We cannot have floats in more than one
 
321
 * register class.  So we bounce them in and out of temps to
 
322
 * move them in and out of the right registers.
 
323
 */
 
324
static void
 
325
param_float(struct symtab *sym, int *regp, int dotemps)
 
326
{
 
327
        NODE *p, *q, *t;
 
328
        int tmpnr;
 
329
 
 
330
        t = tempnode(0, INT, 0, MKAP(INT));
 
331
        tmpnr = regno(t);
 
332
        q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
 
333
        q->n_rval = (*regp)++;
 
334
        p = buildtree(ASSIGN, t, q);
 
335
        ecomp(p);
 
336
 
 
337
        if (dotemps) {
 
338
                sym->soffset = tmpnr;
 
339
                sym->sflags |= STNODE;
 
340
        } else {
 
341
                q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
 
342
                p = nametree(sym);
 
343
                p = buildtree(ASSIGN, p, q);
 
344
                ecomp(p);
 
345
        }
 
346
}
 
347
 
 
348
/*
 
349
 * code for the beginning of a function; a is an array of
 
350
 * indices in symtab for the arguments; n is the number
 
351
 */
 
352
void
 
353
bfcode(struct symtab **sp, int cnt)
 
354
{
 
355
        union arglist *usym;
 
356
        int lastreg = A0 + nargregs - 1;
 
357
        int saveallargs = 0;
 
358
        int i, reg;
 
359
 
 
360
        /*
 
361
         * Detect if this function has ellipses and save all
 
362
         * argument register onto stack.
 
363
         */
 
364
        usym = cftnsp->sdf->dfun;
 
365
        while (usym && usym->type != TNULL) {
 
366
                if (usym->type == TELLIPSIS) {
 
367
                        saveallargs = 1;
 
368
                        break;
 
369
                }
 
370
                ++usym;
 
371
        }
 
372
 
 
373
        reg = A0;
 
374
 
 
375
        /* assign hidden return structure to temporary */
 
376
        if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
 
377
                param_retptr();
 
378
                ++reg;
 
379
        }
 
380
 
 
381
        /* recalculate the arg offset and create TEMP moves */
 
382
        for (i = 0; i < cnt; i++) {
 
383
 
 
384
                if ((reg > lastreg) && !xtemps)
 
385
                        break;
 
386
                else if (reg > lastreg) 
 
387
                        putintemp(sp[i]);
 
388
                else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY)
 
389
                        param_struct(sp[i], &reg);
 
390
                else if (DEUNSIGN(sp[i]->stype) == LONGLONG)
 
391
                        param_64bit(sp[i], &reg, xtemps && !saveallargs);
 
392
                else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE)
 
393
                        param_double(sp[i], &reg, xtemps && !saveallargs);
 
394
                else if (sp[i]->stype == FLOAT)
 
395
                        param_float(sp[i], &reg, xtemps && !saveallargs);
 
396
                else
 
397
                        param_32bit(sp[i], &reg, xtemps && !saveallargs);
 
398
        }
 
399
 
 
400
        /* if saveallargs, save the rest of the args onto the stack */
 
401
        if (!saveallargs)
 
402
                return;
 
403
        while (reg <= lastreg) {
 
404
                NODE *p, *q;
 
405
                int off = ARGINIT/SZINT + (reg - A0);
 
406
                q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
 
407
                q->n_rval = reg++;
 
408
                p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
 
409
                p->n_rval = FP;
 
410
                p = block(PLUS, p, bcon(4*off), INT, 0, MKAP(INT));
 
411
                p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
 
412
                p = buildtree(ASSIGN, p, q);
 
413
                ecomp(p);
 
414
        }
 
415
 
 
416
}
 
417
 
 
418
 
 
419
/*
 
420
 * by now, the automatics and register variables are allocated
 
421
 */
 
422
void
 
423
bccode()
 
424
{
 
425
        SETOFF(autooff, SZINT);
 
426
}
 
427
 
 
428
/* called just before final exit */
 
429
/* flag is 1 if errors, 0 if none */
 
430
void
 
431
ejobcode(int flag )
 
432
{
 
433
}
 
434
 
 
435
void
 
436
bjobcode()
 
437
{
 
438
        printf("\t.section .mdebug.abi32\n");
 
439
        printf("\t.previous\n");
 
440
        printf("\t.abicalls\n");
 
441
}
 
442
 
 
443
#ifdef notdef
 
444
/*
 
445
 * Print character t at position i in one string, until t == -1.
 
446
 * Locctr & label is already defined.
 
447
 */
 
448
void
 
449
bycode(int t, int i)
 
450
{
 
451
        static int lastoctal = 0;
 
452
 
 
453
        /* put byte i+1 in a string */
 
454
 
 
455
        if (t < 0) {
 
456
                if (i != 0)
 
457
                        puts("\\000\"");
 
458
        } else {
 
459
                if (i == 0)
 
460
                        printf("\t.ascii \"");
 
461
                if (t == 0)
 
462
                        return;
 
463
                else if (t == '\\' || t == '"') {
 
464
                        lastoctal = 0;
 
465
                        putchar('\\');
 
466
                        putchar(t);
 
467
                } else if (t == 011) {
 
468
                        printf("\\t");
 
469
                } else if (t == 012) {
 
470
                        printf("\\n");
 
471
                } else if (t < 040 || t >= 0177) {
 
472
                        lastoctal++;
 
473
                        printf("\\%o",t);
 
474
                } else if (lastoctal && '0' <= t && t <= '9') {
 
475
                        lastoctal = 0;
 
476
                        printf("\"\n\t.ascii \"%c", t);
 
477
                } else {        
 
478
                        lastoctal = 0;
 
479
                        putchar(t);
 
480
                }
 
481
        }
 
482
}
 
483
#endif
 
484
 
 
485
/*
 
486
 * return the alignment of field of type t
 
487
 */
 
488
int
 
489
fldal(unsigned int t)
 
490
{
 
491
        uerror("illegal field type");
 
492
        return(ALINT);
 
493
}
 
494
 
 
495
/* fix up type of field p */
 
496
void
 
497
fldty(struct symtab *p)
 
498
{
 
499
}
 
500
 
 
501
/*
 
502
 * XXX - fix genswitch.
 
503
 */
 
504
int
 
505
mygenswitch(int num, TWORD type, struct swents **p, int n)
 
506
{
 
507
        return 0;
 
508
}
 
509
 
 
510
 
 
511
/* setup call stack with a structure */
 
512
/* called from moveargs() */
 
513
static NODE *
 
514
movearg_struct(NODE *p, NODE *parent, int *regp)
 
515
{
 
516
        int reg = *regp;
 
517
        NODE *l, *q, *t, *r;
 
518
        int tmpnr;
 
519
        int navail;
 
520
        int off;
 
521
        int num;
 
522
        int sz;
 
523
        int ty;
 
524
        int i;
 
525
 
 
526
        navail = nargregs - (reg - A0);
 
527
        sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
 
528
        num = sz > navail ? navail : sz;
 
529
 
 
530
        l = p->n_left;
 
531
        nfree(p);
 
532
        ty = l->n_type;
 
533
        t = tempnode(0, l->n_type, l->n_df, l->n_ap);
 
534
        tmpnr = regno(t);
 
535
        l = buildtree(ASSIGN, t, l);
 
536
 
 
537
        if (p != parent) {
 
538
                q = parent->n_left;
 
539
        } else
 
540
                q = NULL;
 
541
 
 
542
        /* copy structure into registers */
 
543
        for (i = 0; i < num; i++) {
 
544
                t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
 
545
                t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
 
546
                t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
 
547
                t = buildtree(UMUL, t, NIL);
 
548
 
 
549
                r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
 
550
                r->n_rval = reg++;
 
551
 
 
552
                r = buildtree(ASSIGN, r, t);
 
553
                if (q == NULL)
 
554
                        q = r;
 
555
                else 
 
556
                        q = block(CM, q, r, INT, 0, MKAP(INT));
 
557
        }
 
558
        off = ARGINIT/SZINT + nargregs;
 
559
        for (i = num; i < sz; i++) {
 
560
                t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
 
561
                t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
 
562
                t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
 
563
                t = buildtree(UMUL, t, NIL);
 
564
 
 
565
                r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
 
566
                r->n_rval = FP;
 
567
                r = block(PLUS, r, bcon(4*off++), INT, 0, MKAP(INT));
 
568
                r = block(UMUL, r, NIL, INT, 0, MKAP(INT));
 
569
 
 
570
                r = buildtree(ASSIGN, r, t);
 
571
                if (q == NULL)
 
572
                        q = r;
 
573
                else
 
574
                        q = block(CM, q, r, INT, 0, MKAP(INT));
 
575
        }
 
576
 
 
577
        if (parent->n_op == CM) {
 
578
                parent->n_left = q;
 
579
                q = l;
 
580
        } else {
 
581
                q = block(CM, q, l, INT, 0, MKAP(INT));
 
582
        }
 
583
 
 
584
        *regp = reg;
 
585
        return q;
 
586
}
 
587
 
 
588
/* setup call stack with 64-bit argument */
 
589
/* called from moveargs() */
 
590
static NODE *
 
591
movearg_64bit(NODE *p, int *regp)
 
592
{
 
593
        int reg = *regp;
 
594
        NODE *q;
 
595
        int lastarg;
 
596
 
 
597
        /* alignment */
 
598
        ++reg;
 
599
        reg &= ~1;
 
600
 
 
601
        lastarg = A0 + nargregs - 1;
 
602
        if (reg > lastarg) {
 
603
                *regp = reg;
 
604
                return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap);
 
605
        }
 
606
 
 
607
        q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
 
608
        q->n_rval = A0A1 + (reg - A0);
 
609
        q = buildtree(ASSIGN, q, p);
 
610
 
 
611
        *regp = reg + 2;
 
612
        return q;
 
613
}
 
614
 
 
615
/* setup call stack with 32-bit argument */
 
616
/* called from moveargs() */
 
617
static NODE *
 
618
movearg_32bit(NODE *p, int *regp)
 
619
{
 
620
        int reg = *regp;
 
621
        NODE *q;
 
622
 
 
623
        q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
 
624
        q->n_rval = reg++;
 
625
        q = buildtree(ASSIGN, q, p);
 
626
 
 
627
        *regp = reg;
 
628
        return q;
 
629
}
 
630
 
 
631
static NODE *
 
632
moveargs(NODE *p, int *regp)
 
633
{
 
634
        NODE *r, **rp;
 
635
        int lastreg;
 
636
        int reg;
 
637
 
 
638
        if (p->n_op == CM) {
 
639
                p->n_left = moveargs(p->n_left, regp);
 
640
                r = p->n_right;
 
641
                rp = &p->n_right;
 
642
        } else {
 
643
                r = p;
 
644
                rp = &p;
 
645
        }
 
646
 
 
647
        lastreg = A0 + nargregs - 1;
 
648
        reg = *regp;
 
649
 
 
650
        if (reg > lastreg && r->n_op != STARG)
 
651
                *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
 
652
        else if (r->n_op == STARG) {
 
653
                *rp = movearg_struct(r, p, regp);
 
654
        } else if (DEUNSIGN(r->n_type) == LONGLONG) {
 
655
                *rp = movearg_64bit(r, regp);
 
656
        } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
 
657
                /* XXX bounce in and out of temporary to change to longlong */
 
658
                NODE *t1 = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
 
659
                int tmpnr = regno(t1);
 
660
                NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
 
661
                t1 =  movearg_64bit(t1, regp);
 
662
                r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
 
663
                if (p->n_op == CM) {
 
664
                        p->n_left = buildtree(CM, p->n_left, t1);
 
665
                        p->n_right = r;
 
666
                } else {
 
667
                        p = buildtree(CM, t1, r);
 
668
                }
 
669
        } else if (r->n_type == FLOAT) {
 
670
                /* XXX bounce in and out of temporary to change to int */
 
671
                NODE *t1 = tempnode(0, INT, 0, MKAP(INT));
 
672
                int tmpnr = regno(t1);
 
673
                NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
 
674
                t1 =  movearg_32bit(t1, regp);
 
675
                r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
 
676
                if (p->n_op == CM) {
 
677
                        p->n_left = buildtree(CM, p->n_left, t1);
 
678
                        p->n_right = r;
 
679
                } else {
 
680
                        p = buildtree(CM, t1, r);
 
681
                }
 
682
        } else {
 
683
                *rp = movearg_32bit(r, regp);
 
684
        }
 
685
 
 
686
        return p;
 
687
}
 
688
 
 
689
/*
 
690
 * Called with a function call with arguments as argument.
 
691
 * This is done early in buildtree() and only done once.
 
692
 */
 
693
NODE *
 
694
funcode(NODE *p)
 
695
{
 
696
        int regnum = A0;
 
697
        NODE *l, *r, *t, *q;
 
698
        int ty;
 
699
 
 
700
        l = p->n_left;
 
701
        r = p->n_right;
 
702
 
 
703
        /*
 
704
         * if returning a structure, make the first argument
 
705
         * a hidden pointer to return structure.
 
706
         */
 
707
        ty = DECREF(l->n_type);
 
708
        if (ty == STRTY+FTN || ty == UNIONTY+FTN) {
 
709
                ty = DECREF(l->n_type) - FTN;
 
710
                q = tempnode(0, ty, l->n_df, l->n_ap);
 
711
                q = buildtree(ADDROF, q, NIL);
 
712
                if (r->n_op != CM) {
 
713
                        p->n_right = block(CM, q, r, INCREF(ty),
 
714
                            l->n_df, l->n_ap);
 
715
                } else {
 
716
                        for (t = r; t->n_left->n_op == CM; t = t->n_left)
 
717
                                ;
 
718
                        t->n_left = block(CM, q, t->n_left, INCREF(ty),
 
719
                            l->n_df, l->n_ap);
 
720
                }
 
721
        }
 
722
 
 
723
        p->n_right = moveargs(p->n_right, &regnum);
 
724
 
 
725
        return p;
 
726
}