source: mainline/uspace/app/pcc/arch/amd64/code.c@ 48fa501

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 48fa501 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: 23.6 KB
RevLine 
[a7de7182]1/* $Id: code.c,v 1.49 2011/01/29 14:55:33 ragge Exp $ */
2/*
3 * Copyright (c) 2008 Michael Shalayeff
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# include "pass1.h"
32
33static int nsse, ngpr, nrsp, rsaoff;
34static int thissse, thisgpr, thisrsp;
35enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87, STRREG, STRMEM, STRCPX };
36static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 };
37/*
38 * The Register Save Area looks something like this.
39 * It is put first on stack with fixed offsets.
40 * struct {
41 * long regs[6];
42 * double xmm[8][2]; // 16 byte in width
43 * };
44 */
45#define RSASZ (6*SZLONG+8*2*SZDOUBLE)
46#define RSALONGOFF(x) (RSASZ-(x)*SZLONG)
47#define RSADBLOFF(x) ((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
48/* va_list */
49#define VAARGSZ (SZINT*2+SZPOINT(CHAR)*2)
50#define VAGPOFF(x) (x)
51#define VAFPOFF(x) (x-SZINT)
52#define VAOFA(x) (x-SZINT-SZINT)
53#define VARSA(x) (x-SZINT-SZINT-SZPOINT(0))
54
55int lastloc = -1;
56static int stroffset;
57
58static int varneeds;
59#define NEED_GPNEXT 001
60#define NEED_FPNEXT 002
61#define NEED_1REGREF 004
62#define NEED_2REGREF 010
63#define NEED_MEMREF 020
64
65static int argtyp(TWORD t, union dimfun *df, struct attr *ap);
66static NODE *movtomem(NODE *p, int off, int reg);
67static NODE *movtoreg(NODE *p, int rno);
68void varattrib(char *name, struct attr *sap);
69
70/*
71 * Define everything needed to print out some data (or text).
72 * This means segment, alignment, visibility, etc.
73 */
74void
75defloc(struct symtab *sp)
76{
77 extern char *nextsect;
78 static char *loctbl[] = { "text", "data", "section .rodata" };
79 extern int tbss;
80 char *name;
81 TWORD t;
82 int s;
83
84 if (sp == NULL) {
85 lastloc = -1;
86 return;
87 }
88 if (kflag) {
89#ifdef MACHOABI
90 loctbl[DATA] = "section .data.rel.rw,\"aw\"";
91 loctbl[RDATA] = "section .data.rel.ro,\"aw\"";
92#else
93 loctbl[DATA] = "section .data.rel.rw,\"aw\",@progbits";
94 loctbl[RDATA] = "section .data.rel.ro,\"aw\",@progbits";
95#endif
96 }
97 t = sp->stype;
98 s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
99 if ((name = sp->soname) == NULL)
100 name = exname(sp->sname);
101
102 if (sp->sflags & STLS) {
103 if (s != DATA)
104 cerror("non-data symbol in tls section");
105 if (tbss)
106 nextsect = ".tbss,\"awT\",@nobits";
107 else
108 nextsect = ".tdata,\"awT\",@progbits";
109 tbss = 0;
110 lastloc = -1;
111 }
112
113 varattrib(name, sp->sap);
114
115 if (nextsect) {
116 printf(" .section %s\n", nextsect);
117 nextsect = NULL;
118 s = -1;
119 } else if (s != lastloc)
120 printf(" .%s\n", loctbl[s]);
121 lastloc = s;
122 while (ISARY(t))
123 t = DECREF(t);
124 s = ISFTN(t) ? ALINT : talign(t, sp->sap);
125 if (s > ALCHAR)
126 printf(" .align %d\n", s/ALCHAR);
127 if (sp->sclass == EXTDEF) {
128 printf("\t.globl %s\n", name);
129#ifndef MACHOABI
130 printf("\t.type %s,@%s\n", name,
131 ISFTN(t)? "function" : "object");
132#endif
133 }
134 if (sp->slevel == 0)
135 printf("%s:\n", name);
136 else
137 printf(LABFMT ":\n", sp->soffset);
138}
139
140/*
141 * Print out variable attributes.
142 */
143void
144varattrib(char *name, struct attr *sap)
145{
146 extern char *nextsect;
147 struct attr *ga;
148
149 if ((ga = attr_find(sap, GCC_ATYP_SECTION)) != NULL)
150 nextsect = ga->sarg(0);
151 if ((ga = attr_find(sap, GCC_ATYP_WEAK)) != NULL)
152 printf(" .weak %s\n", name);
153 if (attr_find(sap, GCC_ATYP_DESTRUCTOR)) {
154 printf("\t.section\t.dtors,\"aw\",@progbits\n");
155 printf("\t.align 8\n\t.quad\t%s\n", name);
156 lastloc = -1;
157 }
158 if (attr_find(sap, GCC_ATYP_CONSTRUCTOR)) {
159 printf("\t.section\t.ctors,\"aw\",@progbits\n");
160 printf("\t.align 8\n\t.quad\t%s\n", name);
161 lastloc = -1;
162 }
163 if ((ga = attr_find(sap, GCC_ATYP_VISIBILITY)) &&
164 strcmp(ga->sarg(0), "default"))
165 printf("\t.%s %s\n", ga->sarg(0), name);
166 if ((ga = attr_find(sap, GCC_ATYP_ALIASWEAK))) {
167 printf(" .weak %s\n", ga->sarg(0));
168 printf(" .set %s,%s\n", ga->sarg(0), name);
169 }
170}
171
172/*
173 * code for the end of a function
174 * deals with struct return here
175 * The return value is in (or pointed to by) RETREG.
176 */
177void
178efcode()
179{
180 struct symtab *sp;
181 extern int gotnr;
182 TWORD t;
183 NODE *p, *r, *l;
184 int typ, ssz, rno;
185
186 gotnr = 0; /* new number for next fun */
187 sp = cftnsp;
188 t = DECREF(sp->stype);
189 if (t != STRTY && t != UNIONTY)
190 return;
191
192 /* XXX should have one routine for this */
193 if ((typ = argtyp(t, sp->sdf, sp->sap)) == STRREG || typ == STRCPX) {
194 /* Cast to long pointer and move to the registers */
195 /* XXX can overrun struct size */
196 /* XXX check carefully for SSE members */
197
198 if ((ssz = tsize(t, sp->sdf, sp->sap)) > SZLONG*2)
199 cerror("efcode1");
200
201 if (typ == STRCPX) {
202 t = DOUBLE;
203 rno = XMM0;
204 } else {
205 t = LONG;
206 rno = RAX;
207 }
208 if (ssz > SZLONG) {
209 p = block(REG, NIL, NIL, INCREF(t), 0, MKAP(t));
210 regno(p) = RAX;
211 p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
212 ecomp(movtoreg(p, rno+1));
213 }
214 p = block(REG, NIL, NIL, INCREF(t), 0, MKAP(t));
215 regno(p) = RAX;
216 p = buildtree(UMUL, p, NIL);
217 ecomp(movtoreg(p, rno));
218 } else if (typ == STRMEM) {
219 r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap);
220 regno(r) = RAX;
221 r = buildtree(UMUL, r, NIL);
222 l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap);
223 l = buildtree(UMUL, l, NIL);
224 ecomp(buildtree(ASSIGN, l, r));
225 l = block(REG, NIL, NIL, LONG, 0, MKAP(LONG));
226 regno(l) = RAX;
227 r = tempnode(stroffset, LONG, 0, MKAP(LONG));
228 ecomp(buildtree(ASSIGN, l, r));
229 } else
230 cerror("efcode");
231}
232
233/*
234 * code for the beginning of a function; a is an array of
235 * indices in symtab for the arguments; n is the number
236 */
237void
238bfcode(struct symtab **s, int cnt)
239{
240 union arglist *al;
241 struct symtab *sp;
242 NODE *p, *r;
243 TWORD t;
244 int i, rno, typ;
245
246 /* recalculate the arg offset and create TEMP moves */
247 /* Always do this for reg, even if not optimizing, to free arg regs */
248 nsse = ngpr = 0;
249 nrsp = ARGINIT;
250 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
251 sp = cftnsp;
252 if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) {
253 r = block(REG, NIL, NIL, LONG, 0, MKAP(LONG));
254 regno(r) = argregsi[ngpr++];
255 p = tempnode(0, r->n_type, r->n_df, r->n_ap);
256 stroffset = regno(p);
257 ecomp(buildtree(ASSIGN, p, r));
258 }
259 }
260
261 for (i = 0; i < cnt; i++) {
262 sp = s[i];
263
264 if (sp == NULL)
265 continue; /* XXX when happens this? */
266
267 switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) {
268 case INTEGER:
269 case SSE:
270 if (typ == SSE)
271 rno = XMM0 + nsse++;
272 else
273 rno = argregsi[ngpr++];
274 r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap);
275 regno(r) = rno;
276 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
277 sp->soffset = regno(p);
278 sp->sflags |= STNODE;
279 ecomp(buildtree(ASSIGN, p, r));
280 break;
281
282 case SSEMEM:
283 sp->soffset = nrsp;
284 nrsp += SZDOUBLE;
285 if (xtemps) {
286 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
287 p = buildtree(ASSIGN, p, nametree(sp));
288 sp->soffset = regno(p->n_left);
289 sp->sflags |= STNODE;
290 ecomp(p);
291 }
292 break;
293
294 case INTMEM:
295 sp->soffset = nrsp;
296 nrsp += SZLONG;
297 if (xtemps) {
298 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
299 p = buildtree(ASSIGN, p, nametree(sp));
300 sp->soffset = regno(p->n_left);
301 sp->sflags |= STNODE;
302 ecomp(p);
303 }
304 break;
305
306 case STRMEM: /* Struct in memory */
307 sp->soffset = nrsp;
308 nrsp += tsize(sp->stype, sp->sdf, sp->sap);
309 break;
310
311 case X87: /* long double args */
312 sp->soffset = nrsp;
313 nrsp += SZLDOUBLE;
314 break;
315
316 case STRCPX:
317 case STRREG: /* Struct in register */
318 /* Allocate space on stack for the struct */
319 /* For simplicity always fetch two longwords */
320 autooff += (2*SZLONG);
321
322 if (typ == STRCPX) {
323 t = DOUBLE;
324 rno = XMM0 + nsse++;
325 } else {
326 t = LONG;
327 rno = argregsi[ngpr++];
328 }
329 r = block(REG, NIL, NIL, t, 0, MKAP(t));
330 regno(r) = rno;
331 ecomp(movtomem(r, -autooff, FPREG));
332
333 if (tsize(sp->stype, sp->sdf, sp->sap) > SZLONG) {
334 r = block(REG, NIL, NIL, t, 0, MKAP(t));
335 regno(r) = (typ == STRCPX ?
336 XMM0 + nsse++ : argregsi[ngpr++]);
337 ecomp(movtomem(r, -autooff+SZLONG, FPREG));
338 }
339
340 sp->soffset = -autooff;
341 break;
342
343 default:
344 cerror("bfcode: %d", typ);
345 }
346 }
347
348 /* Check if there are varargs */
349 if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
350 return; /* no prototype */
351 al = cftnsp->sdf->dfun;
352
353 for (; al->type != TELLIPSIS; al++) {
354 t = al->type;
355 if (t == TNULL)
356 return;
357 if (BTYPE(t) == STRTY || BTYPE(t) == UNIONTY)
358 al++;
359 for (; t > BTMASK; t = DECREF(t))
360 if (ISARY(t) || ISFTN(t))
361 al++;
362 }
363
364 /* fix stack offset */
365 SETOFF(autooff, ALMAX);
366
367 /* Save reg arguments in the reg save area */
368 p = NIL;
369 for (i = ngpr; i < 6; i++) {
370 r = block(REG, NIL, NIL, LONG, 0, MKAP(LONG));
371 regno(r) = argregsi[i];
372 r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG);
373 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKAP(INT)));
374 }
375 for (i = nsse; i < 8; i++) {
376 r = block(REG, NIL, NIL, DOUBLE, 0, MKAP(DOUBLE));
377 regno(r) = i + XMM0;
378 r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG);
379 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKAP(INT)));
380 }
381 autooff += RSASZ;
382 rsaoff = autooff;
383 thissse = nsse;
384 thisgpr = ngpr;
385 thisrsp = nrsp;
386
387 ecomp(p);
388}
389
390
391/*
392 * by now, the automatics and register variables are allocated
393 */
394void
395bccode()
396{
397 SETOFF(autooff, SZINT);
398}
399
400/* called just before final exit */
401/* flag is 1 if errors, 0 if none */
402void
403ejobcode(int flag )
404{
405 if (flag)
406 return;
407
408#ifdef MACHOAPI
409#define PT(x)
410#else
411#define PT(x) printf(".type __pcc_" x ",@function\n")
412#endif
413
414 /* printout varargs routines if used */
415 if (varneeds & NEED_GPNEXT) {
416 printf(".text\n.align 4\n");
417 PT("gpnext");
418 printf("__pcc_gpnext:\n");
419 printf("cmpl $48,(%%rdi)\njae 1f\n");
420 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
421 printf("movq (%%rax),%%rax\naddl $8,(%%rdi)\nret\n");
422 printf("1:movq 8(%%rdi),%%rax\nmovq (%%rax),%%rax\n");
423 printf("addq $8,8(%%rdi)\nret\n");
424 }
425 if (varneeds & NEED_FPNEXT) {
426 printf(".text\n.align 4\n");
427 PT("fpnext");
428 printf("__pcc_fpnext:\n");
429 printf("cmpl $176,4(%%rdi)\njae 1f\n");
430 printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
431 printf("movsd (%%rax),%%xmm0\naddl $16,4(%%rdi)\nret\n");
432 printf("1:movq 8(%%rdi),%%rax\nmovsd (%%rax),%%xmm0\n");
433 printf("addq $8,8(%%rdi)\nret\n");
434 }
435 if (varneeds & NEED_1REGREF) {
436 printf(".text\n.align 4\n");
437 PT("1regref");
438 printf("__pcc_1regref:\n");
439 printf("cmpl $48,(%%rdi)\njae 1f\n");
440 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
441 printf("addl $8,(%%rdi)\nret\n");
442 printf("1:movq 8(%%rdi),%%rax\n");
443 printf("addq $8,8(%%rdi)\nret\n");
444 }
445 if (varneeds & NEED_2REGREF) {
446 printf(".text\n.align 4\n");
447 PT("2regref");
448 printf("__pcc_2regref:\n");
449 printf("cmpl $40,(%%rdi)\njae 1f\n");
450 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
451 printf("addl $16,(%%rdi)\nret\n");
452 printf("1:movq 8(%%rdi),%%rax\n");
453 printf("addq $16,8(%%rdi)\nret\n");
454 }
455 if (varneeds & NEED_MEMREF) {
456 printf(".text\n.align 4\n");
457 PT("memref");
458 printf("__pcc_memref:\n");
459 printf("movq 8(%%rdi),%%rax\n");
460 printf("addq %%rsi,8(%%rdi)\nret\n");
461 }
462
463
464#define _MKSTR(x) #x
465#define MKSTR(x) _MKSTR(x)
466#define OS MKSTR(TARGOS)
467#ifdef MACHOABI
468 printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
469#else
470 printf("\t.ident \"PCC: %s (%s)\"\n\t.end\n", PACKAGE_STRING, OS);
471#endif
472}
473
474/*
475 * Varargs stuff:
476 * The ABI says that va_list should be declared as this typedef.
477 * We handcraft it here and then just reference it.
478 *
479 * typedef struct {
480 * unsigned int gp_offset;
481 * unsigned int fp_offset;
482 * void *overflow_arg_area;
483 * void *reg_save_area;
484 * } __builtin_va_list[1];
485 *
486 * There are a number of asm routines printed out if varargs are used:
487 * long __pcc_gpnext(va) - get a gpreg value
488 * long __pcc_fpnext(va) - get a fpreg value
489 * void *__pcc_1regref(va) - get reference to a onereg struct
490 * void *__pcc_2regref(va) - get reference to a tworeg struct
491 * void *__pcc_memref(va,sz) - get reference to a large struct
492 */
493
494static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
495static char *gpnext, *fpnext, *_1regref, *_2regref, *memref;
496
497void
498bjobcode()
499{
500 struct symtab *sp;
501 struct rstack *rp;
502 NODE *p, *q;
503 char *c;
504
505 gp_offset = addname("gp_offset");
506 fp_offset = addname("fp_offset");
507 overflow_arg_area = addname("overflow_arg_area");
508 reg_save_area = addname("reg_save_area");
509
510 rp = bstruct(NULL, STNAME, NULL);
511 p = block(NAME, NIL, NIL, UNSIGNED, 0, MKAP(UNSIGNED));
512 soumemb(p, gp_offset, 0);
513 soumemb(p, fp_offset, 0);
514 p->n_type = VOID+PTR;
515 p->n_ap = MKAP(VOID);
516 soumemb(p, overflow_arg_area, 0);
517 soumemb(p, reg_save_area, 0);
518 nfree(p);
519 q = dclstruct(rp);
520 c = addname("__builtin_va_list");
521 p = block(LB, bdty(NAME, c), bcon(1), INT, 0, MKAP(INT));
522 p = tymerge(q, p);
523 p->n_sp = lookup(c, 0);
524 defid(p, TYPEDEF);
525 nfree(q);
526 nfree(p);
527
528 /* for the static varargs functions */
529#define MKN(vn, rn, tp) \
530 { vn = addname(rn); sp = lookup(vn, SNORMAL); \
531 sp->sclass = USTATIC; sp->stype = tp; }
532
533 MKN(gpnext, "__pcc_gpnext", FTN|LONG);
534 MKN(fpnext, "__pcc_fpnext", FTN|DOUBLE);
535 MKN(_1regref, "__pcc_1regref", FTN|VOID|(PTR<<TSHIFT));
536 MKN(_2regref, "__pcc_2regref", FTN|VOID|(PTR<<TSHIFT));
537 MKN(memref, "__pcc_memref", FTN|VOID|(PTR<<TSHIFT));
538}
539
540static NODE *
541mkstkref(int off, TWORD typ)
542{
543 NODE *p;
544
545 p = block(REG, NIL, NIL, PTR|typ, 0, MKAP(LONG));
546 regno(p) = FPREG;
547 return buildtree(PLUS, p, bcon(off/SZCHAR));
548}
549
550NODE *
551amd64_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
552{
553 NODE *p, *r;
554
555 /* use the values from the function header */
556 p = a->n_left;
557 r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area),
558 mkstkref(-rsaoff, VOID));
559 r = buildtree(COMOP, r,
560 buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area),
561 mkstkref(thisrsp, VOID)));
562 r = buildtree(COMOP, r,
563 buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset),
564 bcon(thisgpr*(SZLONG/SZCHAR))));
565 r = buildtree(COMOP, r,
566 buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset),
567 bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
568
569 tfree(f);
570 tfree(a);
571 return r;
572}
573
574NODE *
575amd64_builtin_va_arg(NODE *f, NODE *a, TWORD t)
576{
577 NODE *ap, *r, *dp;
578
579 ap = a->n_left;
580 dp = a->n_right;
581 if (dp->n_type <= ULONGLONG || ISPTR(dp->n_type) ||
582 dp->n_type == FLOAT || dp->n_type == DOUBLE) {
583 /* type might be in general register */
584 if (dp->n_type == FLOAT || dp->n_type == DOUBLE) {
585 f->n_sp = lookup(fpnext, SNORMAL);
586 varneeds |= NEED_FPNEXT;
587 } else {
588 f->n_sp = lookup(gpnext, SNORMAL);
589 varneeds |= NEED_GPNEXT;
590 }
591 f->n_type = f->n_sp->stype = INCREF(dp->n_type) + (FTN-PTR);
592 f->n_ap = dp->n_ap;
593 f->n_df = /* dp->n_df */ NULL;
594 f = clocal(f);
595 r = buildtree(CALL, f, ccopy(ap));
596 } else if (ISSOU(dp->n_type) || dp->n_type == LDOUBLE) {
597 /* put a reference directly to the stack */
598 int sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
599 int al = talign(dp->n_type, dp->n_ap);
600 if (al < ALLONG)
601 al = ALLONG;
602 if (sz <= SZLONG*2 && al == ALLONG) {
603 if (sz <= SZLONG) {
604 f->n_sp = lookup(_1regref, SNORMAL);
605 varneeds |= NEED_1REGREF;
606 } else {
607 f->n_sp = lookup(_2regref, SNORMAL);
608 varneeds |= NEED_2REGREF;
609 }
610 f->n_type = f->n_sp->stype;
611 f = clocal(f);
612 r = buildtree(CALL, f, ccopy(ap));
613 r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
614 r = buildtree(UMUL, r, NIL);
615 } else {
616 f->n_sp = lookup(memref, SNORMAL);
617 varneeds |= NEED_MEMREF;
618 f->n_type = f->n_sp->stype;
619 f = clocal(f);
620 SETOFF(sz, al);
621 r = buildtree(CALL, f,
622 buildtree(CM, ccopy(ap), bcon(sz/SZCHAR)));
623 r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
624 r = buildtree(UMUL, r, NIL);
625 }
626 } else {
627 uerror("amd64_builtin_va_arg not supported type");
628 goto bad;
629 }
630 tfree(a);
631 return r;
632bad:
633 uerror("bad argument to __builtin_va_arg");
634 return bcon(0);
635}
636
637NODE *
638amd64_builtin_va_end(NODE *f, NODE *a, TWORD t)
639{
640 tfree(f);
641 tfree(a);
642 return bcon(0); /* nothing */
643}
644
645NODE *
646amd64_builtin_va_copy(NODE *f, NODE *a, TWORD t)
647{
648 tfree(f);
649 f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL),
650 buildtree(UMUL, a->n_right, NIL));
651 nfree(a);
652 return f;
653}
654
655static NODE *
656movtoreg(NODE *p, int rno)
657{
658 NODE *r;
659
660 r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
661 regno(r) = rno;
662 return clocal(buildtree(ASSIGN, r, p));
663}
664
665static NODE *
666movtomem(NODE *p, int off, int reg)
667{
668 struct symtab s;
669 NODE *r, *l;
670
671 s.stype = p->n_type;
672 s.squal = 0;
673 s.sdf = p->n_df;
674 s.sap = p->n_ap;
675 s.soffset = off;
676 s.sclass = AUTO;
677
678 l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
679 l->n_lval = 0;
680 regno(l) = reg;
681
682 r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
683 r->n_sp = &s;
684 r = stref(block(STREF, l, r, 0, 0, 0));
685
686 return clocal(buildtree(ASSIGN, r, p));
687}
688
689
690/*
691 * AMD64 parameter classification.
692 */
693static int
694argtyp(TWORD t, union dimfun *df, struct attr *ap)
695{
696 int cl = 0;
697
698 if (t <= ULONG || ISPTR(t) || t == BOOL) {
699 cl = ngpr < 6 ? INTEGER : INTMEM;
700 } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
701 cl = nsse < 8 ? SSE : SSEMEM;
702 } else if (t == LDOUBLE || t == LIMAG) {
703 cl = X87; /* XXX */
704 } else if (t == STRTY || t == UNIONTY) {
705 int sz = tsize(t, df, ap);
706
707 if (sz <= 2*SZLONG && attr_find(ap, ATTR_COMPLEX) != NULL) {
708 cl = nsse < 7 ? STRCPX : STRMEM;
709 } else if (sz > 2*SZLONG || ((sz+SZLONG)/SZLONG)+ngpr > 6 ||
710 attr_find(ap, GCC_ATYP_PACKED) != NULL)
711 cl = STRMEM;
712 else
713 cl = STRREG;
714 } else
715 cerror("FIXME: classify");
716 return cl;
717}
718
719/*
720 * Do the "hard work" in assigning correct destination for arguments.
721 * Also convert arguments < INT to inte (default argument promotions).
722 * XXX - should be dome elsewhere.
723 */
724static NODE *
725argput(NODE *p)
726{
727 NODE *q;
728 TWORD ty;
729 int typ, r, ssz;
730
731 if (p->n_op == CM) {
732 p->n_left = argput(p->n_left);
733 p->n_right = argput(p->n_right);
734 return p;
735 }
736
737 /* first arg may be struct return pointer */
738 /* XXX - check if varargs; setup al */
739 switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) {
740 case INTEGER:
741 case SSE:
742 if (typ == SSE)
743 r = XMM0 + nsse++;
744 else
745 r = argregsi[ngpr++];
746 if (p->n_type < INT || p->n_type == BOOL)
747 p = cast(p, INT, 0);
748 p = movtoreg(p, r);
749 break;
750
751 case X87:
752 r = nrsp;
753 nrsp += SZLDOUBLE;
754 p = movtomem(p, r, STKREG);
755 break;
756
757 case SSEMEM:
758 r = nrsp;
759 nrsp += SZDOUBLE;
760 p = movtomem(p, r, STKREG);
761 break;
762
763 case INTMEM:
764 r = nrsp;
765 nrsp += SZLONG;
766 p = movtomem(p, r, STKREG);
767 break;
768
769 case STRCPX:
770 case STRREG: /* Struct in registers */
771 /* Cast to long pointer and move to the registers */
772 /* XXX can overrun struct size */
773 /* XXX check carefully for SSE members */
774 ssz = tsize(p->n_type, p->n_df, p->n_ap);
775
776 if (typ == STRCPX) {
777 ty = DOUBLE;
778 r = XMM0 + nsse++;
779 } else {
780 ty = LONG;
781 r = argregsi[ngpr++];
782 }
783 if (ssz <= SZLONG) {
784 q = cast(p->n_left, INCREF(ty), 0);
785 nfree(p);
786 q = buildtree(UMUL, q, NIL);
787 p = movtoreg(q, r);
788 } else if (ssz <= SZLONG*2) {
789 NODE *ql, *qr;
790
791 qr = cast(ccopy(p->n_left), INCREF(ty), 0);
792 qr = movtoreg(buildtree(UMUL, qr, NIL), r);
793
794 ql = cast(p->n_left, INCREF(ty), 0);
795 ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL);
796 r = (typ == STRCPX ? XMM0 + nsse++ : argregsi[ngpr++]);
797 ql = movtoreg(ql, r);
798
799 nfree(p);
800 p = buildtree(CM, ql, qr);
801 } else
802 cerror("STRREG");
803 break;
804
805 case STRMEM: {
806 struct symtab s;
807 NODE *l, *t;
808
809 q = buildtree(UMUL, p->n_left, NIL);
810
811 s.stype = p->n_type;
812 s.squal = 0;
813 s.sdf = p->n_df;
814 s.sap = p->n_ap;
815 s.soffset = nrsp;
816 s.sclass = AUTO;
817
818 nrsp += tsize(p->n_type, p->n_df, p->n_ap);
819
820 l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
821 l->n_lval = 0;
822 regno(l) = STKREG;
823
824 t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
825 t->n_sp = &s;
826 t = stref(block(STREF, l, t, 0, 0, 0));
827
828 t = (buildtree(ASSIGN, t, q));
829 nfree(p);
830 p = t->n_left;
831 nfree(t);
832 break;
833 }
834
835 default:
836 cerror("argument %d", typ);
837 }
838 return p;
839}
840
841/*
842 * Sort arglist so that register assignments ends up last.
843 */
844static int
845argsort(NODE *p)
846{
847 NODE *q, *r;
848 int rv = 0;
849
850 if (p->n_op != CM) {
851 if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
852 coptype(p->n_right->n_op) != LTYPE) {
853 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
854 r = ccopy(q);
855 p->n_right = buildtree(COMOP,
856 buildtree(ASSIGN, q, p->n_right), r);
857 }
858 return rv;
859 }
860 if (p->n_right->n_op == CM) {
861 /* fixup for small structs in regs */
862 q = p->n_right->n_left;
863 p->n_right->n_left = p->n_left;
864 p->n_left = p->n_right;
865 p->n_right = q;
866 }
867 if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
868 coptype(p->n_right->n_right->n_op) != LTYPE) {
869 /* move before everything to avoid reg trashing */
870 q = tempnode(0, p->n_right->n_type,
871 p->n_right->n_df, p->n_right->n_ap);
872 r = ccopy(q);
873 p->n_right->n_right = buildtree(COMOP,
874 buildtree(ASSIGN, q, p->n_right->n_right), r);
875 }
876 if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
877 if (p->n_left->n_op == CM &&
878 p->n_left->n_right->n_op == STASG) {
879 q = p->n_left->n_right;
880 p->n_left->n_right = p->n_right;
881 p->n_right = q;
882 rv = 1;
883 } else if (p->n_left->n_op == STASG) {
884 q = p->n_left;
885 p->n_left = p->n_right;
886 p->n_right = q;
887 rv = 1;
888 }
889 }
890 return rv | argsort(p->n_left);
891}
892
893/*
894 * Called with a function call with arguments as argument.
895 * This is done early in buildtree() and only done once.
896 * Returns p.
897 */
898NODE *
899funcode(NODE *p)
900{
901 NODE *l, *r;
902 TWORD t;
903
904 nsse = ngpr = nrsp = 0;
905 /* Check if hidden arg needed */
906 /* If so, add it in pass2 */
907 if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
908 l->n_type == INCREF(FTN)+UNIONTY) {
909 int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap);
910 if (ssz > 2*SZLONG)
911 ngpr++;
912 }
913
914 /* Convert just regs to assign insn's */
915 p->n_right = argput(p->n_right);
916
917 /* Must sort arglist so that STASG ends up first */
918 /* This avoids registers being clobbered */
919 while (argsort(p->n_right))
920 ;
921 /* Check if there are varargs */
922 if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
923 ; /* Need RAX */
924 } else {
925 union arglist *al = l->n_df->dfun;
926
927 for (; al->type != TELLIPSIS; al++) {
928 if ((t = al->type) == TNULL)
929 return p; /* No need */
930 if (BTYPE(t) == STRTY || BTYPE(t) == UNIONTY)
931 al++;
932 for (; t > BTMASK; t = DECREF(t))
933 if (ISARY(t) || ISFTN(t))
934 al++;
935 }
936 }
937
938 /* Always emit number of SSE regs used */
939 l = movtoreg(bcon(nsse), RAX);
940 if (p->n_right->n_op != CM) {
941 p->n_right = block(CM, l, p->n_right, INT, 0, MKAP(INT));
942 } else {
943 for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
944 ;
945 r->n_left = block(CM, l, r->n_left, INT, 0, MKAP(INT));
946 }
947 return p;
948}
949
950/*
951 * return the alignment of field of type t
952 */
953int
954fldal(unsigned int t)
955{
956 uerror("illegal field type");
957 return(ALINT);
958}
959
960/* fix up type of field p */
961void
962fldty(struct symtab *p)
963{
964}
965
966/*
967 * XXX - fix genswitch.
968 */
969int
970mygenswitch(int num, TWORD type, struct swents **p, int n)
971{
972 return 0;
973}
Note: See TracBrowser for help on using the repository browser.