github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/gc/order.c (about)

     1  // Copyright 2012 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Rewrite tree to use separate statements to enforce
     6  // order of evaluation.  Makes walk easier, because it
     7  // can (after this runs) reorder at will within an expression.
     8  
     9  #include	<u.h>
    10  #include	<libc.h>
    11  #include	"go.h"
    12  
    13  static void	orderstmt(Node*, NodeList**);
    14  static void	orderstmtlist(NodeList*, NodeList**);
    15  static void	orderblock(NodeList **l);
    16  static void	orderexpr(Node**, NodeList**);
    17  static void	orderexprlist(NodeList*, NodeList**);
    18  
    19  void
    20  order(Node *fn)
    21  {
    22  	orderblock(&fn->nbody);
    23  }
    24  
    25  static void
    26  orderstmtlist(NodeList *l, NodeList **out)
    27  {
    28  	for(; l; l=l->next)
    29  		orderstmt(l->n, out);
    30  }
    31  
    32  // Order the block of statements *l onto a new list,
    33  // and then replace *l with that list.
    34  static void
    35  orderblock(NodeList **l)
    36  {
    37  	NodeList *out;
    38  	
    39  	out = nil;
    40  	orderstmtlist(*l, &out);
    41  	*l = out;
    42  }
    43  
    44  // Order the side effects in *np and leave them as
    45  // the init list of the final *np.
    46  static void
    47  orderexprinplace(Node **np)
    48  {
    49  	Node *n;
    50  	NodeList *out;
    51  	
    52  	n = *np;
    53  	out = nil;
    54  	orderexpr(&n, &out);
    55  	addinit(&n, out);
    56  	*np = n;
    57  }
    58  
    59  // Like orderblock, but applied to a single statement.
    60  static void
    61  orderstmtinplace(Node **np)
    62  {
    63  	Node *n;
    64  	NodeList *out;
    65  
    66  	n = *np;
    67  	out = nil;
    68  	orderstmt(n, &out);
    69  	*np = liststmt(out);
    70  }
    71  
    72  // Move n's init list to *out.
    73  static void
    74  orderinit(Node *n, NodeList **out)
    75  {
    76  	orderstmtlist(n->ninit, out);
    77  	n->ninit = nil;
    78  }
    79  
    80  // Is the list l actually just f() for a multi-value function?
    81  static int
    82  ismulticall(NodeList *l)
    83  {
    84  	Node *n;
    85  	
    86  	// one arg only
    87  	if(l == nil || l->next != nil)
    88  		return 0;
    89  	n = l->n;
    90  	
    91  	// must be call
    92  	switch(n->op) {
    93  	default:
    94  		return 0;
    95  	case OCALLFUNC:
    96  	case OCALLMETH:
    97  	case OCALLINTER:
    98  		break;
    99  	}
   100  	
   101  	// call must return multiple values
   102  	return n->left->type->outtuple > 1;
   103  }
   104  
   105  // n is a multi-value function call.  Add t1, t2, .. = n to out
   106  // and return the list t1, t2, ...
   107  static NodeList*
   108  copyret(Node *n, NodeList **out)
   109  {
   110  	Type *t;
   111  	Node *tmp, *as;
   112  	NodeList *l1, *l2;
   113  	Iter tl;
   114  	
   115  	if(n->type->etype != TSTRUCT || !n->type->funarg)
   116  		fatal("copyret %T %d", n->type, n->left->type->outtuple);
   117  
   118  	l1 = nil;
   119  	l2 = nil;
   120  	for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) {
   121  		tmp = temp(t->type);
   122  		l1 = list(l1, tmp);
   123  		l2 = list(l2, tmp);
   124  	}
   125  	
   126  	as = nod(OAS2, N, N);
   127  	as->list = l1;
   128  	as->rlist = list1(n);
   129  	typecheck(&as, Etop);
   130  	orderstmt(as, out);
   131  
   132  	return l2;
   133  }
   134  
   135  static void
   136  ordercallargs(NodeList **l, NodeList **out)
   137  {
   138  	if(ismulticall(*l)) {
   139  		// return f() where f() is multiple values.
   140  		*l = copyret((*l)->n, out);
   141  	} else {
   142  		orderexprlist(*l, out);
   143  	}
   144  }
   145  
   146  static void
   147  ordercall(Node *n, NodeList **out)
   148  {
   149  	orderexpr(&n->left, out);
   150  	ordercallargs(&n->list, out);
   151  }
   152  
   153  static void
   154  orderstmt(Node *n, NodeList **out)
   155  {
   156  	int lno;
   157  	NodeList *l;
   158  	Node *r;
   159  
   160  	if(n == N)
   161  		return;
   162  
   163  	lno = setlineno(n);
   164  
   165  	orderinit(n, out);
   166  
   167  	switch(n->op) {
   168  	default:
   169  		fatal("orderstmt %O", n->op);
   170  
   171  	case OAS2:
   172  	case OAS2DOTTYPE:
   173  	case OAS2MAPR:
   174  	case OAS:
   175  	case OASOP:
   176  	case OCLOSE:
   177  	case OCOPY:
   178  	case ODELETE:
   179  	case OPANIC:
   180  	case OPRINT:
   181  	case OPRINTN:
   182  	case ORECOVER:
   183  	case ORECV:
   184  	case OSEND:
   185  		orderexpr(&n->left, out);
   186  		orderexpr(&n->right, out);
   187  		orderexprlist(n->list, out);
   188  		orderexprlist(n->rlist, out);
   189  		*out = list(*out, n);
   190  		break;
   191  	
   192  	case OAS2FUNC:
   193  		// Special: avoid copy of func call n->rlist->n.
   194  		orderexprlist(n->list, out);
   195  		ordercall(n->rlist->n, out);
   196  		*out = list(*out, n);
   197  		break;
   198  
   199  	case OAS2RECV:
   200  		// Special: avoid copy of receive.
   201  		orderexprlist(n->list, out);
   202  		orderexpr(&n->rlist->n->left, out);  // arg to recv
   203  		*out = list(*out, n);
   204  		break;
   205  
   206  	case OBLOCK:
   207  	case OEMPTY:
   208  		// Special: does not save n onto out.
   209  		orderstmtlist(n->list, out);
   210  		break;
   211  
   212  	case OBREAK:
   213  	case OCONTINUE:
   214  	case ODCL:
   215  	case ODCLCONST:
   216  	case ODCLTYPE:
   217  	case OFALL:
   218  	case_OFALL:
   219  	case OGOTO:
   220  	case OLABEL:
   221  		// Special: n->left is not an expression; save as is.
   222  		*out = list(*out, n);
   223  		break;
   224  
   225  	case OCALLFUNC:
   226  	case OCALLINTER:
   227  	case OCALLMETH:
   228  		// Special: handle call arguments.
   229  		ordercall(n, out);
   230  		*out = list(*out, n);
   231  		break;
   232  
   233  	case ODEFER:
   234  	case OPROC:
   235  		// Special: order arguments to inner call but not call itself.
   236  		ordercall(n->left, out);
   237  		*out = list(*out, n);
   238  		break;
   239  
   240  	case OFOR:
   241  		orderexprinplace(&n->ntest);
   242  		orderstmtinplace(&n->nincr);
   243  		orderblock(&n->nbody);
   244  		*out = list(*out, n);
   245  		break;
   246  		
   247  	case OIF:
   248  		orderexprinplace(&n->ntest);
   249  		orderblock(&n->nbody);
   250  		orderblock(&n->nelse);
   251  		*out = list(*out, n);
   252  		break;
   253  
   254  	case ORANGE:
   255  		orderexpr(&n->right, out);
   256  		for(l=n->list; l; l=l->next)
   257  			orderexprinplace(&l->n);
   258  		orderblock(&n->nbody);
   259  		*out = list(*out, n);
   260  		break;
   261  
   262  	case ORETURN:
   263  		ordercallargs(&n->list, out);
   264  		*out = list(*out, n);
   265  		break;
   266  		
   267  	case OSELECT:
   268  		for(l=n->list; l; l=l->next) {
   269  			if(l->n->op != OXCASE)
   270  				fatal("order select case %O", l->n->op);
   271  			r = l->n->left;
   272  			if(r == nil)
   273  				continue;
   274  			switch(r->op) {
   275  			case OSELRECV:
   276  			case OSELRECV2:
   277  				orderexprinplace(&r->left);
   278  				orderexprinplace(&r->ntest);
   279  				orderexpr(&r->right->left, &l->n->ninit);
   280  				break;
   281  			case OSEND:
   282  				orderexpr(&r->left, &l->n->ninit);
   283  				orderexpr(&r->right, &l->n->ninit);
   284  				break;
   285  			}
   286  		}
   287  		*out = list(*out, n);
   288  		break;
   289  
   290  	case OSWITCH:
   291  		orderexpr(&n->ntest, out);
   292  		for(l=n->list; l; l=l->next) {
   293  			if(l->n->op != OXCASE)
   294  				fatal("order switch case %O", l->n->op);
   295  			orderexpr(&l->n->left, &l->n->ninit);
   296  		}
   297  		*out = list(*out, n);
   298  		break;
   299  
   300  	case OXFALL:
   301  		yyerror("fallthrough statement out of place");
   302  		n->op = OFALL;
   303  		goto case_OFALL;
   304  	}
   305  	
   306  	lineno = lno;
   307  }
   308  
   309  static void
   310  orderexprlist(NodeList *l, NodeList **out)
   311  {
   312  	for(; l; l=l->next)
   313  		orderexpr(&l->n, out);
   314  }
   315  
   316  static void
   317  orderexpr(Node **np, NodeList **out)
   318  {
   319  	Node *n;
   320  	int lno;
   321  
   322  	n = *np;
   323  	if(n == N)
   324  		return;
   325  
   326  	lno = setlineno(n);
   327  	orderinit(n, out);
   328  
   329  	switch(n->op) {
   330  	default:
   331  		orderexpr(&n->left, out);
   332  		orderexpr(&n->right, out);
   333  		orderexprlist(n->list, out);
   334  		orderexprlist(n->rlist, out);
   335  		break;
   336  	
   337  	case OANDAND:
   338  	case OOROR:
   339  		orderexpr(&n->left, out);
   340  		orderexprinplace(&n->right);
   341  		break;
   342  	
   343  	case OCALLFUNC:
   344  	case OCALLMETH:
   345  	case OCALLINTER:
   346  		ordercall(n, out);
   347  		n = copyexpr(n, n->type, out);
   348  		break;
   349  
   350  	case ORECV:
   351  		n = copyexpr(n, n->type, out);
   352  		break;
   353  	}
   354  	
   355  	lineno = lno;
   356  
   357  	*np = n;
   358  }