cgen.c - scc - simple c99 compiler
 (HTM) git clone git://git.simple-cc.org/scc
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       cgen.c (12306B)
       ---
            1 #include <assert.h>
            2 #include <stdlib.h>
            3 
            4 #include <scc/cstd.h>
            5 #include <scc/scc.h>
            6 
            7 #include "../cc2.h"
            8 #include "arch.h"
            9 
           10 #define I1BYTES 0
           11 #define I2BYTES 1
           12 #define I4BYTES 2
           13 #define I8BYTES 3
           14 
           15 static Node *cgen(Node *);
           16 
           17 static unsigned char opasmw[][2] = {
           18         [OADD] = {ASADDW, ASADDW},
           19         [OSUB] = {ASSUBW, ASSUBW},
           20         [OMUL] = {ASMULW, ASMULW},
           21         [OMOD] = {ASMODW, ASUMODW},
           22         [ODIV] = {ASDIVW, ASUDIVW},
           23         [OSHL] = {ASSHLW, ASSHLW},
           24         [OSHR] = {ASSHRW, ASUSHRW},
           25         [OLT] = {ASLTW, ASULTW},
           26         [OGT] = {ASGTW, ASUGTW},
           27         [OLE] = {ASLEW, ASULEW},
           28         [OGE] = {ASGEW, ASUGEW},
           29         [OEQ] = {ASEQW, ASEQW},
           30         [ONE] = {ASNEW, ASNEW},
           31         [OBAND] = {ASBANDW, ASBANDW},
           32         [OBOR] = {ASBORW, ASBORW},
           33         [OBXOR] = {ASBXORW, ASBXORW},
           34         [OSNEG] = {ASNEGW, ASNEGW},
           35 };
           36 
           37 static unsigned char opasml[][2] = {
           38         [OADD] = {ASADDL, ASADDL},
           39         [OSUB] = {ASSUBL, ASSUBL},
           40         [OMUL] = {ASMULL, ASMULL},
           41         [OMOD] = {ASMODL, ASUMODL},
           42         [ODIV] = {ASDIVL, ASUDIVL},
           43         [OSHL] = {ASSHLL, ASSHLL},
           44         [OSHR] = {ASSHRL, ASUSHRL},
           45         [OLT] = {ASLTL, ASULTL},
           46         [OGT] = {ASGTL, ASUGTL},
           47         [OLE] = {ASLEL, ASULEL},
           48         [OGE] = {ASGEL, ASUGEL},
           49         [OEQ] = {ASEQL, ASEQL},
           50         [ONE] = {ASNEL, ASNEL},
           51         [OBAND] = {ASBANDL, ASBANDL},
           52         [OBOR] = {ASBORL, ASBORL},
           53         [OBXOR] = {ASBXORL, ASBXORL},
           54         [OSNEG] = {ASNEGL, ASNEGL},
           55 };
           56 
           57 static unsigned char opasms[][2] = {
           58         [OADD] = {ASADDS, ASADDS},
           59         [OSUB] = {ASSUBS, ASSUBS},
           60         [OMUL] = {ASMULS, ASMULS},
           61         [ODIV] = {ASDIVS, ASDIVS},
           62         [OLT] = {ASLTS, ASLTS},
           63         [OGT] = {ASGTS, ASGTS},
           64         [OLE] = {ASLES, ASLES},
           65         [OGE] = {ASGES, ASGES},
           66         [OEQ] = {ASEQS, ASEQS},
           67         [ONE] = {ASNES, ASNES},
           68         [OSNEG] = {ASNEGS, ASNEGS},
           69 };
           70 
           71 static unsigned char opasmd[][2] = {
           72         [OADD] = {ASADDD, ASADDD},
           73         [OSUB] = {ASSUBD, ASSUBD},
           74         [OMUL] = {ASMULD, ASMULD},
           75         [ODIV] = {ASDIVD, ASDIVD},
           76         [OLT] = {ASLTD, ASLTD},
           77         [OGT] = {ASGTD, ASGTD},
           78         [OLE] = {ASLED, ASLED},
           79         [OGE] = {ASGED, ASGED},
           80         [OEQ] = {ASEQD, ASEQD},
           81         [ONE] = {ASNED, ASNED},
           82         [OSNEG] = {ASNEGD, ASNEGD},
           83 };
           84 
           85 static unsigned char (*opbin[][2])[2] = {
           86         {opasmw, opasml},
           87         {opasms, opasmd},
           88 };
           89 
           90 static unsigned char i2i_conv[4][4][2] = {
           91         [I1BYTES] = {
           92                 [I4BYTES] = {ASEXTBW, ASUEXTBW},
           93                 [I8BYTES] = {ASEXTBL, ASUEXTBL},
           94         },
           95         [I2BYTES] = {
           96                 [I4BYTES] = {ASEXTHW, ASUEXTHW},
           97                 [I8BYTES] = {ASEXTHL, ASUEXTHL},
           98         },
           99         [I4BYTES] = {
          100                 [I8BYTES] = {ASEXTWL, ASUEXTWL},
          101         }
          102 };
          103 
          104 static unsigned char f2i_conv[4][4][2] = {
          105         [I4BYTES] = {
          106                 [I4BYTES] = {ASSTOW, ASSTOUW},
          107                 [I8BYTES] = {ASSTOL, ASDTOUL},
          108         },
          109         [I8BYTES] = {
          110                 [I4BYTES] = {ASDTOW, ASDTOUW},
          111                 [I8BYTES] = {ASDTOL, ASDTOUL},
          112         }
          113 };
          114 
          115 static unsigned char i2f_conv[4][4][2] = {
          116         [I4BYTES] = {
          117                 [I4BYTES] = {ASSWTOS, ASUWTOS},
          118                 [I8BYTES] = {ASSWTOD, ASUWTOD},
          119         },
          120         [I8BYTES] = {
          121                 [I4BYTES] = {ASSLTOS, ASULTOS},
          122                 [I8BYTES] = {ASSLTOD, ASULTOD},
          123         }
          124 };
          125 
          126 /*
          127  * This is strongly influenced by
          128  * http://plan9.bell-labs.com/sys/doc/compiler.ps (/sys/doc/compiler.ps)
          129  * calculate addresability as follows
          130  *     AUTO => 11          value+fp
          131  *     REG => 11           reg
          132  *     STATIC => 11        (value)
          133  *     CONST => 11         $value
          134  * These values of addressability are not used in the code generation.
          135  * They are only used to calculate the Sethi-Ullman numbers. Since
          136  * QBE is AMD64 targered we could do a better job there, and try to
          137  * detect some of the complex addressing modes of these processors.
          138  */
          139 Node *
          140 tsethi(Node *np)
          141 {
          142         int op;
          143         Node *l, *r;
          144 
          145         l = np->left;
          146         r = np->right;
          147 
          148         switch (np->op) {
          149         case OAUTO:
          150         case OREG:
          151         case OMEM:
          152         case OCONST:
          153                 np->address = 11;
          154                 break;
          155         case OASSIG:
          156                 assert(l->op != OCAST);
          157                 goto binary;
          158         case OCPL:
          159                 assert(np->type.flags & INTF);
          160                 np->op = OBXOR;
          161                 r = constnode(NULL, ~(TUINT) 0, &np->type);
          162                 goto binary;
          163         case OEFUN:
          164                 /*
          165                  * In QBE we need at the end of a basic block
          166                  * a jump, so we have to ensure that the last
          167                  * statement of the function is a ret, a jmp
          168                  * or a branch.
          169                  */
          170 
          171                 op = np->prev->op;
          172                 if (op == ONOP || op == OBRANCH || (op != ORET && op != OJMP))
          173                         addstmt(node(ORET));
          174                 break;
          175         default:
          176         binary:
          177                 l = sethi(l);
          178                 r = sethi(r);
          179                 break;
          180         }
          181         np->left = l;
          182         np->right = r;
          183 
          184         return np;
          185 }
          186 
          187 static int
          188 bytes2idx(int nbytes)
          189 {
          190         if (nbytes== 1)
          191                 return I1BYTES;
          192         else if (nbytes == 2)
          193                 return I2BYTES;
          194         else if (nbytes == 4)
          195                 return I4BYTES;
          196         else if (nbytes == 8)
          197                 return I8BYTES;
          198         else
          199                 abort();
          200 }
          201 
          202 static Node *
          203 load(Type *tp, Node *np)
          204 {
          205         int op;
          206         Node *new;
          207         int flags = tp->flags;
          208 
          209         if (flags & (AGGRF|FUNF|ARRF|PTRF))
          210                 return np;
          211 
          212         switch (tp->size) {
          213         case 1:
          214                 op = ASLDSB;
          215                 break;
          216         case 2:
          217                 op = ASLDSH;
          218                 break;
          219         case 4:
          220                 op = (flags & FLOATF) ? ASLDS : ASLDSW;
          221                 break;
          222         case 8:
          223                 op = (flags & FLOATF) ? ASLDD : ASLDL;
          224                 break;
          225         default:
          226                 abort();
          227         }
          228         /*
          229          * unsigned version of operations are always +1 the
          230          * signed version
          231          */
          232         if ((flags & (INTF|SIGNF)) == INTF && tp->size < 8)
          233                 ++op;
          234 
          235         new = tmpnode(tp, NULL);
          236         code(op, new, np, NULL);
          237 
          238         return new;
          239 }
          240 
          241 static Node *rhs(Node *np);
          242 
          243 static Node *
          244 cast(Type *td, Node *np)
          245 {
          246         Type *ts;
          247         Node *tmp;
          248         int op, d_isint, s_isint, sidx, didx, sign;
          249 
          250         ts = &np->type;
          251         d_isint = (td->flags & INTF) != 0;
          252         s_isint = (ts->flags & INTF) != 0;
          253 
          254         sidx = bytes2idx(ts->size);
          255         didx = bytes2idx(td->size);
          256 
          257         sign = (ts->flags & SIGNF) == 0;
          258 
          259         if (d_isint && s_isint) {
          260                 /* conversion from int to int */
          261                 if (didx < I4BYTES)
          262                         didx = bytes2idx(4);
          263 
          264                 if (didx <= sidx) {
          265                         np->type = *td;
          266                         return np;
          267                 }
          268 
          269                 op = i2i_conv[sidx][didx][sign];
          270         } else if (d_isint) {
          271                 /* conversion from float to int */
          272                 if (didx < I4BYTES)
          273                         didx = bytes2idx(4);
          274 
          275                 op = f2i_conv[sidx][didx][sign];
          276         } else if (s_isint) {
          277                 /* conversion from int to float */
          278                 if (sidx == I1BYTES || sidx == I2BYTES) {
          279                         ts = (ts->flags&SIGNF) ? &int32type : &uint32type;
          280                         np = cast(ts, np);
          281                 }
          282                 op = i2f_conv[sidx][didx][sign];
          283         } else {
          284                 /* conversion from float to float */
          285                 op = (didx == I4BYTES) ? ASEXTS : ASTRUNCD;
          286         }
          287 
          288         assert(op != 0);
          289         tmp = tmpnode(td, NULL);
          290         code(op, tmp, np, NULL);
          291 
          292         return tmp;
          293 }
          294 
          295 static Node *
          296 call(Node *np, Node *fun)
          297 {
          298         int n, op;
          299         Type *tp;
          300         Node **q, *tmp, *p, *pars[NR_FUNPARAM];
          301 
          302         for (n = 0, p = np->right; p; p = p->right)
          303                 pars[n++] = rhs(p->left);
          304 
          305         tp = &np->type;
          306         tmp = tmpnode(tp, NULL);
          307         code(ASCALL, tmp, fun, NULL);
          308 
          309         for (q = pars; q < &pars[n]; ++q) {
          310                 op = (q == &pars[n-1]) ? ASPARE : ASPAR;
          311                 code(op, NULL, *q, tmpnode(&(*q)->type, NULL));
          312         }
          313         code((np->op == OCALL) ? ASCALLE : ASCALLEX, NULL, NULL, NULL);
          314 
          315         return tmp;
          316 }
          317 
          318 static Node *
          319 copy(Type *tp, Node *to, Node *from)
          320 {
          321         int op;
          322 
          323         switch (tp->size) {
          324         case 0:
          325                 return from;
          326         case 1:
          327                 op = ASCOPYB;
          328                 break;
          329         case 2:
          330                 op = ASCOPYH;
          331                 break;
          332         case 4:
          333                 op = (tp->flags & FLOATF) ? ASCOPYS : ASCOPYW;
          334                 break;
          335         case 8:
          336                 op = (tp->flags & FLOATF) ? ASCOPYD : ASCOPYL;
          337                 break;
          338         default:
          339                 abort();
          340         }
          341         code(op, to, from, NULL);
          342         return from;
          343 }
          344 
          345 static Node *
          346 field(Node *np, int islhs)
          347 {
          348         Node *tmp, *addr;
          349         TUINT offset = np->right->u.sym->u.off;
          350 
          351         addr = rhs(np->left);
          352         tmp = node(OADD);
          353         tmp->type = ptrtype;
          354         tmp->left = addr;
          355         tmp->right = constnode(NULL, offset, &ptrtype);
          356         addr = rhs(tmp);
          357 
          358         if (!islhs)
          359                 addr = load(&np->type, addr);
          360         return addr;
          361 }
          362 
          363 static Node *
          364 lhs(Node *np)
          365 {
          366         switch (np->op) {
          367         case OREG:
          368         case OMEM:
          369         case OAUTO:
          370                 return np;
          371         case OPTR:
          372                 return rhs(np->left);
          373         case OFIELD:
          374                 return field(np, 1);
          375         default:
          376                 abort();
          377         }
          378 }
          379 
          380 static Node *
          381 function(void)
          382 {
          383         Node aux;
          384         Symbol *p;
          385 
          386         /* allocate stack space for parameters */
          387         for (p = locals; p; p = p->next) {
          388                 if ((p->type.flags & PARF) == 0)
          389                         continue;
          390                 if ((p->type.flags & AGGRF) != 0)
          391                         continue;
          392                 code(ASALLOC, label2node(&aux, p), NULL, NULL);
          393         }
          394 
          395         /* allocate stack space for local variables) */
          396         for (p = locals; p; p = p->next) {
          397                 if ((p->type.flags & PARF) != 0)
          398                         continue;
          399                 if (p->kind != SAUTO || p->id == TMPSYM)
          400                         continue;
          401                 code(ASALLOC, label2node(&aux, p), NULL, NULL);
          402         }
          403 
          404         /* store formal parameters in parameters */
          405         for (p = locals; p; p = p->next) {
          406                 if ((p->type.flags & PARF) == 0)
          407                         continue;
          408                 if ((p->type.flags & AGGRF) != 0)
          409                         continue;
          410                 if ((p->type.flags & (ARRF|AGGRF)) == 0)
          411                         code(ASFORM, label2node(&aux, p), NULL, NULL);
          412         }
          413         return NULL;
          414 }
          415 
          416 static int
          417 assignop(Type *tp)
          418 {
          419         int flags = tp->flags;
          420 
          421         if (flags & (AGGRF|FUNF|ARRF))
          422                 return ASSTM;
          423 
          424         switch (tp->size) {
          425         case 1:
          426                 return ASSTB;
          427         case 2:
          428                 return ASSTH;
          429         case 4:
          430                 return (tp->flags & FLOATF) ? ASSTS : ASSTW;
          431         case 8:
          432                 return (tp->flags & FLOATF) ? ASSTD : ASSTL;
          433         default:
          434                 abort();
          435         }
          436 }
          437 
          438 static void
          439 rhs_rhs(Node **lpp, Node **rpp)
          440 {
          441         Node *l = *lpp, *r = *rpp;
          442 
          443         if (l->complex >= r->complex) {
          444                 l = rhs(l);
          445                 r = rhs(r);
          446         } else {
          447                 r = rhs(r);
          448                 l = rhs(l);
          449         }
          450 
          451         *lpp = l, *rpp = r;
          452 }
          453 
          454 static void
          455 lhs_rhs(Node **lpp, Node **rpp)
          456 {
          457         Node *l = *lpp, *r = *rpp;
          458 
          459         if (l->complex >= r->complex) {
          460                 l = lhs(l);
          461                 r = rhs(r);
          462         } else {
          463                 r = rhs(r);
          464                 l = lhs(l);
          465         }
          466 
          467         *lpp = l, *rpp = r;
          468 }
          469 
          470 static Node *
          471 assign(Node *np)
          472 {
          473         Node *ret, aux;
          474         Node *l = np->left, *r = np->right;
          475         int op;
          476 
          477         switch (np->u.subop) {
          478         case OINC:
          479                 op = OADD;
          480                 goto post_oper;
          481         case ODEC:
          482                 op = OSUB;
          483         post_oper:
          484                 lhs_rhs(&l, &r);
          485                 ret = load(&l->type, l);
          486                 aux.op = op;
          487                 aux.left = ret;
          488                 aux.right = r;
          489                 aux.type = np->type;
          490                 r = rhs(sethi(&aux));
          491                 break;
          492         default:
          493                 /* assign abbreviation */
          494                 assert(l->type.size == r->type.size);
          495                 if (r->type.size < 4) {
          496                         lhs_rhs(&l, &r);
          497                         aux.op = np->u.subop;
          498                         aux.left = load(&r->type, l);
          499                         aux.right = r;
          500                         aux.type = int32type;
          501                         aux.address = np->address;
          502                         ret = r = sethi(rhs(&aux));
          503                         break;
          504                 }
          505 
          506                 aux.op = np->u.subop;
          507                 aux.left = l;
          508                 aux.right = r;
          509                 aux.type = np->type;
          510                 aux.address = np->address;
          511                 r = sethi(&aux);
          512         case 0:
          513                 if (l->op == OTMP) {
          514                         r = rhs(r);
          515                         copy(&np->type, l, r);
          516                         return r;
          517                 }
          518 
          519                 lhs_rhs(&l, &r);
          520                 ret = r;
          521                 break;
          522         }
          523 
          524         code(assignop(&np->type), l, r, NULL);
          525         return ret;
          526 }
          527 
          528 static Node *
          529 rhs(Node *np)
          530 {
          531         Node *tmp, aux1, aux2;
          532         Node *phi, *l = np->left, *r = np->right;
          533         Type *tp;
          534         int sign, size, isfloat, op;
          535         Symbol *true, *false;
          536 
          537         tp = &np->type;
          538 
          539         switch (np->op) {
          540         case OTMP:
          541         case OCONST:
          542                 return np;
          543         case OMEM:
          544         case OREG:
          545         case OAUTO:
          546                 return load(tp, np);
          547         case OMOD:
          548         case OSHL:
          549         case OBAND:
          550         case OBOR:
          551         case OBXOR:
          552         case OSHR:
          553                 assert(tp->flags & INTF);
          554         case ODIV:
          555         case OLT:
          556         case OGT:
          557         case OLE:
          558         case OGE:
          559         case OADD:
          560         case OSUB:
          561         case OMUL:
          562         case OEQ:
          563         case ONE:
          564                 assert(tp->size == 4 || tp->size == 8);
          565 
          566                 sign = (tp->flags & SIGNF) == 0;
          567                 size = tp->size == 8;
          568                 isfloat = (tp->flags & FLOATF) != 0;
          569                 op = opbin[isfloat][size][np->op][sign];
          570                 rhs_rhs(&l, &r);
          571                 tmp = tmpnode(tp, NULL);
          572                 code(op, tmp, l, r);
          573                 return tmp;
          574         case OCALL:
          575         case OCALLE:
          576                 if (l->op == OPTR)
          577                         l = rhs(l);
          578                 return call(np, l);
          579         case OCAST:
          580                 return cast(tp, rhs(l));
          581         case OASSIG:
          582                 return assign(np);
          583         case OSNEG:
          584                 sign = (tp->flags & SIGNF) == 0;
          585                 size = tp->size == 8;
          586                 isfloat = (tp->flags & FLOATF) != 0;
          587                 op = opbin[isfloat][size][np->op][sign];
          588                 tmp = tmpnode(tp, NULL);
          589                 code(op, tmp, rhs(l), NULL);
          590                 return tmp;
          591         case OPTR:
          592                 return load(tp, rhs(l));
          593         case OADDR:
          594                 l = lhs(l);
          595                 l->type = *tp;
          596                 l->type.flags |= PTRF;
          597                 return l;
          598         case OFIELD:
          599                 return field(np, 0);
          600         case OBUILTIN:
          601                 switch (np->u.subop) {
          602                 case BVA_START:
          603                         l = rhs(l);
          604                         code(ASVSTAR, NULL, l, NULL);
          605                 case BVA_END:
          606                         return NULL;
          607                 case BVA_ARG:
          608                         l = rhs(l);
          609                         tmp = tmpnode(tp, NULL);
          610                         code(ASVARG, tmp, l, NULL);
          611                         return tmp;
          612                 default:
          613                         abort();
          614                 }
          615         default:
          616                 abort();
          617         }
          618         abort();
          619 }
          620 
          621 static Node *
          622 cgen(Node *np)
          623 {
          624         Node true, false, *p, *next;
          625 
          626         setlabel(np->label);
          627         switch (np->op) {
          628         case OBFUN:
          629                 return function();
          630         case ONOP:
          631         case OBLOOP:
          632         case OELOOP:
          633         case OEFUN:
          634                 break;
          635         case OJMP:
          636                 label2node(&true, np->u.sym);
          637                 code(ASJMP, NULL, &true, NULL);
          638                 break;
          639         case OBRANCH:
          640                 /*
          641                  * QBE does not accept labels at the end of a function
          642                  * (ONOP is used for labels) so we have to add a ret
          643                  * there, and in the case of branches we need a label
          644                  * for the next statement.
          645                  */
          646                 next = np->next;
          647                 if (!next->label)
          648                         labelstmt(next, NULL);
          649 
          650                 label2node(&true, np->u.sym);
          651                 label2node(&false, np->next->label);
          652                 code(ASBRANCH, rhs(np->left), &true, &false);
          653                 break;
          654         case ORET:
          655                 p = (np->left) ? rhs(np->left) : NULL;
          656                 code(ASRET, NULL, p, NULL);
          657                 break;
          658         default:
          659                 rhs(np);
          660                 break;
          661         }
          662         return NULL;
          663 }
          664 
          665 void
          666 genasm(void)
          667 {
          668         apply(cgen);
          669 }