github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/6g/peep.c (about)

     1  // Derived from Inferno utils/6c/peep.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  #include <u.h>
    32  #include <libc.h>
    33  #include "gg.h"
    34  #include "opt.h"
    35  
    36  static void	conprop(Flow *r);
    37  static void	elimshortmov(Graph *g);
    38  static int	prevl(Flow *r, int reg);
    39  static void	pushback(Flow *r);
    40  static int	regconsttyp(Adr*);
    41  static int	subprop(Flow*);
    42  static int	copyprop(Graph*, Flow*);
    43  static int	copy1(Adr*, Adr*, Flow*, int);
    44  static int	copyas(Adr*, Adr*);
    45  static int	copyau(Adr*, Adr*);
    46  static int	copysub(Adr*, Adr*, Adr*, int);
    47  
    48  static uint32	gactive;
    49  
    50  // do we need the carry bit
    51  static int
    52  needc(Prog *p)
    53  {
    54  	ProgInfo info;
    55  
    56  	while(p != P) {
    57  		proginfo(&info, p);
    58  		if(info.flags & UseCarry)
    59  			return 1;
    60  		if(info.flags & (SetCarry|KillCarry))
    61  			return 0;
    62  		p = p->link;
    63  	}
    64  	return 0;
    65  }
    66  
    67  static Flow*
    68  rnops(Flow *r)
    69  {
    70  	Prog *p;
    71  	Flow *r1;
    72  
    73  	if(r != nil)
    74  	for(;;) {
    75  		p = r->prog;
    76  		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
    77  			break;
    78  		r1 = uniqs(r);
    79  		if(r1 == nil)
    80  			break;
    81  		r = r1;
    82  	}
    83  	return r;
    84  }
    85  
    86  void
    87  peep(Prog *firstp)
    88  {
    89  	Flow *r, *r1;
    90  	Graph *g;
    91  	Prog *p, *p1;
    92  	int t;
    93  
    94  	g = flowstart(firstp, sizeof(Flow));
    95  	if(g == nil)
    96  		return;
    97  	gactive = 0;
    98  
    99  	// byte, word arithmetic elimination.
   100  	elimshortmov(g);
   101  
   102  	// constant propagation
   103  	// find MOV $con,R followed by
   104  	// another MOV $con,R without
   105  	// setting R in the interim
   106  	for(r=g->start; r!=nil; r=r->link) {
   107  		p = r->prog;
   108  		switch(p->as) {
   109  		case ALEAL:
   110  		case ALEAQ:
   111  			if(regtyp(&p->to))
   112  			if(p->from.sym != S)
   113  			if(p->from.index == D_NONE || p->from.index == D_CONST)
   114  				conprop(r);
   115  			break;
   116  
   117  		case AMOVB:
   118  		case AMOVW:
   119  		case AMOVL:
   120  		case AMOVQ:
   121  		case AMOVSS:
   122  		case AMOVSD:
   123  			if(regtyp(&p->to))
   124  			if(p->from.type == D_CONST)
   125  				conprop(r);
   126  			break;
   127  		}
   128  	}
   129  
   130  loop1:
   131  	if(debug['P'] && debug['v'])
   132  		dumpit("loop1", g->start, 0);
   133  
   134  	t = 0;
   135  	for(r=g->start; r!=nil; r=r->link) {
   136  		p = r->prog;
   137  		switch(p->as) {
   138  		case AMOVL:
   139  		case AMOVQ:
   140  		case AMOVSS:
   141  		case AMOVSD:
   142  			if(regtyp(&p->to))
   143  			if(regtyp(&p->from)) {
   144  				if(copyprop(g, r)) {
   145  					excise(r);
   146  					t++;
   147  				} else
   148  				if(subprop(r) && copyprop(g, r)) {
   149  					excise(r);
   150  					t++;
   151  				}
   152  			}
   153  			break;
   154  
   155  		case AMOVBLZX:
   156  		case AMOVWLZX:
   157  		case AMOVBLSX:
   158  		case AMOVWLSX:
   159  			if(regtyp(&p->to)) {
   160  				r1 = rnops(uniqs(r));
   161  				if(r1 != nil) {
   162  					p1 = r1->prog;
   163  					if(p->as == p1->as && p->to.type == p1->from.type){
   164  						p1->as = AMOVL;
   165  						t++;
   166  					}
   167  				}
   168  			}
   169  			break;
   170  
   171  		case AMOVBQSX:
   172  		case AMOVBQZX:
   173  		case AMOVWQSX:
   174  		case AMOVWQZX:
   175  		case AMOVLQSX:
   176  		case AMOVLQZX:
   177  		case AMOVQL:
   178  			if(regtyp(&p->to)) {
   179  				r1 = rnops(uniqs(r));
   180  				if(r1 != nil) {
   181  					p1 = r1->prog;
   182  					if(p->as == p1->as && p->to.type == p1->from.type){
   183  						p1->as = AMOVQ;
   184  						t++;
   185  					}
   186  				}
   187  			}
   188  			break;
   189  
   190  		case AADDL:
   191  		case AADDQ:
   192  		case AADDW:
   193  			if(p->from.type != D_CONST || needc(p->link))
   194  				break;
   195  			if(p->from.offset == -1){
   196  				if(p->as == AADDQ)
   197  					p->as = ADECQ;
   198  				else
   199  				if(p->as == AADDL)
   200  					p->as = ADECL;
   201  				else
   202  					p->as = ADECW;
   203  				p->from = zprog.from;
   204  				break;
   205  			}
   206  			if(p->from.offset == 1){
   207  				if(p->as == AADDQ)
   208  					p->as = AINCQ;
   209  				else if(p->as == AADDL)
   210  					p->as = AINCL;
   211  				else
   212  					p->as = AINCW;
   213  				p->from = zprog.from;
   214  				break;
   215  			}
   216  			break;
   217  
   218  		case ASUBL:
   219  		case ASUBQ:
   220  		case ASUBW:
   221  			if(p->from.type != D_CONST || needc(p->link))
   222  				break;
   223  			if(p->from.offset == -1) {
   224  				if(p->as == ASUBQ)
   225  					p->as = AINCQ;
   226  				else
   227  				if(p->as == ASUBL)
   228  					p->as = AINCL;
   229  				else
   230  					p->as = AINCW;
   231  				p->from = zprog.from;
   232  				break;
   233  			}
   234  			if(p->from.offset == 1){
   235  				if(p->as == ASUBQ)
   236  					p->as = ADECQ;
   237  				else
   238  				if(p->as == ASUBL)
   239  					p->as = ADECL;
   240  				else
   241  					p->as = ADECW;
   242  				p->from = zprog.from;
   243  				break;
   244  			}
   245  			break;
   246  		}
   247  	}
   248  	if(t)
   249  		goto loop1;
   250  
   251  	// MOVLQZX removal.
   252  	// The MOVLQZX exists to avoid being confused for a
   253  	// MOVL that is just copying 32-bit data around during
   254  	// copyprop.  Now that copyprop is done, remov MOVLQZX R1, R2
   255  	// if it is dominated by an earlier ADDL/MOVL/etc into R1 that
   256  	// will have already cleared the high bits.
   257  	//
   258  	// MOVSD removal.
   259  	// We never use packed registers, so a MOVSD between registers
   260  	// can be replaced by MOVAPD, which moves the pair of float64s
   261  	// instead of just the lower one.  We only use the lower one, but
   262  	// the processor can do better if we do moves using both.
   263  	for(r=g->start; r!=nil; r=r->link) {
   264  		p = r->prog;
   265  		if(p->as == AMOVLQZX)
   266  		if(regtyp(&p->from))
   267  		if(p->from.type == p->to.type)
   268  		if(prevl(r, p->from.type))
   269  			excise(r);
   270  		
   271  		if(p->as == AMOVSD)
   272  		if(regtyp(&p->from))
   273  		if(regtyp(&p->to))
   274  			p->as = AMOVAPD;
   275  	}
   276  
   277  	// load pipelining
   278  	// push any load from memory as early as possible
   279  	// to give it time to complete before use.
   280  	for(r=g->start; r!=nil; r=r->link) {
   281  		p = r->prog;
   282  		switch(p->as) {
   283  		case AMOVB:
   284  		case AMOVW:
   285  		case AMOVL:
   286  		case AMOVQ:
   287  		case AMOVLQZX:
   288  			if(regtyp(&p->to) && !regconsttyp(&p->from))
   289  				pushback(r);
   290  		}
   291  	}
   292  	
   293  	flowend(g);
   294  }
   295  
   296  static void
   297  pushback(Flow *r0)
   298  {
   299  	Flow *r, *b;
   300  	Prog *p0, *p, t;
   301  	
   302  	b = nil;
   303  	p0 = r0->prog;
   304  	for(r=uniqp(r0); r!=nil && uniqs(r)!=nil; r=uniqp(r)) {
   305  		p = r->prog;
   306  		if(p->as != ANOP) {
   307  			if(!regconsttyp(&p->from) || !regtyp(&p->to))
   308  				break;
   309  			if(copyu(p, &p0->to, A) || copyu(p0, &p->to, A))
   310  				break;
   311  		}
   312  		if(p->as == ACALL)
   313  			break;
   314  		b = r;
   315  	}
   316  	
   317  	if(b == nil) {
   318  		if(debug['v']) {
   319  			print("no pushback: %P\n", r0->prog);
   320  			if(r)
   321  				print("\t%P [%d]\n", r->prog, uniqs(r)!=nil);
   322  		}
   323  		return;
   324  	}
   325  
   326  	if(debug['v']) {
   327  		print("pushback\n");
   328  		for(r=b;; r=r->link) {
   329  			print("\t%P\n", r->prog);
   330  			if(r == r0)
   331  				break;
   332  		}
   333  	}
   334  
   335  	t = *r0->prog;
   336  	for(r=uniqp(r0);; r=uniqp(r)) {
   337  		p0 = r->link->prog;
   338  		p = r->prog;
   339  		p0->as = p->as;
   340  		p0->lineno = p->lineno;
   341  		p0->from = p->from;
   342  		p0->to = p->to;
   343  
   344  		if(r == b)
   345  			break;
   346  	}
   347  	p0 = r->prog;
   348  	p0->as = t.as;
   349  	p0->lineno = t.lineno;
   350  	p0->from = t.from;
   351  	p0->to = t.to;
   352  
   353  	if(debug['v']) {
   354  		print("\tafter\n");
   355  		for(r=b;; r=r->link) {
   356  			print("\t%P\n", r->prog);
   357  			if(r == r0)
   358  				break;
   359  		}
   360  	}
   361  }
   362  
   363  void
   364  excise(Flow *r)
   365  {
   366  	Prog *p;
   367  
   368  	p = r->prog;
   369  	if(debug['P'] && debug['v'])
   370  		print("%P ===delete===\n", p);
   371  
   372  	p->as = ANOP;
   373  	p->from = zprog.from;
   374  	p->to = zprog.to;
   375  
   376  	ostats.ndelmov++;
   377  }
   378  
   379  int
   380  regtyp(Adr *a)
   381  {
   382  	int t;
   383  
   384  	t = a->type;
   385  	if(t >= D_AX && t <= D_R15)
   386  		return 1;
   387  	if(t >= D_X0 && t <= D_X0+15)
   388  		return 1;
   389  	return 0;
   390  }
   391  
   392  // movb elimination.
   393  // movb is simulated by the linker
   394  // when a register other than ax, bx, cx, dx
   395  // is used, so rewrite to other instructions
   396  // when possible.  a movb into a register
   397  // can smash the entire 32-bit register without
   398  // causing any trouble.
   399  //
   400  // TODO: Using the Q forms here instead of the L forms
   401  // seems unnecessary, and it makes the instructions longer.
   402  static void
   403  elimshortmov(Graph *g)
   404  {
   405  	Prog *p;
   406  	Flow *r;
   407  
   408  	for(r=g->start; r!=nil; r=r->link) {
   409  		p = r->prog;
   410  		if(regtyp(&p->to)) {
   411  			switch(p->as) {
   412  			case AINCB:
   413  			case AINCW:
   414  				p->as = AINCQ;
   415  				break;
   416  			case ADECB:
   417  			case ADECW:
   418  				p->as = ADECQ;
   419  				break;
   420  			case ANEGB:
   421  			case ANEGW:
   422  				p->as = ANEGQ;
   423  				break;
   424  			case ANOTB:
   425  			case ANOTW:
   426  				p->as = ANOTQ;
   427  				break;
   428  			}
   429  			if(regtyp(&p->from) || p->from.type == D_CONST) {
   430  				// move or artihmetic into partial register.
   431  				// from another register or constant can be movl.
   432  				// we don't switch to 64-bit arithmetic if it can
   433  				// change how the carry bit is set (and the carry bit is needed).
   434  				switch(p->as) {
   435  				case AMOVB:
   436  				case AMOVW:
   437  					p->as = AMOVQ;
   438  					break;
   439  				case AADDB:
   440  				case AADDW:
   441  					if(!needc(p->link))
   442  						p->as = AADDQ;
   443  					break;
   444  				case ASUBB:
   445  				case ASUBW:
   446  					if(!needc(p->link))
   447  						p->as = ASUBQ;
   448  					break;
   449  				case AMULB:
   450  				case AMULW:
   451  					p->as = AMULQ;
   452  					break;
   453  				case AIMULB:
   454  				case AIMULW:
   455  					p->as = AIMULQ;
   456  					break;
   457  				case AANDB:
   458  				case AANDW:
   459  					p->as = AANDQ;
   460  					break;
   461  				case AORB:
   462  				case AORW:
   463  					p->as = AORQ;
   464  					break;
   465  				case AXORB:
   466  				case AXORW:
   467  					p->as = AXORQ;
   468  					break;
   469  				case ASHLB:
   470  				case ASHLW:
   471  					p->as = ASHLQ;
   472  					break;
   473  				}
   474  			} else if(p->from.type >= D_NONE) {
   475  				// explicit zero extension, but don't
   476  				// do that if source is a byte register
   477  				// (only AH can occur and it's forbidden).
   478  				switch(p->as) {
   479  				case AMOVB:
   480  					p->as = AMOVBQZX;
   481  					break;
   482  				case AMOVW:
   483  					p->as = AMOVWQZX;
   484  					break;
   485  				}
   486  			}
   487  		}
   488  	}
   489  }
   490  
   491  // is 'a' a register or constant?
   492  static int
   493  regconsttyp(Adr *a)
   494  {
   495  	if(regtyp(a))
   496  		return 1;
   497  	switch(a->type) {
   498  	case D_CONST:
   499  	case D_FCONST:
   500  	case D_SCONST:
   501  	case D_ADDR:
   502  		return 1;
   503  	}
   504  	return 0;
   505  }
   506  
   507  // is reg guaranteed to be truncated by a previous L instruction?
   508  static int
   509  prevl(Flow *r0, int reg)
   510  {
   511  	Prog *p;
   512  	Flow *r;
   513  	ProgInfo info;
   514  
   515  	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
   516  		p = r->prog;
   517  		if(p->to.type == reg) {
   518  			proginfo(&info, p);
   519  			if(info.flags & RightWrite) {
   520  				if(info.flags & SizeL)
   521  					return 1;
   522  				return 0;
   523  			}
   524  		}
   525  	}
   526  	return 0;
   527  }
   528  
   529  /*
   530   * the idea is to substitute
   531   * one register for another
   532   * from one MOV to another
   533   *	MOV	a, R0
   534   *	ADD	b, R0	/ no use of R1
   535   *	MOV	R0, R1
   536   * would be converted to
   537   *	MOV	a, R1
   538   *	ADD	b, R1
   539   *	MOV	R1, R0
   540   * hopefully, then the former or latter MOV
   541   * will be eliminated by copy propagation.
   542   */
   543  static int
   544  subprop(Flow *r0)
   545  {
   546  	Prog *p;
   547  	ProgInfo info;
   548  	Adr *v1, *v2;
   549  	Flow *r;
   550  	int t;
   551  
   552  	if(debug['P'] && debug['v'])
   553  		print("subprop %P\n", r0->prog);
   554  	p = r0->prog;
   555  	v1 = &p->from;
   556  	if(!regtyp(v1)) {
   557  		if(debug['P'] && debug['v'])
   558  			print("\tnot regtype %D; return 0\n", v1);
   559  		return 0;
   560  	}
   561  	v2 = &p->to;
   562  	if(!regtyp(v2)) {
   563  		if(debug['P'] && debug['v'])
   564  			print("\tnot regtype %D; return 0\n", v2);
   565  		return 0;
   566  	}
   567  	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
   568  		if(debug['P'] && debug['v'])
   569  			print("\t? %P\n", r->prog);
   570  		if(uniqs(r) == nil) {
   571  			if(debug['P'] && debug['v'])
   572  				print("\tno unique successor\n");
   573  			break;
   574  		}
   575  		p = r->prog;
   576  		proginfo(&info, p);
   577  		if(info.flags & Call) {
   578  			if(debug['P'] && debug['v'])
   579  				print("\tfound %P; return 0\n", p);
   580  			return 0;
   581  		}
   582  
   583  		if(info.reguse | info.regset) {
   584  			if(debug['P'] && debug['v'])
   585  				print("\tfound %P; return 0\n", p);
   586  			return 0;
   587  		}
   588  
   589  		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
   590  			goto gotit;
   591  
   592  		if(copyau(&p->from, v2) ||
   593  		   copyau(&p->to, v2)) {
   594  		   	if(debug['P'] && debug['v'])
   595  		   		print("\tcopyau %D failed\n", v2);
   596  			break;
   597  		}
   598  		if(copysub(&p->from, v1, v2, 0) ||
   599  		   copysub(&p->to, v1, v2, 0)) {
   600  		   	if(debug['P'] && debug['v'])
   601  		   		print("\tcopysub failed\n");
   602  			break;
   603  		}
   604  	}
   605  	if(debug['P'] && debug['v'])
   606  		print("\tran off end; return 0\n");
   607  	return 0;
   608  
   609  gotit:
   610  	copysub(&p->to, v1, v2, 1);
   611  	if(debug['P']) {
   612  		print("gotit: %D->%D\n%P", v1, v2, r->prog);
   613  		if(p->from.type == v2->type)
   614  			print(" excise");
   615  		print("\n");
   616  	}
   617  	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
   618  		p = r->prog;
   619  		copysub(&p->from, v1, v2, 1);
   620  		copysub(&p->to, v1, v2, 1);
   621  		if(debug['P'])
   622  			print("%P\n", r->prog);
   623  	}
   624  	t = v1->type;
   625  	v1->type = v2->type;
   626  	v2->type = t;
   627  	if(debug['P'])
   628  		print("%P last\n", r->prog);
   629  	return 1;
   630  }
   631  
   632  /*
   633   * The idea is to remove redundant copies.
   634   *	v1->v2	F=0
   635   *	(use v2	s/v2/v1/)*
   636   *	set v1	F=1
   637   *	use v2	return fail
   638   *	-----------------
   639   *	v1->v2	F=0
   640   *	(use v2	s/v2/v1/)*
   641   *	set v1	F=1
   642   *	set v2	return success
   643   */
   644  static int
   645  copyprop(Graph *g, Flow *r0)
   646  {
   647  	Prog *p;
   648  	Adr *v1, *v2;
   649  
   650  	USED(g);
   651  	if(debug['P'] && debug['v'])
   652  		print("copyprop %P\n", r0->prog);
   653  	p = r0->prog;
   654  	v1 = &p->from;
   655  	v2 = &p->to;
   656  	if(copyas(v1, v2))
   657  		return 1;
   658  	gactive++;
   659  	return copy1(v1, v2, r0->s1, 0);
   660  }
   661  
   662  static int
   663  copy1(Adr *v1, Adr *v2, Flow *r, int f)
   664  {
   665  	int t;
   666  	Prog *p;
   667  
   668  	if(r->active == gactive) {
   669  		if(debug['P'])
   670  			print("act set; return 1\n");
   671  		return 1;
   672  	}
   673  	r->active = gactive;
   674  	if(debug['P'])
   675  		print("copy %D->%D f=%d\n", v1, v2, f);
   676  	for(; r != nil; r = r->s1) {
   677  		p = r->prog;
   678  		if(debug['P'])
   679  			print("%P", p);
   680  		if(!f && uniqp(r) == nil) {
   681  			f = 1;
   682  			if(debug['P'])
   683  				print("; merge; f=%d", f);
   684  		}
   685  		t = copyu(p, v2, A);
   686  		switch(t) {
   687  		case 2:	/* rar, can't split */
   688  			if(debug['P'])
   689  				print("; %D rar; return 0\n", v2);
   690  			return 0;
   691  
   692  		case 3:	/* set */
   693  			if(debug['P'])
   694  				print("; %D set; return 1\n", v2);
   695  			return 1;
   696  
   697  		case 1:	/* used, substitute */
   698  		case 4:	/* use and set */
   699  			if(f) {
   700  				if(!debug['P'])
   701  					return 0;
   702  				if(t == 4)
   703  					print("; %D used+set and f=%d; return 0\n", v2, f);
   704  				else
   705  					print("; %D used and f=%d; return 0\n", v2, f);
   706  				return 0;
   707  			}
   708  			if(copyu(p, v2, v1)) {
   709  				if(debug['P'])
   710  					print("; sub fail; return 0\n");
   711  				return 0;
   712  			}
   713  			if(debug['P'])
   714  				print("; sub %D/%D", v2, v1);
   715  			if(t == 4) {
   716  				if(debug['P'])
   717  					print("; %D used+set; return 1\n", v2);
   718  				return 1;
   719  			}
   720  			break;
   721  		}
   722  		if(!f) {
   723  			t = copyu(p, v1, A);
   724  			if(!f && (t == 2 || t == 3 || t == 4)) {
   725  				f = 1;
   726  				if(debug['P'])
   727  					print("; %D set and !f; f=%d", v1, f);
   728  			}
   729  		}
   730  		if(debug['P'])
   731  			print("\n");
   732  		if(r->s2)
   733  			if(!copy1(v1, v2, r->s2, f))
   734  				return 0;
   735  	}
   736  	return 1;
   737  }
   738  
   739  /*
   740   * return
   741   * 1 if v only used (and substitute),
   742   * 2 if read-alter-rewrite
   743   * 3 if set
   744   * 4 if set and used
   745   * 0 otherwise (not touched)
   746   */
   747  int
   748  copyu(Prog *p, Adr *v, Adr *s)
   749  {
   750  	ProgInfo info;
   751  
   752  	switch(p->as) {
   753  	case AJMP:
   754  		if(s != A) {
   755  			if(copysub(&p->to, v, s, 1))
   756  				return 1;
   757  			return 0;
   758  		}
   759  		if(copyau(&p->to, v))
   760  			return 1;
   761  		return 0;
   762  
   763  	case ARET:
   764  		if(s != A)
   765  			return 1;
   766  		return 3;
   767  
   768  	case ACALL:
   769  		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
   770  			return 2;
   771  		if(REGARG >= 0 && v->type == (uchar)REGARG)
   772  			return 2;
   773  		if(v->type == p->from.type)
   774  			return 2;
   775  
   776  		if(s != A) {
   777  			if(copysub(&p->to, v, s, 1))
   778  				return 1;
   779  			return 0;
   780  		}
   781  		if(copyau(&p->to, v))
   782  			return 4;
   783  		return 3;
   784  
   785  	case ATEXT:
   786  		if(REGARG >= 0 && v->type == (uchar)REGARG)
   787  			return 3;
   788  		return 0;
   789  	}
   790  
   791  	proginfo(&info, p);
   792  
   793  	if((info.reguse|info.regset) & RtoB(v->type))
   794  		return 2;
   795  		
   796  	if(info.flags & LeftAddr)
   797  		if(copyas(&p->from, v))
   798  			return 2;
   799  
   800  	if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
   801  		if(copyas(&p->to, v))
   802  			return 2;
   803  	
   804  	if(info.flags & RightWrite) {
   805  		if(copyas(&p->to, v)) {
   806  			if(s != A)
   807  				return copysub(&p->from, v, s, 1);
   808  			if(copyau(&p->from, v))
   809  				return 4;
   810  			return 3;
   811  		}
   812  	}
   813  	
   814  	if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
   815  		if(s != A) {
   816  			if(copysub(&p->from, v, s, 1))
   817  				return 1;
   818  			return copysub(&p->to, v, s, 1);
   819  		}
   820  		if(copyau(&p->from, v))
   821  			return 1;
   822  		if(copyau(&p->to, v))
   823  			return 1;
   824  	}
   825  
   826  	return 0;
   827  }
   828  
   829  /*
   830   * direct reference,
   831   * could be set/use depending on
   832   * semantics
   833   */
   834  static int
   835  copyas(Adr *a, Adr *v)
   836  {
   837  	if(a->type != v->type)
   838  		return 0;
   839  	if(regtyp(v))
   840  		return 1;
   841  	if(v->type == D_AUTO || v->type == D_PARAM)
   842  		if(v->offset == a->offset)
   843  			return 1;
   844  	return 0;
   845  }
   846  
   847  int
   848  sameaddr(Addr *a, Addr *v)
   849  {
   850  	if(a->type != v->type)
   851  		return 0;
   852  	if(regtyp(v))
   853  		return 1;
   854  	if(v->type == D_AUTO || v->type == D_PARAM)
   855  		if(v->offset == a->offset)
   856  			return 1;
   857  	return 0;
   858  }
   859  
   860  /*
   861   * either direct or indirect
   862   */
   863  static int
   864  copyau(Adr *a, Adr *v)
   865  {
   866  
   867  	if(copyas(a, v)) {
   868  		if(debug['P'] && debug['v'])
   869  			print("\tcopyau: copyas returned 1\n");
   870  		return 1;
   871  	}
   872  	if(regtyp(v)) {
   873  		if(a->type-D_INDIR == v->type) {
   874  			if(debug['P'] && debug['v'])
   875  				print("\tcopyau: found indir use - return 1\n");
   876  			return 1;
   877  		}
   878  		if(a->index == v->type) {
   879  			if(debug['P'] && debug['v'])
   880  				print("\tcopyau: found index use - return 1\n");
   881  			return 1;
   882  		}
   883  	}
   884  	return 0;
   885  }
   886  
   887  /*
   888   * substitute s for v in a
   889   * return failure to substitute
   890   */
   891  static int
   892  copysub(Adr *a, Adr *v, Adr *s, int f)
   893  {
   894  	int t;
   895  
   896  	if(copyas(a, v)) {
   897  		t = s->type;
   898  		if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
   899  			if(f)
   900  				a->type = t;
   901  		}
   902  		return 0;
   903  	}
   904  	if(regtyp(v)) {
   905  		t = v->type;
   906  		if(a->type == t+D_INDIR) {
   907  			if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
   908  				return 1;	/* can't use BP-base with index */
   909  			if(f)
   910  				a->type = s->type+D_INDIR;
   911  //			return 0;
   912  		}
   913  		if(a->index == t) {
   914  			if(f)
   915  				a->index = s->type;
   916  			return 0;
   917  		}
   918  		return 0;
   919  	}
   920  	return 0;
   921  }
   922  
   923  static void
   924  conprop(Flow *r0)
   925  {
   926  	Flow *r;
   927  	Prog *p, *p0;
   928  	int t;
   929  	Adr *v0;
   930  
   931  	p0 = r0->prog;
   932  	v0 = &p0->to;
   933  	r = r0;
   934  
   935  loop:
   936  	r = uniqs(r);
   937  	if(r == nil || r == r0)
   938  		return;
   939  	if(uniqp(r) == nil)
   940  		return;
   941  
   942  	p = r->prog;
   943  	t = copyu(p, v0, A);
   944  	switch(t) {
   945  	case 0:	// miss
   946  	case 1:	// use
   947  		goto loop;
   948  
   949  	case 2:	// rar
   950  	case 4:	// use and set
   951  		break;
   952  
   953  	case 3:	// set
   954  		if(p->as == p0->as)
   955  		if(p->from.type == p0->from.type)
   956  		if(p->from.node == p0->from.node)
   957  		if(p->from.offset == p0->from.offset)
   958  		if(p->from.scale == p0->from.scale)
   959  		if(p->from.u.vval == p0->from.u.vval)
   960  		if(p->from.index == p0->from.index) {
   961  			excise(r);
   962  			goto loop;
   963  		}
   964  		break;
   965  	}
   966  }
   967  
   968  int
   969  smallindir(Addr *a, Addr *reg)
   970  {
   971  	return regtyp(reg) &&
   972  		a->type == D_INDIR + reg->type &&
   973  		a->index == D_NONE &&
   974  		0 <= a->offset && a->offset < 4096;
   975  }
   976  
   977  int
   978  stackaddr(Addr *a)
   979  {
   980  	return regtyp(a) && a->type == D_SP;
   981  }