The Go Programming Language

Text file src/cmd/5l/noop.c

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

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.