mirror of
https://github.com/golang/go
synced 2024-11-18 12:54:44 -07:00
more 8g.
test/turing.go runs if you move the big array off its stack. finally remembered to g4 add cgen.c gsubr.c R=ken OCL=29408 CL=29408
This commit is contained in:
parent
70d711dfb8
commit
5ecd010beb
897
src/cmd/8g/cgen.c
Normal file
897
src/cmd/8g/cgen.c
Normal file
@ -0,0 +1,897 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "gg.h"
|
||||
|
||||
int
|
||||
is64(Type *t)
|
||||
{
|
||||
if(t == T)
|
||||
return 0;
|
||||
switch(simtype[t->etype]) {
|
||||
case TINT64:
|
||||
case TUINT64:
|
||||
case TPTR64:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate:
|
||||
* res = n;
|
||||
* simplifies and calls gmove.
|
||||
*
|
||||
* TODO:
|
||||
* sudoaddable
|
||||
*/
|
||||
void
|
||||
cgen(Node *n, Node *res)
|
||||
{
|
||||
Node *nl, *nr, *r, n1, n2, rr;
|
||||
Prog *p1, *p2, *p3;
|
||||
int a;
|
||||
|
||||
if(debug['g']) {
|
||||
dump("\ncgen-n", n);
|
||||
dump("cgen-res", res);
|
||||
}
|
||||
|
||||
if(n == N || n->type == T)
|
||||
fatal("cgen: n nil");
|
||||
if(res == N || res->type == T)
|
||||
fatal("cgen: res nil");
|
||||
|
||||
// function calls on both sides? introduce temporary
|
||||
if(n->ullman >= UINF && res->ullman >= UINF) {
|
||||
tempname(&n1, n->type);
|
||||
cgen(n, &n1);
|
||||
cgen(&n1, res);
|
||||
return;
|
||||
}
|
||||
|
||||
// structs etc get handled specially
|
||||
if(isfat(n->type)) {
|
||||
sgen(n, res, n->type->width);
|
||||
return;
|
||||
}
|
||||
|
||||
// if both are addressable, move
|
||||
if(n->addable && res->addable) {
|
||||
gmove(n, res);
|
||||
return;
|
||||
}
|
||||
|
||||
// if both are not addressable, use a temporary.
|
||||
if(!n->addable && !res->addable) {
|
||||
tempalloc(&n1, n->type);
|
||||
cgen(n, &n1);
|
||||
cgen(&n1, res);
|
||||
tempfree(&n1);
|
||||
return;
|
||||
}
|
||||
|
||||
// if result is not addressable directly but n is,
|
||||
// compute its address and then store via the address.
|
||||
if(!res->addable) {
|
||||
igen(res, &n1, N);
|
||||
cgen(n, &n1);
|
||||
regfree(&n1);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise, the result is addressable but n is not.
|
||||
// let's do some computation.
|
||||
|
||||
// 64-bit ops are hard on 32-bit machine.
|
||||
if(is64(n->type) && cgen64(n, res))
|
||||
return;
|
||||
|
||||
// use ullman to pick operand to eval first.
|
||||
nl = n->left;
|
||||
nr = n->right;
|
||||
if(nl != N && nl->ullman >= UINF)
|
||||
if(nr != N && nr->ullman >= UINF) {
|
||||
// both are hard
|
||||
tempalloc(&n1, nr->type);
|
||||
cgen(nr, &n1);
|
||||
n2 = *n;
|
||||
n2.right = &n1;
|
||||
cgen(&n2, res);
|
||||
tempfree(&n1);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(n->op) {
|
||||
default:
|
||||
dump("cgen", n);
|
||||
fatal("cgen %O", n->op);
|
||||
break;
|
||||
|
||||
// these call bgen to get a bool value
|
||||
case OOROR:
|
||||
case OANDAND:
|
||||
case OEQ:
|
||||
case ONE:
|
||||
case OLT:
|
||||
case OLE:
|
||||
case OGE:
|
||||
case OGT:
|
||||
case ONOT:
|
||||
p1 = gbranch(AJMP, T);
|
||||
p2 = pc;
|
||||
gmove(nodbool(1), res);
|
||||
p3 = gbranch(AJMP, T);
|
||||
patch(p1, pc);
|
||||
bgen(n, 1, p2);
|
||||
gmove(nodbool(0), res);
|
||||
patch(p3, pc);
|
||||
return;
|
||||
|
||||
case OPLUS:
|
||||
cgen(nl, res);
|
||||
return;
|
||||
|
||||
case OMINUS:
|
||||
a = optoas(n->op, nl->type);
|
||||
goto uop;
|
||||
|
||||
// symmetric binary
|
||||
case OAND:
|
||||
case OOR:
|
||||
case OXOR:
|
||||
case OADD:
|
||||
case OMUL:
|
||||
a = optoas(n->op, nl->type);
|
||||
// TODO: cgen_bmul ?
|
||||
goto sbop;
|
||||
|
||||
// asymmetric binary
|
||||
case OSUB:
|
||||
a = optoas(n->op, nl->type);
|
||||
goto abop;
|
||||
|
||||
case OCONV:
|
||||
if(eqtype(n->type, nl->type)) {
|
||||
cgen(nl, res);
|
||||
break;
|
||||
}
|
||||
tempalloc(&n1, nl->type);
|
||||
cgen(nl, &n1);
|
||||
gmove(&n1, res);
|
||||
tempfree(&n1);
|
||||
break;
|
||||
|
||||
case ODOT:
|
||||
case ODOTPTR:
|
||||
case OINDEX:
|
||||
case OIND:
|
||||
case ONAME: // PHEAP or PPARAMREF var
|
||||
igen(n, &n1, res);
|
||||
gmove(&n1, res);
|
||||
regfree(&n1);
|
||||
break;
|
||||
|
||||
case OLEN:
|
||||
if(istype(nl->type, TSTRING) || istype(nl->type, TMAP)) {
|
||||
// both string and map have len in the first 32-bit word.
|
||||
// a zero pointer means zero length
|
||||
tempalloc(&n1, types[tptr]);
|
||||
cgen(nl, &n1);
|
||||
regalloc(&n2, types[tptr], N);
|
||||
gmove(&n1, &n2);
|
||||
tempfree(&n1);
|
||||
n1 = n2;
|
||||
|
||||
nodconst(&n2, types[tptr], 0);
|
||||
gins(optoas(OCMP, types[tptr]), &n1, &n2);
|
||||
p1 = gbranch(optoas(OEQ, types[tptr]), T);
|
||||
|
||||
n2 = n1;
|
||||
n2.op = OINDREG;
|
||||
n2.type = types[TINT32];
|
||||
gmove(&n2, &n1);
|
||||
|
||||
patch(p1, pc);
|
||||
|
||||
gmove(&n1, res);
|
||||
regfree(&n1);
|
||||
break;
|
||||
}
|
||||
if(isslice(nl->type)) {
|
||||
igen(nl, &n1, res);
|
||||
n1.op = OINDREG;
|
||||
n1.type = types[TUINT32];
|
||||
n1.xoffset = Array_nel;
|
||||
gmove(&n1, res);
|
||||
regfree(&n1);
|
||||
break;
|
||||
}
|
||||
fatal("cgen: OLEN: unknown type %lT", nl->type);
|
||||
break;
|
||||
|
||||
case OCAP:
|
||||
if(isslice(nl->type)) {
|
||||
igen(nl, &n1, res);
|
||||
n1.op = OINDREG;
|
||||
n1.type = types[TUINT32];
|
||||
n1.xoffset = Array_cap;
|
||||
gmove(&n1, res);
|
||||
regfree(&n1);
|
||||
break;
|
||||
}
|
||||
fatal("cgen: OCAP: unknown type %lT", nl->type);
|
||||
break;
|
||||
|
||||
case OADDR:
|
||||
agen(nl, res);
|
||||
break;
|
||||
|
||||
case OCALLMETH:
|
||||
cgen_callmeth(n, 0);
|
||||
cgen_callret(n, res);
|
||||
break;
|
||||
|
||||
case OCALLINTER:
|
||||
cgen_callinter(n, res, 0);
|
||||
cgen_callret(n, res);
|
||||
break;
|
||||
|
||||
case OCALL:
|
||||
cgen_call(n, 0);
|
||||
cgen_callret(n, res);
|
||||
break;
|
||||
|
||||
case OMOD:
|
||||
case ODIV:
|
||||
if(isfloat[n->type->etype]) {
|
||||
a = optoas(n->op, nl->type);
|
||||
goto abop;
|
||||
}
|
||||
cgen_div(n->op, nl, nr, res);
|
||||
break;
|
||||
|
||||
case OLSH:
|
||||
case ORSH:
|
||||
cgen_shift(n->op, nl, nr, res);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
sbop: // symmetric binary
|
||||
if(nl->ullman < nr->ullman) {
|
||||
r = nl;
|
||||
nl = nr;
|
||||
nr = r;
|
||||
}
|
||||
|
||||
abop: // asymmetric binary
|
||||
if(nl->ullman >= nr->ullman) {
|
||||
tempalloc(&n1, nl->type);
|
||||
cgen(nl, &n1);
|
||||
tempalloc(&n2, nr->type);
|
||||
cgen(nr, &n2);
|
||||
} else {
|
||||
tempalloc(&n1, nl->type);
|
||||
tempalloc(&n2, nr->type);
|
||||
cgen(nr, &n2);
|
||||
cgen(nl, &n1);
|
||||
}
|
||||
regalloc(&rr, res->type, N);
|
||||
gmove(&n1, &rr);
|
||||
gins(a, &n2, &rr);
|
||||
gmove(&rr, res);
|
||||
regfree(&rr);
|
||||
tempfree(&n2);
|
||||
tempfree(&n1);
|
||||
return;
|
||||
|
||||
uop: // unary
|
||||
tempalloc(&n1, nl->type);
|
||||
cgen(nl, &n1);
|
||||
gins(a, N, &n1);
|
||||
gmove(&n1, res);
|
||||
tempfree(&n1);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* address gen
|
||||
* res = &n;
|
||||
*/
|
||||
void
|
||||
agen(Node *n, Node *res)
|
||||
{
|
||||
Node *nl, *nr;
|
||||
Node n1, n2, n3, tmp;
|
||||
Type *t;
|
||||
uint32 w;
|
||||
uint64 v;
|
||||
Prog *p1;
|
||||
|
||||
if(debug['g']) {
|
||||
dump("\nagen-res", res);
|
||||
dump("agen-r", n);
|
||||
}
|
||||
if(n == N || n->type == T || res == N || res->type == T)
|
||||
fatal("agen");
|
||||
|
||||
// addressable var is easy
|
||||
if(n->addable) {
|
||||
regalloc(&n1, types[tptr], res);
|
||||
gins(ALEAL, n, &n1);
|
||||
gmove(&n1, res);
|
||||
regfree(&n1);
|
||||
return;
|
||||
}
|
||||
|
||||
// let's compute
|
||||
nl = n->left;
|
||||
nr = n->right;
|
||||
|
||||
switch(n->op) {
|
||||
default:
|
||||
fatal("agen %O", n->op);
|
||||
|
||||
case OCONV:
|
||||
if(!eqtype(n->type, nl->type))
|
||||
fatal("agen: non-trivial OCONV");
|
||||
agen(nl, res);
|
||||
break;
|
||||
|
||||
case OCALLMETH:
|
||||
cgen_callmeth(n, 0);
|
||||
cgen_aret(n, res);
|
||||
break;
|
||||
|
||||
case OCALLINTER:
|
||||
cgen_callinter(n, res, 0);
|
||||
cgen_aret(n, res);
|
||||
break;
|
||||
|
||||
case OCALL:
|
||||
cgen_call(n, 0);
|
||||
cgen_aret(n, res);
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
w = n->type->width;
|
||||
if(nr->addable) {
|
||||
agenr(nl, &n3, res);
|
||||
if(!isconst(nr, CTINT)) {
|
||||
regalloc(&n1, nr->type, N);
|
||||
cgen(nr, &n1);
|
||||
}
|
||||
} else if(nl->addable) {
|
||||
if(!isconst(nr, CTINT)) {
|
||||
tempalloc(&tmp, nr->type);
|
||||
cgen(nr, &tmp);
|
||||
regalloc(&n1, nr->type, N);
|
||||
gmove(&tmp, &n1);
|
||||
tempfree(&tmp);
|
||||
}
|
||||
regalloc(&n3, types[tptr], res);
|
||||
agen(nl, &n3);
|
||||
} else {
|
||||
tempalloc(&tmp, nr->type);
|
||||
cgen(nr, &tmp);
|
||||
nr = &tmp;
|
||||
agenr(nl, &n3, res);
|
||||
regalloc(&n1, nr->type, N);
|
||||
gins(optoas(OAS, nr->type), &tmp, &n1);
|
||||
tempfree(&tmp);
|
||||
}
|
||||
|
||||
// &a is in &n3 (allocated in res)
|
||||
// i is in &n1 (if not constant)
|
||||
// w is width
|
||||
|
||||
if(w == 0)
|
||||
fatal("index is zero width");
|
||||
|
||||
// constant index
|
||||
if(isconst(nr, CTINT)) {
|
||||
v = mpgetfix(nr->val.u.xval);
|
||||
if(isslice(nl->type)) {
|
||||
|
||||
if(!debug['B']) {
|
||||
n1 = n3;
|
||||
n1.op = OINDREG;
|
||||
n1.type = types[tptr];
|
||||
n1.xoffset = Array_nel;
|
||||
nodconst(&n2, types[TUINT32], v);
|
||||
gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
|
||||
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
|
||||
ginscall(throwindex, 0);
|
||||
patch(p1, pc);
|
||||
}
|
||||
|
||||
n1 = n3;
|
||||
n1.op = OINDREG;
|
||||
n1.type = types[tptr];
|
||||
n1.xoffset = Array_array;
|
||||
gmove(&n1, &n3);
|
||||
} else
|
||||
if(!debug['B']) {
|
||||
if(v < 0)
|
||||
yyerror("out of bounds on array");
|
||||
else
|
||||
if(v >= nl->type->bound)
|
||||
yyerror("out of bounds on array");
|
||||
}
|
||||
|
||||
nodconst(&n2, types[tptr], v*w);
|
||||
gins(optoas(OADD, types[tptr]), &n2, &n3);
|
||||
|
||||
gmove(&n3, res);
|
||||
regfree(&n3);
|
||||
break;
|
||||
}
|
||||
|
||||
// type of the index
|
||||
t = types[TUINT32];
|
||||
if(issigned[n1.type->etype])
|
||||
t = types[TINT32];
|
||||
|
||||
regalloc(&n2, t, &n1); // i
|
||||
gmove(&n1, &n2);
|
||||
regfree(&n1);
|
||||
|
||||
if(!debug['B']) {
|
||||
// check bounds
|
||||
if(isslice(nl->type)) {
|
||||
n1 = n3;
|
||||
n1.op = OINDREG;
|
||||
n1.type = types[tptr];
|
||||
n1.xoffset = Array_nel;
|
||||
} else
|
||||
nodconst(&n1, types[TUINT32], nl->type->bound);
|
||||
gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
|
||||
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
|
||||
ginscall(throwindex, 0);
|
||||
patch(p1, pc);
|
||||
}
|
||||
|
||||
if(isslice(nl->type)) {
|
||||
n1 = n3;
|
||||
n1.op = OINDREG;
|
||||
n1.type = types[tptr];
|
||||
n1.xoffset = Array_array;
|
||||
gmove(&n1, &n3);
|
||||
}
|
||||
|
||||
if(w == 1 || w == 2 || w == 4 || w == 8) {
|
||||
p1 = gins(ALEAL, &n2, &n3);
|
||||
p1->from.scale = w;
|
||||
p1->from.index = p1->from.type;
|
||||
p1->from.type = p1->to.type + D_INDIR;
|
||||
} else {
|
||||
nodconst(&n1, t, w);
|
||||
gins(optoas(OMUL, t), &n1, &n2);
|
||||
gins(optoas(OADD, types[tptr]), &n2, &n3);
|
||||
gmove(&n3, res);
|
||||
}
|
||||
|
||||
gmove(&n3, res);
|
||||
regfree(&n2);
|
||||
regfree(&n3);
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
// should only get here with names in this func.
|
||||
if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
|
||||
dump("bad agen", n);
|
||||
fatal("agen: bad ONAME funcdepth %d != %d",
|
||||
n->funcdepth, funcdepth);
|
||||
}
|
||||
|
||||
// should only get here for heap vars or paramref
|
||||
if(!(n->class & PHEAP) && n->class != PPARAMREF) {
|
||||
dump("bad agen", n);
|
||||
fatal("agen: bad ONAME class %#x", n->class);
|
||||
}
|
||||
cgen(n->heapaddr, res);
|
||||
if(n->xoffset != 0) {
|
||||
nodconst(&n1, types[tptr], n->xoffset);
|
||||
gins(optoas(OADD, types[tptr]), &n1, res);
|
||||
}
|
||||
break;
|
||||
|
||||
case OIND:
|
||||
cgen(nl, res);
|
||||
break;
|
||||
|
||||
case ODOT:
|
||||
t = nl->type;
|
||||
agen(nl, res);
|
||||
if(n->xoffset != 0) {
|
||||
nodconst(&n1, types[tptr], n->xoffset);
|
||||
gins(optoas(OADD, types[tptr]), &n1, res);
|
||||
}
|
||||
break;
|
||||
|
||||
case ODOTPTR:
|
||||
t = nl->type;
|
||||
if(!isptr[t->etype])
|
||||
fatal("agen: not ptr %N", n);
|
||||
cgen(nl, res);
|
||||
if(n->xoffset != 0) {
|
||||
nodconst(&n1, types[tptr], n->xoffset);
|
||||
gins(optoas(OADD, types[tptr]), &n1, res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* generate:
|
||||
* newreg = &n;
|
||||
* res = newreg
|
||||
*
|
||||
* on exit, a has been changed to be *newreg.
|
||||
* caller must regfree(a).
|
||||
*/
|
||||
void
|
||||
igen(Node *n, Node *a, Node *res)
|
||||
{
|
||||
Node n1;
|
||||
|
||||
tempalloc(&n1, types[tptr]);
|
||||
agen(n, &n1);
|
||||
regalloc(a, types[tptr], res);
|
||||
gins(optoas(OAS, types[tptr]), &n1, a);
|
||||
tempfree(&n1);
|
||||
a->op = OINDREG;
|
||||
a->type = n->type;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate:
|
||||
* newreg = &n;
|
||||
*
|
||||
* caller must regfree(a).
|
||||
*/
|
||||
void
|
||||
agenr(Node *n, Node *a, Node *res)
|
||||
{
|
||||
Node n1;
|
||||
|
||||
tempalloc(&n1, types[tptr]);
|
||||
agen(n, &n1);
|
||||
regalloc(a, types[tptr], res);
|
||||
gmove(&n1, a);
|
||||
tempfree(&n1);
|
||||
}
|
||||
|
||||
/*
|
||||
* branch gen
|
||||
* if(n == true) goto to;
|
||||
*/
|
||||
void
|
||||
bgen(Node *n, int true, Prog *to)
|
||||
{
|
||||
int et, a;
|
||||
Node *nl, *nr, *r;
|
||||
Node n1, n2, tmp;
|
||||
Prog *p1, *p2;
|
||||
|
||||
if(debug['g']) {
|
||||
dump("\nbgen", n);
|
||||
}
|
||||
|
||||
if(n == N)
|
||||
n = nodbool(1);
|
||||
|
||||
nl = n->left;
|
||||
nr = n->right;
|
||||
|
||||
if(n->type == T) {
|
||||
convlit(n, types[TBOOL]);
|
||||
if(n->type == T)
|
||||
return;
|
||||
}
|
||||
|
||||
et = n->type->etype;
|
||||
if(et != TBOOL) {
|
||||
yyerror("cgen: bad type %T for %O", n->type, n->op);
|
||||
patch(gins(AEND, N, N), to);
|
||||
return;
|
||||
}
|
||||
nl = N;
|
||||
nr = N;
|
||||
|
||||
switch(n->op) {
|
||||
default:
|
||||
regalloc(&n1, n->type, N);
|
||||
cgen(n, &n1);
|
||||
nodconst(&n2, n->type, 0);
|
||||
gins(optoas(OCMP, n->type), &n1, &n2);
|
||||
a = AJNE;
|
||||
if(!true)
|
||||
a = AJEQ;
|
||||
patch(gbranch(a, n->type), to);
|
||||
regfree(&n1);
|
||||
return;
|
||||
|
||||
case OLITERAL:
|
||||
// need to ask if it is bool?
|
||||
if(!true == !n->val.u.bval)
|
||||
patch(gbranch(AJMP, T), to);
|
||||
return;
|
||||
|
||||
case ONAME:
|
||||
nodconst(&n1, n->type, 0);
|
||||
gins(optoas(OCMP, n->type), n, &n1);
|
||||
a = AJNE;
|
||||
if(!true)
|
||||
a = AJEQ;
|
||||
patch(gbranch(a, n->type), to);
|
||||
return;
|
||||
|
||||
case OANDAND:
|
||||
if(!true)
|
||||
goto caseor;
|
||||
|
||||
caseand:
|
||||
p1 = gbranch(AJMP, T);
|
||||
p2 = gbranch(AJMP, T);
|
||||
patch(p1, pc);
|
||||
bgen(n->left, !true, p2);
|
||||
bgen(n->right, !true, p2);
|
||||
p1 = gbranch(AJMP, T);
|
||||
patch(p1, to);
|
||||
patch(p2, pc);
|
||||
return;
|
||||
|
||||
case OOROR:
|
||||
if(!true)
|
||||
goto caseand;
|
||||
|
||||
caseor:
|
||||
bgen(n->left, true, to);
|
||||
bgen(n->right, true, to);
|
||||
return;
|
||||
|
||||
case OEQ:
|
||||
case ONE:
|
||||
case OLT:
|
||||
case OGT:
|
||||
case OLE:
|
||||
case OGE:
|
||||
nr = n->right;
|
||||
if(nr == N || nr->type == T)
|
||||
return;
|
||||
|
||||
case ONOT: // unary
|
||||
nl = n->left;
|
||||
if(nl == N || nl->type == T)
|
||||
return;
|
||||
}
|
||||
|
||||
switch(n->op) {
|
||||
case ONOT:
|
||||
bgen(nl, !true, to);
|
||||
break;
|
||||
|
||||
case OEQ:
|
||||
case ONE:
|
||||
case OLT:
|
||||
case OGT:
|
||||
case OLE:
|
||||
case OGE:
|
||||
a = n->op;
|
||||
if(!true)
|
||||
a = brcom(a);
|
||||
|
||||
// make simplest on right
|
||||
if(nl->op == OLITERAL || nl->ullman < nr->ullman) {
|
||||
a = brrev(a);
|
||||
r = nl;
|
||||
nl = nr;
|
||||
nr = r;
|
||||
}
|
||||
|
||||
if(isslice(nl->type)) {
|
||||
// only valid to cmp darray to literal nil
|
||||
if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
|
||||
yyerror("illegal array comparison");
|
||||
break;
|
||||
}
|
||||
a = optoas(a, types[tptr]);
|
||||
regalloc(&n1, types[tptr], N);
|
||||
agen(nl, &n1);
|
||||
n2 = n1;
|
||||
n2.op = OINDREG;
|
||||
n2.xoffset = Array_array;
|
||||
nodconst(&tmp, types[tptr], 0);
|
||||
gins(optoas(OCMP, types[tptr]), &n2, &tmp);
|
||||
patch(gbranch(a, types[tptr]), to);
|
||||
regfree(&n1);
|
||||
break;
|
||||
}
|
||||
|
||||
if(is64(nr->type)) {
|
||||
fatal("cmp64");
|
||||
// cmp64(nl, nr, a, to);
|
||||
break;
|
||||
}
|
||||
|
||||
a = optoas(a, nr->type);
|
||||
|
||||
if(nr->ullman >= UINF) {
|
||||
regalloc(&n1, nr->type, N);
|
||||
cgen(nr, &n1);
|
||||
|
||||
tempname(&tmp, nr->type);
|
||||
gmove(&n1, &tmp);
|
||||
regfree(&n1);
|
||||
|
||||
regalloc(&n1, nl->type, N);
|
||||
cgen(nl, &n1);
|
||||
|
||||
regalloc(&n2, nr->type, &n2);
|
||||
cgen(&tmp, &n2);
|
||||
|
||||
gins(optoas(OCMP, nr->type), &n1, &n2);
|
||||
patch(gbranch(a, nr->type), to);
|
||||
|
||||
regfree(&n1);
|
||||
regfree(&n2);
|
||||
break;
|
||||
}
|
||||
|
||||
regalloc(&n1, nl->type, N);
|
||||
cgen(nl, &n1);
|
||||
|
||||
if(smallintconst(nr)) {
|
||||
gins(optoas(OCMP, nr->type), &n1, nr);
|
||||
patch(gbranch(a, nr->type), to);
|
||||
regfree(&n1);
|
||||
break;
|
||||
}
|
||||
|
||||
regalloc(&n2, nr->type, N);
|
||||
cgen(nr, &n2);
|
||||
|
||||
gins(optoas(OCMP, nr->type), &n1, &n2);
|
||||
patch(gbranch(a, nr->type), to);
|
||||
|
||||
regfree(&n1);
|
||||
regfree(&n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* n is on stack, either local variable
|
||||
* or return value from function call.
|
||||
* return n's offset from SP.
|
||||
*/
|
||||
int32
|
||||
stkof(Node *n)
|
||||
{
|
||||
Type *t;
|
||||
Iter flist;
|
||||
|
||||
switch(n->op) {
|
||||
case OINDREG:
|
||||
return n->xoffset;
|
||||
|
||||
case OCALLMETH:
|
||||
case OCALLINTER:
|
||||
case OCALL:
|
||||
t = n->left->type;
|
||||
if(isptr[t->etype])
|
||||
t = t->type;
|
||||
|
||||
t = structfirst(&flist, getoutarg(t));
|
||||
if(t != T)
|
||||
return t->width;
|
||||
break;
|
||||
}
|
||||
|
||||
// botch - probably failing to recognize address
|
||||
// arithmetic on the above. eg INDEX and DOT
|
||||
return -1000;
|
||||
}
|
||||
|
||||
/*
|
||||
* struct gen
|
||||
* memmove(&res, &n, w);
|
||||
*/
|
||||
void
|
||||
sgen(Node *n, Node *res, int w)
|
||||
{
|
||||
Node nodl, nodr;
|
||||
int32 c, q, odst, osrc;
|
||||
|
||||
if(debug['g']) {
|
||||
print("\nsgen w=%d\n", w);
|
||||
dump("r", n);
|
||||
dump("res", res);
|
||||
}
|
||||
if(w == 0)
|
||||
return;
|
||||
if(n->ullman >= UINF && res->ullman >= UINF) {
|
||||
fatal("sgen UINF");
|
||||
}
|
||||
|
||||
if(w < 0)
|
||||
fatal("sgen copy %d", w);
|
||||
|
||||
// offset on the stack
|
||||
osrc = stkof(n);
|
||||
odst = stkof(res);
|
||||
|
||||
// TODO(rsc): Should these be tempalloc instead?
|
||||
nodreg(&nodl, types[tptr], D_DI);
|
||||
nodreg(&nodr, types[tptr], D_SI);
|
||||
|
||||
if(n->ullman >= res->ullman) {
|
||||
agen(n, &nodr);
|
||||
agen(res, &nodl);
|
||||
} else {
|
||||
agen(res, &nodl);
|
||||
agen(n, &nodr);
|
||||
}
|
||||
|
||||
c = w % 4; // bytes
|
||||
q = w / 4; // doublewords
|
||||
|
||||
// if we are copying forward on the stack and
|
||||
// the src and dst overlap, then reverse direction
|
||||
if(osrc < odst && odst < osrc+w) {
|
||||
// reverse direction
|
||||
gins(ASTD, N, N); // set direction flag
|
||||
if(c > 0) {
|
||||
gconreg(AADDL, w-1, D_SI);
|
||||
gconreg(AADDL, w-1, D_DI);
|
||||
|
||||
gconreg(AMOVL, c, D_CX);
|
||||
gins(AREP, N, N); // repeat
|
||||
gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
|
||||
}
|
||||
|
||||
if(q > 0) {
|
||||
if(c > 0) {
|
||||
gconreg(AADDL, -7, D_SI);
|
||||
gconreg(AADDL, -7, D_DI);
|
||||
} else {
|
||||
gconreg(AADDL, w-8, D_SI);
|
||||
gconreg(AADDL, w-8, D_DI);
|
||||
}
|
||||
gconreg(AMOVL, q, D_CX);
|
||||
gins(AREP, N, N); // repeat
|
||||
gins(AMOVSL, N, N); // MOVL *(SI)-,*(DI)-
|
||||
}
|
||||
// we leave with the flag clear
|
||||
gins(ACLD, N, N);
|
||||
} else {
|
||||
// normal direction
|
||||
if(q >= 4) {
|
||||
gconreg(AMOVL, q, D_CX);
|
||||
gins(AREP, N, N); // repeat
|
||||
gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
|
||||
} else
|
||||
while(q > 0) {
|
||||
gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
|
||||
q--;
|
||||
}
|
||||
while(c > 0) {
|
||||
gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
|
||||
c--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* attempt to generate 64-bit
|
||||
* res = n
|
||||
* return 1 on success, 0 if op not handled.
|
||||
*/
|
||||
int
|
||||
cgen64(Node *n, Node *res)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -85,6 +85,7 @@ void ginscall(Node*, int);
|
||||
* cgen
|
||||
*/
|
||||
void agen(Node*, Node*);
|
||||
void agenr(Node *n, Node *a, Node *res);
|
||||
void igen(Node*, Node*, Node*);
|
||||
vlong fieldoffset(Type*, Node*);
|
||||
void bgen(Node*, int, Prog*);
|
||||
@ -129,7 +130,7 @@ void buildtxt(void);
|
||||
Plist* newplist(void);
|
||||
int isfat(Type*);
|
||||
void sudoclean(void);
|
||||
int sudoaddable(Node*, Addr*);
|
||||
int sudoaddable(int, Node*, Addr*);
|
||||
void afunclit(Addr*);
|
||||
|
||||
/*
|
||||
|
@ -99,7 +99,40 @@ ret:
|
||||
void
|
||||
clearfat(Node *nl)
|
||||
{
|
||||
fatal("clearfat");
|
||||
uint32 w, c, q;
|
||||
Node n1;
|
||||
|
||||
/* clear a fat object */
|
||||
if(debug['g'])
|
||||
dump("\nclearfat", nl);
|
||||
|
||||
w = nl->type->width;
|
||||
c = w % 4; // bytes
|
||||
q = w / 4; // quads
|
||||
|
||||
gconreg(AMOVL, 0, D_AX);
|
||||
nodreg(&n1, types[tptr], D_DI);
|
||||
agen(nl, &n1);
|
||||
|
||||
if(q >= 4) {
|
||||
gconreg(AMOVL, q, D_CX);
|
||||
gins(AREP, N, N); // repeat
|
||||
gins(ASTOSL, N, N); // STOL AL,*(DI)+
|
||||
} else
|
||||
while(q > 0) {
|
||||
gins(ASTOSL, N, N); // STOL AL,*(DI)+
|
||||
q--;
|
||||
}
|
||||
|
||||
if(c >= 4) {
|
||||
gconreg(AMOVL, c, D_CX);
|
||||
gins(AREP, N, N); // repeat
|
||||
gins(ASTOSB, N, N); // STOB AL,*(DI)+
|
||||
} else
|
||||
while(c > 0) {
|
||||
gins(ASTOSB, N, N); // STOB AL,*(DI)+
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -290,7 +323,127 @@ cgen_ret(Node *n)
|
||||
void
|
||||
cgen_asop(Node *n)
|
||||
{
|
||||
fatal("cgen_asop");
|
||||
Node n1, n2, n3, n4;
|
||||
Node *nl, *nr;
|
||||
Prog *p1;
|
||||
Addr addr;
|
||||
int a;
|
||||
|
||||
nl = n->left;
|
||||
nr = n->right;
|
||||
|
||||
if(nr->ullman >= UINF && nl->ullman >= UINF) {
|
||||
tempname(&n1, nr->type);
|
||||
cgen(nr, &n1);
|
||||
n2 = *n;
|
||||
n2.right = &n1;
|
||||
cgen_asop(&n2);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if(!isint[nl->type->etype])
|
||||
goto hard;
|
||||
if(!isint[nr->type->etype])
|
||||
goto hard;
|
||||
|
||||
switch(n->etype) {
|
||||
case OADD:
|
||||
if(smallintconst(nr))
|
||||
if(mpgetfix(nr->val.u.xval) == 1) {
|
||||
a = optoas(OINC, nl->type);
|
||||
if(nl->addable) {
|
||||
gins(a, N, nl);
|
||||
goto ret;
|
||||
}
|
||||
if(sudoaddable(a, nl, &addr)) {
|
||||
p1 = gins(a, N, N);
|
||||
p1->to = addr;
|
||||
sudoclean();
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OSUB:
|
||||
if(smallintconst(nr))
|
||||
if(mpgetfix(nr->val.u.xval) == 1) {
|
||||
a = optoas(ODEC, nl->type);
|
||||
if(nl->addable) {
|
||||
gins(a, N, nl);
|
||||
goto ret;
|
||||
}
|
||||
if(sudoaddable(a, nl, &addr)) {
|
||||
p1 = gins(a, N, N);
|
||||
p1->to = addr;
|
||||
sudoclean();
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch(n->etype) {
|
||||
case OADD:
|
||||
case OSUB:
|
||||
case OXOR:
|
||||
case OAND:
|
||||
case OOR:
|
||||
a = optoas(n->etype, nl->type);
|
||||
if(nl->addable) {
|
||||
if(smallintconst(nr)) {
|
||||
gins(a, nr, nl);
|
||||
goto ret;
|
||||
}
|
||||
regalloc(&n2, nr->type, N);
|
||||
cgen(nr, &n2);
|
||||
gins(a, &n2, nl);
|
||||
regfree(&n2);
|
||||
goto ret;
|
||||
}
|
||||
if(nr->ullman < UINF)
|
||||
if(sudoaddable(a, nl, &addr)) {
|
||||
if(smallintconst(nr)) {
|
||||
p1 = gins(a, nr, N);
|
||||
p1->to = addr;
|
||||
sudoclean();
|
||||
goto ret;
|
||||
}
|
||||
regalloc(&n2, nr->type, N);
|
||||
cgen(nr, &n2);
|
||||
p1 = gins(a, &n2, N);
|
||||
p1->to = addr;
|
||||
regfree(&n2);
|
||||
sudoclean();
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
|
||||
hard:
|
||||
if(nr->ullman > nl->ullman) {
|
||||
regalloc(&n2, nr->type, N);
|
||||
cgen(nr, &n2);
|
||||
igen(nl, &n1, N);
|
||||
} else {
|
||||
igen(nl, &n1, N);
|
||||
tempalloc(&n2, nr->type);
|
||||
cgen(nr, &n2);
|
||||
}
|
||||
|
||||
n3 = *n;
|
||||
n3.left = &n1;
|
||||
n3.right = &n2;
|
||||
n3.op = n->etype;
|
||||
|
||||
tempalloc(&n4, nl->type);
|
||||
cgen(&n3, &n4);
|
||||
gmove(&n4, &n1);
|
||||
|
||||
regfree(&n1);
|
||||
tempfree(&n4);
|
||||
tempfree(&n2);
|
||||
|
||||
ret:
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
|
1161
src/cmd/8g/gsubr.c
Executable file
1161
src/cmd/8g/gsubr.c
Executable file
File diff suppressed because it is too large
Load Diff
@ -82,7 +82,7 @@ Dconv(Fmt *fp)
|
||||
i = a->type;
|
||||
if(i >= D_INDIR) {
|
||||
if(a->offset)
|
||||
snprint(str, sizeof(str), "%ld(%R)", a->offset, i-D_INDIR);
|
||||
snprint(str, sizeof(str), "%d(%R)", a->offset, i-D_INDIR);
|
||||
else
|
||||
snprint(str, sizeof(str), "(%R)", i-D_INDIR);
|
||||
goto brk;
|
||||
@ -91,7 +91,7 @@ Dconv(Fmt *fp)
|
||||
|
||||
default:
|
||||
if(a->offset)
|
||||
snprint(str, sizeof(str), "$%ld,%R", a->offset, i);
|
||||
snprint(str, sizeof(str), "$%d,%R", a->offset, i);
|
||||
else
|
||||
snprint(str, sizeof(str), "%R", i);
|
||||
break;
|
||||
@ -101,33 +101,33 @@ Dconv(Fmt *fp)
|
||||
break;
|
||||
|
||||
case D_BRANCH:
|
||||
snprint(str, sizeof(str), "%ld", a->branch->loc);
|
||||
snprint(str, sizeof(str), "%d", a->branch->loc);
|
||||
break;
|
||||
|
||||
case D_EXTERN:
|
||||
snprint(str, sizeof(str), "%S+%ld(SB)", a->sym, a->offset);
|
||||
snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset);
|
||||
break;
|
||||
|
||||
case D_STATIC:
|
||||
snprint(str, sizeof(str), "%S<>+%ld(SB)", a->sym, a->offset);
|
||||
snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset);
|
||||
break;
|
||||
|
||||
case D_AUTO:
|
||||
snprint(str, sizeof(str), "%S+%ld(SP)", a->sym, a->offset);
|
||||
snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset);
|
||||
break;
|
||||
|
||||
case D_PARAM:
|
||||
snprint(str, sizeof(str), "%S+%ld(FP)", a->sym, a->offset);
|
||||
snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset);
|
||||
break;
|
||||
|
||||
case D_CONST:
|
||||
if(fp->flags & FmtLong) {
|
||||
d1 = a->offset;
|
||||
d2 = a->offset2;
|
||||
snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2);
|
||||
snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
|
||||
break;
|
||||
}
|
||||
snprint(str, sizeof(str), "$%ld", a->offset);
|
||||
snprint(str, sizeof(str), "$%d", a->offset);
|
||||
break;
|
||||
|
||||
case D_FCONST:
|
||||
|
Loading…
Reference in New Issue
Block a user