aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/gc/gsubr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/gsubr.c')
-rw-r--r--src/cmd/gc/gsubr.c654
1 files changed, 0 insertions, 654 deletions
diff --git a/src/cmd/gc/gsubr.c b/src/cmd/gc/gsubr.c
deleted file mode 100644
index 5175ae34f5..0000000000
--- a/src/cmd/gc/gsubr.c
+++ /dev/null
@@ -1,654 +0,0 @@
-// Derived from Inferno utils/6c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.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 <libc.h>
-#include "go.h"
-#include "../../runtime/funcdata.h"
-#include "../ld/textflag.h"
-
-void
-ggloblnod(Node *nam)
-{
- Prog *p;
-
- p = thearch.gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->from.sym->gotype = linksym(ngotype(nam));
- p->to.sym = nil;
- p->to.type = TYPE_CONST;
- p->to.offset = nam->type->width;
- if(nam->readonly)
- p->from3.offset = RODATA;
- if(nam->type != T && !haspointers(nam->type))
- p->from3.offset |= NOPTR;
-}
-
-void
-gtrack(Sym *s)
-{
- Prog *p;
-
- p = thearch.gins(AUSEFIELD, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
- Prog *p;
-
- p = thearch.gins(AGLOBL, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->to.type = TYPE_CONST;
- p->to.offset = width;
- p->from3.offset = flags;
-}
-
-void
-clearp(Prog *p)
-{
- nopout(p);
- p->as = AEND;
- p->pc = pcloc;
- pcloc++;
-}
-
-static int ddumped;
-static Prog *dfirst;
-static Prog *dpc;
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
- Prog *p;
-
- if(as == ADATA || as == AGLOBL) {
- if(ddumped)
- fatal("already dumped data");
- if(dpc == nil) {
- dpc = mal(sizeof(*dpc));
- dfirst = dpc;
- }
- p = dpc;
- dpc = mal(sizeof(*dpc));
- p->link = dpc;
- } else {
- p = pc;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p->link = pc;
- }
-
- if(lineno == 0) {
- if(debug['K'])
- warn("prog: line 0");
- }
-
- p->as = as;
- p->lineno = lineno;
- return p;
-}
-
-void
-dumpdata(void)
-{
- ddumped = 1;
- if(dfirst == nil)
- return;
- newplist();
- *pc = *dfirst;
- pc = dpc;
- clearp(pc);
-}
-
-/*
- * generate a branch.
- * t is ignored.
- * likely values are for branch prediction:
- * -1 unlikely
- * 0 no opinion
- * +1 likely
- */
-Prog*
-gbranch(int as, Type *t, int likely)
-{
- Prog *p;
-
- USED(t);
-
- p = prog(as);
- p->to.type = TYPE_BRANCH;
- p->to.u.branch = P;
- if(as != AJMP && likely != 0 && thearch.thechar != '9') {
- p->from.type = TYPE_CONST;
- p->from.offset = likely > 0;
- }
- return p;
-}
-
-/*
- * patch previous branch to jump to to.
- */
-void
-patch(Prog *p, Prog *to)
-{
- if(p->to.type != TYPE_BRANCH)
- fatal("patch: not a branch");
- p->to.u.branch = to;
- p->to.offset = to->pc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
- Prog *q;
-
- if(p->to.type != TYPE_BRANCH)
- fatal("unpatch: not a branch");
- q = p->to.u.branch;
- p->to.u.branch = P;
- p->to.offset = 0;
- return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
- Plist *pl;
-
- pl = linknewplist(ctxt);
-
- pc = mal(sizeof(*pc));
- clearp(pc);
- pl->firstpc = pc;
-
- return pl;
-}
-
-void
-gused(Node *n)
-{
- thearch.gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(AJMP, T, 0);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-int
-isfat(Type *t)
-{
- if(t != T)
- switch(t->etype) {
- case TSTRUCT:
- case TARRAY:
- case TSTRING:
- case TINTER: // maybe remove later
- return 1;
- }
- return 0;
-}
-
-/*
- * naddr of func generates code for address of func.
- * if using opcode that can take address implicitly,
- * call afunclit to fix up the argument.
- */
-void
-afunclit(Addr *a, Node *n)
-{
- if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
- a->type = TYPE_MEM;
- a->sym = linksym(n->sym);
- }
-}
-
-/*
- * initialize n to be register r of type t.
- */
-void
-nodreg(Node *n, Type *t, int r)
-{
- if(t == T)
- fatal("nodreg: t nil");
-
- memset(n, 0, sizeof(*n));
- n->op = OREGISTER;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.reg = r;
- n->type = t;
-}
-
-/*
- * initialize n to be indirect of register r; n is type t.
- */
-void
-nodindreg(Node *n, Type *t, int r)
-{
- nodreg(n, t, r);
- n->op = OINDREG;
-}
-
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
- switch(n->op) {
- case OITAB:
- case OSPTR:
- case OLEN:
- case OCAP:
- case OINDREG:
- case ONAME:
- case OPARAM:
- case OCLOSUREVAR:
- return 1;
- case OADDR:
- return thearch.thechar == '6' || thearch.thechar == '9'; // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
- }
- return 0;
-}
-
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
- continue;
-
- if (p->from.node)
- ((Node*)(p->from.node))->used = 1;
-
- if (p->to.node)
- ((Node*)(p->to.node))->used = 1;
- }
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog *p)
-{
- Prog **lp;
-
- for (lp=&p; (p=*lp) != P; ) {
- if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
- *lp = p->link;
- continue;
- }
- if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
- // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
- // VARDEFs are interspersed with other code, and a jump might be using the
- // VARDEF as a target. Replace with a no-op instead. A later pass will remove
- // the no-ops.
- nopout(p);
- continue;
- }
- if (p->from.name == NAME_AUTO && p->from.node)
- p->from.offset += ((Node*)(p->from.node))->stkdelta;
-
- if (p->to.name == NAME_AUTO && p->to.node)
- p->to.offset += ((Node*)(p->to.node))->stkdelta;
-
- lp = &p->link;
- }
-}
-
-int
-samereg(Node *a, Node *b)
-{
- if(a == N || b == N)
- return 0;
- if(a->op != OREGISTER)
- return 0;
- if(b->op != OREGISTER)
- return 0;
- if(a->val.u.reg != b->val.u.reg)
- return 0;
- return 1;
-}
-
-Node*
-nodarg(Type *t, int fp)
-{
- Node *n;
- NodeList *l;
- Type *first;
- Iter savet;
-
- // entire argument struct, not just one arg
- if(t->etype == TSTRUCT && t->funarg) {
- n = nod(ONAME, N, N);
- n->sym = lookup(".args");
- n->type = t;
- first = structfirst(&savet, &t);
- if(first == nil)
- fatal("nodarg: bad struct");
- if(first->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = first->width;
- n->addable = 1;
- goto fp;
- }
-
- if(t->etype != TFIELD)
- fatal("nodarg: not field %T", t);
-
- if(fp == 1) {
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
- return n;
- }
- }
-
- n = nod(ONAME, N, N);
- n->type = t->type;
- n->sym = t->sym;
-
- if(t->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = t->width;
- n->addable = 1;
- n->orig = t->nname;
-
-fp:
- // Rewrite argument named _ to __,
- // or else the assignment to _ will be
- // discarded during code generation.
- if(isblank(n))
- n->sym = lookup("__");
-
- switch(fp) {
- case 0: // output arg
- n->op = OINDREG;
- n->val.u.reg = thearch.REGSP;
- if(thearch.thechar == '5')
- n->xoffset += 4;
- if(thearch.thechar == '9')
- n->xoffset += 8;
- break;
-
- case 1: // input arg
- n->class = PPARAM;
- break;
-
- case 2: // offset output arg
-fatal("shouldn't be used");
- n->op = OINDREG;
- n->val.u.reg = thearch.REGSP;
- n->xoffset += types[tptr]->width;
- break;
- }
- n->typecheck = 1;
- return n;
-}
-
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- Sym *s;
-
- *a = zprog.from;
- if(n == N)
- return;
-
- if(n->type != T && n->type->etype != TIDEAL) {
- // TODO(rsc): This is undone by the selective clearing of width below,
- // to match architectures that were not as aggressive in setting width
- // during naddr. Those widths must be cleared to avoid triggering
- // failures in gins when it detects real but heretofore latent (and one
- // hopes innocuous) type mismatches.
- // The type mismatches should be fixed and the clearing below removed.
- dowidth(n->type);
- a->width = n->type->width;
- }
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = TYPE_REG;
- a->reg = n->val.u.reg;
- a->sym = nil;
- if(thearch.thechar == '8') // TODO(rsc): Never clear a->width.
- a->width = 0;
- break;
-
- case OINDREG:
- a->type = TYPE_MEM;
- a->reg = n->val.u.reg;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- if(a->offset != (int32)a->offset)
- yyerror("offset %lld too large for OINDREG", a->offset);
- if(thearch.thechar == '8') // TODO(rsc): Never clear a->width.
- a->width = 0;
- break;
-
- case OPARAM:
- // n->left is PHEAP ONAME for stack parameter.
- // compute address of actual parameter on stack.
- a->etype = simtype[n->left->type->etype];
- a->width = n->left->type->width;
- a->offset = n->xoffset;
- a->sym = linksym(n->left->sym);
- a->type = TYPE_MEM;
- a->name = NAME_PARAM;
- a->node = n->left->orig;
- break;
-
- case OCLOSUREVAR:
- if(!curfn->needctxt)
- fatal("closurevar without needctxt");
- a->type = TYPE_MEM;
- a->reg = thearch.REGCTXT;
- a->sym = nil;
- a->offset = n->xoffset;
- break;
-
- case OCFUNC:
- naddr(n->left, a, canemitcode);
- a->sym = linksym(n->left->sym);
- break;
-
- case ONAME:
- a->etype = 0;
- if(n->type != T)
- a->etype = simtype[n->type->etype];
- a->offset = n->xoffset;
- s = n->sym;
- a->node = n->orig;
- //if(a->node >= (Node*)&n)
- // fatal("stack node");
- if(s == S)
- s = lookup(".noname");
- if(n->method) {
- if(n->type != T)
- if(n->type->sym != S)
- if(n->type->sym->pkg != nil)
- s = pkglookup(s->name, n->type->sym->pkg);
- }
-
- a->type = TYPE_MEM;
- switch(n->class) {
- default:
- fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
- case PEXTERN:
- a->name = NAME_EXTERN;
- break;
- case PAUTO:
- a->name = NAME_AUTO;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->name = NAME_PARAM;
- break;
- case PFUNC:
- a->name = NAME_EXTERN;
- a->type = TYPE_ADDR;
- a->width = widthptr;
- s = funcsym(s);
- break;
- }
- a->sym = linksym(s);
- break;
-
- case OLITERAL:
- if(thearch.thechar == '8')
- a->width = 0;
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = TYPE_FCONST;
- a->u.dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- case CTRUNE:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = mpgetfix(n->val.u.xval);
- break;
- case CTSTR:
- datagostring(n->val.u.sval, a);
- break;
- case CTBOOL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- a->etype = tptr;
- if(thearch.thechar != '5' && thearch.thechar != '9') // TODO(rsc): Do this even for arm, ppc64.
- a->width = widthptr;
- if(a->type != TYPE_MEM)
- fatal("naddr: OADDR %D (from %O)", a, n->left->op);
- a->type = TYPE_ADDR;
- break;
-
- case OITAB:
- // itable of interface value
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // itab(nil)
- a->etype = tptr;
- a->width = widthptr;
- break;
-
- case OSPTR:
- // pointer in a string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // ptr(nil)
- a->etype = simtype[tptr];
- a->offset += Array_array;
- a->width = widthptr;
- break;
-
- case OLEN:
- // len of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // len(nil)
- a->etype = simtype[TUINT];
- if(thearch.thechar == '9')
- a->etype = simtype[TINT];
- a->offset += Array_nel;
- if(thearch.thechar != '5') // TODO(rsc): Do this even on arm.
- a->width = widthint;
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // cap(nil)
- a->etype = simtype[TUINT];
- if(thearch.thechar == '9')
- a->etype = simtype[TINT];
- a->offset += Array_cap;
- if(thearch.thechar != '5') // TODO(rsc): Do this even on arm.
- a->width = widthint;
- break;
-
-// case OADD:
-// if(n->right->op == OLITERAL) {
-// v = n->right->vconst;
-// naddr(n->left, a, canemitcode);
-// } else
-// if(n->left->op == OLITERAL) {
-// v = n->left->vconst;
-// naddr(n->right, a, canemitcode);
-// } else
-// goto bad;
-// a->offset += v;
-// break;
-
- }
-}