mirror of https://github.com/golang/go.git
cmd/gc: inline slice[arr,str] in the frontend (mostly).
R=rsc, ality, rogpeppe, minux.ma, dave CC=golang-dev https://golang.org/cl/5966075
This commit is contained in:
parent
192550592a
commit
40af78c19e
|
|
@ -30,6 +30,19 @@ cgen(Node *n, Node *res)
|
|||
if(res == N || res->type == T)
|
||||
fatal("cgen: res nil");
|
||||
|
||||
switch(n->op) {
|
||||
case OSLICE:
|
||||
case OSLICEARR:
|
||||
case OSLICESTR:
|
||||
if (res->op != ONAME || !res->addable) {
|
||||
tempname(&n1, n->type);
|
||||
cgen_slice(n, &n1);
|
||||
cgen(&n1, res);
|
||||
} else
|
||||
cgen_slice(n, res);
|
||||
return;
|
||||
}
|
||||
|
||||
while(n->op == OCONVNOP)
|
||||
n = n->left;
|
||||
|
||||
|
|
@ -577,6 +590,14 @@ agen(Node *n, Node *res)
|
|||
cgen_aret(n, res);
|
||||
break;
|
||||
|
||||
case OSLICE:
|
||||
case OSLICEARR:
|
||||
case OSLICESTR:
|
||||
tempname(&n1, n->type);
|
||||
cgen_slice(n, &n1);
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
p2 = nil; // to be patched to panicindex.
|
||||
w = n->type->width;
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ void cgen_callinter(Node*, Node*, int);
|
|||
void cgen_proc(Node*, int);
|
||||
void cgen_callret(Node*, Node*);
|
||||
void cgen_dcl(Node*);
|
||||
int cgen_inline(Node*, Node*);
|
||||
int needconvert(Type*, Type*);
|
||||
void genconv(Type*, Type*);
|
||||
void allocparams(void);
|
||||
|
|
|
|||
|
|
@ -68,8 +68,11 @@ ginscall(Node *f, int proc)
|
|||
break;
|
||||
|
||||
case 0: // normal call
|
||||
case -1: // normal call but no return
|
||||
p = gins(ABL, N, f);
|
||||
afunclit(&p->to);
|
||||
if(proc == -1 || noreturn(p))
|
||||
gins(AUNDEF, N, N);
|
||||
break;
|
||||
|
||||
case 1: // call in new proc (go)
|
||||
|
|
@ -656,395 +659,3 @@ clearfat(Node *nl)
|
|||
regfree(&dst);
|
||||
regfree(&nz);
|
||||
}
|
||||
|
||||
static int
|
||||
regcmp(const void *va, const void *vb)
|
||||
{
|
||||
Node *ra, *rb;
|
||||
|
||||
ra = (Node*)va;
|
||||
rb = (Node*)vb;
|
||||
return ra->local - rb->local;
|
||||
}
|
||||
|
||||
static Prog* throwpc;
|
||||
|
||||
// We're only going to bother inlining if we can
|
||||
// convert all the arguments to 32 bits safely. Can we?
|
||||
static int
|
||||
fix64(NodeList *nn, int n)
|
||||
{
|
||||
NodeList *l;
|
||||
Node *r;
|
||||
int i;
|
||||
|
||||
l = nn;
|
||||
for(i=0; i<n; i++) {
|
||||
r = l->n->right;
|
||||
if(is64(r->type) && !smallintconst(r)) {
|
||||
if(r->op == OCONV)
|
||||
r = r->left;
|
||||
if(is64(r->type))
|
||||
return 0;
|
||||
}
|
||||
l = l->next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
getargs(NodeList *nn, Node *reg, int n)
|
||||
{
|
||||
NodeList *l;
|
||||
int i;
|
||||
|
||||
throwpc = nil;
|
||||
|
||||
l = nn;
|
||||
for(i=0; i<n; i++) {
|
||||
if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
|
||||
regalloc(reg+i, l->n->right->type, N);
|
||||
cgen(l->n->right, reg+i);
|
||||
} else
|
||||
reg[i] = *l->n->right;
|
||||
if(reg[i].local != 0)
|
||||
yyerror("local used");
|
||||
reg[i].local = l->n->left->xoffset;
|
||||
l = l->next;
|
||||
}
|
||||
qsort((void*)reg, n, sizeof(*reg), regcmp);
|
||||
for(i=0; i<n; i++)
|
||||
reg[i].local = 0;
|
||||
}
|
||||
|
||||
void
|
||||
cmpandthrow(Node *nl, Node *nr)
|
||||
{
|
||||
vlong cl;
|
||||
Prog *p1;
|
||||
int op;
|
||||
Node *c, n1, n2;
|
||||
|
||||
op = OLE;
|
||||
if(smallintconst(nl)) {
|
||||
cl = mpgetfix(nl->val.u.xval);
|
||||
if(cl == 0)
|
||||
return;
|
||||
if(smallintconst(nr))
|
||||
return;
|
||||
|
||||
// put the constant on the right
|
||||
op = brrev(op);
|
||||
c = nl;
|
||||
nl = nr;
|
||||
nr = c;
|
||||
}
|
||||
|
||||
n1.op = OXXX;
|
||||
if(nr->op != OREGISTER) {
|
||||
regalloc(&n1, types[TUINT32], N);
|
||||
gmove(nr, &n1);
|
||||
nr = &n1;
|
||||
}
|
||||
n2.op = OXXX;
|
||||
if(nl->op != OREGISTER) {
|
||||
regalloc(&n2, types[TUINT32], N);
|
||||
gmove(nl, &n2);
|
||||
nl = &n2;
|
||||
}
|
||||
gcmp(optoas(OCMP, types[TUINT32]), nl, nr);
|
||||
if(nr == &n1)
|
||||
regfree(&n1);
|
||||
if(nl == &n2)
|
||||
regfree(&n2);
|
||||
if(throwpc == nil) {
|
||||
p1 = gbranch(optoas(op, types[TUINT32]), T, +1);
|
||||
throwpc = pc;
|
||||
ginscall(panicslice, 0);
|
||||
patch(p1, pc);
|
||||
} else {
|
||||
op = brcom(op);
|
||||
p1 = gbranch(optoas(op, types[TUINT32]), T, -1);
|
||||
patch(p1, throwpc);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sleasy(Node *n)
|
||||
{
|
||||
if(n->op != ONAME)
|
||||
return 0;
|
||||
if(!n->addable)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// generate inline code for
|
||||
// slicearray
|
||||
// sliceslice
|
||||
// arraytoslice
|
||||
int
|
||||
cgen_inline(Node *n, Node *res)
|
||||
{
|
||||
Node nodes[5];
|
||||
Node n1, n2, n3, nres, ntemp;
|
||||
vlong v;
|
||||
int i, narg;
|
||||
|
||||
if(n->op != OCALLFUNC)
|
||||
goto no;
|
||||
if(!n->left->addable)
|
||||
goto no;
|
||||
if(n->left->sym == S)
|
||||
goto no;
|
||||
if(n->left->sym->pkg != runtimepkg)
|
||||
goto no;
|
||||
if(strcmp(n->left->sym->name, "slicearray") == 0)
|
||||
goto slicearray;
|
||||
if(strcmp(n->left->sym->name, "sliceslice") == 0) {
|
||||
narg = 4;
|
||||
goto sliceslice;
|
||||
}
|
||||
if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
|
||||
narg = 3;
|
||||
goto sliceslice;
|
||||
}
|
||||
goto no;
|
||||
|
||||
slicearray:
|
||||
if(!sleasy(res))
|
||||
goto no;
|
||||
if(!fix64(n->list, 5))
|
||||
goto no;
|
||||
getargs(n->list, nodes, 5);
|
||||
|
||||
// if(hb[3] > nel[1]) goto throw
|
||||
cmpandthrow(&nodes[3], &nodes[1]);
|
||||
|
||||
// if(lb[2] > hb[3]) goto throw
|
||||
cmpandthrow(&nodes[2], &nodes[3]);
|
||||
|
||||
// len = hb[3] - lb[2] (destroys hb)
|
||||
n2 = *res;
|
||||
n2.type = types[TUINT32];
|
||||
n2.xoffset += Array_nel;
|
||||
|
||||
if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
|
||||
v = mpgetfix(nodes[3].val.u.xval) -
|
||||
mpgetfix(nodes[2].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gmove(&n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[3]);
|
||||
gmove(&nodes[3], &n1);
|
||||
if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
|
||||
gmove(&n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
|
||||
// cap = nel[1] - lb[2] (destroys nel)
|
||||
n2 = *res;
|
||||
n2.type = types[TUINT32];
|
||||
n2.xoffset += Array_cap;
|
||||
|
||||
if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
|
||||
v = mpgetfix(nodes[1].val.u.xval) -
|
||||
mpgetfix(nodes[2].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gmove(&n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[1]);
|
||||
gmove(&nodes[1], &n1);
|
||||
if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
|
||||
gmove(&n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
|
||||
// if slice could be too big, dereference to
|
||||
// catch nil array pointer.
|
||||
if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
|
||||
n2 = nodes[0];
|
||||
n2.xoffset = 0;
|
||||
n2.op = OINDREG;
|
||||
n2.type = types[TUINT8];
|
||||
regalloc(&n1, types[TUINT32], N);
|
||||
gins(AMOVB, &n2, &n1);
|
||||
regfree(&n1);
|
||||
}
|
||||
|
||||
// ary = old[0] + (lb[2] * width[4]) (destroys old)
|
||||
n2 = *res;
|
||||
n2.type = types[tptr];
|
||||
n2.xoffset += Array_array;
|
||||
|
||||
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
|
||||
v = mpgetfix(nodes[2].val.u.xval) *
|
||||
mpgetfix(nodes[4].val.u.xval);
|
||||
if(v != 0) {
|
||||
nodconst(&n1, types[tptr], v);
|
||||
gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
|
||||
}
|
||||
} else {
|
||||
regalloc(&n1, types[tptr], &nodes[2]);
|
||||
gmove(&nodes[2], &n1);
|
||||
if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) {
|
||||
regalloc(&n3, types[tptr], N);
|
||||
gmove(&nodes[4], &n3);
|
||||
gins(optoas(OMUL, types[tptr]), &n3, &n1);
|
||||
regfree(&n3);
|
||||
}
|
||||
gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
|
||||
regfree(&n1);
|
||||
}
|
||||
gmove(&nodes[0], &n2);
|
||||
|
||||
for(i=0; i<5; i++) {
|
||||
if(nodes[i].op == OREGISTER)
|
||||
regfree(&nodes[i]);
|
||||
}
|
||||
return 1;
|
||||
|
||||
sliceslice:
|
||||
if(!fix64(n->list, narg))
|
||||
goto no;
|
||||
ntemp.op = OXXX;
|
||||
if(!sleasy(n->list->n->right)) {
|
||||
Node *n0;
|
||||
|
||||
n0 = n->list->n->right;
|
||||
tempname(&ntemp, res->type);
|
||||
cgen(n0, &ntemp);
|
||||
n->list->n->right = &ntemp;
|
||||
getargs(n->list, nodes, narg);
|
||||
n->list->n->right = n0;
|
||||
} else
|
||||
getargs(n->list, nodes, narg);
|
||||
|
||||
nres = *res; // result
|
||||
if(!sleasy(res)) {
|
||||
if(ntemp.op == OXXX)
|
||||
tempname(&ntemp, res->type);
|
||||
nres = ntemp;
|
||||
}
|
||||
|
||||
if(narg == 3) { // old[lb:]
|
||||
// move width to where it would be for old[lb:hb]
|
||||
nodes[3] = nodes[2];
|
||||
nodes[2].op = OXXX;
|
||||
|
||||
// if(lb[1] > old.nel[0]) goto throw;
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
cmpandthrow(&nodes[1], &n2);
|
||||
|
||||
// ret.nel = old.nel[0]-lb[1];
|
||||
n2 = nodes[0];
|
||||
n2.type = types[TUINT32];
|
||||
n2.xoffset += Array_nel;
|
||||
|
||||
regalloc(&n1, types[TUINT32], N);
|
||||
gmove(&n2, &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
|
||||
n2 = nres;
|
||||
n2.type = types[TUINT32];
|
||||
n2.xoffset += Array_nel;
|
||||
gmove(&n1, &n2);
|
||||
regfree(&n1);
|
||||
} else { // old[lb:hb]
|
||||
// if(hb[2] > old.cap[0]) goto throw;
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
cmpandthrow(&nodes[2], &n2);
|
||||
|
||||
// if(lb[1] > hb[2]) goto throw;
|
||||
cmpandthrow(&nodes[1], &nodes[2]);
|
||||
|
||||
// ret.len = hb[2]-lb[1]; (destroys hb[2])
|
||||
n2 = nres;
|
||||
n2.type = types[TUINT32];
|
||||
n2.xoffset += Array_nel;
|
||||
|
||||
if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
|
||||
v = mpgetfix(nodes[2].val.u.xval) -
|
||||
mpgetfix(nodes[1].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gmove(&n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[2]);
|
||||
gmove(&nodes[2], &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
gmove(&n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
}
|
||||
|
||||
// ret.cap = old.cap[0]-lb[1]; (uses hb[2])
|
||||
n2 = nodes[0];
|
||||
n2.type = types[TUINT32];
|
||||
n2.xoffset += Array_cap;
|
||||
|
||||
regalloc(&n1, types[TUINT32], &nodes[2]);
|
||||
gmove(&n2, &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
|
||||
n2 = nres;
|
||||
n2.type = types[TUINT32];
|
||||
n2.xoffset += Array_cap;
|
||||
gmove(&n1, &n2);
|
||||
regfree(&n1);
|
||||
|
||||
// ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
|
||||
n2 = nodes[0];
|
||||
n2.type = types[tptr];
|
||||
n2.xoffset += Array_array;
|
||||
regalloc(&n3, types[tptr], N);
|
||||
gmove(&n2, &n3);
|
||||
|
||||
regalloc(&n1, types[tptr], &nodes[1]);
|
||||
if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
|
||||
gmove(&n2, &n1);
|
||||
v = mpgetfix(nodes[1].val.u.xval) *
|
||||
mpgetfix(nodes[3].val.u.xval);
|
||||
if(v != 0) {
|
||||
nodconst(&n2, types[tptr], v);
|
||||
gins(optoas(OADD, types[tptr]), &n3, &n1);
|
||||
}
|
||||
} else {
|
||||
gmove(&nodes[1], &n1);
|
||||
if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) {
|
||||
regalloc(&n2, types[tptr], N);
|
||||
gmove(&nodes[3], &n2);
|
||||
gins(optoas(OMUL, types[tptr]), &n2, &n1);
|
||||
regfree(&n2);
|
||||
}
|
||||
gins(optoas(OADD, types[tptr]), &n3, &n1);
|
||||
}
|
||||
regfree(&n3);
|
||||
|
||||
n2 = nres;
|
||||
n2.type = types[tptr];
|
||||
n2.xoffset += Array_array;
|
||||
gmove(&n1, &n2);
|
||||
regfree(&n1);
|
||||
|
||||
for(i=0; i<4; i++) {
|
||||
if(nodes[i].op == OREGISTER)
|
||||
regfree(&nodes[i]);
|
||||
}
|
||||
|
||||
if(!sleasy(res)) {
|
||||
cgen(&nres, res);
|
||||
}
|
||||
return 1;
|
||||
|
||||
no:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1141,6 +1141,27 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
|
|||
return p;
|
||||
}
|
||||
|
||||
// Generate an instruction referencing *n
|
||||
// to force segv on nil pointer dereference.
|
||||
bsdvoid
|
||||
checkref(Node *n)
|
||||
{
|
||||
Node m1, m2;
|
||||
|
||||
if(n->type->type->width < unmappedzero)
|
||||
return;
|
||||
|
||||
regalloc(&m1, types[TUINTPTR], n);
|
||||
regalloc(&m2, types[TUINT8], n);
|
||||
cgen(n, &m1);
|
||||
m1.xoffset = 0;
|
||||
m1.op = OINDREG;
|
||||
m1.type = types[TUINT8];
|
||||
gins(AMOVBU, &m1, &m2);
|
||||
regfree(&m2);
|
||||
regfree(&m1);
|
||||
}
|
||||
|
||||
static void
|
||||
checkoffset(Addr *a, int canemitcode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,9 +33,18 @@ cgen(Node *n, Node *res)
|
|||
while(n->op == OCONVNOP)
|
||||
n = n->left;
|
||||
|
||||
// inline slices
|
||||
if(cgen_inline(n, res))
|
||||
switch(n->op) {
|
||||
case OSLICE:
|
||||
case OSLICEARR:
|
||||
case OSLICESTR:
|
||||
if (res->op != ONAME || !res->addable) {
|
||||
tempname(&n1, n->type);
|
||||
cgen_slice(n, &n1);
|
||||
cgen(&n1, res);
|
||||
} else
|
||||
cgen_slice(n, res);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if(n->ullman >= UINF) {
|
||||
if(n->op == OINDREG)
|
||||
|
|
@ -532,6 +541,14 @@ agen(Node *n, Node *res)
|
|||
cgen_aret(n, res);
|
||||
break;
|
||||
|
||||
case OSLICE:
|
||||
case OSLICEARR:
|
||||
case OSLICESTR:
|
||||
tempname(&n1, n->type);
|
||||
cgen_slice(n, &n1);
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
w = n->type->width;
|
||||
if(nr->addable)
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ Prog* gins(int, Node*, Node*);
|
|||
int samaddr(Node*, Node*);
|
||||
void naddr(Node*, Addr*, int);
|
||||
void cgen_aret(Node*, Node*);
|
||||
int cgen_inline(Node*, Node*);
|
||||
void restx(Node*, Node*);
|
||||
void savex(int, Node*, Node*, Node*, Type*);
|
||||
int componentgen(Node*, Node*);
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ ginscall(Node *f, int proc)
|
|||
case -1: // normal call but no return
|
||||
p = gins(ACALL, N, f);
|
||||
afunclit(&p->to);
|
||||
if(proc == -1)
|
||||
if(proc == -1 || noreturn(p))
|
||||
gins(AUNDEF, N, N);
|
||||
break;
|
||||
|
||||
|
|
@ -1068,366 +1068,3 @@ clearfat(Node *nl)
|
|||
restx(&n1, &oldn1);
|
||||
restx(&ax, &oldax);
|
||||
}
|
||||
|
||||
static int
|
||||
regcmp(const void *va, const void *vb)
|
||||
{
|
||||
Node *ra, *rb;
|
||||
|
||||
ra = (Node*)va;
|
||||
rb = (Node*)vb;
|
||||
return ra->local - rb->local;
|
||||
}
|
||||
|
||||
static Prog* throwpc;
|
||||
|
||||
void
|
||||
getargs(NodeList *nn, Node *reg, int n)
|
||||
{
|
||||
NodeList *l;
|
||||
int i;
|
||||
|
||||
throwpc = nil;
|
||||
|
||||
l = nn;
|
||||
for(i=0; i<n; i++) {
|
||||
if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
|
||||
regalloc(reg+i, l->n->right->type, N);
|
||||
cgen(l->n->right, reg+i);
|
||||
} else
|
||||
reg[i] = *l->n->right;
|
||||
if(reg[i].local != 0)
|
||||
yyerror("local used");
|
||||
reg[i].local = l->n->left->xoffset;
|
||||
l = l->next;
|
||||
}
|
||||
qsort((void*)reg, n, sizeof(*reg), regcmp);
|
||||
for(i=0; i<n; i++)
|
||||
reg[i].local = 0;
|
||||
}
|
||||
|
||||
void
|
||||
cmpandthrow(Node *nl, Node *nr)
|
||||
{
|
||||
vlong cl;
|
||||
Prog *p1;
|
||||
int op;
|
||||
Node *c;
|
||||
Type *t;
|
||||
Node n1;
|
||||
|
||||
if(nl->op == OCONV && is64(nl->type))
|
||||
nl = nl->left;
|
||||
if(nr->op == OCONV && is64(nr->type))
|
||||
nr = nr->left;
|
||||
|
||||
op = OLE;
|
||||
if(smallintconst(nl)) {
|
||||
cl = mpgetfix(nl->val.u.xval);
|
||||
if(cl == 0)
|
||||
return;
|
||||
if(smallintconst(nr))
|
||||
return;
|
||||
// put the constant on the right
|
||||
op = brrev(op);
|
||||
c = nl;
|
||||
nl = nr;
|
||||
nr = c;
|
||||
}
|
||||
if(is64(nr->type) && smallintconst(nr))
|
||||
nr->type = types[TUINT32];
|
||||
|
||||
n1.op = OXXX;
|
||||
t = types[TUINT32];
|
||||
if(nl->type->width != t->width || nr->type->width != t->width) {
|
||||
if((is64(nl->type) && nl->op != OLITERAL) || (is64(nr->type) && nr->op != OLITERAL))
|
||||
t = types[TUINT64];
|
||||
|
||||
// Check if we need to use a temporary.
|
||||
// At least one of the arguments is 32 bits
|
||||
// (the len or cap) so one temporary suffices.
|
||||
if(nl->type->width != t->width && nl->op != OLITERAL) {
|
||||
regalloc(&n1, t, nl);
|
||||
gmove(nl, &n1);
|
||||
nl = &n1;
|
||||
} else if(nr->type->width != t->width && nr->op != OLITERAL) {
|
||||
regalloc(&n1, t, nr);
|
||||
gmove(nr, &n1);
|
||||
nr = &n1;
|
||||
}
|
||||
}
|
||||
gins(optoas(OCMP, t), nl, nr);
|
||||
if(n1.op != OXXX)
|
||||
regfree(&n1);
|
||||
if(throwpc == nil) {
|
||||
p1 = gbranch(optoas(op, t), T, +1);
|
||||
throwpc = pc;
|
||||
ginscall(panicslice, -1);
|
||||
patch(p1, pc);
|
||||
} else {
|
||||
op = brcom(op);
|
||||
p1 = gbranch(optoas(op, t), T, -1);
|
||||
patch(p1, throwpc);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sleasy(Node *n)
|
||||
{
|
||||
if(n->op != ONAME)
|
||||
return 0;
|
||||
if(!n->addable)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// generate inline code for
|
||||
// slicearray
|
||||
// sliceslice
|
||||
// arraytoslice
|
||||
int
|
||||
cgen_inline(Node *n, Node *res)
|
||||
{
|
||||
Node nodes[5];
|
||||
Node n1, n2, nres, ntemp;
|
||||
vlong v;
|
||||
int i, narg, nochk;
|
||||
|
||||
if(n->op != OCALLFUNC)
|
||||
goto no;
|
||||
if(!n->left->addable)
|
||||
goto no;
|
||||
if(n->left->sym == S)
|
||||
goto no;
|
||||
if(n->left->sym->pkg != runtimepkg)
|
||||
goto no;
|
||||
if(strcmp(n->left->sym->name, "slicearray") == 0)
|
||||
goto slicearray;
|
||||
if(strcmp(n->left->sym->name, "sliceslice") == 0) {
|
||||
narg = 4;
|
||||
goto sliceslice;
|
||||
}
|
||||
if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
|
||||
narg = 3;
|
||||
goto sliceslice;
|
||||
}
|
||||
goto no;
|
||||
|
||||
slicearray:
|
||||
if(!sleasy(res))
|
||||
goto no;
|
||||
getargs(n->list, nodes, 5);
|
||||
|
||||
// if(hb[3] > nel[1]) goto throw
|
||||
cmpandthrow(&nodes[3], &nodes[1]);
|
||||
|
||||
// if(lb[2] > hb[3]) goto throw
|
||||
cmpandthrow(&nodes[2], &nodes[3]);
|
||||
|
||||
// len = hb[3] - lb[2] (destroys hb)
|
||||
n2 = *res;
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
|
||||
v = mpgetfix(nodes[3].val.u.xval) -
|
||||
mpgetfix(nodes[2].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[3]);
|
||||
gmove(&nodes[3], &n1);
|
||||
if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
|
||||
// cap = nel[1] - lb[2] (destroys nel)
|
||||
n2 = *res;
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
|
||||
v = mpgetfix(nodes[1].val.u.xval) -
|
||||
mpgetfix(nodes[2].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[1]);
|
||||
gmove(&nodes[1], &n1);
|
||||
if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
|
||||
// if slice could be too big, dereference to
|
||||
// catch nil array pointer.
|
||||
if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
|
||||
n2 = nodes[0];
|
||||
n2.xoffset = 0;
|
||||
n2.op = OINDREG;
|
||||
n2.type = types[TUINT8];
|
||||
gins(ATESTB, nodintconst(0), &n2);
|
||||
}
|
||||
|
||||
// ary = old[0] + (lb[2] * width[4]) (destroys old)
|
||||
n2 = *res;
|
||||
n2.xoffset += Array_array;
|
||||
n2.type = types[tptr];
|
||||
|
||||
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
|
||||
v = mpgetfix(nodes[2].val.u.xval) *
|
||||
mpgetfix(nodes[4].val.u.xval);
|
||||
if(v != 0)
|
||||
ginscon(optoas(OADD, types[tptr]), v, &nodes[0]);
|
||||
} else {
|
||||
regalloc(&n1, types[tptr], &nodes[2]);
|
||||
gmove(&nodes[2], &n1);
|
||||
if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1)
|
||||
gins(optoas(OMUL, types[tptr]), &nodes[4], &n1);
|
||||
gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
|
||||
regfree(&n1);
|
||||
}
|
||||
gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
|
||||
|
||||
for(i=0; i<5; i++) {
|
||||
if(nodes[i].op == OREGISTER)
|
||||
regfree(&nodes[i]);
|
||||
}
|
||||
return 1;
|
||||
|
||||
sliceslice:
|
||||
nochk = n->etype; // skip bounds checking
|
||||
ntemp.op = OXXX;
|
||||
if(!sleasy(n->list->n->right)) {
|
||||
Node *n0;
|
||||
|
||||
n0 = n->list->n->right;
|
||||
tempname(&ntemp, res->type);
|
||||
cgen(n0, &ntemp);
|
||||
n->list->n->right = &ntemp;
|
||||
getargs(n->list, nodes, narg);
|
||||
n->list->n->right = n0;
|
||||
} else
|
||||
getargs(n->list, nodes, narg);
|
||||
|
||||
nres = *res; // result
|
||||
if(!sleasy(res)) {
|
||||
if(ntemp.op == OXXX)
|
||||
tempname(&ntemp, res->type);
|
||||
nres = ntemp;
|
||||
}
|
||||
|
||||
if(narg == 3) { // old[lb:]
|
||||
// move width to where it would be for old[lb:hb]
|
||||
nodes[3] = nodes[2];
|
||||
nodes[2].op = OXXX;
|
||||
|
||||
// if(lb[1] > old.nel[0]) goto throw;
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
if(!nochk)
|
||||
cmpandthrow(&nodes[1], &n2);
|
||||
|
||||
// ret.nel = old.nel[0]-lb[1];
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
regalloc(&n1, types[TUINT32], N);
|
||||
gins(optoas(OAS, types[TUINT32]), &n2, &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
|
||||
n2 = nres;
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
} else { // old[lb:hb]
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
if(!nochk) {
|
||||
// if(hb[2] > old.cap[0]) goto throw;
|
||||
cmpandthrow(&nodes[2], &n2);
|
||||
// if(lb[1] > hb[2]) goto throw;
|
||||
cmpandthrow(&nodes[1], &nodes[2]);
|
||||
}
|
||||
// ret.len = hb[2]-lb[1]; (destroys hb[2])
|
||||
n2 = nres;
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
|
||||
v = mpgetfix(nodes[2].val.u.xval) -
|
||||
mpgetfix(nodes[1].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[2]);
|
||||
gmove(&nodes[2], &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
}
|
||||
|
||||
// ret.cap = old.cap[0]-lb[1]; (uses hb[2])
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
regalloc(&n1, types[TUINT32], &nodes[2]);
|
||||
gins(optoas(OAS, types[TUINT32]), &n2, &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
|
||||
n2 = nres;
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
|
||||
// ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_array;
|
||||
n2.type = types[tptr];
|
||||
regalloc(&n1, types[tptr], &nodes[1]);
|
||||
if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
|
||||
gins(optoas(OAS, types[tptr]), &n2, &n1);
|
||||
v = mpgetfix(nodes[1].val.u.xval) *
|
||||
mpgetfix(nodes[3].val.u.xval);
|
||||
if(v != 0)
|
||||
ginscon(optoas(OADD, types[tptr]), v, &n1);
|
||||
} else {
|
||||
gmove(&nodes[1], &n1);
|
||||
if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
|
||||
gins(optoas(OMUL, types[tptr]), &nodes[3], &n1);
|
||||
gins(optoas(OADD, types[tptr]), &n2, &n1);
|
||||
}
|
||||
|
||||
n2 = nres;
|
||||
n2.xoffset += Array_array;
|
||||
n2.type = types[tptr];
|
||||
gins(optoas(OAS, types[tptr]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
|
||||
for(i=0; i<4; i++) {
|
||||
if(nodes[i].op == OREGISTER)
|
||||
regfree(&nodes[i]);
|
||||
}
|
||||
|
||||
if(!sleasy(res)) {
|
||||
cgen(&nres, res);
|
||||
}
|
||||
return 1;
|
||||
|
||||
no:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1029,6 +1029,25 @@ gins(int as, Node *f, Node *t)
|
|||
return p;
|
||||
}
|
||||
|
||||
// Generate an instruction referencing *n
|
||||
// to force segv on nil pointer dereference.
|
||||
void
|
||||
checkref(Node *n)
|
||||
{
|
||||
Node m;
|
||||
|
||||
if(n->type->type->width < unmappedzero)
|
||||
return;
|
||||
|
||||
regalloc(&m, types[TUINTPTR], n);
|
||||
cgen(n, &m);
|
||||
m.xoffset = 0;
|
||||
m.op = OINDREG;
|
||||
m.type = types[TUINT8];
|
||||
gins(ATESTB, nodintconst(0), &m);
|
||||
regfree(&m);
|
||||
}
|
||||
|
||||
static void
|
||||
checkoffset(Addr *a, int canemitcode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -63,9 +63,18 @@ cgen(Node *n, Node *res)
|
|||
if(res == N || res->type == T)
|
||||
fatal("cgen: res nil");
|
||||
|
||||
// inline slices
|
||||
if(cgen_inline(n, res))
|
||||
switch(n->op) {
|
||||
case OSLICE:
|
||||
case OSLICEARR:
|
||||
case OSLICESTR:
|
||||
if (res->op != ONAME || !res->addable) {
|
||||
tempname(&n1, n->type);
|
||||
cgen_slice(n, &n1);
|
||||
cgen(&n1, res);
|
||||
} else
|
||||
cgen_slice(n, res);
|
||||
return;
|
||||
}
|
||||
|
||||
while(n->op == OCONVNOP)
|
||||
n = n->left;
|
||||
|
|
@ -532,6 +541,14 @@ agen(Node *n, Node *res)
|
|||
cgen_aret(n, res);
|
||||
break;
|
||||
|
||||
case OSLICE:
|
||||
case OSLICEARR:
|
||||
case OSLICESTR:
|
||||
tempname(&n1, n->type);
|
||||
cgen_slice(n, &n1);
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
p2 = nil; // to be patched to panicindex.
|
||||
w = n->type->width;
|
||||
|
|
|
|||
|
|
@ -104,7 +104,6 @@ Prog* gins(int, Node*, Node*);
|
|||
int samaddr(Node*, Node*);
|
||||
void naddr(Node*, Addr*, int);
|
||||
void cgen_aret(Node*, Node*);
|
||||
int cgen_inline(Node*, Node*);
|
||||
Node* ncon(uint32);
|
||||
void mgen(Node*, Node*, Node*);
|
||||
void mfree(Node*);
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ ginscall(Node *f, int proc)
|
|||
case -1: // normal call but no return
|
||||
p = gins(ACALL, N, f);
|
||||
afunclit(&p->to);
|
||||
if(proc == -1)
|
||||
if(proc == -1 || noreturn(p))
|
||||
gins(AUNDEF, N, N);
|
||||
break;
|
||||
|
||||
|
|
@ -780,401 +780,3 @@ cgen_bmul(int op, Node *nl, Node *nr, Node *res)
|
|||
regfree(&n1b);
|
||||
regfree(&n2b);
|
||||
}
|
||||
|
||||
static int
|
||||
regcmp(const void *va, const void *vb)
|
||||
{
|
||||
Node *ra, *rb;
|
||||
|
||||
ra = (Node*)va;
|
||||
rb = (Node*)vb;
|
||||
return ra->local - rb->local;
|
||||
}
|
||||
|
||||
static Prog* throwpc;
|
||||
|
||||
// We're only going to bother inlining if we can
|
||||
// convert all the arguments to 32 bits safely. Can we?
|
||||
static int
|
||||
fix64(NodeList *nn, int n)
|
||||
{
|
||||
NodeList *l;
|
||||
Node *r;
|
||||
int i;
|
||||
|
||||
l = nn;
|
||||
for(i=0; i<n; i++) {
|
||||
r = l->n->right;
|
||||
if(is64(r->type) && !smallintconst(r)) {
|
||||
if(r->op == OCONV)
|
||||
r = r->left;
|
||||
if(is64(r->type))
|
||||
return 0;
|
||||
}
|
||||
l = l->next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
getargs(NodeList *nn, Node *reg, int n)
|
||||
{
|
||||
NodeList *l;
|
||||
Node *r;
|
||||
int i;
|
||||
|
||||
throwpc = nil;
|
||||
|
||||
l = nn;
|
||||
for(i=0; i<n; i++) {
|
||||
r = l->n->right;
|
||||
if(is64(r->type)) {
|
||||
if(r->op == OCONV)
|
||||
r = r->left;
|
||||
else if(smallintconst(r))
|
||||
r->type = types[TUINT32];
|
||||
if(is64(r->type))
|
||||
fatal("getargs");
|
||||
}
|
||||
if(!smallintconst(r) && !isslice(r->type)) {
|
||||
if(i < 3) // AX CX DX
|
||||
nodreg(reg+i, r->type, D_AX+i);
|
||||
else
|
||||
reg[i].op = OXXX;
|
||||
regalloc(reg+i, r->type, reg+i);
|
||||
cgen(r, reg+i);
|
||||
} else
|
||||
reg[i] = *r;
|
||||
if(reg[i].local != 0)
|
||||
yyerror("local used");
|
||||
reg[i].local = l->n->left->xoffset;
|
||||
l = l->next;
|
||||
}
|
||||
qsort((void*)reg, n, sizeof(*reg), regcmp);
|
||||
for(i=0; i<n; i++)
|
||||
reg[i].local = 0;
|
||||
}
|
||||
|
||||
void
|
||||
cmpandthrow(Node *nl, Node *nr)
|
||||
{
|
||||
vlong cl;
|
||||
Prog *p1;
|
||||
int op;
|
||||
Node *c, n1;
|
||||
Type *t;
|
||||
|
||||
op = OLE;
|
||||
if(smallintconst(nl)) {
|
||||
cl = mpgetfix(nl->val.u.xval);
|
||||
if(cl == 0)
|
||||
return;
|
||||
if(smallintconst(nr))
|
||||
return;
|
||||
// put the constant on the right
|
||||
op = brrev(op);
|
||||
c = nl;
|
||||
nl = nr;
|
||||
nr = c;
|
||||
}
|
||||
|
||||
// Arguments are known not to be 64-bit,
|
||||
// but they might be smaller than 32 bits.
|
||||
// Check if we need to use a temporary.
|
||||
// At least one of the arguments is 32 bits
|
||||
// (the len or cap) so one temporary suffices.
|
||||
n1.op = OXXX;
|
||||
t = types[TUINT32];
|
||||
if(nl->type->width != t->width) {
|
||||
regalloc(&n1, t, nl);
|
||||
gmove(nl, &n1);
|
||||
nl = &n1;
|
||||
} else if(nr->type->width != t->width) {
|
||||
regalloc(&n1, t, nr);
|
||||
gmove(nr, &n1);
|
||||
nr = &n1;
|
||||
}
|
||||
gins(optoas(OCMP, t), nl, nr);
|
||||
if(n1.op != OXXX)
|
||||
regfree(&n1);
|
||||
if(throwpc == nil) {
|
||||
p1 = gbranch(optoas(op, t), T, +1);
|
||||
throwpc = pc;
|
||||
ginscall(panicslice, -1);
|
||||
patch(p1, pc);
|
||||
} else {
|
||||
op = brcom(op);
|
||||
p1 = gbranch(optoas(op, t), T, -1);
|
||||
patch(p1, throwpc);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sleasy(Node *n)
|
||||
{
|
||||
if(n->op != ONAME)
|
||||
return 0;
|
||||
if(!n->addable)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// generate inline code for
|
||||
// slicearray
|
||||
// sliceslice
|
||||
// arraytoslice
|
||||
int
|
||||
cgen_inline(Node *n, Node *res)
|
||||
{
|
||||
Node nodes[5];
|
||||
Node n1, n2, nres, ntemp;
|
||||
vlong v;
|
||||
int i, narg, nochk;
|
||||
|
||||
if(n->op != OCALLFUNC)
|
||||
goto no;
|
||||
if(!n->left->addable)
|
||||
goto no;
|
||||
if(n->left->sym == S)
|
||||
goto no;
|
||||
if(n->left->sym->pkg != runtimepkg)
|
||||
goto no;
|
||||
if(strcmp(n->left->sym->name, "slicearray") == 0)
|
||||
goto slicearray;
|
||||
if(strcmp(n->left->sym->name, "sliceslice") == 0) {
|
||||
narg = 4;
|
||||
goto sliceslice;
|
||||
}
|
||||
if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
|
||||
narg = 3;
|
||||
goto sliceslice;
|
||||
}
|
||||
goto no;
|
||||
|
||||
slicearray:
|
||||
if(!sleasy(res))
|
||||
goto no;
|
||||
if(!fix64(n->list, 5))
|
||||
goto no;
|
||||
getargs(n->list, nodes, 5);
|
||||
|
||||
// if(hb[3] > nel[1]) goto throw
|
||||
cmpandthrow(&nodes[3], &nodes[1]);
|
||||
|
||||
// if(lb[2] > hb[3]) goto throw
|
||||
cmpandthrow(&nodes[2], &nodes[3]);
|
||||
|
||||
// len = hb[3] - lb[2] (destroys hb)
|
||||
n2 = *res;
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
|
||||
v = mpgetfix(nodes[3].val.u.xval) -
|
||||
mpgetfix(nodes[2].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[3]);
|
||||
gmove(&nodes[3], &n1);
|
||||
if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
|
||||
// cap = nel[1] - lb[2] (destroys nel)
|
||||
n2 = *res;
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
|
||||
v = mpgetfix(nodes[1].val.u.xval) -
|
||||
mpgetfix(nodes[2].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[1]);
|
||||
gmove(&nodes[1], &n1);
|
||||
if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
|
||||
// if slice could be too big, dereference to
|
||||
// catch nil array pointer.
|
||||
if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
|
||||
n2 = nodes[0];
|
||||
n2.xoffset = 0;
|
||||
n2.op = OINDREG;
|
||||
n2.type = types[TUINT8];
|
||||
gins(ATESTB, nodintconst(0), &n2);
|
||||
}
|
||||
|
||||
// ary = old[0] + (lb[2] * width[4]) (destroys old)
|
||||
n2 = *res;
|
||||
n2.xoffset += Array_array;
|
||||
n2.type = types[tptr];
|
||||
|
||||
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
|
||||
v = mpgetfix(nodes[2].val.u.xval) *
|
||||
mpgetfix(nodes[4].val.u.xval);
|
||||
if(v != 0) {
|
||||
nodconst(&n1, types[tptr], v);
|
||||
gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
|
||||
}
|
||||
} else {
|
||||
regalloc(&n1, types[tptr], &nodes[2]);
|
||||
gmove(&nodes[2], &n1);
|
||||
if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1)
|
||||
gins(optoas(OMUL, types[tptr]), &nodes[4], &n1);
|
||||
gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
|
||||
regfree(&n1);
|
||||
}
|
||||
gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
|
||||
|
||||
for(i=0; i<5; i++) {
|
||||
if(nodes[i].op == OREGISTER)
|
||||
regfree(&nodes[i]);
|
||||
}
|
||||
return 1;
|
||||
|
||||
sliceslice:
|
||||
if(!fix64(n->list, narg))
|
||||
goto no;
|
||||
nochk = n->etype; // skip bounds checking
|
||||
ntemp.op = OXXX;
|
||||
if(!sleasy(n->list->n->right)) {
|
||||
Node *n0;
|
||||
|
||||
n0 = n->list->n->right;
|
||||
tempname(&ntemp, res->type);
|
||||
cgen(n0, &ntemp);
|
||||
n->list->n->right = &ntemp;
|
||||
getargs(n->list, nodes, narg);
|
||||
n->list->n->right = n0;
|
||||
} else
|
||||
getargs(n->list, nodes, narg);
|
||||
|
||||
nres = *res; // result
|
||||
if(!sleasy(res)) {
|
||||
if(ntemp.op == OXXX)
|
||||
tempname(&ntemp, res->type);
|
||||
nres = ntemp;
|
||||
}
|
||||
|
||||
if(narg == 3) { // old[lb:]
|
||||
// move width to where it would be for old[lb:hb]
|
||||
nodes[3] = nodes[2];
|
||||
nodes[2].op = OXXX;
|
||||
|
||||
// if(lb[1] > old.nel[0]) goto throw;
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
if(!nochk)
|
||||
cmpandthrow(&nodes[1], &n2);
|
||||
|
||||
// ret.nel = old.nel[0]-lb[1];
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
regalloc(&n1, types[TUINT32], N);
|
||||
gins(optoas(OAS, types[TUINT32]), &n2, &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
|
||||
n2 = nres;
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
} else { // old[lb:hb]
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
if (!nochk) {
|
||||
// if(hb[2] > old.cap[0]) goto throw;
|
||||
cmpandthrow(&nodes[2], &n2);
|
||||
// if(lb[1] > hb[2]) goto throw;
|
||||
cmpandthrow(&nodes[1], &nodes[2]);
|
||||
}
|
||||
|
||||
// ret.len = hb[2]-lb[1]; (destroys hb[2])
|
||||
n2 = nres;
|
||||
n2.xoffset += Array_nel;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
|
||||
v = mpgetfix(nodes[2].val.u.xval) -
|
||||
mpgetfix(nodes[1].val.u.xval);
|
||||
nodconst(&n1, types[TUINT32], v);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
} else {
|
||||
regalloc(&n1, types[TUINT32], &nodes[2]);
|
||||
gmove(&nodes[2], &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
}
|
||||
}
|
||||
|
||||
// ret.cap = old.cap[0]-lb[1]; (uses hb[2])
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
|
||||
regalloc(&n1, types[TUINT32], &nodes[2]);
|
||||
gins(optoas(OAS, types[TUINT32]), &n2, &n1);
|
||||
if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
|
||||
gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
|
||||
|
||||
n2 = nres;
|
||||
n2.xoffset += Array_cap;
|
||||
n2.type = types[TUINT32];
|
||||
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
|
||||
// ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
|
||||
n2 = nodes[0];
|
||||
n2.xoffset += Array_array;
|
||||
n2.type = types[tptr];
|
||||
|
||||
regalloc(&n1, types[tptr], &nodes[1]);
|
||||
if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
|
||||
gins(optoas(OAS, types[tptr]), &n2, &n1);
|
||||
v = mpgetfix(nodes[1].val.u.xval) *
|
||||
mpgetfix(nodes[3].val.u.xval);
|
||||
if(v != 0) {
|
||||
nodconst(&n2, types[tptr], v);
|
||||
gins(optoas(OADD, types[tptr]), &n2, &n1);
|
||||
}
|
||||
} else {
|
||||
gmove(&nodes[1], &n1);
|
||||
if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
|
||||
gins(optoas(OMUL, types[tptr]), &nodes[3], &n1);
|
||||
gins(optoas(OADD, types[tptr]), &n2, &n1);
|
||||
}
|
||||
|
||||
n2 = nres;
|
||||
n2.xoffset += Array_array;
|
||||
n2.type = types[tptr];
|
||||
gins(optoas(OAS, types[tptr]), &n1, &n2);
|
||||
regfree(&n1);
|
||||
|
||||
for(i=0; i<4; i++) {
|
||||
if(nodes[i].op == OREGISTER)
|
||||
regfree(&nodes[i]);
|
||||
}
|
||||
|
||||
if(!sleasy(res)) {
|
||||
cgen(&nres, res);
|
||||
}
|
||||
return 1;
|
||||
|
||||
no:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1768,6 +1768,25 @@ gins(int as, Node *f, Node *t)
|
|||
return p;
|
||||
}
|
||||
|
||||
// Generate an instruction referencing *n
|
||||
// to force segv on nil pointer dereference.
|
||||
void
|
||||
checkref(Node *n)
|
||||
{
|
||||
Node m;
|
||||
|
||||
if(n->type->type->width < unmappedzero)
|
||||
return;
|
||||
|
||||
regalloc(&m, types[TUINTPTR], n);
|
||||
cgen(n, &m);
|
||||
m.xoffset = 0;
|
||||
m.op = OINDREG;
|
||||
m.type = types[TUINT8];
|
||||
gins(ATESTB, nodintconst(0), &m);
|
||||
regfree(&m);
|
||||
}
|
||||
|
||||
static void
|
||||
checkoffset(Addr *a, int canemitcode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -86,9 +86,6 @@ char *runtimeimport =
|
|||
"func @\"\".block()\n"
|
||||
"func @\"\".makeslice(@\"\".typ *byte, @\"\".nel int64, @\"\".cap int64) (@\"\".ary []any)\n"
|
||||
"func @\"\".growslice(@\"\".typ *byte, @\"\".old []any, @\"\".n int64) (@\"\".ary []any)\n"
|
||||
"func @\"\".sliceslice1(@\"\".old []any, @\"\".lb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
|
||||
"func @\"\".sliceslice(@\"\".old []any, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
|
||||
"func @\"\".slicearray(@\"\".old *any, @\"\".nel uint64, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
|
||||
"func @\"\".closure()\n"
|
||||
"func @\"\".memequal(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
|
||||
"func @\"\".memequal8(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
|
||||
|
|
|
|||
|
|
@ -734,6 +734,66 @@ ret:
|
|||
;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* generate:
|
||||
* res = s[lo, hi];
|
||||
* n->left is s
|
||||
* n->list is (cap(s)-lo(TUINT32), hi-lo(TUINT32)[, lo*width(TUINTPTR)])
|
||||
* caller (cgen) guarantees res is an addable ONAME.
|
||||
*
|
||||
*/
|
||||
void
|
||||
cgen_slice(Node *n, Node *res)
|
||||
{
|
||||
Node src, dst, *cap, *len, *offs, *add;
|
||||
|
||||
// print("cgen_slice: %N = %+N\n", res, n);
|
||||
|
||||
cap = n->list->n;
|
||||
len = n->list->next->n;
|
||||
offs = N;
|
||||
if(n->list->next->next)
|
||||
offs = n->list->next->next->n;
|
||||
|
||||
// dst.len = hi [ - lo ]
|
||||
dst = *res;
|
||||
dst.xoffset += Array_nel;
|
||||
dst.type = types[TUINT32];
|
||||
cgen(len, &dst);
|
||||
|
||||
if(n->op != OSLICESTR) {
|
||||
// dst.cap = cap [ - lo ]
|
||||
dst = *res;
|
||||
dst.xoffset += Array_cap;
|
||||
dst.type = types[TUINT32];
|
||||
cgen(cap, &dst);
|
||||
}
|
||||
|
||||
// dst.array = src.array [ + lo *width ]
|
||||
dst = *res;
|
||||
dst.xoffset += Array_array;
|
||||
dst.type = types[TUINTPTR];
|
||||
|
||||
if(n->op == OSLICEARR) {
|
||||
if(!isptr[n->left->type->etype])
|
||||
fatal("slicearr is supposed to work on pointer: %+N\n", n);
|
||||
checkref(n->left);
|
||||
}
|
||||
|
||||
src = *n->left;
|
||||
src.xoffset += Array_array;
|
||||
src.type = types[TUINTPTR];
|
||||
|
||||
if(offs == N) {
|
||||
cgen(&src, &dst);
|
||||
} else {
|
||||
add = nod(OADD, &src, offs);
|
||||
typecheck(&add, Erv);
|
||||
cgen(add, &dst);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* gather series of offsets
|
||||
* >=0 is direct addressed field
|
||||
|
|
|
|||
|
|
@ -987,6 +987,7 @@ void dumplist(char *s, NodeList *l);
|
|||
void addrescapes(Node *n);
|
||||
void cgen_as(Node *nl, Node *nr);
|
||||
void cgen_callmeth(Node *n, int proc);
|
||||
void cgen_slice(Node* n, Node* res);
|
||||
void clearlabels(void);
|
||||
void checklabels(void);
|
||||
int dotoffset(Node *n, int *oary, Node **nn);
|
||||
|
|
@ -1305,6 +1306,7 @@ EXTERN Node* nodfp;
|
|||
int anyregalloc(void);
|
||||
void betypeinit(void);
|
||||
void bgen(Node *n, int true, int likely, Prog *to);
|
||||
void checkref(Node*);
|
||||
void cgen(Node*, Node*);
|
||||
void cgen_asop(Node *n);
|
||||
void cgen_call(Node *n, int proc);
|
||||
|
|
|
|||
|
|
@ -117,9 +117,6 @@ func block()
|
|||
|
||||
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
|
||||
func growslice(typ *byte, old []any, n int64) (ary []any)
|
||||
func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
|
||||
func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
|
||||
func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any)
|
||||
|
||||
func closure() // has args, but compiler fills in
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ static NodeList* reorder3(NodeList*);
|
|||
static Node* addstr(Node*, NodeList**);
|
||||
static Node* appendslice(Node*, NodeList**);
|
||||
static Node* append(Node*, NodeList**);
|
||||
static Node* sliceany(Node*, NodeList**);
|
||||
static void walkcompare(Node**, NodeList**);
|
||||
static void walkrotate(Node**);
|
||||
static int bounded(Node*, int64);
|
||||
|
|
@ -371,7 +372,7 @@ walkexpr(Node **np, NodeList **init)
|
|||
NodeList *ll, *lr, *lpost;
|
||||
Type *t;
|
||||
int et;
|
||||
int64 v, v1, v2, len;
|
||||
int64 v;
|
||||
int32 lno;
|
||||
Node *n, *fn;
|
||||
char buf[100], *p;
|
||||
|
|
@ -916,95 +917,29 @@ walkexpr(Node **np, NodeList **init)
|
|||
goto ret;
|
||||
|
||||
case OSLICE:
|
||||
if(n->right != N && n->right->left == N && n->right->right == N) { // noop
|
||||
walkexpr(&n->left, init);
|
||||
n = n->left;
|
||||
goto ret;
|
||||
}
|
||||
// fallthrough
|
||||
case OSLICEARR:
|
||||
case OSLICESTR:
|
||||
if(n->right == N) // already processed
|
||||
goto ret;
|
||||
|
||||
walkexpr(&n->left, init);
|
||||
n->left = safeexpr(n->left, init);
|
||||
// cgen_slice can't handle string literals as source
|
||||
// TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi]
|
||||
if((n->op == OSLICESTR && n->left->op == OLITERAL) || (n->left->op == OINDEX))
|
||||
n->left = copyexpr(n->left, n->left->type, init);
|
||||
else
|
||||
n->left = safeexpr(n->left, init);
|
||||
walkexpr(&n->right->left, init);
|
||||
n->right->left = safeexpr(n->right->left, init);
|
||||
walkexpr(&n->right->right, init);
|
||||
n->right->right = safeexpr(n->right->right, init);
|
||||
|
||||
len = 1LL<<60;
|
||||
t = n->left->type;
|
||||
if(t != T && isptr[t->etype])
|
||||
t = t->type;
|
||||
if(isfixedarray(t))
|
||||
len = t->bound;
|
||||
|
||||
// check for static out of bounds
|
||||
// NOTE: v > len not v >= len.
|
||||
v1 = -1;
|
||||
v2 = -1;
|
||||
if(isconst(n->right->left, CTINT)) {
|
||||
v1 = mpgetfix(n->right->left->val.u.xval);
|
||||
if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) {
|
||||
yyerror("slice index out of bounds");
|
||||
v1 = -1;
|
||||
}
|
||||
}
|
||||
if(isconst(n->right->right, CTINT)) {
|
||||
v2 = mpgetfix(n->right->right->val.u.xval);
|
||||
if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) {
|
||||
yyerror("slice index out of bounds");
|
||||
v2 = -1;
|
||||
}
|
||||
}
|
||||
if(v1 >= 0 && v2 >= 0 && v1 > v2)
|
||||
yyerror("inverted slice range");
|
||||
|
||||
if(n->op == OSLICEARR)
|
||||
goto slicearray;
|
||||
|
||||
// dynamic slice
|
||||
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
|
||||
// sliceslice1(old []any, lb uint64, width uint64) (ary []any)
|
||||
t = n->type;
|
||||
et = n->bounded;
|
||||
if(n->right->left == N)
|
||||
l = nodintconst(0);
|
||||
else
|
||||
l = conv(n->right->left, types[TUINT64]);
|
||||
if(n->right->right != N) {
|
||||
fn = syslook("sliceslice", 1);
|
||||
argtype(fn, t->type); // any-1
|
||||
argtype(fn, t->type); // any-2
|
||||
n = mkcall1(fn, t, init,
|
||||
n->left,
|
||||
l,
|
||||
conv(n->right->right, types[TUINT64]),
|
||||
nodintconst(t->type->width));
|
||||
} else {
|
||||
fn = syslook("sliceslice1", 1);
|
||||
argtype(fn, t->type); // any-1
|
||||
argtype(fn, t->type); // any-2
|
||||
n = mkcall1(fn, t, init,
|
||||
n->left,
|
||||
l,
|
||||
nodintconst(t->type->width));
|
||||
}
|
||||
n->bounded = et; // preserve flag from OSLICE to the slice* call.
|
||||
goto ret;
|
||||
|
||||
slicearray:
|
||||
// static slice
|
||||
// slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any)
|
||||
t = n->type;
|
||||
fn = syslook("slicearray", 1);
|
||||
argtype(fn, n->left->type->type); // any-1
|
||||
argtype(fn, t->type); // any-2
|
||||
if(n->right->left == N)
|
||||
l = nodintconst(0);
|
||||
else
|
||||
l = conv(n->right->left, types[TUINT64]);
|
||||
if(n->right->right == N)
|
||||
r = nodintconst(n->left->type->type->bound);
|
||||
else
|
||||
r = conv(n->right->right, types[TUINT64]);
|
||||
n = mkcall1(fn, t, init,
|
||||
n->left, nodintconst(n->left->type->type->bound),
|
||||
l,
|
||||
r,
|
||||
nodintconst(t->type->width));
|
||||
n = sliceany(n, init); // chops n->right, sets n->list
|
||||
goto ret;
|
||||
|
||||
case OADDR:
|
||||
|
|
@ -1082,25 +1017,7 @@ walkexpr(Node **np, NodeList **init)
|
|||
case OADDSTR:
|
||||
n = addstr(n, init);
|
||||
goto ret;
|
||||
|
||||
case OSLICESTR:
|
||||
// sys_slicestring(s, lb, hb)
|
||||
if(n->right->left == N)
|
||||
l = nodintconst(0);
|
||||
else
|
||||
l = conv(n->right->left, types[TINT]);
|
||||
if(n->right->right) {
|
||||
n = mkcall("slicestring", n->type, init,
|
||||
conv(n->left, types[TSTRING]),
|
||||
l,
|
||||
conv(n->right->right, types[TINT]));
|
||||
} else {
|
||||
n = mkcall("slicestring1", n->type, init,
|
||||
conv(n->left, types[TSTRING]),
|
||||
l);
|
||||
}
|
||||
goto ret;
|
||||
|
||||
|
||||
case OAPPEND:
|
||||
if(n->isddd) {
|
||||
if(istype(n->type->type, TUINT8) && istype(n->list->next->n->type, TSTRING))
|
||||
|
|
@ -2433,6 +2350,155 @@ append(Node *n, NodeList **init)
|
|||
return ns;
|
||||
}
|
||||
|
||||
|
||||
// Generate frontend part for OSLICE[ARR|STR]
|
||||
//
|
||||
static Node*
|
||||
sliceany(Node* n, NodeList **init)
|
||||
{
|
||||
int bounded;
|
||||
Node *src, *lb, *hb, *bound, *chk, *chk1, *chk2;
|
||||
int64 lbv, hbv, bv, w;
|
||||
Type *bt;
|
||||
|
||||
// print("before sliceany: %+N\n", n);
|
||||
|
||||
src = n->left;
|
||||
lb = n->right->left;
|
||||
hb = n->right->right;
|
||||
|
||||
bounded = n->etype;
|
||||
|
||||
if(n->op == OSLICESTR)
|
||||
bound = nod(OLEN, src, N);
|
||||
else
|
||||
bound = nod(OCAP, src, N);
|
||||
|
||||
typecheck(&bound, Erv);
|
||||
walkexpr(&bound, init); // if src is an array, bound will be a const now.
|
||||
|
||||
// static checks if possible
|
||||
bv = 1LL<<50;
|
||||
if(isconst(bound, CTINT)) {
|
||||
if(!smallintconst(bound))
|
||||
yyerror("array len too large");
|
||||
else
|
||||
bv = mpgetfix(bound->val.u.xval);
|
||||
}
|
||||
lbv = -1;
|
||||
hbv = -1;
|
||||
|
||||
if(isconst(hb, CTINT)) {
|
||||
hbv = mpgetfix(hb->val.u.xval);
|
||||
if(hbv < 0 || hbv > bv || !smallintconst(hb)) {
|
||||
yyerror("slice index out of bounds");
|
||||
hbv = -1;
|
||||
}
|
||||
}
|
||||
if(isconst(lb, CTINT)) {
|
||||
lbv = mpgetfix(lb->val.u.xval);
|
||||
if(lbv < 0 || lbv > bv || !smallintconst(lb)) {
|
||||
yyerror("slice index out of bounds");
|
||||
lbv = -1;
|
||||
}
|
||||
if(lbv == 0)
|
||||
lb = N;
|
||||
}
|
||||
if(lbv >= 0 && hbv >= 0 && lbv > hbv)
|
||||
yyerror("inverted slice range");
|
||||
|
||||
// dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison
|
||||
// generate
|
||||
// if hb > bound || lb > hb { panicslice() }
|
||||
chk = N;
|
||||
chk1 = N;
|
||||
chk2 = N;
|
||||
|
||||
bt = types[TUINT32];
|
||||
if(hb != N && hb->type->width > 4)
|
||||
bt = types[TUINT64];
|
||||
if(lb != N && lb->type->width > 4)
|
||||
bt = types[TUINT64];
|
||||
|
||||
bound = cheapexpr(conv(bound, bt), init);
|
||||
|
||||
if(hb != N) {
|
||||
hb = cheapexpr(conv(hb, bt), init);
|
||||
if(!bounded)
|
||||
chk1 = nod(OLT, bound, hb);
|
||||
} else if(n->op == OSLICEARR) {
|
||||
hb = bound;
|
||||
} else {
|
||||
hb = nod(OLEN, src, N);
|
||||
typecheck(&hb, Erv);
|
||||
walkexpr(&hb, init);
|
||||
hb = cheapexpr(conv(hb, bt), init);
|
||||
}
|
||||
|
||||
if(lb != N) {
|
||||
lb = cheapexpr(conv(lb, bt), init);
|
||||
if(!bounded)
|
||||
chk2 = nod(OLT, hb, lb);
|
||||
}
|
||||
|
||||
if(chk1 != N || chk2 != N) {
|
||||
chk = nod(OIF, N, N);
|
||||
chk->nbody = list1(mkcall("panicslice", T, init));
|
||||
if(chk1 != N)
|
||||
chk->ntest = chk1;
|
||||
if(chk2 != N) {
|
||||
if(chk->ntest == N)
|
||||
chk->ntest = chk2;
|
||||
else
|
||||
chk->ntest = nod(OOROR, chk->ntest, chk2);
|
||||
}
|
||||
typecheck(&chk, Etop);
|
||||
walkstmt(&chk);
|
||||
*init = concat(*init, chk->ninit);
|
||||
chk->ninit = nil;
|
||||
*init = list(*init, chk);
|
||||
}
|
||||
|
||||
// prepare new cap, len and offs for backend cgen_slice
|
||||
// cap = bound [ - lo ]
|
||||
n->right = N;
|
||||
n->list = nil;
|
||||
if(lb == N)
|
||||
bound = conv(bound, types[TUINT32]);
|
||||
else
|
||||
bound = nod(OSUB, conv(bound, types[TUINT32]), conv(lb, types[TUINT32]));
|
||||
typecheck(&bound, Erv);
|
||||
walkexpr(&bound, init);
|
||||
n->list = list(n->list, bound);
|
||||
|
||||
// len = hi [ - lo]
|
||||
if(lb == N)
|
||||
hb = conv(hb, types[TUINT32]);
|
||||
else
|
||||
hb = nod(OSUB, conv(hb, types[TUINT32]), conv(lb, types[TUINT32]));
|
||||
typecheck(&hb, Erv);
|
||||
walkexpr(&hb, init);
|
||||
n->list = list(n->list, hb);
|
||||
|
||||
// offs = [width *] lo, but omit if zero
|
||||
if(lb != N) {
|
||||
if(n->op == OSLICESTR)
|
||||
w = 1;
|
||||
else
|
||||
w = n->type->type->width;
|
||||
lb = conv(lb, types[TUINTPTR]);
|
||||
if(w > 1)
|
||||
lb = nod(OMUL, nodintconst(w), lb);
|
||||
typecheck(&lb, Erv);
|
||||
walkexpr(&lb, init);
|
||||
n->list = list(n->list, lb);
|
||||
}
|
||||
|
||||
// print("after sliceany: %+N\n", n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static Node*
|
||||
eqfor(Type *t)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -147,149 +147,6 @@ growslice1(SliceType *t, Slice x, int32 newcap, Slice *ret)
|
|||
runtime·memmove(ret->array, x.array, ret->len * t->elem->size);
|
||||
}
|
||||
|
||||
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
|
||||
void
|
||||
runtime·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)
|
||||
{
|
||||
if(hb > old.cap || lb > hb) {
|
||||
if(debug) {
|
||||
runtime·prints("runtime.sliceslice: old=");
|
||||
runtime·printslice(old);
|
||||
runtime·prints("; lb=");
|
||||
runtime·printint(lb);
|
||||
runtime·prints("; hb=");
|
||||
runtime·printint(hb);
|
||||
runtime·prints("; width=");
|
||||
runtime·printint(width);
|
||||
runtime·prints("\n");
|
||||
|
||||
runtime·prints("oldarray: nel=");
|
||||
runtime·printint(old.len);
|
||||
runtime·prints("; cap=");
|
||||
runtime·printint(old.cap);
|
||||
runtime·prints("\n");
|
||||
}
|
||||
runtime·panicslice();
|
||||
}
|
||||
|
||||
// new array is inside old array
|
||||
ret.len = hb - lb;
|
||||
ret.cap = old.cap - lb;
|
||||
ret.array = old.array + lb*width;
|
||||
|
||||
FLUSH(&ret);
|
||||
|
||||
if(debug) {
|
||||
runtime·prints("runtime.sliceslice: old=");
|
||||
runtime·printslice(old);
|
||||
runtime·prints("; lb=");
|
||||
runtime·printint(lb);
|
||||
runtime·prints("; hb=");
|
||||
runtime·printint(hb);
|
||||
runtime·prints("; width=");
|
||||
runtime·printint(width);
|
||||
runtime·prints("; ret=");
|
||||
runtime·printslice(ret);
|
||||
runtime·prints("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// sliceslice1(old []any, lb uint64, width uint64) (ary []any);
|
||||
void
|
||||
runtime·sliceslice1(Slice old, uint64 lb, uint64 width, Slice ret)
|
||||
{
|
||||
if(lb > old.len) {
|
||||
if(debug) {
|
||||
runtime·prints("runtime.sliceslice: old=");
|
||||
runtime·printslice(old);
|
||||
runtime·prints("; lb=");
|
||||
runtime·printint(lb);
|
||||
runtime·prints("; width=");
|
||||
runtime·printint(width);
|
||||
runtime·prints("\n");
|
||||
|
||||
runtime·prints("oldarray: nel=");
|
||||
runtime·printint(old.len);
|
||||
runtime·prints("; cap=");
|
||||
runtime·printint(old.cap);
|
||||
runtime·prints("\n");
|
||||
}
|
||||
runtime·panicslice();
|
||||
}
|
||||
|
||||
// new array is inside old array
|
||||
ret.len = old.len - lb;
|
||||
ret.cap = old.cap - lb;
|
||||
ret.array = old.array + lb*width;
|
||||
|
||||
FLUSH(&ret);
|
||||
|
||||
if(debug) {
|
||||
runtime·prints("runtime.sliceslice: old=");
|
||||
runtime·printslice(old);
|
||||
runtime·prints("; lb=");
|
||||
runtime·printint(lb);
|
||||
runtime·prints("; width=");
|
||||
runtime·printint(width);
|
||||
runtime·prints("; ret=");
|
||||
runtime·printslice(ret);
|
||||
runtime·prints("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any);
|
||||
void
|
||||
runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, Slice ret)
|
||||
{
|
||||
if(nel > 0 && old == nil) {
|
||||
// crash if old == nil.
|
||||
// could give a better message
|
||||
// but this is consistent with all the in-line checks
|
||||
// that the compiler inserts for other uses.
|
||||
*old = 0;
|
||||
}
|
||||
|
||||
if(hb > nel || lb > hb) {
|
||||
if(debug) {
|
||||
runtime·prints("runtime.slicearray: old=");
|
||||
runtime·printpointer(old);
|
||||
runtime·prints("; nel=");
|
||||
runtime·printint(nel);
|
||||
runtime·prints("; lb=");
|
||||
runtime·printint(lb);
|
||||
runtime·prints("; hb=");
|
||||
runtime·printint(hb);
|
||||
runtime·prints("; width=");
|
||||
runtime·printint(width);
|
||||
runtime·prints("\n");
|
||||
}
|
||||
runtime·panicslice();
|
||||
}
|
||||
|
||||
// new array is inside old array
|
||||
ret.len = hb-lb;
|
||||
ret.cap = nel-lb;
|
||||
ret.array = old + lb*width;
|
||||
|
||||
FLUSH(&ret);
|
||||
|
||||
if(debug) {
|
||||
runtime·prints("runtime.slicearray: old=");
|
||||
runtime·printpointer(old);
|
||||
runtime·prints("; nel=");
|
||||
runtime·printint(nel);
|
||||
runtime·prints("; lb=");
|
||||
runtime·printint(lb);
|
||||
runtime·prints("; hb=");
|
||||
runtime·printint(hb);
|
||||
runtime·prints("; width=");
|
||||
runtime·printint(width);
|
||||
runtime·prints("; ret=");
|
||||
runtime·printslice(ret);
|
||||
runtime·prints("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// copy(to any, fr any, wid uint32) int
|
||||
void
|
||||
runtime·copy(Slice to, Slice fm, uintptr width, int32 ret)
|
||||
|
|
|
|||
|
|
@ -235,31 +235,6 @@ runtime·strstr(byte *s1, byte *s2)
|
|||
return nil;
|
||||
}
|
||||
|
||||
func slicestring(si String, lindex int32, hindex int32) (so String) {
|
||||
int32 l;
|
||||
|
||||
if(lindex < 0 || lindex > si.len ||
|
||||
hindex < lindex || hindex > si.len) {
|
||||
runtime·panicslice();
|
||||
}
|
||||
|
||||
l = hindex-lindex;
|
||||
so.str = si.str + lindex;
|
||||
so.len = l;
|
||||
}
|
||||
|
||||
func slicestring1(si String, lindex int32) (so String) {
|
||||
int32 l;
|
||||
|
||||
if(lindex < 0 || lindex > si.len) {
|
||||
runtime·panicslice();
|
||||
}
|
||||
|
||||
l = si.len-lindex;
|
||||
so.str = si.str + lindex;
|
||||
so.len = l;
|
||||
}
|
||||
|
||||
func intstring(v int64) (s String) {
|
||||
s = gostringsize(8);
|
||||
s.len = runtime·runetochar(s.str, v);
|
||||
|
|
|
|||
Loading…
Reference in New Issue