github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/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 != nil)
   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 || p->from.type == D_FCONST)
   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, nil) || copyu(p0, &p->to, nil))
   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_X15)
   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  		if(p->as == AVARDEF || p->as == AVARKILL)
   577  			continue;
   578  		proginfo(&info, p);
   579  		if(info.flags & Call) {
   580  			if(debug['P'] && debug['v'])
   581  				print("\tfound %P; return 0\n", p);
   582  			return 0;
   583  		}
   584  
   585  		if(info.reguse | info.regset) {
   586  			if(debug['P'] && debug['v'])
   587  				print("\tfound %P; return 0\n", p);
   588  			return 0;
   589  		}
   590  
   591  		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
   592  			goto gotit;
   593  
   594  		if(copyau(&p->from, v2) ||
   595  		   copyau(&p->to, v2)) {
   596  		   	if(debug['P'] && debug['v'])
   597  		   		print("\tcopyau %D failed\n", v2);
   598  			break;
   599  		}
   600  		if(copysub(&p->from, v1, v2, 0) ||
   601  		   copysub(&p->to, v1, v2, 0)) {
   602  		   	if(debug['P'] && debug['v'])
   603  		   		print("\tcopysub failed\n");
   604  			break;
   605  		}
   606  	}
   607  	if(debug['P'] && debug['v'])
   608  		print("\tran off end; return 0\n");
   609  	return 0;
   610  
   611  gotit:
   612  	copysub(&p->to, v1, v2, 1);
   613  	if(debug['P']) {
   614  		print("gotit: %D->%D\n%P", v1, v2, r->prog);
   615  		if(p->from.type == v2->type)
   616  			print(" excise");
   617  		print("\n");
   618  	}
   619  	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
   620  		p = r->prog;
   621  		copysub(&p->from, v1, v2, 1);
   622  		copysub(&p->to, v1, v2, 1);
   623  		if(debug['P'])
   624  			print("%P\n", r->prog);
   625  	}
   626  	t = v1->type;
   627  	v1->type = v2->type;
   628  	v2->type = t;
   629  	if(debug['P'])
   630  		print("%P last\n", r->prog);
   631  	return 1;
   632  }
   633  
   634  /*
   635   * The idea is to remove redundant copies.
   636   *	v1->v2	F=0
   637   *	(use v2	s/v2/v1/)*
   638   *	set v1	F=1
   639   *	use v2	return fail
   640   *	-----------------
   641   *	v1->v2	F=0
   642   *	(use v2	s/v2/v1/)*
   643   *	set v1	F=1
   644   *	set v2	return success
   645   */
   646  static int
   647  copyprop(Graph *g, Flow *r0)
   648  {
   649  	Prog *p;
   650  	Adr *v1, *v2;
   651  
   652  	USED(g);
   653  	if(debug['P'] && debug['v'])
   654  		print("copyprop %P\n", r0->prog);
   655  	p = r0->prog;
   656  	v1 = &p->from;
   657  	v2 = &p->to;
   658  	if(copyas(v1, v2))
   659  		return 1;
   660  	gactive++;
   661  	return copy1(v1, v2, r0->s1, 0);
   662  }
   663  
   664  static int
   665  copy1(Adr *v1, Adr *v2, Flow *r, int f)
   666  {
   667  	int t;
   668  	Prog *p;
   669  
   670  	if(r->active == gactive) {
   671  		if(debug['P'])
   672  			print("act set; return 1\n");
   673  		return 1;
   674  	}
   675  	r->active = gactive;
   676  	if(debug['P'])
   677  		print("copy %D->%D f=%d\n", v1, v2, f);
   678  	for(; r != nil; r = r->s1) {
   679  		p = r->prog;
   680  		if(debug['P'])
   681  			print("%P", p);
   682  		if(!f && uniqp(r) == nil) {
   683  			f = 1;
   684  			if(debug['P'])
   685  				print("; merge; f=%d", f);
   686  		}
   687  		t = copyu(p, v2, nil);
   688  		switch(t) {
   689  		case 2:	/* rar, can't split */
   690  			if(debug['P'])
   691  				print("; %D rar; return 0\n", v2);
   692  			return 0;
   693  
   694  		case 3:	/* set */
   695  			if(debug['P'])
   696  				print("; %D set; return 1\n", v2);
   697  			return 1;
   698  
   699  		case 1:	/* used, substitute */
   700  		case 4:	/* use and set */
   701  			if(f) {
   702  				if(!debug['P'])
   703  					return 0;
   704  				if(t == 4)
   705  					print("; %D used+set and f=%d; return 0\n", v2, f);
   706  				else
   707  					print("; %D used and f=%d; return 0\n", v2, f);
   708  				return 0;
   709  			}
   710  			if(copyu(p, v2, v1)) {
   711  				if(debug['P'])
   712  					print("; sub fail; return 0\n");
   713  				return 0;
   714  			}
   715  			if(debug['P'])
   716  				print("; sub %D/%D", v2, v1);
   717  			if(t == 4) {
   718  				if(debug['P'])
   719  					print("; %D used+set; return 1\n", v2);
   720  				return 1;
   721  			}
   722  			break;
   723  		}
   724  		if(!f) {
   725  			t = copyu(p, v1, nil);
   726  			if(!f && (t == 2 || t == 3 || t == 4)) {
   727  				f = 1;
   728  				if(debug['P'])
   729  					print("; %D set and !f; f=%d", v1, f);
   730  			}
   731  		}
   732  		if(debug['P'])
   733  			print("\n");
   734  		if(r->s2)
   735  			if(!copy1(v1, v2, r->s2, f))
   736  				return 0;
   737  	}
   738  	return 1;
   739  }
   740  
   741  /*
   742   * return
   743   * 1 if v only used (and substitute),
   744   * 2 if read-alter-rewrite
   745   * 3 if set
   746   * 4 if set and used
   747   * 0 otherwise (not touched)
   748   */
   749  int
   750  copyu(Prog *p, Adr *v, Adr *s)
   751  {
   752  	ProgInfo info;
   753  
   754  	switch(p->as) {
   755  	case AJMP:
   756  		if(s != nil) {
   757  			if(copysub(&p->to, v, s, 1))
   758  				return 1;
   759  			return 0;
   760  		}
   761  		if(copyau(&p->to, v))
   762  			return 1;
   763  		return 0;
   764  
   765  	case ARET:
   766  		if(s != nil)
   767  			return 1;
   768  		return 3;
   769  
   770  	case ACALL:
   771  		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
   772  			return 2;
   773  		if(REGARG >= 0 && v->type == (uchar)REGARG)
   774  			return 2;
   775  		if(v->type == p->from.type)
   776  			return 2;
   777  
   778  		if(s != nil) {
   779  			if(copysub(&p->to, v, s, 1))
   780  				return 1;
   781  			return 0;
   782  		}
   783  		if(copyau(&p->to, v))
   784  			return 4;
   785  		return 3;
   786  
   787  	case ATEXT:
   788  		if(REGARG >= 0 && v->type == (uchar)REGARG)
   789  			return 3;
   790  		return 0;
   791  	}
   792  
   793  	if(p->as == AVARDEF || p->as == AVARKILL)
   794  		return 0;
   795  	proginfo(&info, p);
   796  
   797  	if((info.reguse|info.regset) & RtoB(v->type))
   798  		return 2;
   799  		
   800  	if(info.flags & LeftAddr)
   801  		if(copyas(&p->from, v))
   802  			return 2;
   803  
   804  	if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
   805  		if(copyas(&p->to, v))
   806  			return 2;
   807  	
   808  	if(info.flags & RightWrite) {
   809  		if(copyas(&p->to, v)) {
   810  			if(s != nil)
   811  				return copysub(&p->from, v, s, 1);
   812  			if(copyau(&p->from, v))
   813  				return 4;
   814  			return 3;
   815  		}
   816  	}
   817  	
   818  	if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
   819  		if(s != nil) {
   820  			if(copysub(&p->from, v, s, 1))
   821  				return 1;
   822  			return copysub(&p->to, v, s, 1);
   823  		}
   824  		if(copyau(&p->from, v))
   825  			return 1;
   826  		if(copyau(&p->to, v))
   827  			return 1;
   828  	}
   829  
   830  	return 0;
   831  }
   832  
   833  /*
   834   * direct reference,
   835   * could be set/use depending on
   836   * semantics
   837   */
   838  static int
   839  copyas(Adr *a, Adr *v)
   840  {
   841  	if(D_AL <= a->type && a->type <= D_R15B)
   842  		fatal("use of byte register");
   843  	if(D_AL <= v->type && v->type <= D_R15B)
   844  		fatal("use of byte register");
   845  
   846  	if(a->type != v->type)
   847  		return 0;
   848  	if(regtyp(v))
   849  		return 1;
   850  	if(v->type == D_AUTO || v->type == D_PARAM)
   851  		if(v->offset == a->offset)
   852  			return 1;
   853  	return 0;
   854  }
   855  
   856  int
   857  sameaddr(Addr *a, Addr *v)
   858  {
   859  	if(a->type != v->type)
   860  		return 0;
   861  	if(regtyp(v))
   862  		return 1;
   863  	if(v->type == D_AUTO || v->type == D_PARAM)
   864  		if(v->offset == a->offset)
   865  			return 1;
   866  	return 0;
   867  }
   868  
   869  /*
   870   * either direct or indirect
   871   */
   872  static int
   873  copyau(Adr *a, Adr *v)
   874  {
   875  
   876  	if(copyas(a, v)) {
   877  		if(debug['P'] && debug['v'])
   878  			print("\tcopyau: copyas returned 1\n");
   879  		return 1;
   880  	}
   881  	if(regtyp(v)) {
   882  		if(a->type-D_INDIR == v->type) {
   883  			if(debug['P'] && debug['v'])
   884  				print("\tcopyau: found indir use - return 1\n");
   885  			return 1;
   886  		}
   887  		if(a->index == v->type) {
   888  			if(debug['P'] && debug['v'])
   889  				print("\tcopyau: found index use - return 1\n");
   890  			return 1;
   891  		}
   892  	}
   893  	return 0;
   894  }
   895  
   896  /*
   897   * substitute s for v in a
   898   * return failure to substitute
   899   */
   900  static int
   901  copysub(Adr *a, Adr *v, Adr *s, int f)
   902  {
   903  	int t;
   904  
   905  	if(copyas(a, v)) {
   906  		t = s->type;
   907  		if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
   908  			if(f)
   909  				a->type = t;
   910  		}
   911  		return 0;
   912  	}
   913  	if(regtyp(v)) {
   914  		t = v->type;
   915  		if(a->type == t+D_INDIR) {
   916  			if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
   917  				return 1;	/* can't use BP-base with index */
   918  			if(f)
   919  				a->type = s->type+D_INDIR;
   920  //			return 0;
   921  		}
   922  		if(a->index == t) {
   923  			if(f)
   924  				a->index = s->type;
   925  			return 0;
   926  		}
   927  		return 0;
   928  	}
   929  	return 0;
   930  }
   931  
   932  static void
   933  conprop(Flow *r0)
   934  {
   935  	Flow *r;
   936  	Prog *p, *p0;
   937  	int t;
   938  	Adr *v0;
   939  
   940  	p0 = r0->prog;
   941  	v0 = &p0->to;
   942  	r = r0;
   943  
   944  loop:
   945  	r = uniqs(r);
   946  	if(r == nil || r == r0)
   947  		return;
   948  	if(uniqp(r) == nil)
   949  		return;
   950  
   951  	p = r->prog;
   952  	t = copyu(p, v0, nil);
   953  	switch(t) {
   954  	case 0:	// miss
   955  	case 1:	// use
   956  		goto loop;
   957  
   958  	case 2:	// rar
   959  	case 4:	// use and set
   960  		break;
   961  
   962  	case 3:	// set
   963  		if(p->as == p0->as)
   964  		if(p->from.type == p0->from.type)
   965  		if(p->from.node == p0->from.node)
   966  		if(p->from.offset == p0->from.offset)
   967  		if(p->from.scale == p0->from.scale)
   968  		if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval)
   969  		if(p->from.index == p0->from.index) {
   970  			excise(r);
   971  			goto loop;
   972  		}
   973  		break;
   974  	}
   975  }
   976  
   977  int
   978  smallindir(Addr *a, Addr *reg)
   979  {
   980  	return regtyp(reg) &&
   981  		a->type == D_INDIR + reg->type &&
   982  		a->index == D_NONE &&
   983  		0 <= a->offset && a->offset < 4096;
   984  }
   985  
   986  int
   987  stackaddr(Addr *a)
   988  {
   989  	return regtyp(a) && a->type == D_SP;
   990  }