github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/5l/noop.c (about)

     1  // Inferno utils/5l/noop.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5l/noop.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  // Code transformations.
    32  
    33  #include	"l.h"
    34  #include	"../ld/lib.h"
    35  
    36  // see ../../runtime/proc.c:/StackGuard
    37  enum
    38  {
    39  	StackBig = 4096,
    40  	StackSmall = 128,
    41  };
    42  
    43  static	Sym*	sym_div;
    44  static	Sym*	sym_divu;
    45  static	Sym*	sym_mod;
    46  static	Sym*	sym_modu;
    47  
    48  static void
    49  linkcase(Prog *casep)
    50  {
    51  	Prog *p;
    52  
    53  	for(p = casep; p != P; p = p->link){
    54  		if(p->as == ABCASE) {
    55  			for(; p != P && p->as == ABCASE; p = p->link)
    56  				p->pcrel = casep;
    57  			break;
    58  		}
    59  	}
    60  }
    61  
    62  void
    63  noops(void)
    64  {
    65  	Prog *p, *q, *q1;
    66  	int o;
    67  	Prog *pmorestack;
    68  	Sym *symmorestack;
    69  
    70  	/*
    71  	 * find leaf subroutines
    72  	 * strip NOPs
    73  	 * expand RET
    74  	 * expand BECOME pseudo
    75  	 */
    76  
    77  	if(debug['v'])
    78  		Bprint(&bso, "%5.2f noops\n", cputime());
    79  	Bflush(&bso);
    80  
    81  	symmorestack = lookup("runtime.morestack", 0);
    82  	if(symmorestack->type != STEXT) {
    83  		diag("runtime·morestack not defined");
    84  		errorexit();
    85  	}
    86  	pmorestack = symmorestack->text;
    87  	pmorestack->reg |= NOSPLIT;
    88  
    89  	q = P;
    90  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
    91  		for(p = cursym->text; p != P; p = p->link) {
    92  			switch(p->as) {
    93  			case ACASE:
    94  				if(flag_shared)
    95  					linkcase(p);
    96  				break;
    97  
    98  			case ATEXT:
    99  				p->mark |= LEAF;
   100  				break;
   101  	
   102  			case ARET:
   103  				break;
   104  	
   105  			case ADIV:
   106  			case ADIVU:
   107  			case AMOD:
   108  			case AMODU:
   109  				q = p;
   110  				if(prog_div == P)
   111  					initdiv();
   112  				cursym->text->mark &= ~LEAF;
   113  				continue;
   114  	
   115  			case ANOP:
   116  				q1 = p->link;
   117  				q->link = q1;		/* q is non-nop */
   118  				if(q1 != P)
   119  					q1->mark |= p->mark;
   120  				continue;
   121  	
   122  			case ABL:
   123  			case ABX:
   124  				cursym->text->mark &= ~LEAF;
   125  	
   126  			case ABCASE:
   127  			case AB:
   128  	
   129  			case ABEQ:
   130  			case ABNE:
   131  			case ABCS:
   132  			case ABHS:
   133  			case ABCC:
   134  			case ABLO:
   135  			case ABMI:
   136  			case ABPL:
   137  			case ABVS:
   138  			case ABVC:
   139  			case ABHI:
   140  			case ABLS:
   141  			case ABGE:
   142  			case ABLT:
   143  			case ABGT:
   144  			case ABLE:
   145  				q1 = p->cond;
   146  				if(q1 != P) {
   147  					while(q1->as == ANOP) {
   148  						q1 = q1->link;
   149  						p->cond = q1;
   150  					}
   151  				}
   152  				break;
   153  			}
   154  			q = p;
   155  		}
   156  	}
   157  
   158  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   159  		for(p = cursym->text; p != P; p = p->link) {
   160  			o = p->as;
   161  			switch(o) {
   162  			case ATEXT:
   163  				autosize = p->to.offset + 4;
   164  				if(autosize <= 4)
   165  				if(cursym->text->mark & LEAF) {
   166  					p->to.offset = -4;
   167  					autosize = 0;
   168  				}
   169  	
   170  				if(!autosize && !(cursym->text->mark & LEAF)) {
   171  					if(debug['v'])
   172  						Bprint(&bso, "save suppressed in: %s\n",
   173  							cursym->name);
   174  					Bflush(&bso);
   175  					cursym->text->mark |= LEAF;
   176  				}
   177  				if(cursym->text->mark & LEAF) {
   178  					cursym->leaf = 1;
   179  					if(!autosize)
   180  						break;
   181  				}
   182  	
   183  				if(p->reg & NOSPLIT) {
   184  					q1 = prg();
   185  					q1->as = AMOVW;
   186  					q1->scond |= C_WBIT;
   187  					q1->line = p->line;
   188  					q1->from.type = D_REG;
   189  					q1->from.reg = REGLINK;
   190  					q1->to.type = D_OREG;
   191  					q1->to.offset = -autosize;
   192  					q1->to.reg = REGSP;
   193  					q1->spadj = autosize;
   194  					q1->link = p->link;
   195  					p->link = q1;
   196  				} else if (autosize < StackBig) {
   197  					// split stack check for small functions
   198  					// MOVW			g_stackguard(g), R1
   199  					// CMP			R1, $-autosize(SP)
   200  					// MOVW.LO		$autosize, R1
   201  					// MOVW.LO		$args, R2
   202  					// MOVW.LO		R14, R3
   203  					// BL.LO			runtime.morestack(SB) // modifies LR
   204  					// MOVW.W		R14,$-autosize(SP)
   205  	
   206  					// TODO(kaib): add more trampolines
   207  					// TODO(kaib): put stackguard in register
   208  					// TODO(kaib): add support for -K and underflow detection
   209  
   210  					// MOVW			g_stackguard(g), R1
   211  					p = appendp(p);
   212  					p->as = AMOVW;
   213  					p->from.type = D_OREG;
   214  					p->from.reg = REGG;
   215  					p->to.type = D_REG;
   216  					p->to.reg = 1;
   217  					
   218  					if(autosize < StackSmall) {	
   219  						// CMP			R1, SP
   220  						p = appendp(p);
   221  						p->as = ACMP;
   222  						p->from.type = D_REG;
   223  						p->from.reg = 1;
   224  						p->reg = REGSP;
   225  					} else {
   226  						// MOVW		$-autosize(SP), R2
   227  						// CMP	R1, R2
   228  						p = appendp(p);
   229  						p->as = AMOVW;
   230  						p->from.type = D_CONST;
   231  						p->from.reg = REGSP;
   232  						p->from.offset = -autosize;
   233  						p->to.type = D_REG;
   234  						p->to.reg = 2;
   235  						
   236  						p = appendp(p);
   237  						p->as = ACMP;
   238  						p->from.type = D_REG;
   239  						p->from.reg = 1;
   240  						p->reg = 2;
   241  					}
   242  
   243  					// MOVW.LO		$autosize, R1
   244  					p = appendp(p);
   245  					p->as = AMOVW;
   246  					p->scond = C_SCOND_LO;
   247  					p->from.type = D_CONST;
   248  					p->from.offset = autosize;
   249  					p->to.type = D_REG;
   250  					p->to.reg = 1;
   251  	
   252  					// MOVW.LO		$args, R2
   253  					p = appendp(p);
   254  					p->as = AMOVW;
   255  					p->scond = C_SCOND_LO;
   256  					p->from.type = D_CONST;
   257  					p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
   258  					p->to.type = D_REG;
   259  					p->to.reg = 2;
   260  	
   261  					// MOVW.LO	R14, R3
   262  					p = appendp(p);
   263  					p->as = AMOVW;
   264  					p->scond = C_SCOND_LO;
   265  					p->from.type = D_REG;
   266  					p->from.reg = REGLINK;
   267  					p->to.type = D_REG;
   268  					p->to.reg = 3;
   269  	
   270  					// BL.LO		runtime.morestack(SB) // modifies LR
   271  					p = appendp(p);
   272  					p->as = ABL;
   273  					p->scond = C_SCOND_LO;
   274  					p->to.type = D_BRANCH;
   275  					p->to.sym = symmorestack;
   276  					p->cond = pmorestack;
   277  	
   278  					// MOVW.W		R14,$-autosize(SP)
   279  					p = appendp(p);
   280  					p->as = AMOVW;
   281  					p->scond |= C_WBIT;
   282  					p->from.type = D_REG;
   283  					p->from.reg = REGLINK;
   284  					p->to.type = D_OREG;
   285  					p->to.offset = -autosize;
   286  					p->to.reg = REGSP;
   287  					p->spadj = autosize;
   288  				} else { // > StackBig
   289  					// MOVW		$autosize, R1
   290  					// MOVW		$args, R2
   291  					// MOVW		R14, R3
   292  					// BL			runtime.morestack(SB) // modifies LR
   293  					// MOVW.W		R14,$-autosize(SP)
   294  	
   295  					// MOVW		$autosize, R1
   296  					p = appendp(p);
   297  					p->as = AMOVW;
   298  					p->from.type = D_CONST;
   299  					p->from.offset = autosize;
   300  					p->to.type = D_REG;
   301  					p->to.reg = 1;
   302  	
   303  					// MOVW		$args, R2
   304  					// also need to store the extra 4 bytes.
   305  					p = appendp(p);
   306  					p->as = AMOVW;
   307  					p->from.type = D_CONST;
   308  					p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
   309  					p->to.type = D_REG;
   310  					p->to.reg = 2;
   311  	
   312  					// MOVW	R14, R3
   313  					p = appendp(p);
   314  					p->as = AMOVW;
   315  					p->from.type = D_REG;
   316  					p->from.reg = REGLINK;
   317  					p->to.type = D_REG;
   318  					p->to.reg = 3;
   319  	
   320  					// BL		runtime.morestack(SB) // modifies LR
   321  					p = appendp(p);
   322  					p->as = ABL;
   323  					p->to.type = D_BRANCH;
   324  					p->to.sym = symmorestack;
   325  					p->cond = pmorestack;
   326  	
   327  					// MOVW.W		R14,$-autosize(SP)
   328  					p = appendp(p);
   329  					p->as = AMOVW;
   330  					p->scond |= C_WBIT;
   331  					p->from.type = D_REG;
   332  					p->from.reg = REGLINK;
   333  					p->to.type = D_OREG;
   334  					p->to.offset = -autosize;
   335  					p->to.reg = REGSP;
   336  					p->spadj = autosize;
   337  				}
   338  				break;
   339  	
   340  			case ARET:
   341  				nocache(p);
   342  				if(cursym->text->mark & LEAF) {
   343  					if(!autosize) {
   344  						p->as = AB;
   345  						p->from = zprg.from;
   346  						p->to.type = D_OREG;
   347  						p->to.offset = 0;
   348  						p->to.reg = REGLINK;
   349  						break;
   350  					}
   351  				}
   352  				p->as = AMOVW;
   353  				p->scond |= C_PBIT;
   354  				p->from.type = D_OREG;
   355  				p->from.offset = autosize;
   356  				p->from.reg = REGSP;
   357  				p->to.type = D_REG;
   358  				p->to.reg = REGPC;
   359  				// If there are instructions following
   360  				// this ARET, they come from a branch
   361  				// with the same stackframe, so no spadj.
   362  				break;
   363  	
   364  			case AADD:
   365  				if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
   366  					p->spadj = -p->from.offset;
   367  				break;
   368  
   369  			case ASUB:
   370  				if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
   371  					p->spadj = p->from.offset;
   372  				break;
   373  
   374  			case ADIV:
   375  			case ADIVU:
   376  			case AMOD:
   377  			case AMODU:
   378  				if(debug['M'])
   379  					break;
   380  				if(p->from.type != D_REG)
   381  					break;
   382  				if(p->to.type != D_REG)
   383  					break;
   384  				q1 = p;
   385  	
   386  				/* MOV a,4(SP) */
   387  				p = appendp(p);
   388  				p->as = AMOVW;
   389  				p->line = q1->line;
   390  				p->from.type = D_REG;
   391  				p->from.reg = q1->from.reg;
   392  				p->to.type = D_OREG;
   393  				p->to.reg = REGSP;
   394  				p->to.offset = 4;
   395  	
   396  				/* MOV b,REGTMP */
   397  				p = appendp(p);
   398  				p->as = AMOVW;
   399  				p->line = q1->line;
   400  				p->from.type = D_REG;
   401  				p->from.reg = q1->reg;
   402  				if(q1->reg == NREG)
   403  					p->from.reg = q1->to.reg;
   404  				p->to.type = D_REG;
   405  				p->to.reg = REGTMP;
   406  				p->to.offset = 0;
   407  	
   408  				/* CALL appropriate */
   409  				p = appendp(p);
   410  				p->as = ABL;
   411  				p->line = q1->line;
   412  				p->to.type = D_BRANCH;
   413  				p->cond = p;
   414  				switch(o) {
   415  				case ADIV:
   416  					p->cond = prog_div;
   417  					p->to.sym = sym_div;
   418  					break;
   419  				case ADIVU:
   420  					p->cond = prog_divu;
   421  					p->to.sym = sym_divu;
   422  					break;
   423  				case AMOD:
   424  					p->cond = prog_mod;
   425  					p->to.sym = sym_mod;
   426  					break;
   427  				case AMODU:
   428  					p->cond = prog_modu;
   429  					p->to.sym = sym_modu;
   430  					break;
   431  				}
   432  	
   433  				/* MOV REGTMP, b */
   434  				p = appendp(p);
   435  				p->as = AMOVW;
   436  				p->line = q1->line;
   437  				p->from.type = D_REG;
   438  				p->from.reg = REGTMP;
   439  				p->from.offset = 0;
   440  				p->to.type = D_REG;
   441  				p->to.reg = q1->to.reg;
   442  	
   443  				/* ADD $8,SP */
   444  				p = appendp(p);
   445  				p->as = AADD;
   446  				p->line = q1->line;
   447  				p->from.type = D_CONST;
   448  				p->from.reg = NREG;
   449  				p->from.offset = 8;
   450  				p->reg = NREG;
   451  				p->to.type = D_REG;
   452  				p->to.reg = REGSP;
   453  				p->spadj = -8;
   454  	
   455  				/* SUB $8,SP */
   456  				q1->as = ASUB;
   457  				q1->from.type = D_CONST;
   458  				q1->from.offset = 8;
   459  				q1->from.reg = NREG;
   460  				q1->reg = NREG;
   461  				q1->to.type = D_REG;
   462  				q1->to.reg = REGSP;
   463  				q1->spadj = 8;
   464  	
   465  				break;
   466  			case AMOVW:
   467  				if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
   468  					p->spadj = -p->to.offset;
   469  				if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
   470  					p->spadj = -p->from.offset;
   471  				if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
   472  					p->spadj = -p->from.offset;
   473  				break;
   474  			}
   475  		}
   476  	}
   477  }
   478  
   479  static void
   480  sigdiv(char *n)
   481  {
   482  	Sym *s;
   483  
   484  	s = lookup(n, 0);
   485  	if(s->type == STEXT)
   486  		if(s->sig == 0)
   487  			s->sig = SIGNINTERN;
   488  }
   489  
   490  void
   491  divsig(void)
   492  {
   493  	sigdiv("_div");
   494  	sigdiv("_divu");
   495  	sigdiv("_mod");
   496  	sigdiv("_modu");
   497  }
   498  
   499  void
   500  initdiv(void)
   501  {
   502  	Sym *s2, *s3, *s4, *s5;
   503  
   504  	if(prog_div != P)
   505  		return;
   506  	sym_div = s2 = lookup("_div", 0);
   507  	sym_divu = s3 = lookup("_divu", 0);
   508  	sym_mod = s4 = lookup("_mod", 0);
   509  	sym_modu = s5 = lookup("_modu", 0);
   510  	prog_div = s2->text;
   511  	prog_divu = s3->text;
   512  	prog_mod = s4->text;
   513  	prog_modu = s5->text;
   514  	if(prog_div == P) {
   515  		diag("undefined: %s", s2->name);
   516  		prog_div = cursym->text;
   517  	}
   518  	if(prog_divu == P) {
   519  		diag("undefined: %s", s3->name);
   520  		prog_divu = cursym->text;
   521  	}
   522  	if(prog_mod == P) {
   523  		diag("undefined: %s", s4->name);
   524  		prog_mod = cursym->text;
   525  	}
   526  	if(prog_modu == P) {
   527  		diag("undefined: %s", s5->name);
   528  		prog_modu = cursym->text;
   529  	}
   530  }
   531  
   532  void
   533  nocache(Prog *p)
   534  {
   535  	p->optab = 0;
   536  	p->from.class = 0;
   537  	p->to.class = 0;
   538  }