diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/1c/sgen.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/1c/sgen.c')
-rwxr-xr-x | sys/src/cmd/1c/sgen.c | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/sys/src/cmd/1c/sgen.c b/sys/src/cmd/1c/sgen.c new file mode 100755 index 000000000..0621c264c --- /dev/null +++ b/sys/src/cmd/1c/sgen.c @@ -0,0 +1,714 @@ +#include "gc.h" + +void +codgen(Node *n, Node *nn) +{ + Prog *sp; + + argoff = 0; + inargs = 0; + for(;; nn = nn->left) { + if(nn == Z) { + diag(Z, "cant find function name"); + return; + } + if(nn->op == ONAME) + break; + } + nearln = nn->lineno; + gpseudo(ATEXT, nn->sym, D_CONST, stkoff); + sp = p; + + retok = 0; + gen(n); + if(!retok) + if(thisfn->link->etype != TVOID) + warn(Z, "no return at end of function: %s", nn->sym->name); + + noretval(3); + gbranch(ORETURN); + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); +} + +void +gen(Node *n) +{ + Node *l; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int snbreak; + int g, o; + +loop: + if(n == Z) + return; + nearln = n->lineno; + o = n->op; + if(debug['G']) + if(o != OLIST) + print("%L %O\n", nearln, o); + + retok = 0; + switch(o) { + + default: + complex(n); + doinc(n, PRE); + cgen(n, D_NONE, n); + doinc(n, POST); + break; + + case OLIST: + gen(n->left); + + rloop: + n = n->right; + goto loop; + + case ORETURN: + retok = 1; + complex(n); + if(n->type == T) + break; + l = n->left; + if(l == Z) { + noretval(3); + gbranch(ORETURN); + break; + } + doinc(l, PRE); + if(typesuv[n->type->etype]) { + sugen(l, D_TREE, nodret, n->type->width); + doinc(l, POST); + noretval(3); + gbranch(ORETURN); + break; + } + g = regalloc(n->type, regret(n->type)); + cgen(l, g, n); + doinc(l, POST); + if(typefd[n->type->etype]) + noretval(1); + else + noretval(2); + gbranch(ORETURN); + regfree(g); + break; + + case OLABEL: + l = n->left; + if(l) { + l->xoffset = pc; + if(l->label) + patch(l->label, pc); + } + gbranch(OGOTO); /* prevent self reference in reg */ + patch(p, pc); + goto rloop; + + case OGOTO: + retok = 1; + n = n->left; + if(n == Z) + return; + if(n->complex == 0) { + diag(Z, "label undefined: %s", n->sym->name); + return; + } + gbranch(OGOTO); + if(n->xoffset) { + patch(p, n->xoffset); + return; + } + if(n->label) + patch(n->label, pc-1); + n->label = p; + return; + + case OCASE: + l = n->left; + if(cases == C) + diag(n, "case/default outside a switch"); + if(l == Z) { + casf(); + cases->val = 0; + cases->def = 1; + cases->label = pc; + setsp();; + goto rloop; + } + complex(l); + if(l->type == T) + goto rloop; + if(l->op == OCONST) + if(typechl[l->type->etype]) { + casf(); + cases->val = l->vconst; + cases->def = 0; + cases->label = pc; + setsp(); + goto rloop; + } + diag(n, "case expression must be integer constant"); + goto rloop; + + case OSWITCH: + l = n->left; + complex(l); + doinc(l, PRE); + if(l->type == T) + break; + if(!typechl[l->type->etype]) { + diag(n, "switch expression must be integer"); + break; + } + g = regalloc(types[TLONG], D_NONE); + n->type = types[TLONG]; + cgen(l, g, n); + regfree(g); + doinc(l, POST); + setsp(); + gbranch(OGOTO); /* entry */ + sp = p; + + cn = cases; + cases = C; + casf(); + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + gen(n->right); + gbranch(OGOTO); + patch(p, breakpc); + nbreak++; + + patch(sp, pc); + doswit(g, l); + + patch(spb, pc); + cases = cn; + breakpc = sbc; + nbreak = snbreak; + setsp(); + break; + + case OWHILE: + case ODWHILE: + l = n->left; + gbranch(OGOTO); /* entry */ + sp = p; + + scc = continpc; + continpc = pc; + gbranch(OGOTO); + spc = p; + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + patch(spc, pc); + if(n->op == OWHILE) + patch(sp, pc); + bcomplex(l); /* test */ + patch(p, breakpc); + if(l->op != OCONST || vconst(l) == 0) + nbreak++; + + if(n->op == ODWHILE) + patch(sp, pc); + gen(n->right); /* body */ + gbranch(OGOTO); + patch(p, continpc); + + patch(spb, pc); + continpc = scc; + breakpc = sbc; + if(nbreak == 0) + retok = 1; + nbreak = snbreak; + break; + + case OFOR: + l = n->left; + gen(l->right->left); /* init */ + gbranch(OGOTO); /* entry */ + sp = p; + + scc = continpc; + continpc = pc; + gbranch(OGOTO); + spc = p; + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + patch(spc, pc); + gen(l->right->right); /* inc */ + patch(sp, pc); + if(l->left != Z) { /* test */ + bcomplex(l->left); + patch(p, breakpc); + if(l->left->op != OCONST || vconst(l->left) == 0) + nbreak++; + } + gen(n->right); /* body */ + gbranch(OGOTO); + patch(p, continpc); + + patch(spb, pc); + continpc = scc; + breakpc = sbc; + if(nbreak == 0) + retok = 1; + nbreak = snbreak; + break; + + case OCONTINUE: + if(continpc < 0) { + diag(n, "continue not in a loop"); + break; + } + gbranch(OGOTO); + patch(p, continpc); + break; + + case OBREAK: + if(breakpc < 0) { + diag(n, "break not in a loop"); + break; + } + gbranch(OGOTO); + patch(p, breakpc); + nbreak++; + break; + + case OIF: + l = n->left; + bcomplex(l); + sp = p; + if(n->right->left != Z) + gen(n->right->left); + if(n->right->right != Z) { + gbranch(OGOTO); + patch(sp, pc); + sp = p; + gen(n->right->right); + } + patch(sp, pc); + break; + + case OSET: + case OUSED: + usedset(n->left, o); + break; + } +} + +void +usedset(Node *n, int o) +{ + if(n->op == OLIST) { + usedset(n->left, o); + usedset(n->right, o); + return; + } + complex(n); + switch(n->op) { + case OADDR: /* volatile */ + gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z); + p->as = ANOP; + break; + case ONAME: + if(o == OSET) + gopcode(OTST, types[TINT], D_NONE, Z, D_TREE, n); + else + gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z); + p->as = ANOP; + break; + } +} + +void +noretval(int n) +{ + + if(n & 1) { + gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TLONG]), Z); + p->as = ANOP; + } + if(n & 2) { + gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TDOUBLE]), Z); + p->as = ANOP; + } +} + +/* + * calculate addressability as follows + * REGISTER ==> 12 register + * NAME ==> 11 name+value(SB/SP) + * note that 10 is no longer generated + * CONST ==> 20 $value + * *(20) ==> 21 value + * &(10) ==> 12 $name+value(SB) + * &(11) ==> 1 $name+value(SP) + * (12) + (20) ==> 12 fold constants + * (1) + (20) ==> 1 fold constants + * *(12) ==> 10 back to name + * *(1) ==> 11 back to name + * + * (2,10,11) + (20) ==> 2 indirect w offset + * (2) ==> &13 + * *(10,11) ==> 13 indirect, no index + * + * (20) * (X) ==> 7 multiplier in indexing + * (X,7) + (12,1) ==> 8 adder in indexing (addresses) + * (X,7) + (10,11,2) ==> 8 adder in indexing (names) + * (8) ==> &9 index, almost addressable + * + * (X)++ ==> X fake addressability + * + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int g; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->complex = 0; + n->addable = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + break; + + case ONAME: + n->addable = 11; /* difference to make relocatable */ + break; + + case OREGISTER: + n->addable = 12; + break; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 12; + else + if(l->addable == 11) + n->addable = 1; + break; + + case OADD: + xcom(l); + xcom(r); + if(n->type->etype != TIND) + break; + + if(l->addable == 20) + switch(r->addable) { + case 12: + case 1: + n->addable = r->addable; + goto brk; + } + if(r->addable == 20) + switch(l->addable) { + case 12: + case 1: + n->addable = l->addable; + goto brk; + } + break; + + case OIND: + xcom(l); + if(l->op == OADDR) { + l = l->left; + l->type = n->type; + *n = *l; + return; + } + switch(l->addable) { + case 20: + n->addable = 21; + break; + case 1: + n->addable = 11; + break; + case 12: + n->addable = 10; + break; + } + break; + + case OASHL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vconst(r); + if(g >= 0 && g < 4) + n->addable = 7; + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + n->op = OASHL; + r->vconst = g; + if(g < 4) + n->addable = 7; + break; + } + g = vlog(l); + if(g >= 0) { + n->left = r; + n->right = l; + l = r; + r = n->right; + n->op = OASHL; + r->vconst = g; + if(g < 4) + n->addable = 7; + break; + } + break; + + case ODIV: + case OLDIV: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + if(n->op == ODIV) + n->op = OASHR; + else + n->op = OLSHR; + r->vconst = g; + } + break; + + case OSUB: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + if(vconst(l) == 0) { + n->op = ONEG; + n->left = r; + n->right = Z; + } + break; + + case OXOR: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + if(vconst(l) == -1) { + n->op = OCOM; + n->left = r; + n->right = Z; + } + break; + + case OASMUL: + case OASLMUL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + n->op = OASASHL; + r->vconst = g; + } + goto aseae; + + case OASDIV: + case OASLDIV: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + if(n->op == OASDIV) + n->op = OASASHR; + else + n->op = OASLSHR; + r->vconst = g; + } + goto aseae; + + case OASLMOD: + case OASMOD: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + + aseae: /* hack that there are no byte/short mul/div operators */ + if(n->type->etype == TCHAR || n->type->etype == TSHORT) { + n->right = new1(OCAST, n->right, Z); + n->right->type = types[TLONG]; + n->type = types[TLONG]; + } + if(n->type->etype == TUCHAR || n->type->etype == TUSHORT) { + n->right = new1(OCAST, n->right, Z); + n->right->type = types[TULONG]; + n->type = types[TULONG]; + } + goto asop; + + case OASXOR: + case OASOR: + case OASADD: + case OASSUB: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASAND: + case OAS: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + + asop: + if(l->addable > INDEXED && + l->complex < FNX && + r && r->complex < FNX) + n->addable = l->addable; + break; + + case OPOSTINC: + case OPREINC: + case OPOSTDEC: + case OPREDEC: + xcom(l); + if(typev[n->type->etype]) + break; + if(l->addable > INDEXED && + l->complex < FNX) + n->addable = l->addable; + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + +brk: + n->complex = 0; + if(n->addable >= 10) + return; + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + if(com64(n)) + return; + + switch(n->op) { + + case OFUNC: + n->complex = FNX; + break; + + case OADD: + case OMUL: + case OLMUL: + case OXOR: + case OAND: + case OOR: + /* + * symmetric operators, make right side simple + * if same, put constant on left to get movq + */ + if(r->complex > l->complex || + (r->complex == l->complex && r->addable == 20)) { + n->left = r; + n->right = l; + } + break; + + case OLE: + case OLT: + case OGE: + case OGT: + case OEQ: + case ONE: + /* + * relational operators, make right side simple + * if same, put constant on left to get movq + */ + if(r->complex > l->complex || r->addable == 20) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + } +} + +void +bcomplex(Node *n) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type != T) { + bool64(n); + doinc(n, PRE); + boolgen(n, 1, D_NONE, Z, n); + } else + gbranch(OGOTO); +} + +Node* +nodconst(long v) +{ + + return (Node*)v; +} |