summaryrefslogtreecommitdiff
path: root/src/cmd/gc/subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/subr.c')
-rw-r--r--src/cmd/gc/subr.c193
1 files changed, 123 insertions, 70 deletions
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 72a9ac20c..c3bc5af3b 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -529,7 +529,8 @@ algtype1(Type *t, Type **bad)
if(bad)
*bad = T;
-
+ if(t->broke)
+ return AMEM;
if(t->noalg)
return ANOEQ;
@@ -656,11 +657,15 @@ maptype(Type *key, Type *val)
{
Type *t;
Type *bad;
- int atype;
+ int atype, mtype;
if(key != nil) {
atype = algtype1(key, &bad);
- switch(bad == T ? key->etype : bad->etype) {
+ if(bad == T)
+ mtype = key->etype;
+ else
+ mtype = bad->etype;
+ switch(mtype) {
default:
if(atype == ANOEQ)
yyerror("invalid map key type %T", key);
@@ -2625,9 +2630,10 @@ hashmem(Type *t)
n = newname(sym);
n->class = PFUNC;
tfn = nod(OTFUNC, N, N);
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR]))));
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
typecheck(&tfn, Etype);
n->type = tfn->type;
return n;
@@ -2673,9 +2679,10 @@ hashfor(Type *t)
n = newname(sym);
n->class = PFUNC;
tfn = nod(OTFUNC, N, N);
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR]))));
- tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
typecheck(&tfn, Etype);
n->type = tfn->type;
return n;
@@ -2687,7 +2694,7 @@ hashfor(Type *t)
void
genhash(Sym *sym, Type *t)
{
- Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn;
+ Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn, *r;
Node *hashel;
Type *first, *t1;
int old_safemode;
@@ -2700,21 +2707,23 @@ genhash(Sym *sym, Type *t)
dclcontext = PEXTERN;
markdcl();
- // func sym(h *uintptr, s uintptr, p *T)
+ // func sym(p *T, s uintptr, h uintptr) uintptr
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(sym);
fn->nname->class = PFUNC;
tfn = nod(OTFUNC, N, N);
fn->nname->ntype = tfn;
- n = nod(ODCLFIELD, newname(lookup("h")), typenod(ptrto(types[TUINTPTR])));
+ n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
tfn->list = list(tfn->list, n);
- nh = n->left;
+ np = n->left;
n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
tfn->list = list(tfn->list, n);
- n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
+ n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR]));
tfn->list = list(tfn->list, n);
- np = n->left;
+ nh = n->left;
+ n = nod(ODCLFIELD, N, typenod(types[TUINTPTR])); // return value
+ tfn->rlist = list(tfn->rlist, n);
funchdr(fn);
typecheck(&fn->nname->ntype, Etype);
@@ -2740,15 +2749,17 @@ genhash(Sym *sym, Type *t)
colasdefn(n->list, n);
ni = n->list->n;
- // *h = *h<<3 | *h>>61
+ // TODO: with aeshash we don't need these shift/mul parts
+
+ // h = h<<3 | h>>61
n->nbody = list(n->nbody,
nod(OAS,
- nod(OIND, nh, N),
+ nh,
nod(OOR,
- nod(OLSH, nod(OIND, nh, N), nodintconst(3)),
- nod(ORSH, nod(OIND, nh, N), nodintconst(widthptr*8-3)))));
+ nod(OLSH, nh, nodintconst(3)),
+ nod(ORSH, nh, nodintconst(widthptr*8-3)))));
- // *h *= mul
+ // h *= mul
// Same multipliers as in runtime.memhash.
if(widthptr == 4)
mul = 3267000013LL;
@@ -2756,19 +2767,19 @@ genhash(Sym *sym, Type *t)
mul = 23344194077549503LL;
n->nbody = list(n->nbody,
nod(OAS,
- nod(OIND, nh, N),
- nod(OMUL, nod(OIND, nh, N), nodintconst(mul))));
+ nh,
+ nod(OMUL, nh, nodintconst(mul))));
- // hashel(h, sizeof(p[i]), &p[i])
+ // h = hashel(&p[i], sizeof(p[i]), h)
call = nod(OCALL, hashel, N);
- call->list = list(call->list, nh);
- call->list = list(call->list, nodintconst(t->type->width));
nx = nod(OINDEX, np, ni);
nx->bounded = 1;
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
- n->nbody = list(n->nbody, call);
+ call->list = list(call->list, nodintconst(t->type->width));
+ call->list = list(call->list, nh);
+ n->nbody = list(n->nbody, nod(OAS, nh, call));
fn->nbody = list(fn->nbody, n);
break;
@@ -2793,15 +2804,15 @@ genhash(Sym *sym, Type *t)
if(first != T) {
size = offend - first->width; // first->width is offset
hashel = hashmem(first->type);
- // hashel(h, size, &p.first)
+ // h = hashel(&p.first, size, h)
call = nod(OCALL, hashel, N);
- call->list = list(call->list, nh);
- call->list = list(call->list, nodintconst(size));
nx = nod(OXDOT, np, newname(first->sym)); // TODO: fields from other packages?
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
- fn->nbody = list(fn->nbody, call);
+ call->list = list(call->list, nodintconst(size));
+ call->list = list(call->list, nh);
+ fn->nbody = list(fn->nbody, nod(OAS, nh, call));
first = T;
}
@@ -2812,20 +2823,21 @@ genhash(Sym *sym, Type *t)
// Run hash for this field.
hashel = hashfor(t1->type);
- // hashel(h, size, &p.t1)
+ // h = hashel(&p.t1, size, h)
call = nod(OCALL, hashel, N);
- call->list = list(call->list, nh);
- call->list = list(call->list, nodintconst(t1->type->width));
nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
- fn->nbody = list(fn->nbody, call);
+ call->list = list(call->list, nodintconst(t1->type->width));
+ call->list = list(call->list, nh);
+ fn->nbody = list(fn->nbody, nod(OAS, nh, call));
}
- // make sure body is not empty.
- fn->nbody = list(fn->nbody, nod(ORETURN, N, N));
break;
}
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nh);
+ fn->nbody = list(fn->nbody, r);
if(debug['r'])
dumplist("genhash body", fn->nbody);
@@ -2849,18 +2861,19 @@ genhash(Sym *sym, Type *t)
}
// Return node for
-// if p.field != q.field { *eq = false; return }
+// if p.field != q.field { return false }
static Node*
-eqfield(Node *p, Node *q, Node *field, Node *eq)
+eqfield(Node *p, Node *q, Node *field)
{
- Node *nif, *nx, *ny;
+ Node *nif, *nx, *ny, *r;
nx = nod(OXDOT, p, field);
ny = nod(OXDOT, q, field);
nif = nod(OIF, N, N);
nif->ntest = nod(ONE, nx, ny);
- nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, eq, N), nodbool(0)));
- nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nodbool(0));
+ nif->nbody = list(nif->nbody, r);
return nif;
}
@@ -2889,11 +2902,11 @@ eqmemfunc(vlong size, Type *type)
}
// Return node for
-// if memequal(size, &p.field, &q.field, eq); !*eq { return }
+// if !memequal(&p.field, &q.field, size) { return false }
static Node*
-eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq)
+eqmem(Node *p, Node *q, Node *field, vlong size)
{
- Node *nif, *nx, *ny, *call;
+ Node *nif, *nx, *ny, *call, *r;
nx = nod(OADDR, nod(OXDOT, p, field), N);
nx->etype = 1; // does not escape
@@ -2903,15 +2916,16 @@ eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq)
typecheck(&ny, Erv);
call = nod(OCALL, eqmemfunc(size, nx->type->type), N);
- call->list = list(call->list, eq);
- call->list = list(call->list, nodintconst(size));
call->list = list(call->list, nx);
call->list = list(call->list, ny);
+ call->list = list(call->list, nodintconst(size));
nif = nod(OIF, N, N);
nif->ninit = list(nif->ninit, call);
- nif->ntest = nod(ONOT, nod(OIND, eq, N), N);
- nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ nif->ntest = nod(ONOT, call, N);
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nodbool(0));
+ nif->nbody = list(nif->nbody, r);
return nif;
}
@@ -2921,7 +2935,7 @@ eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq)
void
geneq(Sym *sym, Type *t)
{
- Node *n, *fn, *np, *neq, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange;
+ Node *n, *fn, *np, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange, *r;
Type *t1, *first;
int old_safemode;
int64 size;
@@ -2934,24 +2948,23 @@ geneq(Sym *sym, Type *t)
dclcontext = PEXTERN;
markdcl();
- // func sym(eq *bool, s uintptr, p, q *T)
+ // func sym(p, q *T, s uintptr) bool
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(sym);
fn->nname->class = PFUNC;
tfn = nod(OTFUNC, N, N);
fn->nname->ntype = tfn;
- n = nod(ODCLFIELD, newname(lookup("eq")), typenod(ptrto(types[TBOOL])));
- tfn->list = list(tfn->list, n);
- neq = n->left;
- n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
- tfn->list = list(tfn->list, n);
n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
tfn->list = list(tfn->list, n);
np = n->left;
n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
tfn->list = list(tfn->list, n);
nq = n->left;
+ n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
+ tfn->list = list(tfn->list, n);
+ n = nod(ODCLFIELD, N, typenod(types[TBOOL]));
+ tfn->rlist = list(tfn->rlist, n);
funchdr(fn);
@@ -2977,7 +2990,7 @@ geneq(Sym *sym, Type *t)
colasdefn(nrange->list, nrange);
ni = nrange->list->n;
- // if p[i] != q[i] { *eq = false; return }
+ // if p[i] != q[i] { return false }
nx = nod(OINDEX, np, ni);
nx->bounded = 1;
ny = nod(OINDEX, nq, ni);
@@ -2985,13 +2998,11 @@ geneq(Sym *sym, Type *t)
nif = nod(OIF, N, N);
nif->ntest = nod(ONE, nx, ny);
- nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, neq, N), nodbool(0)));
- nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nodbool(0));
+ nif->nbody = list(nif->nbody, r);
nrange->nbody = list(nrange->nbody, nif);
fn->nbody = list(fn->nbody, nrange);
-
- // *eq = true;
- fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1)));
break;
case TSTRUCT:
@@ -3016,16 +3027,16 @@ geneq(Sym *sym, Type *t)
// cross-package unexported fields.
if(first != T) {
if(first->down == t1) {
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
} else if(first->down->down == t1) {
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
first = first->down;
if(!isblanksym(first->sym))
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
} else {
// More than two fields: use memequal.
size = offend - first->width; // first->width is offset
- fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size, neq));
+ fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size));
}
first = T;
}
@@ -3035,14 +3046,17 @@ geneq(Sym *sym, Type *t)
continue;
// Check this field, which is not just memory.
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym), neq));
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym)));
}
- // *eq = true;
- fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1)));
break;
}
+ // return true
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nodbool(1));
+ fn->nbody = list(fn->nbody, r);
+
if(debug['r'])
dumplist("geneq body", fn->nbody);
@@ -3445,7 +3459,7 @@ smagic(Magic *m)
mask = 0xffffffffLL;
break;
case 64:
- mask = 0xffffffffffffffffLL;
+ mask = 0xffffffffffffffffULL;
break;
}
two31 = mask ^ (mask>>1);
@@ -3453,7 +3467,7 @@ smagic(Magic *m)
p = m->w-1;
ad = m->sd;
if(m->sd < 0)
- ad = -m->sd;
+ ad = -(uvlong)m->sd;
// bad denominators
if(ad == 0 || ad == 1 || ad == two31) {
@@ -3543,7 +3557,7 @@ umagic(Magic *m)
mask = 0xffffffffLL;
break;
case 64:
- mask = 0xffffffffffffffffLL;
+ mask = 0xffffffffffffffffULL;
break;
}
two31 = mask ^ (mask>>1);
@@ -3628,7 +3642,7 @@ ngotype(Node *n)
* users if we escape that as little as possible.
*
* If you edit this, edit ../ld/lib.c:/^pathtoprefix too.
- * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too.
+ * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
*/
static char*
pathtoprefix(char *s)
@@ -3785,3 +3799,42 @@ checknil(Node *x, NodeList **init)
n->typecheck = 1;
*init = list(*init, n);
}
+
+/*
+ * Can this type be stored directly in an interface word?
+ */
+int
+isdirectiface(Type *t)
+{
+ // Setting IfacePointerOnly = 1 changes the
+ // interface representation so that the data word
+ // in an interface value must always be a pointer.
+ // Setting it to 0 uses the original representation,
+ // where the data word can hold a pointer or any
+ // non-pointer value no bigger than a pointer.
+ enum {
+ IfacePointerOnly = 1,
+ };
+
+ if(IfacePointerOnly) {
+ switch(t->etype) {
+ case TPTR32:
+ case TPTR64:
+ case TCHAN:
+ case TMAP:
+ case TFUNC:
+ case TUNSAFEPTR:
+ return 1;
+ case TARRAY:
+ // Array of 1 direct iface type can be direct.
+ return t->bound == 1 && isdirectiface(t->type);
+ case TSTRUCT:
+ // Struct with 1 field of direct iface type can be direct.
+ return t->type != T && t->type->down == T && isdirectiface(t->type->type);
+ }
+ return 0;
+ }
+
+ dowidth(t);
+ return t->width <= widthptr;
+}