| // Inferno utils/cc/funct.c | |
| // http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.c | |
| // | |
| // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. | |
| // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) | |
| // Portions Copyright © 1997-1999 Vita Nuova Limited | |
| // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) | |
| // Portions Copyright © 2004,2006 Bruce Ellis | |
| // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) | |
| // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others | |
| // Portions Copyright © 2009 The Go Authors. All rights reserved. | |
| // | |
| // Permission is hereby granted, free of charge, to any person obtaining a copy | |
| // of this software and associated documentation files (the "Software"), to deal | |
| // in the Software without restriction, including without limitation the rights | |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| // copies of the Software, and to permit persons to whom the Software is | |
| // furnished to do so, subject to the following conditions: | |
| // | |
| // The above copyright notice and this permission notice shall be included in | |
| // all copies or substantial portions of the Software. | |
| // | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| // THE SOFTWARE. | |
| #include <u.h> | |
| #include "cc.h" | |
| typedef struct Ftab Ftab; | |
| struct Ftab | |
| { | |
| char op; | |
| char* name; | |
| char typ; | |
| }; | |
| typedef struct Gtab Gtab; | |
| struct Gtab | |
| { | |
| char etype; | |
| char* name; | |
| }; | |
| Ftab ftabinit[OEND]; | |
| Gtab gtabinit[NTYPE]; | |
| int | |
| isfunct(Node *n) | |
| { | |
| Type *t, *t1; | |
| Funct *f; | |
| Node *l; | |
| Sym *s; | |
| int o; | |
| o = n->op; | |
| if(n->left == Z) | |
| goto no; | |
| t = n->left->type; | |
| if(t == T) | |
| goto no; | |
| f = t->funct; | |
| switch(o) { | |
| case OAS: // put cast on rhs | |
| case OASI: | |
| case OASADD: | |
| case OASAND: | |
| case OASASHL: | |
| case OASASHR: | |
| case OASDIV: | |
| case OASLDIV: | |
| case OASLMOD: | |
| case OASLMUL: | |
| case OASLSHR: | |
| case OASMOD: | |
| case OASMUL: | |
| case OASOR: | |
| case OASSUB: | |
| case OASXOR: | |
| if(n->right == Z) | |
| goto no; | |
| t1 = n->right->type; | |
| if(t1 == T) | |
| goto no; | |
| if(t1->funct == f) | |
| break; | |
| l = new(OXXX, Z, Z); | |
| *l = *n->right; | |
| n->right->left = l; | |
| n->right->right = Z; | |
| n->right->type = t; | |
| n->right->op = OCAST; | |
| if(!isfunct(n->right)) | |
| prtree(n, "isfunc !"); | |
| break; | |
| case OCAST: // t f(T) or T f(t) | |
| t1 = n->type; | |
| if(t1 == T) | |
| goto no; | |
| if(f != nil) { | |
| s = f->castfr[t1->etype]; | |
| if(s == S) | |
| goto no; | |
| n->right = n->left; | |
| goto build; | |
| } | |
| f = t1->funct; | |
| if(f != nil) { | |
| s = f->castto[t->etype]; | |
| if(s == S) | |
| goto no; | |
| n->right = n->left; | |
| goto build; | |
| } | |
| goto no; | |
| } | |
| if(f == nil) | |
| goto no; | |
| s = f->sym[o]; | |
| if(s == S) | |
| goto no; | |
| /* | |
| * the answer is yes, | |
| * now we rewrite the node | |
| * and give diagnostics | |
| */ | |
| switch(o) { | |
| default: | |
| diag(n, "isfunct op missing %O\n", o); | |
| goto bad; | |
| case OADD: // T f(T, T) | |
| case OAND: | |
| case OASHL: | |
| case OASHR: | |
| case ODIV: | |
| case OLDIV: | |
| case OLMOD: | |
| case OLMUL: | |
| case OLSHR: | |
| case OMOD: | |
| case OMUL: | |
| case OOR: | |
| case OSUB: | |
| case OXOR: | |
| case OEQ: // int f(T, T) | |
| case OGE: | |
| case OGT: | |
| case OHI: | |
| case OHS: | |
| case OLE: | |
| case OLO: | |
| case OLS: | |
| case OLT: | |
| case ONE: | |
| if(n->right == Z) | |
| goto bad; | |
| t1 = n->right->type; | |
| if(t1 == T) | |
| goto bad; | |
| if(t1->funct != f) | |
| goto bad; | |
| n->right = new(OLIST, n->left, n->right); | |
| break; | |
| case OAS: // structure copies done by the compiler | |
| case OASI: | |
| goto no; | |
| case OASADD: // T f(T*, T) | |
| case OASAND: | |
| case OASASHL: | |
| case OASASHR: | |
| case OASDIV: | |
| case OASLDIV: | |
| case OASLMOD: | |
| case OASLMUL: | |
| case OASLSHR: | |
| case OASMOD: | |
| case OASMUL: | |
| case OASOR: | |
| case OASSUB: | |
| case OASXOR: | |
| if(n->right == Z) | |
| goto bad; | |
| t1 = n->right->type; | |
| if(t1 == T) | |
| goto bad; | |
| if(t1->funct != f) | |
| goto bad; | |
| n->right = new(OLIST, new(OADDR, n->left, Z), n->right); | |
| break; | |
| case OPOS: // T f(T) | |
| case ONEG: | |
| case ONOT: | |
| case OCOM: | |
| n->right = n->left; | |
| break; | |
| } | |
| build: | |
| l = new(ONAME, Z, Z); | |
| l->sym = s; | |
| l->type = s->type; | |
| l->etype = s->type->etype; | |
| l->xoffset = s->offset; | |
| l->class = s->class; | |
| tcomo(l, 0); | |
| n->op = OFUNC; | |
| n->left = l; | |
| n->type = l->type->link; | |
| if(tcompat(n, T, l->type, tfunct)) | |
| goto bad; | |
| if(tcoma(n->left, n->right, l->type->down, 1)) | |
| goto bad; | |
| return 1; | |
| no: | |
| return 0; | |
| bad: | |
| diag(n, "cant rewrite typestr for op %O\n", o); | |
| prtree(n, "isfunct"); | |
| n->type = T; | |
| return 1; | |
| } | |
| void | |
| dclfunct(Type *t, Sym *s) | |
| { | |
| Funct *f; | |
| Node *n; | |
| Type *f1, *f2, *f3, *f4; | |
| int o, i, c; | |
| char str[100]; | |
| if(t->funct) | |
| return; | |
| // recognize generated tag of dorm _%d_ | |
| if(t->tag == S) | |
| goto bad; | |
| for(i=0; c = t->tag->name[i]; i++) { | |
| if(c == '_') { | |
| if(i == 0 || t->tag->name[i+1] == 0) | |
| continue; | |
| break; | |
| } | |
| if(c < '0' || c > '9') | |
| break; | |
| } | |
| if(c == 0) | |
| goto bad; | |
| f = alloc(sizeof(*f)); | |
| for(o=0; o<sizeof(f->sym); o++) | |
| f->sym[o] = S; | |
| t->funct = f; | |
| f1 = typ(TFUNC, t); | |
| f1->down = copytyp(t); | |
| f1->down->down = t; | |
| f2 = typ(TFUNC, types[TINT]); | |
| f2->down = copytyp(t); | |
| f2->down->down = t; | |
| f3 = typ(TFUNC, t); | |
| f3->down = typ(TIND, t); | |
| f3->down->down = t; | |
| f4 = typ(TFUNC, t); | |
| f4->down = t; | |
| for(i=0;; i++) { | |
| o = ftabinit[i].op; | |
| if(o == OXXX) | |
| break; | |
| sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name); | |
| n = new(ONAME, Z, Z); | |
| n->sym = slookup(str); | |
| f->sym[o] = n->sym; | |
| switch(ftabinit[i].typ) { | |
| default: | |
| diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ); | |
| break; | |
| case 1: // T f(T,T) + | |
| dodecl(xdecl, CEXTERN, f1, n); | |
| break; | |
| case 2: // int f(T,T) == | |
| dodecl(xdecl, CEXTERN, f2, n); | |
| break; | |
| case 3: // void f(T*,T) += | |
| dodecl(xdecl, CEXTERN, f3, n); | |
| break; | |
| case 4: // T f(T) ~ | |
| dodecl(xdecl, CEXTERN, f4, n); | |
| break; | |
| } | |
| } | |
| for(i=0;; i++) { | |
| o = gtabinit[i].etype; | |
| if(o == TXXX) | |
| break; | |
| /* | |
| * OCAST types T1 _T2_T1_(T2) | |
| */ | |
| sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name); | |
| n = new(ONAME, Z, Z); | |
| n->sym = slookup(str); | |
| f->castto[o] = n->sym; | |
| f1 = typ(TFUNC, t); | |
| f1->down = types[o]; | |
| dodecl(xdecl, CEXTERN, f1, n); | |
| sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name); | |
| n = new(ONAME, Z, Z); | |
| n->sym = slookup(str); | |
| f->castfr[o] = n->sym; | |
| f1 = typ(TFUNC, types[o]); | |
| f1->down = t; | |
| dodecl(xdecl, CEXTERN, f1, n); | |
| } | |
| return; | |
| bad: | |
| diag(Z, "dclfunct bad %T %s\n", t, s->name); | |
| } | |
| Gtab gtabinit[NTYPE] = | |
| { | |
| TCHAR, "c", | |
| TUCHAR, "uc", | |
| TSHORT, "h", | |
| TUSHORT, "uh", | |
| TINT, "i", | |
| TUINT, "ui", | |
| TLONG, "l", | |
| TULONG, "ul", | |
| TVLONG, "v", | |
| TUVLONG, "uv", | |
| TFLOAT, "f", | |
| TDOUBLE, "d", | |
| TXXX | |
| }; | |
| Ftab ftabinit[OEND] = | |
| { | |
| OADD, "add", 1, | |
| OAND, "and", 1, | |
| OASHL, "ashl", 1, | |
| OASHR, "ashr", 1, | |
| ODIV, "div", 1, | |
| OLDIV, "ldiv", 1, | |
| OLMOD, "lmod", 1, | |
| OLMUL, "lmul", 1, | |
| OLSHR, "lshr", 1, | |
| OMOD, "mod", 1, | |
| OMUL, "mul", 1, | |
| OOR, "or", 1, | |
| OSUB, "sub", 1, | |
| OXOR, "xor", 1, | |
| OEQ, "eq", 2, | |
| OGE, "ge", 2, | |
| OGT, "gt", 2, | |
| OHI, "hi", 2, | |
| OHS, "hs", 2, | |
| OLE, "le", 2, | |
| OLO, "lo", 2, | |
| OLS, "ls", 2, | |
| OLT, "lt", 2, | |
| ONE, "ne", 2, | |
| OASADD, "asadd", 3, | |
| OASAND, "asand", 3, | |
| OASASHL, "asashl", 3, | |
| OASASHR, "asashr", 3, | |
| OASDIV, "asdiv", 3, | |
| OASLDIV, "asldiv", 3, | |
| OASLMOD, "aslmod", 3, | |
| OASLMUL, "aslmul", 3, | |
| OASLSHR, "aslshr", 3, | |
| OASMOD, "asmod", 3, | |
| OASMUL, "asmul", 3, | |
| OASOR, "asor", 3, | |
| OASSUB, "assub", 3, | |
| OASXOR, "asxor", 3, | |
| OPOS, "pos", 4, | |
| ONEG, "neg", 4, | |
| OCOM, "com", 4, | |
| ONOT, "not", 4, | |
| // OPOSTDEC, | |
| // OPOSTINC, | |
| // OPREDEC, | |
| // OPREINC, | |
| OXXX, | |
| }; | |
| // Node* nodtestv; | |
| // Node* nodvpp; | |
| // Node* nodppv; | |
| // Node* nodvmm; | |
| // Node* nodmmv; |