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