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