github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 != S)
   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  		proginfo(&info, p);
   391  		if(info.flags & Call)
   392  			return 0;
   393  
   394  		if(info.reguse | info.regset)
   395  			return 0;
   396  
   397  		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
   398  			goto gotit;
   399  
   400  		if(copyau(&p->from, v2) || copyau(&p->to, v2))
   401  			break;
   402  		if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0))
   403  			break;
   404  	}
   405  	return 0;
   406  
   407  gotit:
   408  	copysub(&p->to, v1, v2, 1);
   409  	if(debug['P']) {
   410  		print("gotit: %D->%D\n%P", v1, v2, r->prog);
   411  		if(p->from.type == v2->type)
   412  			print(" excise");
   413  		print("\n");
   414  	}
   415  	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
   416  		p = r->prog;
   417  		copysub(&p->from, v1, v2, 1);
   418  		copysub(&p->to, v1, v2, 1);
   419  		if(debug['P'])
   420  			print("%P\n", r->prog);
   421  	}
   422  	t = v1->type;
   423  	v1->type = v2->type;
   424  	v2->type = t;
   425  	if(debug['P'])
   426  		print("%P last\n", r->prog);
   427  	return 1;
   428  }
   429  
   430  /*
   431   * The idea is to remove redundant copies.
   432   *	v1->v2	F=0
   433   *	(use v2	s/v2/v1/)*
   434   *	set v1	F=1
   435   *	use v2	return fail
   436   *	-----------------
   437   *	v1->v2	F=0
   438   *	(use v2	s/v2/v1/)*
   439   *	set v1	F=1
   440   *	set v2	return success
   441   */
   442  static int
   443  copyprop(Graph *g, Flow *r0)
   444  {
   445  	Prog *p;
   446  	Adr *v1, *v2;
   447  
   448  	USED(g);
   449  	p = r0->prog;
   450  	v1 = &p->from;
   451  	v2 = &p->to;
   452  	if(copyas(v1, v2))
   453  		return 1;
   454  	gactive++;
   455  	return copy1(v1, v2, r0->s1, 0);
   456  }
   457  
   458  static int
   459  copy1(Adr *v1, Adr *v2, Flow *r, int f)
   460  {
   461  	int t;
   462  	Prog *p;
   463  
   464  	if(r->active == gactive) {
   465  		if(debug['P'])
   466  			print("act set; return 1\n");
   467  		return 1;
   468  	}
   469  	r->active = gactive;
   470  	if(debug['P'])
   471  		print("copy %D->%D f=%d\n", v1, v2, f);
   472  	for(; r != nil; r = r->s1) {
   473  		p = r->prog;
   474  		if(debug['P'])
   475  			print("%P", p);
   476  		if(!f && uniqp(r) == nil) {
   477  			f = 1;
   478  			if(debug['P'])
   479  				print("; merge; f=%d", f);
   480  		}
   481  		t = copyu(p, v2, A);
   482  		switch(t) {
   483  		case 2:	/* rar, can't split */
   484  			if(debug['P'])
   485  				print("; %D rar; return 0\n", v2);
   486  			return 0;
   487  
   488  		case 3:	/* set */
   489  			if(debug['P'])
   490  				print("; %D set; return 1\n", v2);
   491  			return 1;
   492  
   493  		case 1:	/* used, substitute */
   494  		case 4:	/* use and set */
   495  			if(f) {
   496  				if(!debug['P'])
   497  					return 0;
   498  				if(t == 4)
   499  					print("; %D used+set and f=%d; return 0\n", v2, f);
   500  				else
   501  					print("; %D used and f=%d; return 0\n", v2, f);
   502  				return 0;
   503  			}
   504  			if(copyu(p, v2, v1)) {
   505  				if(debug['P'])
   506  					print("; sub fail; return 0\n");
   507  				return 0;
   508  			}
   509  			if(debug['P'])
   510  				print("; sub %D/%D", v2, v1);
   511  			if(t == 4) {
   512  				if(debug['P'])
   513  					print("; %D used+set; return 1\n", v2);
   514  				return 1;
   515  			}
   516  			break;
   517  		}
   518  		if(!f) {
   519  			t = copyu(p, v1, A);
   520  			if(!f && (t == 2 || t == 3 || t == 4)) {
   521  				f = 1;
   522  				if(debug['P'])
   523  					print("; %D set and !f; f=%d", v1, f);
   524  			}
   525  		}
   526  		if(debug['P'])
   527  			print("\n");
   528  		if(r->s2)
   529  			if(!copy1(v1, v2, r->s2, f))
   530  				return 0;
   531  	}
   532  	return 1;
   533  }
   534  
   535  /*
   536   * return
   537   * 1 if v only used (and substitute),
   538   * 2 if read-alter-rewrite
   539   * 3 if set
   540   * 4 if set and used
   541   * 0 otherwise (not touched)
   542   */
   543  int
   544  copyu(Prog *p, Adr *v, Adr *s)
   545  {
   546  	ProgInfo info;
   547  
   548  	switch(p->as) {
   549  	case AJMP:
   550  		if(s != A) {
   551  			if(copysub(&p->to, v, s, 1))
   552  				return 1;
   553  			return 0;
   554  		}
   555  		if(copyau(&p->to, v))
   556  			return 1;
   557  		return 0;
   558  
   559  	case ARET:
   560  		if(s != A)
   561  			return 1;
   562  		return 3;
   563  
   564  	case ACALL:
   565  		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
   566  			return 2;
   567  		if(REGARG >= 0 && v->type == (uchar)REGARG)
   568  			return 2;
   569  		if(v->type == p->from.type)
   570  			return 2;
   571  
   572  		if(s != A) {
   573  			if(copysub(&p->to, v, s, 1))
   574  				return 1;
   575  			return 0;
   576  		}
   577  		if(copyau(&p->to, v))
   578  			return 4;
   579  		return 3;
   580  
   581  	case ATEXT:
   582  		if(REGARG >= 0 && v->type == (uchar)REGARG)
   583  			return 3;
   584  		return 0;
   585  	}
   586  
   587  	proginfo(&info, p);
   588  
   589  	if((info.reguse|info.regset) & RtoB(v->type))
   590  		return 2;
   591  		
   592  	if(info.flags & LeftAddr)
   593  		if(copyas(&p->from, v))
   594  			return 2;
   595  
   596  	if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
   597  		if(copyas(&p->to, v))
   598  			return 2;
   599  	
   600  	if(info.flags & RightWrite) {
   601  		if(copyas(&p->to, v)) {
   602  			if(s != A)
   603  				return copysub(&p->from, v, s, 1);
   604  			if(copyau(&p->from, v))
   605  				return 4;
   606  			return 3;
   607  		}
   608  	}
   609  	
   610  	if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
   611  		if(s != A) {
   612  			if(copysub(&p->from, v, s, 1))
   613  				return 1;
   614  			return copysub(&p->to, v, s, 1);
   615  		}
   616  		if(copyau(&p->from, v))
   617  			return 1;
   618  		if(copyau(&p->to, v))
   619  			return 1;
   620  	}
   621  
   622  	return 0;
   623  }
   624  
   625  /*
   626   * direct reference,
   627   * could be set/use depending on
   628   * semantics
   629   */
   630  static int
   631  copyas(Adr *a, Adr *v)
   632  {
   633  	if(a->type != v->type)
   634  		return 0;
   635  	if(regtyp(v))
   636  		return 1;
   637  	if(v->type == D_AUTO || v->type == D_PARAM)
   638  		if(v->offset == a->offset)
   639  			return 1;
   640  	return 0;
   641  }
   642  
   643  int
   644  sameaddr(Addr *a, Addr *v)
   645  {
   646  	if(a->type != v->type)
   647  		return 0;
   648  	if(regtyp(v))
   649  		return 1;
   650  	if(v->type == D_AUTO || v->type == D_PARAM)
   651  		if(v->offset == a->offset)
   652  			return 1;
   653  	return 0;
   654  }
   655  
   656  /*
   657   * either direct or indirect
   658   */
   659  static int
   660  copyau(Adr *a, Adr *v)
   661  {
   662  
   663  	if(copyas(a, v))
   664  		return 1;
   665  	if(regtyp(v)) {
   666  		if(a->type-D_INDIR == v->type)
   667  			return 1;
   668  		if(a->index == v->type)
   669  			return 1;
   670  	}
   671  	return 0;
   672  }
   673  
   674  /*
   675   * substitute s for v in a
   676   * return failure to substitute
   677   */
   678  static int
   679  copysub(Adr *a, Adr *v, Adr *s, int f)
   680  {
   681  	int t;
   682  
   683  	if(copyas(a, v)) {
   684  		t = s->type;
   685  		if(t >= D_AX && t <= D_DI || t >= D_X0 && t <= D_X7) {
   686  			if(f)
   687  				a->type = t;
   688  		}
   689  		return 0;
   690  	}
   691  	if(regtyp(v)) {
   692  		t = v->type;
   693  		if(a->type == t+D_INDIR) {
   694  			if((s->type == D_BP) && a->index != D_NONE)
   695  				return 1;	/* can't use BP-base with index */
   696  			if(f)
   697  				a->type = s->type+D_INDIR;
   698  //			return 0;
   699  		}
   700  		if(a->index == t) {
   701  			if(f)
   702  				a->index = s->type;
   703  			return 0;
   704  		}
   705  		return 0;
   706  	}
   707  	return 0;
   708  }
   709  
   710  static void
   711  conprop(Flow *r0)
   712  {
   713  	Flow *r;
   714  	Prog *p, *p0;
   715  	int t;
   716  	Adr *v0;
   717  
   718  	p0 = r0->prog;
   719  	v0 = &p0->to;
   720  	r = r0;
   721  
   722  loop:
   723  	r = uniqs(r);
   724  	if(r == nil || r == r0)
   725  		return;
   726  	if(uniqp(r) == nil)
   727  		return;
   728  
   729  	p = r->prog;
   730  	t = copyu(p, v0, A);
   731  	switch(t) {
   732  	case 0:	// miss
   733  	case 1:	// use
   734  		goto loop;
   735  
   736  	case 2:	// rar
   737  	case 4:	// use and set
   738  		break;
   739  
   740  	case 3:	// set
   741  		if(p->as == p0->as)
   742  		if(p->from.type == p0->from.type)
   743  		if(p->from.node == p0->from.node)
   744  		if(p->from.offset == p0->from.offset)
   745  		if(p->from.scale == p0->from.scale)
   746  		if(p->from.u.vval == p0->from.u.vval)
   747  		if(p->from.index == p0->from.index) {
   748  			excise(r);
   749  			goto loop;
   750  		}
   751  		break;
   752  	}
   753  }
   754  
   755  int
   756  smallindir(Addr *a, Addr *reg)
   757  {
   758  	return regtyp(reg) &&
   759  		a->type == D_INDIR + reg->type &&
   760  		a->index == D_NONE &&
   761  		0 <= a->offset && a->offset < 4096;
   762  }
   763  
   764  int
   765  stackaddr(Addr *a)
   766  {
   767  	return regtyp(a) && a->type == D_SP;
   768  }