This source file includes following definitions.
- order
- ordertemp
- ordercopyexpr
- ordercheapexpr
- ordersafeexpr
- istemp
- isaddrokay
- orderaddrtemp
- marktemp
- poptemp
- cleantempnopop
- cleantemp
- orderstmtlist
- orderblock
- orderexprinplace
- orderstmtinplace
- orderinit
- ismulticall
- copyret
- ordercallargs
- ordercall
- ordermapassign
- orderstmt
- orderexprlist
- orderexprlistinplace
- orderexpr
#include <u.h>
#include <libc.h>
#include "go.h"
typedef struct Order Order;
struct Order
{
NodeList *out;
NodeList *temp;
NodeList *free;
};
static void orderstmt(Node*, Order*);
static void orderstmtlist(NodeList*, Order*);
static void orderblock(NodeList **l);
static void orderexpr(Node**, Order*);
static void orderexprinplace(Node**, Order*);
static void orderexprlist(NodeList*, Order*);
static void orderexprlistinplace(NodeList*, Order*);
void
order(Node *fn)
{
orderblock(&fn->nbody);
}
static Node*
ordertemp(Type *t, Order *order, int clear)
{
Node *var, *a;
NodeList *l;
var = temp(t);
if(clear) {
a = nod(OAS, var, N);
typecheck(&a, Etop);
order->out = list(order->out, a);
}
if((l = order->free) == nil)
l = mal(sizeof *l);
order->free = l->next;
l->next = order->temp;
l->n = var;
order->temp = l;
return var;
}
static Node*
ordercopyexpr(Node *n, Type *t, Order *order, int clear)
{
Node *a, *var;
var = ordertemp(t, order, clear);
a = nod(OAS, var, n);
typecheck(&a, Etop);
order->out = list(order->out, a);
return var;
}
static Node*
ordercheapexpr(Node *n, Order *order)
{
switch(n->op) {
case ONAME:
case OLITERAL:
return n;
}
return ordercopyexpr(n, n->type, order, 0);
}
static Node*
ordersafeexpr(Node *n, Order *order)
{
Node *l, *r, *a;
switch(n->op) {
default:
fatal("ordersafeexpr %O", n->op);
case ONAME:
case OLITERAL:
return n;
case ODOT:
l = ordersafeexpr(n->left, order);
if(l == n->left)
return n;
a = nod(OXXX, N, N);
*a = *n;
a->orig = a;
a->left = l;
typecheck(&a, Erv);
return a;
case ODOTPTR:
case OIND:
l = ordercheapexpr(n->left, order);
if(l == n->left)
return n;
a = nod(OXXX, N, N);
*a = *n;
a->orig = a;
a->left = l;
typecheck(&a, Erv);
return a;
case OINDEX:
case OINDEXMAP:
if(isfixedarray(n->left->type))
l = ordersafeexpr(n->left, order);
else
l = ordercheapexpr(n->left, order);
r = ordercheapexpr(n->right, order);
if(l == n->left && r == n->right)
return n;
a = nod(OXXX, N, N);
*a = *n;
a->orig = a;
a->left = l;
a->right = r;
typecheck(&a, Erv);
return a;
}
}
static int
istemp(Node *n)
{
if(n->op != ONAME)
return 0;
return strncmp(n->sym->name, "autotmp_", 8) == 0;
}
static int
isaddrokay(Node *n)
{
return islvalue(n) && (n->op != ONAME || n->class == PEXTERN || istemp(n));
}
static void
orderaddrtemp(Node **np, Order *order)
{
Node *n;
n = *np;
if(isaddrokay(n))
return;
*np = ordercopyexpr(n, n->type, order, 0);
}
static NodeList*
marktemp(Order *order)
{
return order->temp;
}
static void
poptemp(NodeList *mark, Order *order)
{
NodeList *l;
while((l = order->temp) != mark) {
order->temp = l->next;
l->next = order->free;
order->free = l;
}
}
static void
cleantempnopop(NodeList *mark, Order *order, NodeList **out)
{
NodeList *l;
Node *kill;
for(l=order->temp; l != mark; l=l->next) {
kill = nod(OVARKILL, l->n, N);
typecheck(&kill, Etop);
*out = list(*out, kill);
}
}
static void
cleantemp(NodeList *top, Order *order)
{
cleantempnopop(top, order, &order->out);
poptemp(top, order);
}
static void
orderstmtlist(NodeList *l, Order *order)
{
for(; l; l=l->next)
orderstmt(l->n, order);
}
static void
orderblock(NodeList **l)
{
Order order;
NodeList *mark;
memset(&order, 0, sizeof order);
mark = marktemp(&order);
orderstmtlist(*l, &order);
cleantemp(mark, &order);
*l = order.out;
}
static void
orderexprinplace(Node **np, Order *outer)
{
Node *n;
NodeList **lp;
Order order;
n = *np;
memset(&order, 0, sizeof order);
orderexpr(&n, &order);
addinit(&n, order.out);
lp = &order.temp;
while(*lp != nil)
lp = &(*lp)->next;
*lp = outer->temp;
outer->temp = order.temp;
*np = n;
}
static void
orderstmtinplace(Node **np)
{
Node *n;
Order order;
NodeList *mark;
n = *np;
memset(&order, 0, sizeof order);
mark = marktemp(&order);
orderstmt(n, &order);
cleantemp(mark, &order);
*np = liststmt(order.out);
}
static void
orderinit(Node *n, Order *order)
{
orderstmtlist(n->ninit, order);
n->ninit = nil;
}
static int
ismulticall(NodeList *l)
{
Node *n;
if(l == nil || l->next != nil)
return 0;
n = l->n;
switch(n->op) {
default:
return 0;
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
break;
}
return n->left->type->outtuple > 1;
}
static NodeList*
copyret(Node *n, Order *order)
{
Type *t;
Node *tmp, *as;
NodeList *l1, *l2;
Iter tl;
if(n->type->etype != TSTRUCT || !n->type->funarg)
fatal("copyret %T %d", n->type, n->left->type->outtuple);
l1 = nil;
l2 = nil;
for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) {
tmp = temp(t->type);
l1 = list(l1, tmp);
l2 = list(l2, tmp);
}
as = nod(OAS2, N, N);
as->list = l1;
as->rlist = list1(n);
typecheck(&as, Etop);
orderstmt(as, order);
return l2;
}
static void
ordercallargs(NodeList **l, Order *order)
{
if(ismulticall(*l)) {
*l = copyret((*l)->n, order);
} else {
orderexprlist(*l, order);
}
}
static void
ordercall(Node *n, Order *order)
{
orderexpr(&n->left, order);
orderexpr(&n->right, order);
ordercallargs(&n->list, order);
}
static void
ordermapassign(Node *n, Order *order)
{
Node *m, *a;
NodeList *l;
NodeList *post;
switch(n->op) {
default:
fatal("ordermapassign %O", n->op);
case OAS:
order->out = list(order->out, n);
if(n->left->op == OINDEXMAP && !isaddrokay(n->right)) {
m = n->left;
n->left = ordertemp(m->type, order, 0);
a = nod(OAS, m, n->left);
typecheck(&a, Etop);
order->out = list(order->out, a);
}
break;
case OAS2:
case OAS2DOTTYPE:
case OAS2MAPR:
case OAS2FUNC:
post = nil;
for(l=n->list; l != nil; l=l->next) {
if(l->n->op == OINDEXMAP) {
m = l->n;
if(!istemp(m->left))
m->left = ordercopyexpr(m->left, m->left->type, order, 0);
if(!istemp(m->right))
m->right = ordercopyexpr(m->right, m->right->type, order, 0);
l->n = ordertemp(m->type, order, 0);
a = nod(OAS, m, l->n);
typecheck(&a, Etop);
post = list(post, a);
}
}
order->out = list(order->out, n);
order->out = concat(order->out, post);
break;
}
}
static void
orderstmt(Node *n, Order *order)
{
int lno;
NodeList *l, *t, *t1;
Node *r, *tmp1, *tmp2, **np;
Type *ch;
if(n == N)
return;
lno = setlineno(n);
orderinit(n, order);
switch(n->op) {
default:
fatal("orderstmt %O", n->op);
case OVARKILL:
order->out = list(order->out, n);
break;
case OAS:
case OAS2:
case OAS2DOTTYPE:
case OCLOSE:
case OCOPY:
case OPRINT:
case OPRINTN:
case ORECOVER:
case ORECV:
t = marktemp(order);
orderexpr(&n->left, order);
orderexpr(&n->right, order);
orderexprlist(n->list, order);
orderexprlist(n->rlist, order);
switch(n->op) {
case OAS:
case OAS2:
case OAS2DOTTYPE:
ordermapassign(n, order);
break;
default:
order->out = list(order->out, n);
break;
}
cleantemp(t, order);
break;
case OASOP:
t = marktemp(order);
orderexpr(&n->left, order);
n->left = ordersafeexpr(n->left, order);
tmp1 = treecopy(n->left);
if(tmp1->op == OINDEXMAP)
tmp1->etype = 0;
tmp1 = ordercopyexpr(tmp1, n->left->type, order, 0);
n->right = nod(n->etype, tmp1, n->right);
typecheck(&n->right, Erv);
orderexpr(&n->right, order);
n->etype = 0;
n->op = OAS;
ordermapassign(n, order);
cleantemp(t, order);
break;
case OAS2MAPR:
t = marktemp(order);
orderexprlist(n->list, order);
r = n->rlist->n;
orderexpr(&r->left, order);
orderexpr(&r->right, order);
if(r->right->op == OARRAYBYTESTR)
r->right->op = OARRAYBYTESTRTMP;
orderaddrtemp(&r->right, order);
ordermapassign(n, order);
cleantemp(t, order);
break;
case OAS2FUNC:
t = marktemp(order);
orderexprlist(n->list, order);
ordercall(n->rlist->n, order);
ordermapassign(n, order);
cleantemp(t, order);
break;
case OAS2RECV:
t = marktemp(order);
orderexprlist(n->list, order);
orderexpr(&n->rlist->n->left, order);
ch = n->rlist->n->left->type;
tmp1 = ordertemp(ch->type, order, haspointers(ch->type));
tmp2 = ordertemp(types[TBOOL], order, 0);
order->out = list(order->out, n);
r = nod(OAS, n->list->n, tmp1);
typecheck(&r, Etop);
ordermapassign(r, order);
r = nod(OAS, n->list->next->n, tmp2);
typecheck(&r, Etop);
ordermapassign(r, order);
n->list = list(list1(tmp1), tmp2);
cleantemp(t, order);
break;
case OBLOCK:
case OEMPTY:
orderstmtlist(n->list, order);
break;
case OBREAK:
case OCONTINUE:
case ODCL:
case ODCLCONST:
case ODCLTYPE:
case OFALL:
case OXFALL:
case OGOTO:
case OLABEL:
case ORETJMP:
order->out = list(order->out, n);
break;
case OCALLFUNC:
case OCALLINTER:
case OCALLMETH:
t = marktemp(order);
ordercall(n, order);
order->out = list(order->out, n);
cleantemp(t, order);
break;
case ODEFER:
case OPROC:
t = marktemp(order);
switch(n->left->op) {
case ODELETE:
orderexprlist(n->left->list, order);
t1 = marktemp(order);
np = &n->left->list->next->n;
*np = ordercopyexpr(*np, (*np)->type, order, 0);
poptemp(t1, order);
break;
default:
ordercall(n->left, order);
break;
}
order->out = list(order->out, n);
cleantemp(t, order);
break;
case ODELETE:
t = marktemp(order);
orderexpr(&n->list->n, order);
orderexpr(&n->list->next->n, order);
orderaddrtemp(&n->list->next->n, order);
order->out = list(order->out, n);
cleantemp(t, order);
break;
case OFOR:
t = marktemp(order);
orderexprinplace(&n->ntest, order);
l = nil;
cleantempnopop(t, order, &l);
n->nbody = concat(l, n->nbody);
orderblock(&n->nbody);
orderstmtinplace(&n->nincr);
order->out = list(order->out, n);
cleantemp(t, order);
break;
case OIF:
t = marktemp(order);
orderexprinplace(&n->ntest, order);
l = nil;
cleantempnopop(t, order, &l);
n->nbody = concat(l, n->nbody);
l = nil;
cleantempnopop(t, order, &l);
n->nelse = concat(l, n->nelse);
poptemp(t, order);
orderblock(&n->nbody);
orderblock(&n->nelse);
order->out = list(order->out, n);
break;
case OPANIC:
t = marktemp(order);
orderexpr(&n->left, order);
if(!isinter(n->left->type))
orderaddrtemp(&n->left, order);
order->out = list(order->out, n);
cleantemp(t, order);
break;
case ORANGE:
t = marktemp(order);
orderexpr(&n->right, order);
switch(n->type->etype) {
default:
fatal("orderstmt range %T", n->type);
case TARRAY:
if(count(n->list) < 2 || isblank(n->list->next->n)) {
break;
}
case TCHAN:
case TSTRING:
r = n->right;
if(r->type->etype == TSTRING && r->type != types[TSTRING]) {
r = nod(OCONV, r, N);
r->type = types[TSTRING];
typecheck(&r, Erv);
}
n->right = ordercopyexpr(r, r->type, order, 0);
break;
case TMAP:
r = n->right;
n->right = ordercopyexpr(r, r->type, order, 0);
n->alloc = ordertemp(types[TUINT8], order, 1);
break;
}
for(l=n->list; l; l=l->next)
orderexprinplace(&l->n, order);
orderblock(&n->nbody);
order->out = list(order->out, n);
cleantemp(t, order);
break;
case ORETURN:
ordercallargs(&n->list, order);
order->out = list(order->out, n);
break;
case OSELECT:
t = marktemp(order);
for(l=n->list; l; l=l->next) {
if(l->n->op != OXCASE)
fatal("order select case %O", l->n->op);
r = l->n->left;
setlineno(l->n);
if(l->n->ninit != nil)
fatal("order select ninit");
if(r != nil) {
switch(r->op) {
default:
yyerror("unknown op in select %O", r->op);
dump("select case", r);
break;
case OSELRECV:
case OSELRECV2:
if(r->colas) {
t = r->ninit;
if(t != nil && t->n->op == ODCL && t->n->left == r->left)
t = t->next;
if(t != nil && t->n->op == ODCL && t->n->left == r->ntest)
t = t->next;
if(t == nil)
r->ninit = nil;
}
if(r->ninit != nil) {
yyerror("ninit on select recv");
dumplist("ninit", r->ninit);
}
orderexpr(&r->right->left, order);
if(r->left != N && isblank(r->left))
r->left = N;
if(r->left != N) {
tmp1 = r->left;
if(r->colas) {
tmp2 = nod(ODCL, tmp1, N);
typecheck(&tmp2, Etop);
l->n->ninit = list(l->n->ninit, tmp2);
}
r->left = ordertemp(r->right->left->type->type, order, haspointers(r->right->left->type->type));
tmp2 = nod(OAS, tmp1, r->left);
typecheck(&tmp2, Etop);
l->n->ninit = list(l->n->ninit, tmp2);
}
if(r->ntest != N && isblank(r->ntest))
r->ntest = N;
if(r->ntest != N) {
tmp1 = r->ntest;
if(r->colas) {
tmp2 = nod(ODCL, tmp1, N);
typecheck(&tmp2, Etop);
l->n->ninit = list(l->n->ninit, tmp2);
}
r->ntest = ordertemp(tmp1->type, order, 0);
tmp2 = nod(OAS, tmp1, r->ntest);
typecheck(&tmp2, Etop);
l->n->ninit = list(l->n->ninit, tmp2);
}
orderblock(&l->n->ninit);
break;
case OSEND:
if(r->ninit != nil) {
yyerror("ninit on select send");
dumplist("ninit", r->ninit);
}
orderexpr(&r->left, order);
if(!istemp(r->left))
r->left = ordercopyexpr(r->left, r->left->type, order, 0);
orderexpr(&r->right, order);
if(!istemp(r->right))
r->right = ordercopyexpr(r->right, r->right->type, order, 0);
break;
}
}
orderblock(&l->n->nbody);
}
for(l=n->list; l; l=l->next) {
cleantempnopop(t, order, &l->n->ninit);
l->n->nbody = concat(l->n->ninit, l->n->nbody);
l->n->ninit = nil;
}
order->out = list(order->out, n);
poptemp(t, order);
break;
case OSEND:
t = marktemp(order);
orderexpr(&n->left, order);
orderexpr(&n->right, order);
orderaddrtemp(&n->right, order);
order->out = list(order->out, n);
cleantemp(t, order);
break;
case OSWITCH:
t = marktemp(order);
orderexpr(&n->ntest, order);
for(l=n->list; l; l=l->next) {
if(l->n->op != OXCASE)
fatal("order switch case %O", l->n->op);
orderexprlistinplace(l->n->list, order);
orderblock(&l->n->nbody);
}
order->out = list(order->out, n);
cleantemp(t, order);
break;
}
lineno = lno;
}
static void
orderexprlist(NodeList *l, Order *order)
{
for(; l; l=l->next)
orderexpr(&l->n, order);
}
static void
orderexprlistinplace(NodeList *l, Order *order)
{
for(; l; l=l->next)
orderexprinplace(&l->n, order);
}
static void
orderexpr(Node **np, Order *order)
{
Node *n;
NodeList *mark, *l;
Type *t;
int lno;
n = *np;
if(n == N)
return;
lno = setlineno(n);
orderinit(n, order);
switch(n->op) {
default:
orderexpr(&n->left, order);
orderexpr(&n->right, order);
orderexprlist(n->list, order);
orderexprlist(n->rlist, order);
break;
case OADDSTR:
orderexprlist(n->list, order);
if(count(n->list) > 5) {
t = typ(TARRAY);
t->bound = count(n->list);
t->type = types[TSTRING];
n->alloc = ordertemp(t, order, 0);
}
break;
case OINDEXMAP:
orderexpr(&n->left, order);
orderexpr(&n->right, order);
if(n->etype == 0 && n->right->op == OARRAYBYTESTR)
n->right->op = OARRAYBYTESTRTMP;
orderaddrtemp(&n->right, order);
if(n->etype == 0) {
n = ordercopyexpr(n, n->type, order, 0);
}
break;
case OCONVIFACE:
orderexpr(&n->left, order);
if(!isinter(n->left->type))
orderaddrtemp(&n->left, order);
break;
case OANDAND:
case OOROR:
mark = marktemp(order);
orderexpr(&n->left, order);
l = nil;
cleantempnopop(mark, order, &l);
n->right->ninit = concat(l, n->right->ninit);
orderexprinplace(&n->right, order);
break;
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
case OAPPEND:
case OCOMPLEX:
ordercall(n, order);
n = ordercopyexpr(n, n->type, order, 0);
break;
case OCLOSURE:
if(n->noescape && n->cvars != nil)
n->alloc = ordertemp(types[TUINT8], order, 0);
break;
case OARRAYLIT:
case OCALLPART:
orderexpr(&n->left, order);
orderexpr(&n->right, order);
orderexprlist(n->list, order);
orderexprlist(n->rlist, order);
if(n->noescape)
n->alloc = ordertemp(types[TUINT8], order, 0);
break;
case ODDDARG:
if(n->noescape) {
n->alloc = ordertemp(n->type->type, order, 0);
}
break;
case ORECV:
orderexpr(&n->left, order);
n = ordercopyexpr(n, n->type, order, 1);
break;
}
lineno = lno;
*np = n;
}