github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/8g/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  #define	REGEXT	0
    37  
    38  static void	conprop(Flow *r);
    39  static void	elimshortmov(Graph*);
    40  static int	subprop(Flow*);
    41  static int	copyprop(Graph*, Flow*);
    42  static int	copy1(Adr*, Adr*, Flow*, int);
    43  static int	copyas(Adr*, Adr*);
    44  static int	copyau(Adr*, Adr*);
    45  static int	copysub(Adr*, Adr*, Adr*, int);
    46  
    47  static uint32	gactive;
    48  
    49  // do we need the carry bit
    50  static int
    51  needc(Prog *p)
    52  {
    53  	ProgInfo info;
    54  
    55  	while(p != P) {
    56  		proginfo(&info, p);
    57  		if(info.flags & UseCarry)
    58  			return 1;
    59  		if(info.flags & (SetCarry|KillCarry))
    60  			return 0;
    61  		p = p->link;
    62  	}
    63  	return 0;
    64  }
    65  
    66  static Flow*
    67  rnops(Flow *r)
    68  {
    69  	Prog *p;
    70  	Flow *r1;
    71  
    72  	if(r != nil)
    73  	for(;;) {
    74  		p = r->prog;
    75  		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
    76  			break;
    77  		r1 = uniqs(r);
    78  		if(r1 == nil)
    79  			break;
    80  		r = r1;
    81  	}
    82  	return r;
    83  }
    84  
    85  void
    86  peep(Prog *firstp)
    87  {
    88  	Flow *r, *r1;
    89  	Graph *g;
    90  	Prog *p, *p1;
    91  	int t;
    92  
    93  	g = flowstart(firstp, sizeof(Flow));
    94  	if(g == nil)
    95  		return;
    96  	gactive = 0;
    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  			if(regtyp(&p->to))
   110  			if(p->from.sym != nil)
   111  			if(p->from.index == D_NONE || p->from.index == D_CONST)
   112  				conprop(r);
   113  			break;
   114  
   115  		case AMOVB:
   116  		case AMOVW:
   117  		case AMOVL:
   118  		case AMOVSS:
   119  		case AMOVSD:
   120  			if(regtyp(&p->to))
   121  			if(p->from.type == D_CONST)
   122  				conprop(r);
   123  			break;
   124  		}
   125  	}
   126  
   127  loop1:
   128  	if(debug['P'] && debug['v'])
   129  		dumpit("loop1", g->start, 0);
   130  
   131  	t = 0;
   132  	for(r=g->start; r!=nil; r=r->link) {
   133  		p = r->prog;
   134  		switch(p->as) {
   135  		case AMOVL:
   136  		case AMOVSS:
   137  		case AMOVSD:
   138  			if(regtyp(&p->to))
   139  			if(regtyp(&p->from)) {
   140  				if(copyprop(g, r)) {
   141  					excise(r);
   142  					t++;
   143  				} else
   144  				if(subprop(r) && copyprop(g, r)) {
   145  					excise(r);
   146  					t++;
   147  				}
   148  			}
   149  			break;
   150  
   151  		case AMOVBLZX:
   152  		case AMOVWLZX:
   153  		case AMOVBLSX:
   154  		case AMOVWLSX:
   155  			if(regtyp(&p->to)) {
   156  				r1 = rnops(uniqs(r));
   157  				if(r1 != nil) {
   158  					p1 = r1->prog;
   159  					if(p->as == p1->as && p->to.type == p1->from.type){
   160  						p1->as = AMOVL;
   161  						t++;
   162  					}
   163  				}
   164  			}
   165  			break;
   166  
   167  		case AADDL:
   168  		case AADDW:
   169  			if(p->from.type != D_CONST || needc(p->link))
   170  				break;
   171  			if(p->from.offset == -1){
   172  				if(p->as == AADDL)
   173  					p->as = ADECL;
   174  				else
   175  					p->as = ADECW;
   176  				p->from = zprog.from;
   177  				break;
   178  			}
   179  			if(p->from.offset == 1){
   180  				if(p->as == AADDL)
   181  					p->as = AINCL;
   182  				else
   183  					p->as = AINCW;
   184  				p->from = zprog.from;
   185  				break;
   186  			}
   187  			break;
   188  
   189  		case ASUBL:
   190  		case ASUBW:
   191  			if(p->from.type != D_CONST || needc(p->link))
   192  				break;
   193  			if(p->from.offset == -1) {
   194  				if(p->as == ASUBL)
   195  					p->as = AINCL;
   196  				else
   197  					p->as = AINCW;
   198  				p->from = zprog.from;
   199  				break;
   200  			}
   201  			if(p->from.offset == 1){
   202  				if(p->as == ASUBL)
   203  					p->as = ADECL;
   204  				else
   205  					p->as = ADECW;
   206  				p->from = zprog.from;
   207  				break;
   208  			}
   209  			break;
   210  		}
   211  	}
   212  	if(t)
   213  		goto loop1;
   214  
   215  	// MOVSD removal.
   216  	// We never use packed registers, so a MOVSD between registers
   217  	// can be replaced by MOVAPD, which moves the pair of float64s
   218  	// instead of just the lower one.  We only use the lower one, but
   219  	// the processor can do better if we do moves using both.
   220  	for(r=g->start; r!=nil; r=r->link) {
   221  		p = r->prog;
   222  		if(p->as == AMOVSD)
   223  		if(regtyp(&p->from))
   224  		if(regtyp(&p->to))
   225  			p->as = AMOVAPD;
   226  	}
   227  	
   228  	flowend(g);
   229  }
   230  
   231  void
   232  excise(Flow *r)
   233  {
   234  	Prog *p;
   235  
   236  	p = r->prog;
   237  	if(debug['P'] && debug['v'])
   238  		print("%P ===delete===\n", p);
   239  
   240  	p->as = ANOP;
   241  	p->from = zprog.from;
   242  	p->to = zprog.to;
   243  
   244  	ostats.ndelmov++;
   245  }
   246  
   247  int
   248  regtyp(Adr *a)
   249  {
   250  	int t;
   251  
   252  	t = a->type;
   253  	if(t >= D_AX && t <= D_DI)
   254  		return 1;
   255  	if(t >= D_X0 && t <= D_X7)
   256  		return 1;
   257  	return 0;
   258  }
   259  
   260  // movb elimination.
   261  // movb is simulated by the linker
   262  // when a register other than ax, bx, cx, dx
   263  // is used, so rewrite to other instructions
   264  // when possible.  a movb into a register
   265  // can smash the entire 64-bit register without
   266  // causing any trouble.
   267  static void
   268  elimshortmov(Graph *g)
   269  {
   270  	Prog *p;
   271  	Flow *r;
   272  
   273  	for(r=g->start; r!=nil; r=r->link) {
   274  		p = r->prog;
   275  		if(regtyp(&p->to)) {
   276  			switch(p->as) {
   277  			case AINCB:
   278  			case AINCW:
   279  				p->as = AINCL;
   280  				break;
   281  			case ADECB:
   282  			case ADECW:
   283  				p->as = ADECL;
   284  				break;
   285  			case ANEGB:
   286  			case ANEGW:
   287  				p->as = ANEGL;
   288  				break;
   289  			case ANOTB:
   290  			case ANOTW:
   291  				p->as = ANOTL;
   292  				break;
   293  			}
   294  			if(regtyp(&p->from) || p->from.type == D_CONST) {
   295  				// move or artihmetic into partial register.
   296  				// from another register or constant can be movl.
   297  				// we don't switch to 32-bit arithmetic if it can
   298  				// change how the carry bit is set (and the carry bit is needed).
   299  				switch(p->as) {
   300  				case AMOVB:
   301  				case AMOVW:
   302  					p->as = AMOVL;
   303  					break;
   304  				case AADDB:
   305  				case AADDW:
   306  					if(!needc(p->link))
   307  						p->as = AADDL;
   308  					break;
   309  				case ASUBB:
   310  				case ASUBW:
   311  					if(!needc(p->link))
   312  						p->as = ASUBL;
   313  					break;
   314  				case AMULB:
   315  				case AMULW:
   316  					p->as = AMULL;
   317  					break;
   318  				case AIMULB:
   319  				case AIMULW:
   320  					p->as = AIMULL;
   321  					break;
   322  				case AANDB:
   323  				case AANDW:
   324  					p->as = AANDL;
   325  					break;
   326  				case AORB:
   327  				case AORW:
   328  					p->as = AORL;
   329  					break;
   330  				case AXORB:
   331  				case AXORW:
   332  					p->as = AXORL;
   333  					break;
   334  				case ASHLB:
   335  				case ASHLW:
   336  					p->as = ASHLL;
   337  					break;
   338  				}
   339  			} else {
   340  				// explicit zero extension
   341  				switch(p->as) {
   342  				case AMOVB:
   343  					p->as = AMOVBLZX;
   344  					break;
   345  				case AMOVW:
   346  					p->as = AMOVWLZX;
   347  					break;
   348  				}
   349  			}
   350  		}
   351  	}
   352  }
   353  
   354  /*
   355   * the idea is to substitute
   356   * one register for another
   357   * from one MOV to another
   358   *	MOV	a, R0
   359   *	ADD	b, R0	/ no use of R1
   360   *	MOV	R0, R1
   361   * would be converted to
   362   *	MOV	a, R1
   363   *	ADD	b, R1
   364   *	MOV	R1, R0
   365   * hopefully, then the former or latter MOV
   366   * will be eliminated by copy propagation.
   367   */
   368  static int
   369  subprop(Flow *r0)
   370  {
   371  	Prog *p;
   372  	Adr *v1, *v2;
   373  	Flow *r;
   374  	int t;
   375  	ProgInfo info;
   376  
   377  	p = r0->prog;
   378  	v1 = &p->from;
   379  	if(!regtyp(v1))
   380  		return 0;
   381  	v2 = &p->to;
   382  	if(!regtyp(v2))
   383  		return 0;
   384  	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
   385  		if(debug['P'] && debug['v'])
   386  			print("\t? %P\n", r->prog);
   387  		if(uniqs(r) == nil)
   388  			break;
   389  		p = r->prog;
   390  		if(p->as == AVARDEF || p->as == AVARKILL)
   391  			continue;
   392  		proginfo(&info, p);
   393  		if(info.flags & Call)
   394  			return 0;
   395  
   396  		if(info.reguse | info.regset)
   397  			return 0;
   398  
   399  		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
   400  			goto gotit;
   401  
   402  		if(copyau(&p->from, v2) || copyau(&p->to, v2))
   403  			break;
   404  		if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0))
   405  			break;
   406  	}
   407  	return 0;
   408  
   409  gotit:
   410  	copysub(&p->to, v1, v2, 1);
   411  	if(debug['P']) {
   412  		print("gotit: %D->%D\n%P", v1, v2, r->prog);
   413  		if(p->from.type == v2->type)
   414  			print(" excise");
   415  		print("\n");
   416  	}
   417  	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
   418  		p = r->prog;
   419  		copysub(&p->from, v1, v2, 1);
   420  		copysub(&p->to, v1, v2, 1);
   421  		if(debug['P'])
   422  			print("%P\n", r->prog);
   423  	}
   424  	t = v1->type;
   425  	v1->type = v2->type;
   426  	v2->type = t;
   427  	if(debug['P'])
   428  		print("%P last\n", r->prog);
   429  	return 1;
   430  }
   431  
   432  /*
   433   * The idea is to remove redundant copies.
   434   *	v1->v2	F=0
   435   *	(use v2	s/v2/v1/)*
   436   *	set v1	F=1
   437   *	use v2	return fail
   438   *	-----------------
   439   *	v1->v2	F=0
   440   *	(use v2	s/v2/v1/)*
   441   *	set v1	F=1
   442   *	set v2	return success
   443   */
   444  static int
   445  copyprop(Graph *g, Flow *r0)
   446  {
   447  	Prog *p;
   448  	Adr *v1, *v2;
   449  
   450  	USED(g);
   451  	p = r0->prog;
   452  	v1 = &p->from;
   453  	v2 = &p->to;
   454  	if(copyas(v1, v2))
   455  		return 1;
   456  	gactive++;
   457  	return copy1(v1, v2, r0->s1, 0);
   458  }
   459  
   460  static int
   461  copy1(Adr *v1, Adr *v2, Flow *r, int f)
   462  {
   463  	int t;
   464  	Prog *p;
   465  
   466  	if(r->active == gactive) {
   467  		if(debug['P'])
   468  			print("act set; return 1\n");
   469  		return 1;
   470  	}
   471  	r->active = gactive;
   472  	if(debug['P'])
   473  		print("copy %D->%D f=%d\n", v1, v2, f);
   474  	for(; r != nil; r = r->s1) {
   475  		p = r->prog;
   476  		if(debug['P'])
   477  			print("%P", p);
   478  		if(!f && uniqp(r) == nil) {
   479  			f = 1;
   480  			if(debug['P'])
   481  				print("; merge; f=%d", f);
   482  		}
   483  		t = copyu(p, v2, nil);
   484  		switch(t) {
   485  		case 2:	/* rar, can't split */
   486  			if(debug['P'])
   487  				print("; %D rar; return 0\n", v2);
   488  			return 0;
   489  
   490  		case 3:	/* set */
   491  			if(debug['P'])
   492  				print("; %D set; return 1\n", v2);
   493  			return 1;
   494  
   495  		case 1:	/* used, substitute */
   496  		case 4:	/* use and set */
   497  			if(f) {
   498  				if(!debug['P'])
   499  					return 0;
   500  				if(t == 4)
   501  					print("; %D used+set and f=%d; return 0\n", v2, f);
   502  				else
   503  					print("; %D used and f=%d; return 0\n", v2, f);
   504  				return 0;
   505  			}
   506  			if(copyu(p, v2, v1)) {
   507  				if(debug['P'])
   508  					print("; sub fail; return 0\n");
   509  				return 0;
   510  			}
   511  			if(debug['P'])
   512  				print("; sub %D/%D", v2, v1);
   513  			if(t == 4) {
   514  				if(debug['P'])
   515  					print("; %D used+set; return 1\n", v2);
   516  				return 1;
   517  			}
   518  			break;
   519  		}
   520  		if(!f) {
   521  			t = copyu(p, v1, nil);
   522  			if(!f && (t == 2 || t == 3 || t == 4)) {
   523  				f = 1;
   524  				if(debug['P'])
   525  					print("; %D set and !f; f=%d", v1, f);
   526  			}
   527  		}
   528  		if(debug['P'])
   529  			print("\n");
   530  		if(r->s2)
   531  			if(!copy1(v1, v2, r->s2, f))
   532  				return 0;
   533  	}
   534  	return 1;
   535  }
   536  
   537  /*
   538   * return
   539   * 1 if v only used (and substitute),
   540   * 2 if read-alter-rewrite
   541   * 3 if set
   542   * 4 if set and used
   543   * 0 otherwise (not touched)
   544   */
   545  int
   546  copyu(Prog *p, Adr *v, Adr *s)
   547  {
   548  	ProgInfo info;
   549  
   550  	switch(p->as) {
   551  	case AJMP:
   552  		if(s != nil) {
   553  			if(copysub(&p->to, v, s, 1))
   554  				return 1;
   555  			return 0;
   556  		}
   557  		if(copyau(&p->to, v))
   558  			return 1;
   559  		return 0;
   560  
   561  	case ARET:
   562  		if(s != nil)
   563  			return 1;
   564  		return 3;
   565  
   566  	case ACALL:
   567  		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
   568  			return 2;
   569  		if(REGARG >= 0 && v->type == (uchar)REGARG)
   570  			return 2;
   571  		if(v->type == p->from.type)
   572  			return 2;
   573  
   574  		if(s != nil) {
   575  			if(copysub(&p->to, v, s, 1))
   576  				return 1;
   577  			return 0;
   578  		}
   579  		if(copyau(&p->to, v))
   580  			return 4;
   581  		return 3;
   582  
   583  	case ATEXT:
   584  		if(REGARG >= 0 && v->type == (uchar)REGARG)
   585  			return 3;
   586  		return 0;
   587  	}
   588  
   589  	if(p->as == AVARDEF || p->as == AVARKILL)
   590  		return 0;
   591  	proginfo(&info, p);
   592  
   593  	if((info.reguse|info.regset) & RtoB(v->type))
   594  		return 2;
   595  		
   596  	if(info.flags & LeftAddr)
   597  		if(copyas(&p->from, v))
   598  			return 2;
   599  
   600  	if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
   601  		if(copyas(&p->to, v))
   602  			return 2;
   603  	
   604  	if(info.flags & RightWrite) {
   605  		if(copyas(&p->to, v)) {
   606  			if(s != nil)
   607  				return copysub(&p->from, v, s, 1);
   608  			if(copyau(&p->from, v))
   609  				return 4;
   610  			return 3;
   611  		}
   612  	}
   613  	
   614  	if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
   615  		if(s != nil) {
   616  			if(copysub(&p->from, v, s, 1))
   617  				return 1;
   618  			return copysub(&p->to, v, s, 1);
   619  		}
   620  		if(copyau(&p->from, v))
   621  			return 1;
   622  		if(copyau(&p->to, v))
   623  			return 1;
   624  	}
   625  
   626  	return 0;
   627  }
   628  
   629  /*
   630   * direct reference,
   631   * could be set/use depending on
   632   * semantics
   633   */
   634  static int
   635  copyas(Adr *a, Adr *v)
   636  {
   637  	if(a->type != v->type)
   638  		return 0;
   639  	if(regtyp(v))
   640  		return 1;
   641  	if(v->type == D_AUTO || v->type == D_PARAM)
   642  		if(v->offset == a->offset)
   643  			return 1;
   644  	return 0;
   645  }
   646  
   647  int
   648  sameaddr(Addr *a, Addr *v)
   649  {
   650  	if(a->type != v->type)
   651  		return 0;
   652  	if(regtyp(v))
   653  		return 1;
   654  	if(v->type == D_AUTO || v->type == D_PARAM)
   655  		if(v->offset == a->offset)
   656  			return 1;
   657  	return 0;
   658  }
   659  
   660  /*
   661   * either direct or indirect
   662   */
   663  static int
   664  copyau(Adr *a, Adr *v)
   665  {
   666  
   667  	if(copyas(a, v))
   668  		return 1;
   669  	if(regtyp(v)) {
   670  		if(a->type-D_INDIR == v->type)
   671  			return 1;
   672  		if(a->index == v->type)
   673  			return 1;
   674  	}
   675  	return 0;
   676  }
   677  
   678  /*
   679   * substitute s for v in a
   680   * return failure to substitute
   681   */
   682  static int
   683  copysub(Adr *a, Adr *v, Adr *s, int f)
   684  {
   685  	int t;
   686  
   687  	if(copyas(a, v)) {
   688  		t = s->type;
   689  		if(t >= D_AX && t <= D_DI || t >= D_X0 && t <= D_X7) {
   690  			if(f)
   691  				a->type = t;
   692  		}
   693  		return 0;
   694  	}
   695  	if(regtyp(v)) {
   696  		t = v->type;
   697  		if(a->type == t+D_INDIR) {
   698  			if((s->type == D_BP) && a->index != D_NONE)
   699  				return 1;	/* can't use BP-base with index */
   700  			if(f)
   701  				a->type = s->type+D_INDIR;
   702  //			return 0;
   703  		}
   704  		if(a->index == t) {
   705  			if(f)
   706  				a->index = s->type;
   707  			return 0;
   708  		}
   709  		return 0;
   710  	}
   711  	return 0;
   712  }
   713  
   714  static void
   715  conprop(Flow *r0)
   716  {
   717  	Flow *r;
   718  	Prog *p, *p0;
   719  	int t;
   720  	Adr *v0;
   721  
   722  	p0 = r0->prog;
   723  	v0 = &p0->to;
   724  	r = r0;
   725  
   726  loop:
   727  	r = uniqs(r);
   728  	if(r == nil || r == r0)
   729  		return;
   730  	if(uniqp(r) == nil)
   731  		return;
   732  
   733  	p = r->prog;
   734  	t = copyu(p, v0, nil);
   735  	switch(t) {
   736  	case 0:	// miss
   737  	case 1:	// use
   738  		goto loop;
   739  
   740  	case 2:	// rar
   741  	case 4:	// use and set
   742  		break;
   743  
   744  	case 3:	// set
   745  		if(p->as == p0->as)
   746  		if(p->from.type == p0->from.type)
   747  		if(p->from.node == p0->from.node)
   748  		if(p->from.offset == p0->from.offset)
   749  		if(p->from.scale == p0->from.scale)
   750  		if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval)
   751  		if(p->from.index == p0->from.index) {
   752  			excise(r);
   753  			goto loop;
   754  		}
   755  		break;
   756  	}
   757  }
   758  
   759  int
   760  smallindir(Addr *a, Addr *reg)
   761  {
   762  	return regtyp(reg) &&
   763  		a->type == D_INDIR + reg->type &&
   764  		a->index == D_NONE &&
   765  		0 <= a->offset && a->offset < 4096;
   766  }
   767  
   768  int
   769  stackaddr(Addr *a)
   770  {
   771  	return regtyp(a) && a->type == D_SP;
   772  }