1
/* $Id: code.c,v 1.17 2010/09/19 14:01:35 ragge Exp $ */
3
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
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
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.
31
* MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
32
* Simon Olsson (simols-1@student.ltu.se) 2005.
39
* Define everything needed to print out some data (or text).
40
* This means segment, alignment, visibility, etc.
43
defloc(struct symtab *sp)
45
static char *loctbl[] = { "text", "data", "section .rodata" };
46
static int lastloc = -1;
56
s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
59
return; /* text is written in prologue() */
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) {
68
printf("\t.type %s,@object\n", n);
69
printf("\t.size %s," CONFMT "\n", n,
70
tsize(sp->stype, sp->sdf, sp->sap));
74
printf(LABFMT ":\n", sp->soffset);
80
* cause the alignment to become a multiple of n
81
* never called for text segment.
86
n = ispow2(n / SZCHAR);
88
cerror("defalign: n != 2^i");
89
printf("\t.p2align %d\n", n);
93
* define the current location as the name p->sname
94
* never called for text segment.
97
defnam(struct symtab *p)
101
if (p->sclass == EXTDEF)
102
printf("\t.globl %s\n", c);
104
printf("\t.type %s,@object\n", c);
105
printf("\t.size %s," CONFMT "\n", c, tsize(p->stype, p->sdf, p->sap));
114
* code for the end of a function
115
* deals with struct return here
124
if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
127
ty = cftnsp->stype - FTN;
129
q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
131
p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
133
p = buildtree(ASSIGN, p, q);
136
q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
137
q = buildtree(UMUL, q, NIL);
139
p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
140
p = buildtree(UMUL, p, NIL);
142
p = buildtree(ASSIGN, p, q);
145
q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
146
p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
148
p = buildtree(ASSIGN, p, q);
152
/* Put a symbol in a temporary
153
* used by bfcode() and its helpers */
155
putintemp(struct symtab *sym)
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;
165
/* setup the hidden pointer to struct return parameter
166
* used by bfcode() */
172
p = tempnode(0, PTR+STRTY, 0, cftnsp->sap);
174
q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
176
p = buildtree(ASSIGN, p, q);
180
/* setup struct parameter
181
* push the registers out to memory
182
* used by bfcode() */
184
param_struct(struct symtab *sym, int *regp)
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));
201
p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
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);
212
/* setup a 64-bit parameter (double/ldouble/longlong)
213
* used by bfcode() */
215
param_64bit(struct symtab *sym, int *regp, int dotemps)
225
navail = nargregs - (reg - A0);
228
/* would have appeared half in registers/half
229
* on the stack, but alignment ensures it
230
* appears on the stack */
237
q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
238
q->n_rval = A0A1 + (reg - A0);
240
p = tempnode(0, sym->stype, sym->sdf, sym->sap);
241
sym->soffset = regno(p);
242
sym->sflags |= STNODE;
246
p = buildtree(ASSIGN, p, q);
251
/* setup a 32-bit param on the stack
252
* used by bfcode() */
254
param_32bit(struct symtab *sym, int *regp, int dotemps)
258
q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
259
q->n_rval = (*regp)++;
261
p = tempnode(0, sym->stype, sym->sdf, sym->sap);
262
sym->soffset = regno(p);
263
sym->sflags |= STNODE;
267
p = buildtree(ASSIGN, p, q);
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.
277
param_double(struct symtab *sym, int *regp, int dotemps)
288
navail = nargregs - (reg - A0);
291
/* would have appeared half in registers/half
292
* on the stack, but alignment ensures it
293
* appears on the stack */
300
t = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
302
q = block(REG, NIL, NIL, LONGLONG, 0, MKAP(LONGLONG));
303
q->n_rval = A0A1 + (reg - A0);
304
p = buildtree(ASSIGN, t, q);
308
sym->soffset = tmpnr;
309
sym->sflags |= STNODE;
311
q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
313
p = buildtree(ASSIGN, p, q);
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.
325
param_float(struct symtab *sym, int *regp, int dotemps)
330
t = tempnode(0, INT, 0, MKAP(INT));
332
q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
333
q->n_rval = (*regp)++;
334
p = buildtree(ASSIGN, t, q);
338
sym->soffset = tmpnr;
339
sym->sflags |= STNODE;
341
q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
343
p = buildtree(ASSIGN, p, q);
349
* code for the beginning of a function; a is an array of
350
* indices in symtab for the arguments; n is the number
353
bfcode(struct symtab **sp, int cnt)
356
int lastreg = A0 + nargregs - 1;
361
* Detect if this function has ellipses and save all
362
* argument register onto stack.
364
usym = cftnsp->sdf->dfun;
365
while (usym && usym->type != TNULL) {
366
if (usym->type == TELLIPSIS) {
375
/* assign hidden return structure to temporary */
376
if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
381
/* recalculate the arg offset and create TEMP moves */
382
for (i = 0; i < cnt; i++) {
384
if ((reg > lastreg) && !xtemps)
386
else if (reg > lastreg)
388
else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY)
389
param_struct(sp[i], ®);
390
else if (DEUNSIGN(sp[i]->stype) == LONGLONG)
391
param_64bit(sp[i], ®, xtemps && !saveallargs);
392
else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE)
393
param_double(sp[i], ®, xtemps && !saveallargs);
394
else if (sp[i]->stype == FLOAT)
395
param_float(sp[i], ®, xtemps && !saveallargs);
397
param_32bit(sp[i], ®, xtemps && !saveallargs);
400
/* if saveallargs, save the rest of the args onto the stack */
403
while (reg <= lastreg) {
405
int off = ARGINIT/SZINT + (reg - A0);
406
q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
408
p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
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);
420
* by now, the automatics and register variables are allocated
425
SETOFF(autooff, SZINT);
428
/* called just before final exit */
429
/* flag is 1 if errors, 0 if none */
438
printf("\t.section .mdebug.abi32\n");
439
printf("\t.previous\n");
440
printf("\t.abicalls\n");
445
* Print character t at position i in one string, until t == -1.
446
* Locctr & label is already defined.
451
static int lastoctal = 0;
453
/* put byte i+1 in a string */
460
printf("\t.ascii \"");
463
else if (t == '\\' || t == '"') {
467
} else if (t == 011) {
469
} else if (t == 012) {
471
} else if (t < 040 || t >= 0177) {
474
} else if (lastoctal && '0' <= t && t <= '9') {
476
printf("\"\n\t.ascii \"%c", t);
486
* return the alignment of field of type t
489
fldal(unsigned int t)
491
uerror("illegal field type");
495
/* fix up type of field p */
497
fldty(struct symtab *p)
502
* XXX - fix genswitch.
505
mygenswitch(int num, TWORD type, struct swents **p, int n)
511
/* setup call stack with a structure */
512
/* called from moveargs() */
514
movearg_struct(NODE *p, NODE *parent, int *regp)
526
navail = nargregs - (reg - A0);
527
sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
528
num = sz > navail ? navail : sz;
533
t = tempnode(0, l->n_type, l->n_df, l->n_ap);
535
l = buildtree(ASSIGN, t, l);
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);
549
r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
552
r = buildtree(ASSIGN, r, t);
556
q = block(CM, q, r, INT, 0, MKAP(INT));
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);
565
r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
567
r = block(PLUS, r, bcon(4*off++), INT, 0, MKAP(INT));
568
r = block(UMUL, r, NIL, INT, 0, MKAP(INT));
570
r = buildtree(ASSIGN, r, t);
574
q = block(CM, q, r, INT, 0, MKAP(INT));
577
if (parent->n_op == CM) {
581
q = block(CM, q, l, INT, 0, MKAP(INT));
588
/* setup call stack with 64-bit argument */
589
/* called from moveargs() */
591
movearg_64bit(NODE *p, int *regp)
601
lastarg = A0 + nargregs - 1;
604
return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap);
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);
615
/* setup call stack with 32-bit argument */
616
/* called from moveargs() */
618
movearg_32bit(NODE *p, int *regp)
623
q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
625
q = buildtree(ASSIGN, q, p);
632
moveargs(NODE *p, int *regp)
639
p->n_left = moveargs(p->n_left, regp);
647
lastreg = A0 + nargregs - 1;
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);
664
p->n_left = buildtree(CM, p->n_left, t1);
667
p = buildtree(CM, t1, r);
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);
677
p->n_left = buildtree(CM, p->n_left, t1);
680
p = buildtree(CM, t1, r);
683
*rp = movearg_32bit(r, regp);
690
* Called with a function call with arguments as argument.
691
* This is done early in buildtree() and only done once.
704
* if returning a structure, make the first argument
705
* a hidden pointer to return structure.
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);
713
p->n_right = block(CM, q, r, INCREF(ty),
716
for (t = r; t->n_left->n_op == CM; t = t->n_left)
718
t->n_left = block(CM, q, t->n_left, INCREF(ty),
723
p->n_right = moveargs(p->n_right, ®num);