Quick Search:

Mode

Context

Displaying the whole file. None | Less | More | Full

Other Diffs

Ignore

Blank Lines Whitespace: Expand:

Diff

1.67
 
1.68
 
MAIN:ragge:20121228160312
 
code.c
_>11 /*      $Id$    */
 22 /*
 33  * Copyright (c) 2008 Michael Shalayeff
 44  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
 55  * All rights reserved.
 66  *
 77  * Redistribution and use in source and binary forms, with or without
 88  * modification, are permitted provided that the following conditions
 99  * are met:
 1010  * 1. Redistributions of source code must retain the above copyright
 1111  *    notice, this list of conditions and the following disclaimer.
 1212  * 2. Redistributions in binary form must reproduce the above copyright
 1313  *    notice, this list of conditions and the following disclaimer in the
 1414  *    documentation and/or other materials provided with the distribution.
 1515  * 3. The name of the author may not be used to endorse or promote products
 1616  *    derived from this software without specific prior written permission
 1717  *
 1818  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 1919  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 2020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 2121  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 2222  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 2323  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 2424  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 2525  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 2626  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 2727  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 2828  */
 2929 
 3030 
 3131 # include "pass1.h"
 3232 
 3333 static int nsse, ngpr, nrsp, rsaoff;
 3434 static int thissse, thisgpr, thisrsp;
 3535 enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87, STRREG, STRMEM, STRCPX };
 3636 static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 };
 3737 /*
 3838  * The Register Save Area looks something like this.
 3939  * It is put first on stack with fixed offsets.
 4040  * struct {
 4141  *      long regs[6];
 4242  *      double xmm[8][2]; // 16 byte in width
 4343  * };
 4444  */
 4545 #define RSASZ           (6*SZLONG+8*2*SZDOUBLE)
 4646 #define RSALONGOFF(x)   (RSASZ-(x)*SZLONG)
 4747 #define RSADBLOFF(x)    ((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
 4848 /* va_list */
 4949 #define VAARGSZ         (SZINT*2+SZPOINT(CHAR)*2)
 5050 #define VAGPOFF(x)      (x)
 5151 #define VAFPOFF(x)      (x-SZINT)
 5252 #define VAOFA(x)        (x-SZINT-SZINT)
 5353 #define VARSA(x)        (x-SZINT-SZINT-SZPOINT(0))
 5454 
 5555 static int stroffset;
 5656 
 5757 static int varneeds;
 5858 #define NEED_GPNEXT     001
 5959 #define NEED_FPNEXT     002
 6060 #define NEED_1REGREF    004
 6161 #define NEED_2REGREF    010
 6262 #define NEED_MEMREF     020
 6363 
 6464 static int argtyp(TWORD t, union dimfun *df, struct attr *ap);
 6565 static NODE *movtomem(NODE *p, int off, int reg);
 6666 static NODE *movtoreg(NODE *p, int rno);
 6767 void varattrib(char *name, struct attr *sap);
 6868 
 6969 /*
 7070  * Print out assembler segment name.
 7171  */
 7272 void
 7373 setseg(int seg, char *name)
 7474 {
 7575         switch (seg) {
 7676         case PROG: name = ".text"; break;
 7777         case DATA:
 7878         case LDATA: name = ".data"; break;
 7979         case STRNG:
 8080         case RDATA: name = ".section .rodata"; break;
 8181         case UDATA: break;
 8282 #ifdef MACHOABI
 8383         case PICLDATA:
 8484         case PICDATA: name = ".section .data.rel.rw,\"aw\""; break;
 8585         case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break;
 8686 #else
 8787         case PICLDATA:
 8888         case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
 8989         case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
 9090 #endif
 9191         case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
 9292         case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
 9393         case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
 9494         case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
 9595         case NMSEG:
 9696                 printf("\t.section %s,\"aw\",@progbits\n", name);
 9797                 return;
 9898         }
 9999         printf("\t%s\n", name);
 100100 }
 101101 
 102102 /*
 103103  * Define everything needed to print out some data (or text).
 104104  * This means segment, alignment, visibility, etc.
 105105  */
 106106 void
 107107 defloc(struct symtab *sp)
 108108 {
 109109         char *name;
 110110 
 111111         if ((name = sp->soname) == NULL)
 112112                 name = exname(sp->sname);
 113113 
 114114         if (sp->sclass == EXTDEF) {
 115115                 printf("\t.globl %s\n", name);
 116116 #ifndef MACHOABI
<>117 -                printf("\t.type %s,@%s\n", name,
 118 -                    ISFTN(sp->stype)? "function" : "object");
  117+                if (ISFTN(sp->stype)) {
  118+                        printf("\t.type %s,@function\n", name);
  119+                } else {
  120+                        printf("\t.type %s,@object\n", name);
  121+                        printf("\t.size %s,%d\n", name,
  122+                            (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
  123+                }
<_119124 #endif
 120125         }
 121126         if (sp->slevel == 0)
 122127                 printf("%s:\n", name);
 123128         else
 124129                 printf(LABFMT ":\n", sp->soffset);
 125130 }
 126131 
 127132 /*
 128133  * code for the end of a function
 129134  * deals with struct return here
 130135  * The return value is in (or pointed to by) RETREG.
 131136  */
 132137 void
 133138 efcode(void)
 134139 {
 135140         struct symtab *sp;
 136141         extern int gotnr;
 137142         TWORD t;
 138143         NODE *p, *r, *l;
 139144         int typ, ssz, rno;
 140145 
 141146         gotnr = 0;      /* new number for next fun */
 142147         sp = cftnsp;
 143148         t = DECREF(sp->stype);
 144149         if (t != STRTY && t != UNIONTY)
 145150                 return;
 146151 
 147152         /* XXX should have one routine for this */
 148153         ngpr = nsse = 0;
 149154         if ((typ = argtyp(t, sp->sdf, sp->sap)) == STRREG || typ == STRCPX) {
 150155                 /* Cast to long pointer and move to the registers */
 151156                 /* XXX can overrun struct size */
 152157                 /* XXX check carefully for SSE members */
 153158 
 154159                 if ((ssz = tsize(t, sp->sdf, sp->sap)) > SZLONG*2)
 155160                         cerror("efcode1");
 156161 
 157162                 if (typ == STRCPX) {
 158163                         t = DOUBLE;
 159164                         rno = XMM0;
 160165                 } else {
 161166                         t = LONG;
 162167                         rno = RAX;
 163168                 }
 164169                 if (ssz > SZLONG) {
 165170                         p = block(REG, NIL, NIL, INCREF(t), 0, 0);
 166171                         regno(p) = RAX;
 167172                         p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
 168173                         ecomp(movtoreg(p, rno+1));
 169174                 }
 170175                 p = block(REG, NIL, NIL, INCREF(t), 0, 0);
 171176                 regno(p) = RAX;
 172177                 p = buildtree(UMUL, p, NIL);
 173178                 ecomp(movtoreg(p, rno));
 174179         } else if (typ == STRMEM) {
 175180                 r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap);
 176181                 regno(r) = RAX;
 177182                 r = buildtree(UMUL, r, NIL);
 178183                 l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap);
 179184                 l = buildtree(UMUL, l, NIL);
 180185                 ecomp(buildtree(ASSIGN, l, r));
 181186                 l = block(REG, NIL, NIL, LONG, 0, 0);
 182187                 regno(l) = RAX;
 183188                 r = tempnode(stroffset, LONG, 0, 0);
 184189                 ecomp(buildtree(ASSIGN, l, r));
 185190         } else
 186191                 cerror("efcode");
 187192 }
 188193 
 189194 /*
 190195  * code for the beginning of a function; a is an array of
 191196  * indices in symtab for the arguments; n is the number
 192197  */
 193198 void
 194199 bfcode(struct symtab **s, int cnt)
 195200 {
 196201         union arglist *al;
 197202         struct symtab *sp;
 198203         NODE *p, *r;
 199204         TWORD t;
 200205         int i, rno, typ;
 201206 
 202207         /* recalculate the arg offset and create TEMP moves */
 203208         /* Always do this for reg, even if not optimizing, to free arg regs */
 204209         nsse = ngpr = 0;
 205210         nrsp = ARGINIT;
 206211         if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
 207212                 sp = cftnsp;
 208213                 if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) {
 209214                         r = block(REG, NIL, NIL, LONG, 0, 0);
 210215                         regno(r) = argregsi[ngpr++];
 211216                         p = tempnode(0, r->n_type, r->n_df, r->n_ap);
 212217                         stroffset = regno(p);
 213218                         ecomp(buildtree(ASSIGN, p, r));
 214219                 }
 215220         }
 216221 
 217222         for (i = 0; i < cnt; i++) {
 218223                 sp = s[i];
 219224 
 220225                 if (sp == NULL)
 221226                         continue; /* XXX when happens this? */
 222227 
 223228                 switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) {
 224229                 case INTEGER:
 225230                 case SSE:
 226231                         if (typ == SSE)
 227232                                 rno = XMM0 + nsse++;
 228233                         else
 229234                                 rno = argregsi[ngpr++];
 230235                         r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap);
 231236                         regno(r) = rno;
 232237                         p = tempnode(0, sp->stype, sp->sdf, sp->sap);
 233238                         sp->soffset = regno(p);
 234239                         sp->sflags |= STNODE;
 235240                         ecomp(buildtree(ASSIGN, p, r));
 236241                         break;
 237242 
 238243                 case SSEMEM:
 239244                         sp->soffset = nrsp;
 240245                         nrsp += SZDOUBLE;
 241246                         if (xtemps) {
 242247                                 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
 243248                                 p = buildtree(ASSIGN, p, nametree(sp));
 244249                                 sp->soffset = regno(p->n_left);
 245250                                 sp->sflags |= STNODE;
 246251                                 ecomp(p);
 247252                         }
 248253                         break;
 249254 
 250255                 case INTMEM:
 251256                         sp->soffset = nrsp;
 252257                         nrsp += SZLONG;
 253258                         if (xtemps) {
 254259                                 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
 255260                                 p = buildtree(ASSIGN, p, nametree(sp));
 256261                                 sp->soffset = regno(p->n_left);
 257262                                 sp->sflags |= STNODE;
 258263                                 ecomp(p);
 259264                         }
 260265                         break;
 261266 
 262267                 case STRMEM: /* Struct in memory */
 263268                         sp->soffset = nrsp;
 264269                         nrsp += tsize(sp->stype, sp->sdf, sp->sap);
 265270                         break;
 266271 
 267272                 case X87: /* long double args */
 268273                         sp->soffset = nrsp;
 269274                         nrsp += SZLDOUBLE;
 270275                         break;
 271276 
 272277                 case STRCPX:
 273278                 case STRREG: /* Struct in register */
 274279                         /* Allocate space on stack for the struct */
 275280                         /* For simplicity always fetch two longwords */
 276281                         autooff += (2*SZLONG);
 277282 
 278283                         if (typ == STRCPX) {
 279284                                 t = DOUBLE;
 280285                                 rno = XMM0 + nsse++;
 281286                         } else {
 282287                                 t = LONG;
 283288                                 rno = argregsi[ngpr++];
 284289                         }
 285290                         r = block(REG, NIL, NIL, t, 0, 0);
 286291                         regno(r) = rno;
 287292                         ecomp(movtomem(r, -autooff, FPREG));
 288293 
 289294                         if (tsize(sp->stype, sp->sdf, sp->sap) > SZLONG) {
 290295                                 r = block(REG, NIL, NIL, t, 0, 0);
 291296                                 regno(r) = (typ == STRCPX ?
 292297                                     XMM0 + nsse++ : argregsi[ngpr++]);
 293298                                 ecomp(movtomem(r, -autooff+SZLONG, FPREG));
 294299                         }
 295300 
 296301                         sp->soffset = -autooff;
 297302                         break;
 298303 
 299304                 default:
 300305                         cerror("bfcode: %d", typ);
 301306                 }
 302307         }
 303308 
 304309         /* Check if there are varargs */
 305310         if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
 306311                 return; /* no prototype */
 307312         al = cftnsp->sdf->dfun;
 308313 
 309314         for (; al->type != TELLIPSIS; al++) {
 310315                 t = al->type;
 311316                 if (t == TNULL)
 312317                         return;
 313318                 if (ISSOU(BTYPE(t)))
 314319                         al++;
 315320                 for (i = 0; t > BTMASK; t = DECREF(t))
 316321                         if (ISARY(t) || ISFTN(t))
 317322                                 i++;
 318323                 if (i)
 319324                         al++;
 320325         }
 321326 
 322327         /* fix stack offset */
 323328         SETOFF(autooff, ALMAX);
 324329 
 325330         /* Save reg arguments in the reg save area */
 326331         p = NIL;
 327332         for (i = ngpr; i < 6; i++) {
 328333                 r = block(REG, NIL, NIL, LONG, 0, 0);
 329334                 regno(r) = argregsi[i];
 330335                 r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG);
 331336                 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
 332337         }
 333338         for (i = nsse; i < 8; i++) {
 334339                 r = block(REG, NIL, NIL, DOUBLE, 0, 0);
 335340                 regno(r) = i + XMM0;
 336341                 r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG);
 337342                 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
 338343         }
 339344         autooff += RSASZ;
 340345         rsaoff = autooff;
 341346         thissse = nsse;
 342347         thisgpr = ngpr;
 343348         thisrsp = nrsp;
 344349 
 345350         ecomp(p);
 346351 }
 347352 
 348353 
 349354 /* called just before final exit */
 350355 /* flag is 1 if errors, 0 if none */
 351356 void
 352357 ejobcode(int flag)
 353358 {
 354359         if (flag)
 355360                 return;
 356361 
 357362 #ifdef MACHOABI
 358363 #define PT(x)
 359364 #else
 360365 #define PT(x) printf(".type __pcc_" x ",@function\n")
 361366 #endif
 362367 
 363368         /* printout varargs routines if used */
 364369         if (varneeds & NEED_GPNEXT) {
 365370                 printf(".text\n.align 4\n");
 366371                 PT("gpnext");
 367372                 printf("__pcc_gpnext:\n");
 368373                 printf("cmpl $48,(%%rdi)\njae 1f\n");
 369374                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
 370375                 printf("movq (%%rax),%%rax\naddl $8,(%%rdi)\nret\n");
 371376                 printf("1:movq 8(%%rdi),%%rax\nmovq (%%rax),%%rax\n");
 372377                 printf("addq $8,8(%%rdi)\nret\n");
 373378         }
 374379         if (varneeds & NEED_FPNEXT) {
 375380                 printf(".text\n.align 4\n");
 376381                 PT("fpnext");
 377382                 printf("__pcc_fpnext:\n");
 378383                 printf("cmpl $176,4(%%rdi)\njae 1f\n");
 379384                 printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
 380385                 printf("movsd (%%rax),%%xmm0\naddl $16,4(%%rdi)\nret\n");
 381386                 printf("1:movq 8(%%rdi),%%rax\nmovsd (%%rax),%%xmm0\n");
 382387                 printf("addq $8,8(%%rdi)\nret\n");
 383388         }
 384389         if (varneeds & NEED_1REGREF) {
 385390                 printf(".text\n.align 4\n");
 386391                 PT("1regref");
 387392                 printf("__pcc_1regref:\n");
 388393                 printf("cmpl $48,(%%rdi)\njae 1f\n");
 389394                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
 390395                 printf("addl $8,(%%rdi)\nret\n");
 391396                 printf("1:movq 8(%%rdi),%%rax\n");
 392397                 printf("addq $8,8(%%rdi)\nret\n");
 393398         }
 394399         if (varneeds & NEED_2REGREF) {
 395400                 printf(".text\n.align 4\n");
 396401                 PT("2regref");
 397402                 printf("__pcc_2regref:\n");
 398403                 printf("cmpl $40,(%%rdi)\njae 1f\n");
 399404                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
 400405                 printf("addl $16,(%%rdi)\nret\n");
 401406                 printf("1:movq 8(%%rdi),%%rax\n");
 402407                 printf("addq $16,8(%%rdi)\nret\n");
 403408         }
 404409         if (varneeds & NEED_MEMREF) {
 405410                 printf(".text\n.align 4\n");
 406411                 PT("memref");
 407412                 printf("__pcc_memref:\n");
 408413                 printf("movq 8(%%rdi),%%rax\n");
 409414                 printf("addq %%rsi,8(%%rdi)\nret\n");
 410415         }
 411416                 
 412417 
 413418 #ifdef MACHOABI
 414419         printf("\t.ident \"PCC: %s\"\n", VERSSTR);
 415420 #else
 416421         printf("\t.ident \"PCC: %s\"\n\t.end\n", VERSSTR);
 417422 #endif
 418423 }
 419424 
 420425 /*
 421426  * Varargs stuff:
 422427  * The ABI says that va_list should be declared as this typedef.
 423428  * We handcraft it here and then just reference it.
 424429  *
 425430  * typedef struct {
 426431  *      unsigned int gp_offset;
 427432  *      unsigned int fp_offset;
 428433  *      void *overflow_arg_area;
 429434  *      void *reg_save_area;
 430435  * } __builtin_va_list[1];
 431436  *
 432437  * There are a number of asm routines printed out if varargs are used:
 433438  *      long __pcc_gpnext(va)   - get a gpreg value
 434439  *      long __pcc_fpnext(va)   - get a fpreg value
 435440  *      void *__pcc_1regref(va) - get reference to a onereg struct
 436441  *      void *__pcc_2regref(va) - get reference to a tworeg struct
 437442  *      void *__pcc_memref(va,sz)       - get reference to a large struct
 438443  */
 439444 
 440445 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
 441446 static char *gpnext, *fpnext, *_1regref, *_2regref, *memref;
 442447 
 443448 void
 444449 bjobcode(void)
 445450 {
 446451         struct symtab *sp;
 447452         struct rstack *rp;
 448453         NODE *p, *q;
 449454         char *c;
 450455 
 451456         /* amd64 names for some asm constant printouts */
 452457         astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
 453458         astypnames[LONG] = astypnames[ULONG] = "\t.quad";
 454459 
 455460         gp_offset = addname("gp_offset");
 456461         fp_offset = addname("fp_offset");
 457462         overflow_arg_area = addname("overflow_arg_area");
 458463         reg_save_area = addname("reg_save_area");
 459464 
 460465         rp = bstruct(NULL, STNAME, NULL);
 461466         p = block(NAME, NIL, NIL, UNSIGNED, 0, 0);
 462467         soumemb(p, gp_offset, 0);
 463468         soumemb(p, fp_offset, 0);
 464469         p->n_type = VOID+PTR;
 465470         p->n_ap = NULL;
 466471         soumemb(p, overflow_arg_area, 0);
 467472         soumemb(p, reg_save_area, 0);
 468473         nfree(p);
 469474         q = dclstruct(rp);
 470475         c = addname("__builtin_va_list");
 471476         p = block(LB, bdty(NAME, c), bcon(1), INT, 0, 0);
 472477         p = tymerge(q, p);
 473478         p->n_sp = lookup(c, 0);
 474479         defid(p, TYPEDEF);
 475480         nfree(q);
 476481         nfree(p);
 477482 
 478483         /* for the static varargs functions */
 479484 #define MKN(vn, rn, tp) \
 480485         { vn = addname(rn); sp = lookup(vn, SNORMAL); \
 481486           sp->sclass = USTATIC; sp->stype = tp; }
 482487 
 483488         MKN(gpnext, "__pcc_gpnext", FTN|LONG);
 484489         MKN(fpnext, "__pcc_fpnext", FTN|DOUBLE);
 485490         MKN(_1regref, "__pcc_1regref", FTN|VOID|(PTR<<TSHIFT));
 486491         MKN(_2regref, "__pcc_2regref", FTN|VOID|(PTR<<TSHIFT));
 487492         MKN(memref, "__pcc_memref", FTN|VOID|(PTR<<TSHIFT));
 488493 }
 489494 
 490495 static NODE *
 491496 mkstkref(int off, TWORD typ)
 492497 {
 493498         NODE *p;
 494499 
 495500         p = block(REG, NIL, NIL, PTR|typ, 0, 0);
 496501         regno(p) = FPREG;
 497502         return buildtree(PLUS, p, bcon(off/SZCHAR));
 498503 }
 499504 
 500505 NODE *
 501506 amd64_builtin_stdarg_start(const struct bitable *bt, NODE *a)
 502507 {
 503508         NODE *p, *r;
 504509 
 505510         /* use the values from the function header */
 506511         p = a->n_left;
 507512         r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area),
 508513             mkstkref(-rsaoff, VOID));
 509514         r = buildtree(COMOP, r,
 510515             buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area),
 511516             mkstkref(thisrsp, VOID)));
 512517         r = buildtree(COMOP, r,
 513518             buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset),
 514519             bcon(thisgpr*(SZLONG/SZCHAR))));
 515520         r = buildtree(COMOP, r,
 516521             buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset),
 517522             bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
 518523 
 519524         tfree(a);
 520525         return r;
 521526 }
 522527 
 523528 NODE *
 524529 amd64_builtin_va_arg(const struct bitable *bt, NODE *a)
 525530 {
 526531         NODE *ap, *r, *dp;
 527532         NODE *f = block(NAME, NIL, NIL, INT, 0, 0);
 528533 
 529534         ap = a->n_left;
 530535         dp = a->n_right;
 531536         if (dp->n_type <= ULONGLONG || ISPTR(dp->n_type) ||
 532537             dp->n_type == FLOAT || dp->n_type == DOUBLE) {
 533538                 /* type might be in general register */
 534539                 if (dp->n_type == FLOAT || dp->n_type == DOUBLE) {
 535540                         f->n_sp = lookup(fpnext, SNORMAL);
 536541                         varneeds |= NEED_FPNEXT;
 537542                 } else {
 538543                         f->n_sp = lookup(gpnext, SNORMAL);
 539544                         varneeds |= NEED_GPNEXT;
 540545                 }
 541546                 f->n_type = f->n_sp->stype = INCREF(dp->n_type) + (FTN-PTR);
 542547                 f->n_ap = dp->n_ap;
 543548                 f->n_df = /* dp->n_df */ NULL;
 544549                 f = clocal(f);
 545550                 r = buildtree(CALL, f, ccopy(ap));
 546551         } else if (ISSOU(dp->n_type) || dp->n_type == LDOUBLE) {
 547552                 /* put a reference directly to the stack */
 548553                 int sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
 549554                 int al = talign(dp->n_type, dp->n_ap);
 550555                 if (al < ALLONG)
 551556                         al = ALLONG;
 552557                 if (sz <= SZLONG*2 && al == ALLONG) {
 553558                         if (sz <= SZLONG) {
 554559                                 f->n_sp = lookup(_1regref, SNORMAL);
 555560                                 varneeds |= NEED_1REGREF;
 556561                         } else {
 557562                                 f->n_sp = lookup(_2regref, SNORMAL);
 558563                                 varneeds |= NEED_2REGREF;
 559564                         }
 560565                         f->n_type = f->n_sp->stype;
 561566                         f = clocal(f);
 562567                         r = buildtree(CALL, f, ccopy(ap));
 563568                         r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
 564569                         r = buildtree(UMUL, r, NIL);
 565570                 } else {
 566571                         f->n_sp = lookup(memref, SNORMAL);
 567572                         varneeds |= NEED_MEMREF;
 568573                         f->n_type = f->n_sp->stype;
 569574                         f = clocal(f);
 570575                         SETOFF(sz, al);
 571576                         r = buildtree(CALL, f,
 572577                             buildtree(CM, ccopy(ap), bcon(sz/SZCHAR)));
 573578                         r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
 574579                         r = buildtree(UMUL, r, NIL);
 575580                 }
 576581         } else {
 577582                 uerror("amd64_builtin_va_arg not supported type");
 578583                 goto bad;
 579584         }
 580585         tfree(a);
 581586         return r;
 582587 bad:
 583588         uerror("bad argument to __builtin_va_arg");
 584589         return bcon(0);
 585590 }
 586591 
 587592 NODE *
 588593 amd64_builtin_va_end(const struct bitable *bt, NODE *a)
 589594 {
 590595         tfree(a);
 591596         return bcon(0); /* nothing */
 592597 }
 593598 
 594599 NODE *
 595600 amd64_builtin_va_copy(const struct bitable *bt, NODE *a)
 596601 {
 597602         NODE *f;
 598603 
 599604         f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL),
 600605             buildtree(UMUL, a->n_right, NIL));
 601606         nfree(a);
 602607         return f;
 603608 }
 604609 
 605610 static NODE *
 606611 movtoreg(NODE *p, int rno)
 607612 {
 608613         NODE *r;
 609614 
 610615         r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
 611616         regno(r) = rno;
 612617         return clocal(buildtree(ASSIGN, r, p));
 613618 
 614619 
 615620 static NODE *
 616621 movtomem(NODE *p, int off, int reg)
 617622 {
 618623         struct symtab s;
 619624         NODE *r, *l;
 620625 
 621626         s.stype = p->n_type;
 622627         s.squal = 0;
 623628         s.sdf = p->n_df;
 624629         s.sap = p->n_ap;
 625630         s.soffset = off;
 626631         s.sclass = AUTO;
 627632 
 628633         l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
 629634         l->n_lval = 0;
 630635         regno(l) = reg;
 631636 
 632637         r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
 633638         r->n_sp = &s;
 634639         r = stref(block(STREF, l, r, 0, 0, 0));
 635640 
 636641         return clocal(buildtree(ASSIGN, r, p));
 637642 
 638643 
 639644 
 640645 /*
 641646  * AMD64 parameter classification.
 642647  */
 643648 static int
 644649 argtyp(TWORD t, union dimfun *df, struct attr *ap)
 645650 {
 646651         int cl = 0;
 647652 
 648653         if (t <= ULONG || ISPTR(t) || t == BOOL) {
 649654                 cl = ngpr < 6 ? INTEGER : INTMEM;
 650655         } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
 651656                 cl = nsse < 8 ? SSE : SSEMEM;
 652657         } else if (t == LDOUBLE || t == LIMAG) {
 653658                 cl = X87; /* XXX */
 654659         } else if (t == STRTY || t == UNIONTY) {
 655660                 int sz = tsize(t, df, ap);
 656661 
 657662                 if (sz <= 2*SZLONG && attr_find(ap, ATTR_COMPLEX) != NULL) {
 658663                         cl = nsse < 7 ? STRCPX : STRMEM;
 659664                 } else if (sz > 2*SZLONG || ((sz+SZLONG-1)/SZLONG)+ngpr > 6 ||
 660665                     attr_find(ap, GCC_ATYP_PACKED) != NULL)
 661666                         cl = STRMEM;
 662667                 else
 663668                         cl = STRREG;
 664669         } else
 665670                 cerror("FIXME: classify");
 666671         return cl;
 667672 }
 668673 
 669674 /*
 670675  * Do the "hard work" in assigning correct destination for arguments.
 671676  * Also convert arguments < INT to inte (default argument promotions).
 672677  * XXX - should be dome elsewhere.
 673678  */
 674679 static NODE *
 675680 argput(NODE *p)
 676681 {
 677682         NODE *q;
 678683         TWORD ty;
 679684         int typ, r, ssz;
 680685 
 681686         if (p->n_op == CM) {
 682687                 p->n_left = argput(p->n_left);
 683688                 p->n_right = argput(p->n_right);
 684689                 return p;
 685690         }
 686691 
 687692         /* first arg may be struct return pointer */
 688693         /* XXX - check if varargs; setup al */
 689694         switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) {
 690695         case INTEGER:
 691696         case SSE:
 692697                 if (typ == SSE)
 693698                         r = XMM0 + nsse++;
 694699                 else
 695700                         r = argregsi[ngpr++];
 696701                 if (p->n_type < INT || p->n_type == BOOL)
 697702                         p = cast(p, INT, 0);
 698703                 p = movtoreg(p, r);
 699704                 break;
 700705 
 701706         case X87:
 702707                 r = nrsp;
 703708                 nrsp += SZLDOUBLE;
 704709                 p = movtomem(p, r, STKREG);
 705710                 break;
 706711 
 707712         case SSEMEM:
 708713                 r = nrsp;
 709714                 nrsp += SZDOUBLE;
 710715                 p = movtomem(p, r, STKREG);
 711716                 break;
 712717 
 713718         case INTMEM:
 714719                 r = nrsp;
 715720                 nrsp += SZLONG;
 716721                 p = movtomem(p, r, STKREG);
 717722                 break;
 718723 
 719724         case STRCPX:
 720725         case STRREG: /* Struct in registers */
 721726                 /* Cast to long pointer and move to the registers */
 722727                 /* XXX can overrun struct size */
 723728                 /* XXX check carefully for SSE members */
 724729                 ssz = tsize(p->n_type, p->n_df, p->n_ap);
 725730 
 726731                 if (typ == STRCPX) {
 727732                         ty = DOUBLE;
 728733                         r = XMM0 + nsse++;
 729734                 } else {
 730735                         ty = LONG;
 731736                         r = argregsi[ngpr++];
 732737                 }
 733738                 if (ssz <= SZLONG) {
 734739                         q = cast(p->n_left, INCREF(ty), 0);
 735740                         nfree(p);
 736741                         q = buildtree(UMUL, q, NIL);
 737742                         p = movtoreg(q, r);
 738743                 } else if (ssz <= SZLONG*2) {
 739744                         NODE *ql, *qr;
 740745 
 741746                         if (!ISPTR(p->n_left->n_type))
 742747                                 cerror("no struct arg pointer");
 743748                         p = nfree(p);
 744749                         p = makety(p, PTR|ty, 0, 0, 0);
 745750                         qr = ccopy(ql = tempnode(0, PTR|ty, 0, 0));
 746751                         p = buildtree(ASSIGN, ql, p);
 747752 
 748753                         ql = movtoreg(buildtree(UMUL, ccopy(qr), NIL), r);
 749754                         p = buildtree(COMOP, p, ql);
 750755 
 751756                         ql = buildtree(UMUL, buildtree(PLUS, qr, bcon(1)), NIL);
 752757                         r = (typ == STRCPX ? XMM0 + nsse++ : argregsi[ngpr++]);
 753758                         ql = movtoreg(ql, r);
 754759 
 755760                         p = buildtree(CM, p, ql);
 756761                 } else
 757762                         cerror("STRREG");
 758763                 break;
 759764 
 760765         case STRMEM: {
 761766                 struct symtab s;
 762767                 NODE *l, *t;
 763768 
 764769                 q = buildtree(UMUL, p->n_left, NIL);
 765770 
 766771                 s.stype = p->n_type;
 767772                 s.squal = 0;
 768773                 s.sdf = p->n_df;
 769774                 s.sap = p->n_ap;
 770775                 s.soffset = nrsp;
 771776                 s.sclass = AUTO;
 772777 
 773778                 nrsp += tsize(p->n_type, p->n_df, p->n_ap);
 774779 
 775780                 l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
 776781                 l->n_lval = 0;
 777782                 regno(l) = STKREG;
 778783 
 779784                 t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
 780785                 t->n_sp = &s;
 781786                 t = stref(block(STREF, l, t, 0, 0, 0));
 782787 
 783788                 t = (buildtree(ASSIGN, t, q));
 784789                 nfree(p);
 785790                 p = t->n_left;
 786791                 nfree(t);
 787792                 break;
 788793                 }
 789794 
 790795         default:
 791796                 cerror("argument %d", typ);
 792797         }
 793798         return p;
 794799 }
 795800 
 796801 /*
 797802  * Sort arglist so that register assignments ends up last.
 798803  */
 799804 static int
 800805 argsort(NODE *p)
 801806 {
 802807         NODE *q, *r;
 803808         int rv = 0;
 804809 
 805810         if (p->n_op != CM) {
 806811                 if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
 807812                     coptype(p->n_right->n_op) != LTYPE) {
 808813                         q = tempnode(0, p->n_type, p->n_df, p->n_ap);
 809814                         r = ccopy(q);
 810815                         p->n_right = buildtree(COMOP,
 811816                             buildtree(ASSIGN, q, p->n_right), r);
 812817                 }
 813818                 return rv;
 814819         }
 815820         if (p->n_right->n_op == CM) {
 816821                 /* fixup for small structs in regs */
 817822                 q = p->n_right->n_left;
 818823                 p->n_right->n_left = p->n_left;
 819824                 p->n_left = p->n_right;
 820825                 p->n_right = p->n_left->n_right;
 821826                 p->n_left->n_right = q;
 822827         }
 823828         if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
 824829             coptype(p->n_right->n_right->n_op) != LTYPE) {
 825830                 /* move before everything to avoid reg trashing */
 826831                 q = tempnode(0, p->n_right->n_type,
 827832                     p->n_right->n_df, p->n_right->n_ap);
 828833                 r = ccopy(q);
 829834                 p->n_right->n_right = buildtree(COMOP,
 830835                     buildtree(ASSIGN, q, p->n_right->n_right), r);
 831836         }
 832837         if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
 833838                 if (p->n_left->n_op == CM &&
 834839                     p->n_left->n_right->n_op == STASG) {
 835840                         q = p->n_left->n_right;
 836841                         p->n_left->n_right = p->n_right;
 837842                         p->n_right = q;
 838843                         rv = 1;
 839844                 } else if (p->n_left->n_op == STASG) {
 840845                         q = p->n_left;
 841846                         p->n_left = p->n_right;
 842847                         p->n_right = q;
 843848                         rv = 1;
 844849                 }
 845850         }
 846851         return rv | argsort(p->n_left);
 847852 }
 848853 
 849854 /*
 850855  * Called with a function call with arguments as argument.
 851856  * This is done early in buildtree() and only done once.
 852857  * Returns p.
 853858  */
 854859 NODE *
 855860 funcode(NODE *p)
 856861 {
 857862         NODE *l, *r;
 858863         TWORD t;
 859864         int i;
 860865 
 861866         nsse = ngpr = nrsp = 0;
 862867         /* Check if hidden arg needed */
 863868         /* If so, add it in pass2 */
 864869         if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
 865870             l->n_type == INCREF(FTN)+UNIONTY) {
 866871                 int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap);
 867872                 if (ssz > 2*SZLONG)
 868873                         ngpr++;
 869874         }
 870875 
 871876         /* Convert just regs to assign insn's */
 872877         p->n_right = argput(p->n_right);
 873878 
 874879         /* Must sort arglist so that STASG ends up first */
 875880         /* This avoids registers being clobbered */
 876881         while (argsort(p->n_right))
 877882                 ;
 878883         /* Check if there are varargs */
 879884         if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
 880885                 ; /* Need RAX */
 881886         } else {
 882887                 union arglist *al = l->n_df->dfun;
 883888 
 884889                 for (; al->type != TELLIPSIS; al++) {
 885890                         if ((t = al->type) == TNULL)
 886891                                 return p; /* No need */
 887892                         if (ISSOU(BTYPE(t)))
 888893                                 al++;
 889894                         for (i = 0; t > BTMASK; t = DECREF(t))
 890895                                 if (ISARY(t) || ISFTN(t))
 891896                                         i++;
 892897                         if (i)
 893898                                 al++;
 894899                 }
 895900         }
 896901 
 897902         /* Always emit number of SSE regs used */
 898903         l = movtoreg(bcon(nsse), RAX);
 899904         if (p->n_right->n_op != CM) {
 900905                 p->n_right = block(CM, l, p->n_right, INT, 0, 0);
 901906         } else {
 902907                 for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
 903908                         ;
 904909                 r->n_left = block(CM, l, r->n_left, INT, 0, 0);
 905910         }
 906911         return p;
 907912 }
 908913 
 909914 /* fix up type of field p */
 910915 void
 911916 fldty(struct symtab *p)
 912917 {
 913918 }
 914919 
 915920 /*
 916921  * XXX - fix genswitch.
 917922  */
 918923 int
 919924 mygenswitch(int num, TWORD type, struct swents **p, int n)
 920925 {
 921926         return 0;
 922927 }
 923928 
 924929 /*
 925930  * Return return as given by a.
 926931  */
 927932 NODE *
 928933 builtin_return_address(const struct bitable *bt, NODE *a)
 929934 {
 930935         int nframes;
 931936         NODE *f;
 932937 
 933938         nframes = a->n_lval;
 934939         tfree(a);
 935940 
 936941         f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
 937942         regno(f) = FPREG;
 938943 
 939944         while (nframes--)
 940945                 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
 941946 
 942947         f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
 943948         f = buildtree(UMUL, f, NIL);
 944949 
 945950         return f;
 946951 }
 947952 
 948953 /*
 949954  * Return frame as given by a.
 950955  */
 951956 NODE *
 952957 builtin_frame_address(const struct bitable *bt, NODE *a)
 953958 {
 954959         int nframes;
 955960         NODE *f;
 956961 
 957962         nframes = a->n_lval;
 958963         tfree(a);
 959964 
 960965         f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
 961966         regno(f) = FPREG;
 962967 
 963968         while (nframes--)
 964969                 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
 965970 
 966971         return f;
 967972 }
 968973 
 969974 /*
 970975  * Return "canonical frame address".
 971976  */
 972977 NODE *
 973978 builtin_cfa(const struct bitable *bt, NODE *a)
 974979 {
 975980         NODE *f;
 976981 
 977982         f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
 978983         regno(f) = FPREG;
 979984         return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0);
 980985 }
FishEye: Open Source License registered to PCC.
Your maintenance has expired. You can renew your license at http://www.atlassian.com/fisheye/renew
Atlassian FishEye, CVS analysis. (Version:1.6.3 Build:build-336 2008-11-04) - Administration - Page generated 2014-10-02 02:26 +0200