// Inferno utils/6c/sgen.c // http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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 "gc.h" #include "../../runtime/funcdata.h" Prog* gtext(Sym *s, int32 stkoff) { vlong v; v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff); if((textflag & NOSPLIT) && stkoff >= 128) yyerror("stack frame too large for NOSPLIT function"); gpseudo(ATEXT, s, nodgconst(v, types[TVLONG])); return p; } void noretval(int n) { if(n & 1) { gins(ANOP, Z, Z); p->to.type = REGRET; } if(n & 2) { gins(ANOP, Z, Z); p->to.type = FREGRET; } } /* welcome to commute */ static void commute(Node *n) { Node *l, *r; l = n->left; r = n->right; if(r->complex > l->complex) { n->left = r; n->right = l; } } void indexshift(Node *n) { int g; if(!typechlpv[n->type->etype]) return; simplifyshift(n); if(n->op == OASHL && n->right->op == OCONST){ g = vconst(n->right); if(g >= 0 && g <= 3) n->addable = 7; } } /* * calculate addressability as follows * NAME ==> 10/11 name+value(SB/SP) * REGISTER ==> 12 register * CONST ==> 20 $value * *(20) ==> 21 value * &(10) ==> 13 $name+value(SB) * &(11) ==> 1 $name+value(SP) * (13) + (20) ==> 13 fold constants * (1) + (20) ==> 1 fold constants * *(13) ==> 10 back to name * *(1) ==> 11 back to name * * (20) * (X) ==> 7 multiplier in indexing * (X,7) + (13,1) ==> 8 adder in indexing (addresses) * (8) ==> &9(OINDEX) index, almost addressable * * 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 = 9; if(n->class == CPARAM || n->class == CAUTO) n->addable = 11; break; case OEXREG: n->addable = 0; break; case OREGISTER: n->addable = 12; break; case OINDREG: n->addable = 12; break; case OADDR: xcom(l); if(l->addable == 10) n->addable = 13; else if(l->addable == 11) n->addable = 1; break; case OADD: xcom(l); xcom(r); if(n->type->etype != TIND) break; switch(r->addable) { case 20: switch(l->addable) { case 1: case 13: commadd: l->type = n->type; *n = *l; l = new(0, Z, Z); *l = *(n->left); l->xoffset += r->vconst; n->left = l; r = n->right; goto brk; } break; case 1: case 13: case 10: case 11: /* l is the base, r is the index */ if(l->addable != 20) n->addable = 8; break; } switch(l->addable) { case 20: switch(r->addable) { case 13: case 1: r = n->left; l = n->right; n->left = l; n->right = r; goto commadd; } break; case 13: case 1: case 10: case 11: /* r is the base, l is the index */ if(r->addable != 20) n->addable = 8; break; } if(n->addable == 8 && !side(n) && !nacl) { indx(n); l = new1(OINDEX, idx.basetree, idx.regtree); l->scale = idx.scale; l->addable = 9; l->complex = l->right->complex; l->type = l->left->type; n->op = OADDR; n->left = l; n->right = Z; n->addable = 8; break; } break; case OINDEX: xcom(l); xcom(r); n->addable = 9; 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 13: n->addable = 10; break; } break; case OASHL: xcom(l); xcom(r); indexshift(n); break; case OMUL: case OLMUL: xcom(l); xcom(r); g = vlog(l); if(g >= 0) { n->left = r; n->right = l; l = r; r = n->right; } g = vlog(r); if(g >= 0) { n->op = OASHL; r->vconst = g; r->type = types[TINT]; indexshift(n); break; } commute(n); break; case OASLDIV: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASLSHR; r->vconst = g; r->type = types[TINT]; } break; case OLDIV: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OLSHR; r->vconst = g; r->type = types[TINT]; indexshift(n); break; } break; case OASLMOD: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASAND; r->vconst--; } break; case OLMOD: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OAND; r->vconst--; } break; case OASMUL: case OASLMUL: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASASHL; r->vconst = g; } break; case OLSHR: case OASHR: xcom(l); xcom(r); indexshift(n); break; default: if(l != Z) xcom(l); if(r != Z) xcom(r); break; } brk: 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++; switch(n->op) { case OFUNC: n->complex = FNX; break; case OCAST: if(l->type->etype == TUVLONG && typefd[n->type->etype]) n->complex += 2; break; case OLMOD: case OMOD: case OLMUL: case OLDIV: case OMUL: case ODIV: case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(r->complex >= l->complex) { n->complex = l->complex + 3; if(r->complex > n->complex) n->complex = r->complex; } else { n->complex = r->complex + 3; if(l->complex > n->complex) n->complex = l->complex; } break; case OLSHR: case OASHL: case OASHR: case OASLSHR: case OASASHL: case OASASHR: if(r->complex >= l->complex) { n->complex = l->complex + 2; if(r->complex > n->complex) n->complex = r->complex; } else { n->complex = r->complex + 2; if(l->complex > n->complex) n->complex = l->complex; } break; case OADD: case OXOR: case OAND: case OOR: /* * immediate operators, make const on right */ if(l->op == OCONST) { n->left = r; n->right = l; } break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OHI: case OHS: case OLO: case OLS: /* * compare operators, make const on left */ if(r->op == OCONST) { n->left = r; n->right = l; n->op = invrel[relindex(n->op)]; } break; } } void indx(Node *n) { Node *l, *r; if(debug['x']) prtree(n, "indx"); l = n->left; r = n->right; if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) { n->right = l; n->left = r; l = r; r = n->right; } if(l->addable != 7) { idx.regtree = l; idx.scale = 1; } else if(l->right->addable == 20) { idx.regtree = l->left; idx.scale = 1 << l->right->vconst; } else if(l->left->addable == 20) { idx.regtree = l->right; idx.scale = 1 << l->left->vconst; } else diag(n, "bad index"); idx.basetree = r; if(debug['x']) { print("scale = %d\n", idx.scale); prtree(idx.regtree, "index"); prtree(idx.basetree, "base"); } }