github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/5g/peep.c (about)

     1  // Inferno utils/5c/peep.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5c/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  
    32  #include <u.h>
    33  #include <libc.h>
    34  #include "gg.h"
    35  #include "opt.h"
    36  
    37  static int	xtramodes(Graph*, Flow*, Adr*);
    38  static int	shortprop(Flow *r);
    39  static int	subprop(Flow*);
    40  static int	copyprop(Graph*, Flow*);
    41  static int	copy1(Adr*, Adr*, Flow*, int);
    42  static int	copyas(Adr*, Adr*);
    43  static int	copyau(Adr*, Adr*);
    44  static int	copysub(Adr*, Adr*, Adr*, int);
    45  static int	copysub1(Prog*, Adr*, Adr*, int);
    46  static Flow*	findpre(Flow *r, Adr *v);
    47  static int	copyau1(Prog *p, Adr *v);
    48  static int	isdconst(Addr *a);
    49  
    50  static uint32	gactive;
    51  
    52  // UNUSED
    53  int	shiftprop(Flow *r);
    54  void	constprop(Adr *c1, Adr *v1, Flow *r);
    55  void	predicate(Graph*);
    56  
    57  void
    58  peep(Prog *firstp)
    59  {
    60  	Flow *r;
    61  	Graph *g;
    62  	Prog *p;
    63  	int t;
    64  
    65  	g = flowstart(firstp, sizeof(Flow));
    66  	if(g == nil)
    67  		return;
    68  	gactive = 0;
    69  
    70  loop1:
    71  	if(debug['P'] && debug['v'])
    72  		dumpit("loop1", g->start, 0);
    73  
    74  	t = 0;
    75  	for(r=g->start; r!=nil; r=r->link) {
    76  		p = r->prog;
    77  		switch(p->as) {
    78  		case ASLL:
    79  		case ASRL:
    80  		case ASRA:
    81  			/*
    82  			 * elide shift into D_SHIFT operand of subsequent instruction
    83  			 */
    84  //			if(shiftprop(r)) {
    85  //				excise(r);
    86  //				t++;
    87  //				break;
    88  //			}
    89  			break;
    90  
    91  		case AMOVB:
    92  		case AMOVH:
    93  		case AMOVW:
    94  		case AMOVF:
    95  		case AMOVD:
    96  			if(regtyp(&p->from))
    97  			if(p->from.type == p->to.type)
    98  			if(p->scond == C_SCOND_NONE) {
    99  				if(copyprop(g, r)) {
   100  					excise(r);
   101  					t++;
   102  					break;
   103  				}
   104  				if(subprop(r) && copyprop(g, r)) {
   105  					excise(r);
   106  					t++;
   107  					break;
   108  				}
   109  			}
   110  			break;
   111  
   112  		case AMOVHS:
   113  		case AMOVHU:
   114  		case AMOVBS:
   115  		case AMOVBU:
   116  			if(p->from.type == D_REG) {
   117  				if(shortprop(r))
   118  					t++;
   119  			}
   120  			break;
   121  
   122  #ifdef NOTDEF
   123  			if(p->scond == C_SCOND_NONE)
   124  			if(regtyp(&p->to))
   125  			if(isdconst(&p->from)) {
   126  				constprop(&p->from, &p->to, r->s1);
   127  			}
   128  			break;
   129  #endif
   130  		}
   131  	}
   132  	if(t)
   133  		goto loop1;
   134  
   135  	for(r=g->start; r!=nil; r=r->link) {
   136  		p = r->prog;
   137  		switch(p->as) {
   138  		case AEOR:
   139  			/*
   140  			 * EOR -1,x,y => MVN x,y
   141  			 */
   142  			if(isdconst(&p->from) && p->from.offset == -1) {
   143  				p->as = AMVN;
   144  				p->from.type = D_REG;
   145  				if(p->reg != NREG)
   146  					p->from.reg = p->reg;
   147  				else
   148  					p->from.reg = p->to.reg;
   149  				p->reg = NREG;
   150  			}
   151  			break;
   152  		}
   153  	}
   154  
   155  	for(r=g->start; r!=nil; r=r->link) {
   156  		p = r->prog;
   157  		switch(p->as) {
   158  		case AMOVW:
   159  		case AMOVB:
   160  		case AMOVBS:
   161  		case AMOVBU:
   162  			if(p->from.type == D_OREG && p->from.offset == 0)
   163  				xtramodes(g, r, &p->from);
   164  			else
   165  			if(p->to.type == D_OREG && p->to.offset == 0)
   166  				xtramodes(g, r, &p->to);
   167  			else
   168  				continue;
   169  			break;
   170  //		case ACMP:
   171  //			/*
   172  //			 * elide CMP $0,x if calculation of x can set condition codes
   173  //			 */
   174  //			if(isdconst(&p->from) || p->from.offset != 0)
   175  //				continue;
   176  //			r2 = r->s1;
   177  //			if(r2 == nil)
   178  //				continue;
   179  //			t = r2->prog->as;
   180  //			switch(t) {
   181  //			default:
   182  //				continue;
   183  //			case ABEQ:
   184  //			case ABNE:
   185  //			case ABMI:
   186  //			case ABPL:
   187  //				break;
   188  //			case ABGE:
   189  //				t = ABPL;
   190  //				break;
   191  //			case ABLT:
   192  //				t = ABMI;
   193  //				break;
   194  //			case ABHI:
   195  //				t = ABNE;
   196  //				break;
   197  //			case ABLS:
   198  //				t = ABEQ;
   199  //				break;
   200  //			}
   201  //			r1 = r;
   202  //			do
   203  //				r1 = uniqp(r1);
   204  //			while (r1 != nil && r1->prog->as == ANOP);
   205  //			if(r1 == nil)
   206  //				continue;
   207  //			p1 = r1->prog;
   208  //			if(p1->to.type != D_REG)
   209  //				continue;
   210  //			if(p1->to.reg != p->reg)
   211  //			if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
   212  //				continue;
   213  //
   214  //			switch(p1->as) {
   215  //			default:
   216  //				continue;
   217  //			case AMOVW:
   218  //				if(p1->from.type != D_REG)
   219  //					continue;
   220  //			case AAND:
   221  //			case AEOR:
   222  //			case AORR:
   223  //			case ABIC:
   224  //			case AMVN:
   225  //			case ASUB:
   226  //			case ARSB:
   227  //			case AADD:
   228  //			case AADC:
   229  //			case ASBC:
   230  //			case ARSC:
   231  //				break;
   232  //			}
   233  //			p1->scond |= C_SBIT;
   234  //			r2->prog->as = t;
   235  //			excise(r);
   236  //			continue;
   237  		}
   238  	}
   239  
   240  //	predicate(g);
   241  
   242  	flowend(g);
   243  }
   244  
   245  int
   246  regtyp(Adr *a)
   247  {
   248  
   249  	if(a->type == D_REG)
   250  		return 1;
   251  	if(a->type == D_FREG)
   252  		return 1;
   253  	return 0;
   254  }
   255  
   256  /*
   257   * the idea is to substitute
   258   * one register for another
   259   * from one MOV to another
   260   *	MOV	a, R0
   261   *	ADD	b, R0	/ no use of R1
   262   *	MOV	R0, R1
   263   * would be converted to
   264   *	MOV	a, R1
   265   *	ADD	b, R1
   266   *	MOV	R1, R0
   267   * hopefully, then the former or latter MOV
   268   * will be eliminated by copy propagation.
   269   */
   270  static int
   271  subprop(Flow *r0)
   272  {
   273  	Prog *p;
   274  	Adr *v1, *v2;
   275  	Flow *r;
   276  	int t;
   277  	ProgInfo info;
   278  
   279  	p = r0->prog;
   280  	v1 = &p->from;
   281  	if(!regtyp(v1))
   282  		return 0;
   283  	v2 = &p->to;
   284  	if(!regtyp(v2))
   285  		return 0;
   286  	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
   287  		if(uniqs(r) == nil)
   288  			break;
   289  		p = r->prog;
   290  		if(p->as == AVARDEF || p->as == AVARKILL)
   291  			continue;
   292  		proginfo(&info, p);
   293  		if(info.flags & Call)
   294  			return 0;
   295  
   296  		if((info.flags & CanRegRead) && p->to.type == D_REG) {
   297  			info.flags |= RegRead;
   298  			info.flags &= ~(CanRegRead | RightRead);
   299  			p->reg = p->to.reg;
   300  		}
   301  
   302  		switch(p->as) {
   303  		case AMULLU:
   304  		case AMULA:
   305  		case AMVN:
   306  			return 0;
   307  		}
   308  		
   309  		if((info.flags & (RightRead|RightWrite)) == RightWrite) {
   310  			if(p->to.type == v1->type)
   311  			if(p->to.reg == v1->reg)
   312  			if(p->scond == C_SCOND_NONE)
   313  				goto gotit;
   314  		}
   315  
   316  		if(copyau(&p->from, v2) ||
   317  		   copyau1(p, v2) ||
   318  		   copyau(&p->to, v2))
   319  			break;
   320  		if(copysub(&p->from, v1, v2, 0) ||
   321  		   copysub1(p, v1, v2, 0) ||
   322  		   copysub(&p->to, v1, v2, 0))
   323  			break;
   324  	}
   325  	return 0;
   326  
   327  gotit:
   328  	copysub(&p->to, v1, v2, 1);
   329  	if(debug['P']) {
   330  		print("gotit: %D->%D\n%P", v1, v2, r->prog);
   331  		if(p->from.type == v2->type)
   332  			print(" excise");
   333  		print("\n");
   334  	}
   335  	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
   336  		p = r->prog;
   337  		copysub(&p->from, v1, v2, 1);
   338  		copysub1(p, v1, v2, 1);
   339  		copysub(&p->to, v1, v2, 1);
   340  		if(debug['P'])
   341  			print("%P\n", r->prog);
   342  	}
   343  	t = v1->reg;
   344  	v1->reg = v2->reg;
   345  	v2->reg = t;
   346  	if(debug['P'])
   347  		print("%P last\n", r->prog);
   348  	return 1;
   349  }
   350  
   351  /*
   352   * The idea is to remove redundant copies.
   353   *	v1->v2	F=0
   354   *	(use v2	s/v2/v1/)*
   355   *	set v1	F=1
   356   *	use v2	return fail
   357   *	-----------------
   358   *	v1->v2	F=0
   359   *	(use v2	s/v2/v1/)*
   360   *	set v1	F=1
   361   *	set v2	return success
   362   */
   363  static int
   364  copyprop(Graph *g, Flow *r0)
   365  {
   366  	Prog *p;
   367  	Adr *v1, *v2;
   368  
   369  	USED(g);
   370  	p = r0->prog;
   371  	v1 = &p->from;
   372  	v2 = &p->to;
   373  	if(copyas(v1, v2))
   374  		return 1;
   375  	gactive++;
   376  	return copy1(v1, v2, r0->s1, 0);
   377  }
   378  
   379  static int
   380  copy1(Adr *v1, Adr *v2, Flow *r, int f)
   381  {
   382  	int t;
   383  	Prog *p;
   384  
   385  	if(r->active == gactive) {
   386  		if(debug['P'])
   387  			print("act set; return 1\n");
   388  		return 1;
   389  	}
   390  	r->active = gactive;
   391  	if(debug['P'])
   392  		print("copy %D->%D f=%d\n", v1, v2, f);
   393  	for(; r != nil; r = r->s1) {
   394  		p = r->prog;
   395  		if(debug['P'])
   396  			print("%P", p);
   397  		if(!f && uniqp(r) == nil) {
   398  			f = 1;
   399  			if(debug['P'])
   400  				print("; merge; f=%d", f);
   401  		}
   402  		t = copyu(p, v2, nil);
   403  		switch(t) {
   404  		case 2:	/* rar, can't split */
   405  			if(debug['P'])
   406  				print("; %Drar; return 0\n", v2);
   407  			return 0;
   408  
   409  		case 3:	/* set */
   410  			if(debug['P'])
   411  				print("; %Dset; return 1\n", v2);
   412  			return 1;
   413  
   414  		case 1:	/* used, substitute */
   415  		case 4:	/* use and set */
   416  			if(f) {
   417  				if(!debug['P'])
   418  					return 0;
   419  				if(t == 4)
   420  					print("; %Dused+set and f=%d; return 0\n", v2, f);
   421  				else
   422  					print("; %Dused and f=%d; return 0\n", v2, f);
   423  				return 0;
   424  			}
   425  			if(copyu(p, v2, v1)) {
   426  				if(debug['P'])
   427  					print("; sub fail; return 0\n");
   428  				return 0;
   429  			}
   430  			if(debug['P'])
   431  				print("; sub%D/%D", v2, v1);
   432  			if(t == 4) {
   433  				if(debug['P'])
   434  					print("; %Dused+set; return 1\n", v2);
   435  				return 1;
   436  			}
   437  			break;
   438  		}
   439  		if(!f) {
   440  			t = copyu(p, v1, nil);
   441  			if(!f && (t == 2 || t == 3 || t == 4)) {
   442  				f = 1;
   443  				if(debug['P'])
   444  					print("; %Dset and !f; f=%d", v1, f);
   445  			}
   446  		}
   447  		if(debug['P'])
   448  			print("\n");
   449  		if(r->s2)
   450  			if(!copy1(v1, v2, r->s2, f))
   451  				return 0;
   452  	}
   453  	return 1;
   454  }
   455  
   456  // UNUSED
   457  /*
   458   * The idea is to remove redundant constants.
   459   *	$c1->v1
   460   *	($c1->v2 s/$c1/v1)*
   461   *	set v1  return
   462   * The v1->v2 should be eliminated by copy propagation.
   463   */
   464  void
   465  constprop(Adr *c1, Adr *v1, Flow *r)
   466  {
   467  	Prog *p;
   468  
   469  	if(debug['P'])
   470  		print("constprop %D->%D\n", c1, v1);
   471  	for(; r != nil; r = r->s1) {
   472  		p = r->prog;
   473  		if(debug['P'])
   474  			print("%P", p);
   475  		if(uniqp(r) == nil) {
   476  			if(debug['P'])
   477  				print("; merge; return\n");
   478  			return;
   479  		}
   480  		if(p->as == AMOVW && copyas(&p->from, c1)) {
   481  				if(debug['P'])
   482  					print("; sub%D/%D", &p->from, v1);
   483  				p->from = *v1;
   484  		} else if(copyu(p, v1, nil) > 1) {
   485  			if(debug['P'])
   486  				print("; %Dset; return\n", v1);
   487  			return;
   488  		}
   489  		if(debug['P'])
   490  			print("\n");
   491  		if(r->s2)
   492  			constprop(c1, v1, r->s2);
   493  	}
   494  }
   495  
   496  /*
   497   * shortprop eliminates redundant zero/sign extensions.
   498   *
   499   *   MOVBS x, R
   500   *   <no use R>
   501   *   MOVBS R, R'
   502   *
   503   * changed to
   504   *
   505   *   MOVBS x, R
   506   *   ...
   507   *   MOVB  R, R' (compiled to mov)
   508   *
   509   * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU.
   510   */
   511  static int
   512  shortprop(Flow *r)
   513  {
   514  	Prog *p, *p1;
   515  	Flow *r1;
   516  
   517  	p = r->prog;
   518  	r1 = findpre(r, &p->from);
   519  	if(r1 == nil)
   520  		return 0;
   521  
   522  	p1 = r1->prog;
   523  	if(p1->as == p->as) {
   524  		// Two consecutive extensions.
   525  		goto gotit;
   526  	}
   527  
   528  	if(p1->as == AMOVW && isdconst(&p1->from)
   529  	   && p1->from.offset >= 0 && p1->from.offset < 128) {
   530  		// Loaded an immediate.
   531  		goto gotit;
   532  	}
   533  
   534  	return 0;
   535  
   536  gotit:
   537  	if(debug['P'])
   538  		print("shortprop\n%P\n%P", p1, p);
   539  	switch(p->as) {
   540  	case AMOVBS:
   541  	case AMOVBU:
   542  		p->as = AMOVB;
   543  		break;
   544  	case AMOVHS:
   545  	case AMOVHU:
   546  		p->as = AMOVH;
   547  		break;
   548  	}
   549  	if(debug['P'])
   550  		print(" => %A\n", p->as);
   551  	return 1;
   552  }
   553  
   554  // UNUSED
   555  /*
   556   * ASLL x,y,w
   557   * .. (not use w, not set x y w)
   558   * AXXX w,a,b (a != w)
   559   * .. (not use w)
   560   * (set w)
   561   * ----------- changed to
   562   * ..
   563   * AXXX (x<<y),a,b
   564   * ..
   565   */
   566  #define FAIL(msg) { if(debug['P']) print("\t%s; FAILURE\n", msg); return 0; }
   567  /*c2go void FAIL(char*); */
   568  
   569  int
   570  shiftprop(Flow *r)
   571  {
   572  	Flow *r1;
   573  	Prog *p, *p1, *p2;
   574  	int n, o;
   575  	Adr a;
   576  
   577  	p = r->prog;
   578  	if(p->to.type != D_REG)
   579  		FAIL("BOTCH: result not reg");
   580  	n = p->to.reg;
   581  	a = zprog.from;
   582  	if(p->reg != NREG && p->reg != p->to.reg) {
   583  		a.type = D_REG;
   584  		a.reg = p->reg;
   585  	}
   586  	if(debug['P'])
   587  		print("shiftprop\n%P", p);
   588  	r1 = r;
   589  	for(;;) {
   590  		/* find first use of shift result; abort if shift operands or result are changed */
   591  		r1 = uniqs(r1);
   592  		if(r1 == nil)
   593  			FAIL("branch");
   594  		if(uniqp(r1) == nil)
   595  			FAIL("merge");
   596  		p1 = r1->prog;
   597  		if(debug['P'])
   598  			print("\n%P", p1);
   599  		switch(copyu(p1, &p->to, nil)) {
   600  		case 0:	/* not used or set */
   601  			if((p->from.type == D_REG && copyu(p1, &p->from, nil) > 1) ||
   602  			   (a.type == D_REG && copyu(p1, &a, nil) > 1))
   603  				FAIL("args modified");
   604  			continue;
   605  		case 3:	/* set, not used */
   606  			FAIL("BOTCH: noref");
   607  		}
   608  		break;
   609  	}
   610  	/* check whether substitution can be done */
   611  	switch(p1->as) {
   612  	default:
   613  		FAIL("non-dpi");
   614  	case AAND:
   615  	case AEOR:
   616  	case AADD:
   617  	case AADC:
   618  	case AORR:
   619  	case ASUB:
   620  	case ASBC:
   621  	case ARSB:
   622  	case ARSC:
   623  		if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
   624  			if(p1->from.type != D_REG)
   625  				FAIL("can't swap");
   626  			p1->reg = p1->from.reg;
   627  			p1->from.reg = n;
   628  			switch(p1->as) {
   629  			case ASUB:
   630  				p1->as = ARSB;
   631  				break;
   632  			case ARSB:
   633  				p1->as = ASUB;
   634  				break;
   635  			case ASBC:
   636  				p1->as = ARSC;
   637  				break;
   638  			case ARSC:
   639  				p1->as = ASBC;
   640  				break;
   641  			}
   642  			if(debug['P'])
   643  				print("\t=>%P", p1);
   644  		}
   645  	case ABIC:
   646  	case ATST:
   647  	case ACMP:
   648  	case ACMN:
   649  		if(p1->reg == n)
   650  			FAIL("can't swap");
   651  		if(p1->reg == NREG && p1->to.reg == n)
   652  			FAIL("shift result used twice");
   653  //	case AMVN:
   654  		if(p1->from.type == D_SHIFT)
   655  			FAIL("shift result used in shift");
   656  		if(p1->from.type != D_REG || p1->from.reg != n)
   657  			FAIL("BOTCH: where is it used?");
   658  		break;
   659  	}
   660  	/* check whether shift result is used subsequently */
   661  	p2 = p1;
   662  	if(p1->to.reg != n)
   663  	for (;;) {
   664  		r1 = uniqs(r1);
   665  		if(r1 == nil)
   666  			FAIL("inconclusive");
   667  		p1 = r1->prog;
   668  		if(debug['P'])
   669  			print("\n%P", p1);
   670  		switch(copyu(p1, &p->to, nil)) {
   671  		case 0:	/* not used or set */
   672  			continue;
   673  		case 3: /* set, not used */
   674  			break;
   675  		default:/* used */
   676  			FAIL("reused");
   677  		}
   678  		break;
   679  	}
   680  
   681  	/* make the substitution */
   682  	p2->from.type = D_SHIFT;
   683  	p2->from.reg = NREG;
   684  	o = p->reg;
   685  	if(o == NREG)
   686  		o = p->to.reg;
   687  
   688  	switch(p->from.type){
   689  	case D_CONST:
   690  		o |= (p->from.offset&0x1f)<<7;
   691  		break;
   692  	case D_REG:
   693  		o |= (1<<4) | (p->from.reg<<8);
   694  		break;
   695  	}
   696  	switch(p->as){
   697  	case ASLL:
   698  		o |= 0<<5;
   699  		break;
   700  	case ASRL:
   701  		o |= 1<<5;
   702  		break;
   703  	case ASRA:
   704  		o |= 2<<5;
   705  		break;
   706  	}
   707  	p2->from.offset = o;
   708  	if(debug['P'])
   709  		print("\t=>%P\tSUCCEED\n", p2);
   710  	return 1;
   711  }
   712  
   713  /*
   714   * findpre returns the last instruction mentioning v
   715   * before r. It must be a set, and there must be
   716   * a unique path from that instruction to r.
   717   */
   718  static Flow*
   719  findpre(Flow *r, Adr *v)
   720  {
   721  	Flow *r1;
   722  
   723  	for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) {
   724  		if(uniqs(r1) != r)
   725  			return nil;
   726  		switch(copyu(r1->prog, v, nil)) {
   727  		case 1: /* used */
   728  		case 2: /* read-alter-rewrite */
   729  			return nil;
   730  		case 3: /* set */
   731  		case 4: /* set and used */
   732  			return r1;
   733  		}
   734  	}
   735  	return nil;
   736  }
   737  
   738  /*
   739   * findinc finds ADD instructions with a constant
   740   * argument which falls within the immed_12 range.
   741   */
   742  static Flow*
   743  findinc(Flow *r, Flow *r2, Adr *v)
   744  {
   745  	Flow *r1;
   746  	Prog *p;
   747  
   748  
   749  	for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) {
   750  		if(uniqp(r1) != r)
   751  			return nil;
   752  		switch(copyu(r1->prog, v, nil)) {
   753  		case 0: /* not touched */
   754  			continue;
   755  		case 4: /* set and used */
   756  			p = r1->prog;
   757  			if(p->as == AADD)
   758  			if(isdconst(&p->from))
   759  			if(p->from.offset > -4096 && p->from.offset < 4096)
   760  				return r1;
   761  		default:
   762  			return nil;
   763  		}
   764  	}
   765  	return nil;
   766  }
   767  
   768  static int
   769  nochange(Flow *r, Flow *r2, Prog *p)
   770  {
   771  	Adr a[3];
   772  	int i, n;
   773  
   774  	if(r == r2)
   775  		return 1;
   776  	n = 0;
   777  	if(p->reg != NREG && p->reg != p->to.reg) {
   778  		a[n].type = D_REG;
   779  		a[n++].reg = p->reg;
   780  	}
   781  	switch(p->from.type) {
   782  	case D_SHIFT:
   783  		a[n].type = D_REG;
   784  		a[n++].reg = p->from.offset&0xf;
   785  	case D_REG:
   786  		a[n].type = D_REG;
   787  		a[n++].reg = p->from.reg;
   788  	}
   789  	if(n == 0)
   790  		return 1;
   791  	for(; r!=nil && r!=r2; r=uniqs(r)) {
   792  		p = r->prog;
   793  		for(i=0; i<n; i++)
   794  			if(copyu(p, &a[i], nil) > 1)
   795  				return 0;
   796  	}
   797  	return 1;
   798  }
   799  
   800  static int
   801  findu1(Flow *r, Adr *v)
   802  {
   803  	for(; r != nil; r = r->s1) {
   804  		if(r->active)
   805  			return 0;
   806  		r->active = 1;
   807  		switch(copyu(r->prog, v, nil)) {
   808  		case 1: /* used */
   809  		case 2: /* read-alter-rewrite */
   810  		case 4: /* set and used */
   811  			return 1;
   812  		case 3: /* set */
   813  			return 0;
   814  		}
   815  		if(r->s2)
   816  			if (findu1(r->s2, v))
   817  				return 1;
   818  	}
   819  	return 0;
   820  }
   821  
   822  static int
   823  finduse(Graph *g, Flow *r, Adr *v)
   824  {
   825  	Flow *r1;
   826  
   827  	for(r1=g->start; r1!=nil; r1=r1->link)
   828  		r1->active = 0;
   829  	return findu1(r, v);
   830  }
   831  
   832  /*
   833   * xtramodes enables the ARM post increment and
   834   * shift offset addressing modes to transform
   835   *   MOVW   0(R3),R1
   836   *   ADD    $4,R3,R3
   837   * into
   838   *   MOVW.P 4(R3),R1
   839   * and 
   840   *   ADD    R0,R1
   841   *   MOVBU  0(R1),R0
   842   * into 
   843   *   MOVBU  R0<<0(R1),R0
   844   */
   845  static int
   846  xtramodes(Graph *g, Flow *r, Adr *a)
   847  {
   848  	Flow *r1, *r2, *r3;
   849  	Prog *p, *p1;
   850  	Adr v;
   851  
   852  	p = r->prog;
   853  	v = *a;
   854  	v.type = D_REG;
   855  	r1 = findpre(r, &v);
   856  	if(r1 != nil) {
   857  		p1 = r1->prog;
   858  		if(p1->to.type == D_REG && p1->to.reg == v.reg)
   859  		switch(p1->as) {
   860  		case AADD:
   861  			if(p1->scond & C_SBIT)
   862  				// avoid altering ADD.S/ADC sequences.
   863  				break;
   864  			if(p1->from.type == D_REG ||
   865  			   (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
   866  			    ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
   867  			   (p1->from.type == D_CONST &&
   868  			    p1->from.offset > -4096 && p1->from.offset < 4096))
   869  			if(nochange(uniqs(r1), r, p1)) {
   870  				if(a != &p->from || v.reg != p->to.reg)
   871  				if (finduse(g, r->s1, &v)) {
   872  					if(p1->reg == NREG || p1->reg == v.reg)
   873  						/* pre-indexing */
   874  						p->scond |= C_WBIT;
   875  					else return 0;
   876  				}
   877  				switch (p1->from.type) {
   878  				case D_REG:
   879  					/* register offset */
   880  					if(nacl)
   881  						return 0;
   882  					a->type = D_SHIFT;
   883  					a->offset = p1->from.reg;
   884  					break;
   885  				case D_SHIFT:
   886  					/* scaled register offset */
   887  					if(nacl)
   888  						return 0;
   889  					a->type = D_SHIFT;
   890  				case D_CONST:
   891  					/* immediate offset */
   892  					a->offset = p1->from.offset;
   893  					break;
   894  				}
   895  				if(p1->reg != NREG)
   896  					a->reg = p1->reg;
   897  				excise(r1);
   898  				return 1;
   899  			}
   900  			break;
   901  		case AMOVW:
   902  			if(p1->from.type == D_REG)
   903  			if((r2 = findinc(r1, r, &p1->from)) != nil) {
   904  			for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
   905  				;
   906  			if(r3 == r) {
   907  				/* post-indexing */
   908  				p1 = r2->prog;
   909  				a->reg = p1->to.reg;
   910  				a->offset = p1->from.offset;
   911  				p->scond |= C_PBIT;
   912  				if(!finduse(g, r, &r1->prog->to))
   913  					excise(r1);
   914  				excise(r2);
   915  				return 1;
   916  			}
   917  			}
   918  			break;
   919  		}
   920  	}
   921  	if(a != &p->from || a->reg != p->to.reg)
   922  	if((r1 = findinc(r, nil, &v)) != nil) {
   923  		/* post-indexing */
   924  		p1 = r1->prog;
   925  		a->offset = p1->from.offset;
   926  		p->scond |= C_PBIT;
   927  		excise(r1);
   928  		return 1;
   929  	}
   930  	return 0;
   931  }
   932  
   933  /*
   934   * return
   935   * 1 if v only used (and substitute),
   936   * 2 if read-alter-rewrite
   937   * 3 if set
   938   * 4 if set and used
   939   * 0 otherwise (not touched)
   940   */
   941  int
   942  copyu(Prog *p, Adr *v, Adr *s)
   943  {
   944  	switch(p->as) {
   945  
   946  	default:
   947  		print("copyu: can't find %A\n", p->as);
   948  		return 2;
   949  
   950  	case AMOVM:
   951  		if(v->type != D_REG)
   952  			return 0;
   953  		if(p->from.type == D_CONST) {	/* read reglist, read/rar */
   954  			if(s != nil) {
   955  				if(p->from.offset&(1<<v->reg))
   956  					return 1;
   957  				if(copysub(&p->to, v, s, 1))
   958  					return 1;
   959  				return 0;
   960  			}
   961  			if(copyau(&p->to, v)) {
   962  				if(p->scond&C_WBIT)
   963  					return 2;
   964  				return 1;
   965  			}
   966  			if(p->from.offset&(1<<v->reg))
   967  				return 1;
   968  		} else {			/* read/rar, write reglist */
   969  			if(s != nil) {
   970  				if(p->to.offset&(1<<v->reg))
   971  					return 1;
   972  				if(copysub(&p->from, v, s, 1))
   973  					return 1;
   974  				return 0;
   975  			}
   976  			if(copyau(&p->from, v)) {
   977  				if(p->scond&C_WBIT)
   978  					return 2;
   979  				if(p->to.offset&(1<<v->reg))
   980  					return 4;
   981  				return 1;
   982  			}
   983  			if(p->to.offset&(1<<v->reg))
   984  				return 3;
   985  		}
   986  		return 0;
   987  
   988  	case ANOP:	/* read,, write */
   989  	case AMOVW:
   990  	case AMOVF:
   991  	case AMOVD:
   992  	case AMOVH:
   993  	case AMOVHS:
   994  	case AMOVHU:
   995  	case AMOVB:
   996  	case AMOVBS:
   997  	case AMOVBU:
   998  	case AMOVFW:
   999  	case AMOVWF:
  1000  	case AMOVDW:
  1001  	case AMOVWD:
  1002  	case AMOVFD:
  1003  	case AMOVDF:
  1004  		if(p->scond&(C_WBIT|C_PBIT))
  1005  		if(v->type == D_REG) {
  1006  			if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
  1007  				if(p->from.reg == v->reg)
  1008  					return 2;
  1009  			} else {
  1010  		  		if(p->to.reg == v->reg)
  1011  					return 2;
  1012  			}
  1013  		}
  1014  		if(s != nil) {
  1015  			if(copysub(&p->from, v, s, 1))
  1016  				return 1;
  1017  			if(!copyas(&p->to, v))
  1018  				if(copysub(&p->to, v, s, 1))
  1019  					return 1;
  1020  			return 0;
  1021  		}
  1022  		if(copyas(&p->to, v)) {
  1023  			if(p->scond != C_SCOND_NONE)
  1024  				return 2;
  1025  			if(copyau(&p->from, v))
  1026  				return 4;
  1027  			return 3;
  1028  		}
  1029  		if(copyau(&p->from, v))
  1030  			return 1;
  1031  		if(copyau(&p->to, v))
  1032  			return 1;
  1033  		return 0;
  1034  
  1035  	case AMULLU:	/* read, read, write, write */
  1036  	case AMULL:
  1037  	case AMULA:
  1038  	case AMVN:
  1039  		return 2;
  1040  
  1041  	case AADD:	/* read, read, write */
  1042  	case AADC:
  1043  	case ASUB:
  1044  	case ASBC:
  1045  	case ARSB:
  1046  	case ASLL:
  1047  	case ASRL:
  1048  	case ASRA:
  1049  	case AORR:
  1050  	case AAND:
  1051  	case AEOR:
  1052  	case AMUL:
  1053  	case AMULU:
  1054  	case ADIV:
  1055  	case ADIVU:
  1056  	case AMOD:
  1057  	case AMODU:
  1058  	case AADDF:
  1059  	case AADDD:
  1060  	case ASUBF:
  1061  	case ASUBD:
  1062  	case AMULF:
  1063  	case AMULD:
  1064  	case ADIVF:
  1065  	case ADIVD:
  1066  
  1067  	case ACHECKNIL: /* read */
  1068  	case ACMPF:	/* read, read, */
  1069  	case ACMPD:
  1070  	case ACMP:
  1071  	case ACMN:
  1072  	case ACASE:
  1073  	case ATST:	/* read,, */
  1074  		if(s != nil) {
  1075  			if(copysub(&p->from, v, s, 1))
  1076  				return 1;
  1077  			if(copysub1(p, v, s, 1))
  1078  				return 1;
  1079  			if(!copyas(&p->to, v))
  1080  				if(copysub(&p->to, v, s, 1))
  1081  					return 1;
  1082  			return 0;
  1083  		}
  1084  		if(copyas(&p->to, v)) {
  1085  			if(p->scond != C_SCOND_NONE)
  1086  				return 2;
  1087  			if(p->reg == NREG)
  1088  				p->reg = p->to.reg;
  1089  			if(copyau(&p->from, v))
  1090  				return 4;
  1091  			if(copyau1(p, v))
  1092  				return 4;
  1093  			return 3;
  1094  		}
  1095  		if(copyau(&p->from, v))
  1096  			return 1;
  1097  		if(copyau1(p, v))
  1098  			return 1;
  1099  		if(copyau(&p->to, v))
  1100  			return 1;
  1101  		return 0;
  1102  
  1103  	case ABEQ:	/* read, read */
  1104  	case ABNE:
  1105  	case ABCS:
  1106  	case ABHS:
  1107  	case ABCC:
  1108  	case ABLO:
  1109  	case ABMI:
  1110  	case ABPL:
  1111  	case ABVS:
  1112  	case ABVC:
  1113  	case ABHI:
  1114  	case ABLS:
  1115  	case ABGE:
  1116  	case ABLT:
  1117  	case ABGT:
  1118  	case ABLE:
  1119  		if(s != nil) {
  1120  			if(copysub(&p->from, v, s, 1))
  1121  				return 1;
  1122  			return copysub1(p, v, s, 1);
  1123  		}
  1124  		if(copyau(&p->from, v))
  1125  			return 1;
  1126  		if(copyau1(p, v))
  1127  			return 1;
  1128  		return 0;
  1129  
  1130  	case AB:	/* funny */
  1131  		if(s != nil) {
  1132  			if(copysub(&p->to, v, s, 1))
  1133  				return 1;
  1134  			return 0;
  1135  		}
  1136  		if(copyau(&p->to, v))
  1137  			return 1;
  1138  		return 0;
  1139  
  1140  	case ARET:	/* funny */
  1141  		if(s != nil)
  1142  			return 1;
  1143  		return 3;
  1144  
  1145  	case ABL:	/* funny */
  1146  		if(v->type == D_REG) {
  1147  			if(v->reg <= REGEXT && v->reg > exregoffset)
  1148  				return 2;
  1149  			if(v->reg == REGARG)
  1150  				return 2;
  1151  		}
  1152  		if(v->type == D_FREG)
  1153  			if(v->reg <= FREGEXT && v->reg > exfregoffset)
  1154  				return 2;
  1155  		if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg)
  1156  			return 2;
  1157  
  1158  		if(s != nil) {
  1159  			if(copysub(&p->to, v, s, 1))
  1160  				return 1;
  1161  			return 0;
  1162  		}
  1163  		if(copyau(&p->to, v))
  1164  			return 4;
  1165  		return 3;
  1166  	case ADUFFZERO:
  1167  		// R0 is zero, used by DUFFZERO, cannot be substituted.
  1168  		// R1 is ptr to memory, used and set, cannot be substituted.
  1169  		if(v->type == D_REG) {
  1170  			if(v->reg == REGALLOC_R0)
  1171  				return 1;
  1172  			if(v->reg == REGALLOC_R0+1)
  1173  				return 2;
  1174  		}
  1175  		return 0;
  1176  	case ADUFFCOPY:
  1177  		// R0 is scratch, set by DUFFCOPY, cannot be substituted.
  1178  		// R1, R2 areptr to src, dst, used and set, cannot be substituted.
  1179  		if(v->type == D_REG) {
  1180  			if(v->reg == REGALLOC_R0)
  1181  				return 3;
  1182  			if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2)
  1183  				return 2;
  1184  		}
  1185  		return 0;
  1186  			
  1187  	case ATEXT:	/* funny */
  1188  		if(v->type == D_REG)
  1189  			if(v->reg == REGARG)
  1190  				return 3;
  1191  		return 0;
  1192  
  1193  	case APCDATA:
  1194  	case AFUNCDATA:
  1195  	case AVARDEF:
  1196  	case AVARKILL:
  1197  		return 0;
  1198  	}
  1199  }
  1200  
  1201  /*
  1202   * direct reference,
  1203   * could be set/use depending on
  1204   * semantics
  1205   */
  1206  static int
  1207  copyas(Adr *a, Adr *v)
  1208  {
  1209  
  1210  	if(regtyp(v)) {
  1211  		if(a->type == v->type)
  1212  		if(a->reg == v->reg)
  1213  			return 1;
  1214  	} else
  1215  	if(v->type == D_CONST) {		/* for constprop */
  1216  		if(a->type == v->type)
  1217  		if(a->name == v->name)
  1218  		if(a->sym == v->sym)
  1219  		if(a->reg == v->reg)
  1220  		if(a->offset == v->offset)
  1221  			return 1;
  1222  	}
  1223  	return 0;
  1224  }
  1225  
  1226  int
  1227  sameaddr(Adr *a, Adr *v)
  1228  {
  1229  	if(a->type != v->type)
  1230  		return 0;
  1231  	if(regtyp(v) && a->reg == v->reg)
  1232  		return 1;
  1233  	if(v->type == D_AUTO || v->type == D_PARAM) {
  1234  		if(v->offset == a->offset)
  1235  			return 1;
  1236  	}
  1237  	return 0;
  1238  }
  1239  
  1240  /*
  1241   * either direct or indirect
  1242   */
  1243  static int
  1244  copyau(Adr *a, Adr *v)
  1245  {
  1246  
  1247  	if(copyas(a, v))
  1248  		return 1;
  1249  	if(v->type == D_REG) {
  1250  		if(a->type == D_CONST && a->reg != NREG) {
  1251  			if(a->reg == v->reg)
  1252  				return 1;
  1253  		} else
  1254  		if(a->type == D_OREG) {
  1255  			if(a->reg == v->reg)
  1256  				return 1;
  1257  		} else
  1258  		if(a->type == D_REGREG || a->type == D_REGREG2) {
  1259  			if(a->reg == v->reg)
  1260  				return 1;
  1261  			if(a->offset == v->reg)
  1262  				return 1;
  1263  		} else
  1264  		if(a->type == D_SHIFT) {
  1265  			if((a->offset&0xf) == v->reg)
  1266  				return 1;
  1267  			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
  1268  				return 1;
  1269  		}
  1270  	}
  1271  	return 0;
  1272  }
  1273  
  1274  static int
  1275  a2type(Prog *p)
  1276  {
  1277  	if(p->reg == NREG)
  1278  		return D_NONE;
  1279  
  1280  	switch(p->as) {
  1281  	default:
  1282  		fatal("a2type: unhandled %P", p);
  1283  
  1284  	case AAND:
  1285  	case AEOR:
  1286  	case ASUB:
  1287  	case ARSB:
  1288  	case AADD:
  1289  	case AADC:
  1290  	case ASBC:
  1291  	case ARSC:
  1292  	case ATST:
  1293  	case ATEQ:
  1294  	case ACMP:
  1295  	case ACMN:
  1296  	case AORR:
  1297  	case ABIC:
  1298  	case AMVN:
  1299  	case ASRL:
  1300  	case ASRA:
  1301  	case ASLL:
  1302  	case AMULU:
  1303  	case ADIVU:
  1304  	case AMUL:
  1305  	case ADIV:
  1306  	case AMOD:
  1307  	case AMODU:
  1308  	case AMULA:
  1309  	case AMULL:
  1310  	case AMULAL:
  1311  	case AMULLU:
  1312  	case AMULALU:
  1313  	case AMULWT:
  1314  	case AMULWB:
  1315  	case AMULAWT:
  1316  	case AMULAWB:
  1317  		return D_REG;
  1318  
  1319  	case ACMPF:
  1320  	case ACMPD:
  1321  	case AADDF:
  1322  	case AADDD:
  1323  	case ASUBF:
  1324  	case ASUBD:
  1325  	case AMULF:
  1326  	case AMULD:
  1327  	case ADIVF:
  1328  	case ADIVD:
  1329  	case ASQRTF:
  1330  	case ASQRTD:
  1331  	case AABSF:
  1332  	case AABSD:
  1333  		return D_FREG;
  1334  	}
  1335  }
  1336  
  1337  /*
  1338   * compare v to the center
  1339   * register in p (p->reg)
  1340   */
  1341  static int
  1342  copyau1(Prog *p, Adr *v)
  1343  {
  1344  	if(v->type == D_REG && v->reg == NREG)
  1345  		return 0;
  1346  	return p->reg == v->reg && a2type(p) == v->type;
  1347  }
  1348  
  1349  /*
  1350   * substitute s for v in a
  1351   * return failure to substitute
  1352   */
  1353  static int
  1354  copysub(Adr *a, Adr *v, Adr *s, int f)
  1355  {
  1356  
  1357  	if(f)
  1358  	if(copyau(a, v)) {
  1359  		if(a->type == D_SHIFT) {
  1360  			if((a->offset&0xf) == v->reg)
  1361  				a->offset = (a->offset&~0xf)|s->reg;
  1362  			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
  1363  				a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
  1364  		} else
  1365  		if(a->type == D_REGREG || a->type == D_REGREG2) {
  1366  			if(a->offset == v->reg)
  1367  				a->offset = s->reg;
  1368  			if(a->reg == v->reg)
  1369  				a->reg = s->reg;
  1370  		} else
  1371  			a->reg = s->reg;
  1372  	}
  1373  	return 0;
  1374  }
  1375  
  1376  static int
  1377  copysub1(Prog *p1, Adr *v, Adr *s, int f)
  1378  {
  1379  
  1380  	if(f)
  1381  	if(copyau1(p1, v))
  1382  		p1->reg = s->reg;
  1383  	return 0;
  1384  }
  1385  
  1386  struct {
  1387  	int opcode;
  1388  	int notopcode;
  1389  	int scond;
  1390  	int notscond;
  1391  } predinfo[]  = {
  1392  	{ ABEQ,	ABNE,	0x0,	0x1, },
  1393  	{ ABNE,	ABEQ,	0x1,	0x0, },
  1394  	{ ABCS,	ABCC,	0x2,	0x3, },
  1395  	{ ABHS,	ABLO,	0x2,	0x3, },
  1396  	{ ABCC,	ABCS,	0x3,	0x2, },
  1397  	{ ABLO,	ABHS,	0x3,	0x2, },
  1398  	{ ABMI,	ABPL,	0x4,	0x5, },
  1399  	{ ABPL,	ABMI,	0x5,	0x4, },
  1400  	{ ABVS,	ABVC,	0x6,	0x7, },
  1401  	{ ABVC,	ABVS,	0x7,	0x6, },
  1402  	{ ABHI,	ABLS,	0x8,	0x9, },
  1403  	{ ABLS,	ABHI,	0x9,	0x8, },
  1404  	{ ABGE,	ABLT,	0xA,	0xB, },
  1405  	{ ABLT,	ABGE,	0xB,	0xA, },
  1406  	{ ABGT,	ABLE,	0xC,	0xD, },
  1407  	{ ABLE,	ABGT,	0xD,	0xC, },
  1408  };
  1409  
  1410  typedef struct {
  1411  	Flow *start;
  1412  	Flow *last;
  1413  	Flow *end;
  1414  	int len;
  1415  } Joininfo;
  1416  
  1417  enum {
  1418  	Join,
  1419  	Split,
  1420  	End,
  1421  	Branch,
  1422  	Setcond,
  1423  	Toolong
  1424  };
  1425  
  1426  enum {
  1427  	Falsecond,
  1428  	Truecond,
  1429  	Delbranch,
  1430  	Keepbranch
  1431  };
  1432  
  1433  static int
  1434  isbranch(Prog *p)
  1435  {
  1436  	return (ABEQ <= p->as) && (p->as <= ABLE);
  1437  }
  1438  
  1439  static int
  1440  predicable(Prog *p)
  1441  {
  1442  	switch(p->as) {
  1443  	case ANOP:
  1444  	case AXXX:
  1445  	case ADATA:
  1446  	case AGLOBL:
  1447  	case AGOK:
  1448  	case AHISTORY:
  1449  	case ANAME:
  1450  	case ASIGNAME:
  1451  	case ATEXT:
  1452  	case AWORD:
  1453  	case ABCASE:
  1454  	case ACASE:
  1455  		return 0;
  1456  	}
  1457  	if(isbranch(p))
  1458  		return 0;
  1459  	return 1;
  1460  }
  1461  
  1462  /*
  1463   * Depends on an analysis of the encodings performed by 5l.
  1464   * These seem to be all of the opcodes that lead to the "S" bit
  1465   * being set in the instruction encodings.
  1466   *
  1467   * C_SBIT may also have been set explicitly in p->scond.
  1468   */
  1469  static int
  1470  modifiescpsr(Prog *p)
  1471  {
  1472  	switch(p->as) {
  1473  	case AMULLU:
  1474  	case AMULA:
  1475  	case AMULU:
  1476  	case ADIVU:
  1477  
  1478  	case ATEQ:
  1479  	case ACMN:
  1480  	case ATST:
  1481  	case ACMP:
  1482  	case AMUL:
  1483  	case ADIV:
  1484  	case AMOD:
  1485  	case AMODU:
  1486  	case ABL:
  1487  		return 1;
  1488  	}
  1489  	if(p->scond & C_SBIT)
  1490  		return 1;
  1491  	return 0;
  1492  }
  1493  
  1494  /*
  1495   * Find the maximal chain of instructions starting with r which could
  1496   * be executed conditionally
  1497   */
  1498  static int
  1499  joinsplit(Flow *r, Joininfo *j)
  1500  {
  1501  	j->start = r;
  1502  	j->last = r;
  1503  	j->len = 0;
  1504  	do {
  1505  		if (r->p2 && (r->p1 || r->p2->p2link)) {
  1506  			j->end = r;
  1507  			return Join;
  1508  		}
  1509  		if (r->s1 && r->s2) {
  1510  			j->end = r;
  1511  			return Split;
  1512  		}
  1513  		j->last = r;
  1514  		if (r->prog->as != ANOP)
  1515  			j->len++;
  1516  		if (!r->s1 && !r->s2) {
  1517  			j->end = r->link;
  1518  			return End;
  1519  		}
  1520  		if (r->s2) {
  1521  			j->end = r->s2;
  1522  			return Branch;
  1523  		}
  1524  		if (modifiescpsr(r->prog)) {
  1525  			j->end = r->s1;
  1526  			return Setcond;
  1527  		}
  1528  		r = r->s1;
  1529  	} while (j->len < 4);
  1530  	j->end = r;
  1531  	return Toolong;
  1532  }
  1533  
  1534  static Flow*
  1535  successor(Flow *r)
  1536  {
  1537  	if(r->s1)
  1538  		return r->s1;
  1539  	else
  1540  		return r->s2;
  1541  }
  1542  
  1543  static void
  1544  applypred(Flow *rstart, Joininfo *j, int cond, int branch)
  1545  {
  1546  	int pred;
  1547  	Flow *r;
  1548  
  1549  	if(j->len == 0)
  1550  		return;
  1551  	if(cond == Truecond)
  1552  		pred = predinfo[rstart->prog->as - ABEQ].scond;
  1553  	else
  1554  		pred = predinfo[rstart->prog->as - ABEQ].notscond;
  1555  
  1556  	for(r = j->start;; r = successor(r)) {
  1557  		if(r->prog->as == AB) {
  1558  			if(r != j->last || branch == Delbranch)
  1559  				excise(r);
  1560  			else {
  1561  				if(cond == Truecond)
  1562  					r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
  1563  				else
  1564  					r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
  1565  			}
  1566  		}
  1567  		else
  1568  		if(predicable(r->prog))
  1569  			r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
  1570  		if(r->s1 != r->link) {
  1571  			r->s1 = r->link;
  1572  			r->link->p1 = r;
  1573  		}
  1574  		if(r == j->last)
  1575  			break;
  1576  	}
  1577  }
  1578  
  1579  void
  1580  predicate(Graph *g)
  1581  {
  1582  	Flow *r;
  1583  	int t1, t2;
  1584  	Joininfo j1, j2;
  1585  
  1586  	for(r=g->start; r!=nil; r=r->link) {
  1587  		if (isbranch(r->prog)) {
  1588  			t1 = joinsplit(r->s1, &j1);
  1589  			t2 = joinsplit(r->s2, &j2);
  1590  			if(j1.last->link != j2.start)
  1591  				continue;
  1592  			if(j1.end == j2.end)
  1593  			if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
  1594  			   (t2 == Join && (t1 == Join || t1 == Setcond))) {
  1595  				applypred(r, &j1, Falsecond, Delbranch);
  1596  				applypred(r, &j2, Truecond, Delbranch);
  1597  				excise(r);
  1598  				continue;
  1599  			}
  1600  			if(t1 == End || t1 == Branch) {
  1601  				applypred(r, &j1, Falsecond, Keepbranch);
  1602  				excise(r);
  1603  				continue;
  1604  			}
  1605  		}
  1606  	}
  1607  }
  1608  
  1609  static int
  1610  isdconst(Addr *a)
  1611  {
  1612  	if(a->type == D_CONST && a->reg == NREG)
  1613  		return 1;
  1614  	return 0;
  1615  }
  1616  
  1617  int
  1618  stackaddr(Addr *a)
  1619  {
  1620  	return regtyp(a) && a->reg == REGSP;
  1621  }
  1622  
  1623  int
  1624  smallindir(Addr *a, Addr *reg)
  1625  {
  1626  	return reg->type == D_REG && a->type == D_OREG &&
  1627  		a->reg == reg->reg &&
  1628  		0 <= a->offset && a->offset < 4096;
  1629  }