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