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

     1  // Inferno utils/5l/span.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5l/span.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  // Instruction layout.
    32  
    33  #include	"l.h"
    34  #include	"../ld/lib.h"
    35  
    36  static struct {
    37  	uint32	start;
    38  	uint32	size;
    39  	uint32	extra;
    40  } pool;
    41  
    42  int	checkpool(Prog*, int);
    43  int 	flushpool(Prog*, int, int);
    44  
    45  int
    46  isbranch(Prog *p)
    47  {
    48  	int as = p->as;
    49  	return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX;
    50  }
    51  
    52  static int
    53  scan(Prog *op, Prog *p, int c)
    54  {
    55  	Prog *q;
    56  
    57  	for(q = op->link; q != p && q != P; q = q->link){
    58  		q->pc = c;
    59  		c += oplook(q)->size;
    60  		nocache(q);
    61  	}
    62  	return c;
    63  }
    64  
    65  /* size of a case statement including jump table */
    66  static int32
    67  casesz(Prog *p)
    68  {
    69  	int jt = 0;
    70  	int32 n = 0;
    71  	Optab *o;
    72  
    73  	for( ; p != P; p = p->link){
    74  		if(p->as == ABCASE)
    75  			jt = 1;
    76  		else if(jt)
    77  			break;
    78  		o = oplook(p);
    79  		n += o->size;
    80  	}
    81  	return n;
    82  }
    83  
    84  void
    85  span(void)
    86  {
    87  	Prog *p, *op;
    88  	Optab *o;
    89  	int m, bflag, i, v;
    90  	int32 c, otxt, out[6];
    91  	Section *sect;
    92  	uchar *bp;
    93  	Sym *sub;
    94  
    95  	if(debug['v'])
    96  		Bprint(&bso, "%5.2f span\n", cputime());
    97  	Bflush(&bso);
    98  
    99  	sect = addsection(&segtext, ".text", 05);
   100  	lookup("text", 0)->sect = sect;
   101  	lookup("etext", 0)->sect = sect;
   102  
   103  	bflag = 0;
   104  	c = INITTEXT;
   105  	otxt = c;
   106  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   107  		cursym->sect = sect;
   108  		p = cursym->text;
   109  		if(p == P || p->link == P) { // handle external functions and ELF section symbols
   110  			if(cursym->type & SSUB)
   111  				continue;
   112  			if(cursym->align != 0)
   113  				c = rnd(c, cursym->align);
   114  			cursym->value = 0;
   115  			for(sub = cursym; sub != S; sub = sub->sub) {
   116  				sub->value += c;
   117  				for(p = sub->text; p != P; p = p->link)
   118  					p->pc += sub->value;
   119  			}
   120  			c += cursym->size;
   121  			continue;
   122  		}
   123  		p->pc = c;
   124  		cursym->value = c;
   125  
   126  		autosize = p->to.offset + 4;
   127  		if(p->from.sym != S)
   128  			p->from.sym->value = c;
   129  		/* need passes to resolve branches */
   130  		if(c-otxt >= 1L<<17)
   131  			bflag = 1;
   132  		otxt = c;
   133  
   134  		for(op = p, p = p->link; p != P; op = p, p = p->link) {
   135  			curp = p;
   136  			p->pc = c;
   137  			o = oplook(p);
   138  			m = o->size;
   139  			// must check literal pool here in case p generates many instructions
   140  			if(blitrl){
   141  				if(checkpool(op, p->as == ACASE ? casesz(p) : m))
   142  					c = p->pc = scan(op, p, c);
   143  			}
   144  			if(m == 0) {
   145  				diag("zero-width instruction\n%P", p);
   146  				continue;
   147  			}
   148  			switch(o->flag & (LFROM|LTO|LPOOL)) {
   149  			case LFROM:
   150  				addpool(p, &p->from);
   151  				break;
   152  			case LTO:
   153  				addpool(p, &p->to);
   154  				break;
   155  			case LPOOL:
   156  				if ((p->scond&C_SCOND) == 14)
   157  					flushpool(p, 0, 0);
   158  				break;
   159  			}
   160  			if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
   161  				flushpool(p, 0, 0);
   162  			c += m;
   163  		}
   164  		if(blitrl){
   165  			if(checkpool(op, 0))
   166  				c = scan(op, P, c);
   167  		}
   168  		cursym->size = c - cursym->value;
   169  	}
   170  
   171  	/*
   172  	 * if any procedure is large enough to
   173  	 * generate a large SBRA branch, then
   174  	 * generate extra passes putting branches
   175  	 * around jmps to fix. this is rare.
   176  	 */
   177  	while(bflag) {
   178  		if(debug['v'])
   179  			Bprint(&bso, "%5.2f span1\n", cputime());
   180  		bflag = 0;
   181  		c = INITTEXT;
   182  		for(cursym = textp; cursym != nil; cursym = cursym->next) {
   183  			if(!cursym->text || !cursym->text->link)
   184  				continue;
   185  			cursym->value = c;
   186  			for(p = cursym->text; p != P; p = p->link) {
   187  				curp = p;
   188  				p->pc = c;
   189  				o = oplook(p);
   190  /* very large branches
   191  				if(o->type == 6 && p->cond) {
   192  					otxt = p->cond->pc - c;
   193  					if(otxt < 0)
   194  						otxt = -otxt;
   195  					if(otxt >= (1L<<17) - 10) {
   196  						q = prg();
   197  						q->link = p->link;
   198  						p->link = q;
   199  						q->as = AB;
   200  						q->to.type = D_BRANCH;
   201  						q->cond = p->cond;
   202  						p->cond = q;
   203  						q = prg();
   204  						q->link = p->link;
   205  						p->link = q;
   206  						q->as = AB;
   207  						q->to.type = D_BRANCH;
   208  						q->cond = q->link->link;
   209  						bflag = 1;
   210  					}
   211  				}
   212   */
   213  				m = o->size;
   214  				if(m == 0) {
   215  					if(p->as == ATEXT) {
   216  						autosize = p->to.offset + 4;
   217  						if(p->from.sym != S)
   218  							p->from.sym->value = c;
   219  						continue;
   220  					}
   221  					diag("zero-width instruction\n%P", p);
   222  					continue;
   223  				}
   224  				c += m;
   225  			}
   226  			cursym->size = c - cursym->value;
   227  		}
   228  	}
   229  
   230  	c = rnd(c, 8);
   231  	
   232  	/*
   233  	 * lay out the code.  all the pc-relative code references,
   234  	 * even cross-function, are resolved now;
   235  	 * only data references need to be relocated.
   236  	 * with more work we could leave cross-function
   237  	 * code references to be relocated too, and then
   238  	 * perhaps we'd be able to parallelize the span loop above.
   239  	 */
   240  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   241  		p = cursym->text;
   242  		if(p == P || p->link == P)
   243  		       continue;
   244  		autosize = p->to.offset + 4;
   245  		symgrow(cursym, cursym->size);
   246  	
   247  		bp = cursym->p;
   248  		for(p = p->link; p != P; p = p->link) {
   249  			pc = p->pc;
   250  			curp = p;
   251  			o = oplook(p);
   252  			asmout(p, o, out);
   253  			for(i=0; i<o->size/4; i++) {
   254  				v = out[i];
   255  				*bp++ = v;
   256  				*bp++ = v>>8;
   257  				*bp++ = v>>16;
   258  				*bp++ = v>>24;
   259  			}
   260  		}
   261  	}
   262  	sect->vaddr = INITTEXT;
   263  	sect->len = c - INITTEXT;
   264  }
   265  
   266  /*
   267   * when the first reference to the literal pool threatens
   268   * to go out of range of a 12-bit PC-relative offset,
   269   * drop the pool now, and branch round it.
   270   * this happens only in extended basic blocks that exceed 4k.
   271   */
   272  int
   273  checkpool(Prog *p, int sz)
   274  {
   275  	if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
   276  		return flushpool(p, 1, 0);
   277  	else if(p->link == P)
   278  		return flushpool(p, 2, 0);
   279  	return 0;
   280  }
   281  
   282  int
   283  flushpool(Prog *p, int skip, int force)
   284  {
   285  	Prog *q;
   286  
   287  	if(blitrl) {
   288  		if(skip){
   289  			if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
   290  			q = prg();
   291  			q->as = AB;
   292  			q->to.type = D_BRANCH;
   293  			q->cond = p->link;
   294  			q->link = blitrl;
   295  			q->line = p->line;
   296  			blitrl = q;
   297  		}
   298  		else if(!force && (p->pc+pool.size-pool.start < 2048))
   299  			return 0;
   300  		elitrl->link = p->link;
   301  		p->link = blitrl;
   302  		// BUG(minux): how to correctly handle line number for constant pool entries?
   303  		// for now, we set line number to the last instruction preceding them at least
   304  		// this won't bloat the .debug_line tables
   305  		while(blitrl) {
   306  			blitrl->line = p->line;
   307  			blitrl = blitrl->link;
   308  		}
   309  		blitrl = 0;	/* BUG: should refer back to values until out-of-range */
   310  		elitrl = 0;
   311  		pool.size = 0;
   312  		pool.start = 0;
   313  		pool.extra = 0;
   314  		return 1;
   315  	}
   316  	return 0;
   317  }
   318  
   319  void
   320  addpool(Prog *p, Adr *a)
   321  {
   322  	Prog *q, t;
   323  	int c;
   324  
   325  	c = aclass(a);
   326  
   327  	t = zprg;
   328  	t.as = AWORD;
   329  
   330  	switch(c) {
   331  	default:
   332  		t.to = *a;
   333  		if(flag_shared && t.to.sym != S)
   334  			t.pcrel = p;
   335  		break;
   336  
   337  	case C_SROREG:
   338  	case C_LOREG:
   339  	case C_ROREG:
   340  	case C_FOREG:
   341  	case C_SOREG:
   342  	case C_HOREG:
   343  	case C_FAUTO:
   344  	case C_SAUTO:
   345  	case C_LAUTO:
   346  	case C_LACON:
   347  		t.to.type = D_CONST;
   348  		t.to.offset = instoffset;
   349  		break;
   350  	}
   351  
   352  	if(t.pcrel == P) {
   353  		for(q = blitrl; q != P; q = q->link)	/* could hash on t.t0.offset */
   354  			if(q->pcrel == P && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
   355  				p->cond = q;
   356  				return;
   357  			}
   358  	}
   359  
   360  	q = prg();
   361  	*q = t;
   362  	q->pc = pool.size;
   363  
   364  	if(blitrl == P) {
   365  		blitrl = q;
   366  		pool.start = p->pc;
   367  		q->align = 4;
   368  	} else
   369  		elitrl->link = q;
   370  	elitrl = q;
   371  	pool.size += 4;
   372  
   373  	p->cond = q;
   374  }
   375  
   376  void
   377  xdefine(char *p, int t, int32 v)
   378  {
   379  	Sym *s;
   380  
   381  	s = lookup(p, 0);
   382  	s->type = t;
   383  	s->value = v;
   384  	s->reachable = 1;
   385  	s->special = 1;
   386  }
   387  
   388  int32
   389  regoff(Adr *a)
   390  {
   391  
   392  	instoffset = 0;
   393  	aclass(a);
   394  	return instoffset;
   395  }
   396  
   397  int32
   398  immrot(uint32 v)
   399  {
   400  	int i;
   401  
   402  	for(i=0; i<16; i++) {
   403  		if((v & ~0xff) == 0)
   404  			return (i<<8) | v | (1<<25);
   405  		v = (v<<2) | (v>>30);
   406  	}
   407  	return 0;
   408  }
   409  
   410  int32
   411  immaddr(int32 v)
   412  {
   413  	if(v >= 0 && v <= 0xfff)
   414  		return (v & 0xfff) |
   415  			(1<<24) |	/* pre indexing */
   416  			(1<<23);	/* pre indexing, up */
   417  	if(v >= -0xfff && v < 0)
   418  		return (-v & 0xfff) |
   419  			(1<<24);	/* pre indexing */
   420  	return 0;
   421  }
   422  
   423  int
   424  immfloat(int32 v)
   425  {
   426  	return (v & 0xC03) == 0;	/* offset will fit in floating-point load/store */
   427  }
   428  
   429  int
   430  immhalf(int32 v)
   431  {
   432  	if(v >= 0 && v <= 0xff)
   433  		return v|
   434  			(1<<24)|	/* pre indexing */
   435  			(1<<23);	/* pre indexing, up */
   436  	if(v >= -0xff && v < 0)
   437  		return (-v & 0xff)|
   438  			(1<<24);	/* pre indexing */
   439  	return 0;
   440  }
   441  
   442  int32
   443  symaddr(Sym *s)
   444  {
   445  	if(!s->reachable)
   446  		diag("unreachable symbol in symaddr - %s", s->name);
   447  	return s->value;
   448  }
   449  
   450  int
   451  aclass(Adr *a)
   452  {
   453  	Sym *s;
   454  	int t;
   455  
   456  	switch(a->type) {
   457  	case D_NONE:
   458  		return C_NONE;
   459  
   460  	case D_REG:
   461  		return C_REG;
   462  
   463  	case D_REGREG:
   464  		return C_REGREG;
   465  
   466  	case D_REGREG2:
   467  		return C_REGREG2;
   468  
   469  	case D_SHIFT:
   470  		return C_SHIFT;
   471  
   472  	case D_FREG:
   473  		return C_FREG;
   474  
   475  	case D_FPCR:
   476  		return C_FCR;
   477  
   478  	case D_OREG:
   479  		switch(a->name) {
   480  		case D_EXTERN:
   481  		case D_STATIC:
   482  			if(a->sym == 0 || a->sym->name == 0) {
   483  				print("null sym external\n");
   484  				print("%D\n", a);
   485  				return C_GOK;
   486  			}
   487  			instoffset = 0;	// s.b. unused but just in case
   488  			return C_ADDR;
   489  
   490  		case D_AUTO:
   491  			instoffset = autosize + a->offset;
   492  			t = immaddr(instoffset);
   493  			if(t){
   494  				if(immhalf(instoffset))
   495  					return immfloat(t) ? C_HFAUTO : C_HAUTO;
   496  				if(immfloat(t))
   497  					return C_FAUTO;
   498  				return C_SAUTO;
   499  			}
   500  			return C_LAUTO;
   501  
   502  		case D_PARAM:
   503  			instoffset = autosize + a->offset + 4L;
   504  			t = immaddr(instoffset);
   505  			if(t){
   506  				if(immhalf(instoffset))
   507  					return immfloat(t) ? C_HFAUTO : C_HAUTO;
   508  				if(immfloat(t))
   509  					return C_FAUTO;
   510  				return C_SAUTO;
   511  			}
   512  			return C_LAUTO;
   513  		case D_NONE:
   514  			instoffset = a->offset;
   515  			t = immaddr(instoffset);
   516  			if(t) {
   517  				if(immhalf(instoffset))		 /* n.b. that it will also satisfy immrot */
   518  					return immfloat(t) ? C_HFOREG : C_HOREG;
   519  				if(immfloat(t))
   520  					return C_FOREG; /* n.b. that it will also satisfy immrot */
   521  				t = immrot(instoffset);
   522  				if(t)
   523  					return C_SROREG;
   524  				if(immhalf(instoffset))
   525  					return C_HOREG;
   526  				return C_SOREG;
   527  			}
   528  			t = immrot(instoffset);
   529  			if(t)
   530  				return C_ROREG;
   531  			return C_LOREG;
   532  		}
   533  		return C_GOK;
   534  
   535  	case D_PSR:
   536  		return C_PSR;
   537  
   538  	case D_OCONST:
   539  		switch(a->name) {
   540  		case D_EXTERN:
   541  		case D_STATIC:
   542  			instoffset = 0;	// s.b. unused but just in case
   543  			return C_ADDR;
   544  		}
   545  		return C_GOK;
   546  
   547  	case D_FCONST:
   548  		if(chipzero(&a->ieee) >= 0)
   549  			return C_ZFCON;
   550  		if(chipfloat(&a->ieee) >= 0)
   551  			return C_SFCON;
   552  		return C_LFCON;
   553  
   554  	case D_CONST:
   555  	case D_CONST2:
   556  		switch(a->name) {
   557  
   558  		case D_NONE:
   559  			instoffset = a->offset;
   560  			if(a->reg != NREG)
   561  				goto aconsize;
   562  
   563  			t = immrot(instoffset);
   564  			if(t)
   565  				return C_RCON;
   566  			t = immrot(~instoffset);
   567  			if(t)
   568  				return C_NCON;
   569  			return C_LCON;
   570  
   571  		case D_EXTERN:
   572  		case D_STATIC:
   573  			s = a->sym;
   574  			if(s == S)
   575  				break;
   576  			instoffset = 0;	// s.b. unused but just in case
   577  			if(flag_shared)
   578  				return C_LCONADDR;
   579  			else
   580  				return C_LCON;
   581  
   582  		case D_AUTO:
   583  			instoffset = autosize + a->offset;
   584  			goto aconsize;
   585  
   586  		case D_PARAM:
   587  			instoffset = autosize + a->offset + 4L;
   588  		aconsize:
   589  			t = immrot(instoffset);
   590  			if(t)
   591  				return C_RACON;
   592  			return C_LACON;
   593  		}
   594  		return C_GOK;
   595  
   596  	case D_BRANCH:
   597  		return C_SBRA;
   598  	}
   599  	return C_GOK;
   600  }
   601  
   602  Optab*
   603  oplook(Prog *p)
   604  {
   605  	int a1, a2, a3, r;
   606  	char *c1, *c3;
   607  	Optab *o, *e;
   608  
   609  	a1 = p->optab;
   610  	if(a1)
   611  		return optab+(a1-1);
   612  	a1 = p->from.class;
   613  	if(a1 == 0) {
   614  		a1 = aclass(&p->from) + 1;
   615  		p->from.class = a1;
   616  	}
   617  	a1--;
   618  	a3 = p->to.class;
   619  	if(a3 == 0) {
   620  		a3 = aclass(&p->to) + 1;
   621  		p->to.class = a3;
   622  	}
   623  	a3--;
   624  	a2 = C_NONE;
   625  	if(p->reg != NREG)
   626  		a2 = C_REG;
   627  	r = p->as;
   628  	o = oprange[r].start;
   629  	if(o == 0) {
   630  		a1 = opcross[repop[r]][a1][a2][a3];
   631  		if(a1) {
   632  			p->optab = a1+1;
   633  			return optab+a1;
   634  		}
   635  		o = oprange[r].stop; /* just generate an error */
   636  	}
   637  	if(debug['O']) {
   638  		print("oplook %A %O %O %O\n",
   639  			(int)p->as, a1, a2, a3);
   640  		print("		%d %d\n", p->from.type, p->to.type);
   641  	}
   642  	e = oprange[r].stop;
   643  	c1 = xcmp[a1];
   644  	c3 = xcmp[a3];
   645  	for(; o<e; o++)
   646  		if(o->a2 == a2)
   647  		if(c1[o->a1])
   648  		if(c3[o->a3]) {
   649  			p->optab = (o-optab)+1;
   650  			return o;
   651  		}
   652  	diag("illegal combination %A %O %O %O, %d %d",
   653  		p->as, a1, a2, a3, p->from.type, p->to.type);
   654  	prasm(p);
   655  	if(o == 0)
   656  		o = optab;
   657  	return o;
   658  }
   659  
   660  int
   661  cmp(int a, int b)
   662  {
   663  
   664  	if(a == b)
   665  		return 1;
   666  	switch(a) {
   667  	case C_LCON:
   668  		if(b == C_RCON || b == C_NCON)
   669  			return 1;
   670  		break;
   671  	case C_LACON:
   672  		if(b == C_RACON)
   673  			return 1;
   674  		break;
   675  	case C_LFCON:
   676  		if(b == C_ZFCON || b == C_SFCON)
   677  			return 1;
   678  		break;
   679  
   680  	case C_HFAUTO:
   681  		return b == C_HAUTO || b == C_FAUTO;
   682  	case C_FAUTO:
   683  	case C_HAUTO:
   684  		return b == C_HFAUTO;
   685  	case C_SAUTO:
   686  		return cmp(C_HFAUTO, b);
   687  	case C_LAUTO:
   688  		return cmp(C_SAUTO, b);
   689  
   690  	case C_HFOREG:
   691  		return b == C_HOREG || b == C_FOREG;
   692  	case C_FOREG:
   693  	case C_HOREG:
   694  		return b == C_HFOREG;
   695  	case C_SROREG:
   696  		return cmp(C_SOREG, b) || cmp(C_ROREG, b);
   697  	case C_SOREG:
   698  	case C_ROREG:
   699  		return b == C_SROREG || cmp(C_HFOREG, b);
   700  	case C_LOREG:
   701  		return cmp(C_SROREG, b);
   702  
   703  	case C_LBRA:
   704  		if(b == C_SBRA)
   705  			return 1;
   706  		break;
   707  
   708  	case C_HREG:
   709  		return cmp(C_SP, b) || cmp(C_PC, b);
   710  
   711  	}
   712  	return 0;
   713  }
   714  
   715  int
   716  ocmp(const void *a1, const void *a2)
   717  {
   718  	Optab *p1, *p2;
   719  	int n;
   720  
   721  	p1 = (Optab*)a1;
   722  	p2 = (Optab*)a2;
   723  	n = p1->as - p2->as;
   724  	if(n)
   725  		return n;
   726  	n = p1->a1 - p2->a1;
   727  	if(n)
   728  		return n;
   729  	n = p1->a2 - p2->a2;
   730  	if(n)
   731  		return n;
   732  	n = p1->a3 - p2->a3;
   733  	if(n)
   734  		return n;
   735  	return 0;
   736  }
   737  
   738  void
   739  buildop(void)
   740  {
   741  	int i, n, r;
   742  
   743  	for(i=0; i<C_GOK; i++)
   744  		for(n=0; n<C_GOK; n++)
   745  			xcmp[i][n] = cmp(n, i);
   746  	for(n=0; optab[n].as != AXXX; n++) {
   747  		if((optab[n].flag & LPCREL) != 0) {
   748  			if(flag_shared)
   749  				optab[n].size += optab[n].pcrelsiz;
   750  			else
   751  				optab[n].flag &= ~LPCREL;
   752  		}
   753  	}
   754  	qsort(optab, n, sizeof(optab[0]), ocmp);
   755  	for(i=0; i<n; i++) {
   756  		r = optab[i].as;
   757  		oprange[r].start = optab+i;
   758  		while(optab[i].as == r)
   759  			i++;
   760  		oprange[r].stop = optab+i;
   761  		i--;
   762  
   763  		switch(r)
   764  		{
   765  		default:
   766  			diag("unknown op in build: %A", r);
   767  			errorexit();
   768  		case AADD:
   769  			oprange[AAND] = oprange[r];
   770  			oprange[AEOR] = oprange[r];
   771  			oprange[ASUB] = oprange[r];
   772  			oprange[ARSB] = oprange[r];
   773  			oprange[AADC] = oprange[r];
   774  			oprange[ASBC] = oprange[r];
   775  			oprange[ARSC] = oprange[r];
   776  			oprange[AORR] = oprange[r];
   777  			oprange[ABIC] = oprange[r];
   778  			break;
   779  		case ACMP:
   780  			oprange[ATEQ] = oprange[r];
   781  			oprange[ACMN] = oprange[r];
   782  			break;
   783  		case AMVN:
   784  			break;
   785  		case ABEQ:
   786  			oprange[ABNE] = oprange[r];
   787  			oprange[ABCS] = oprange[r];
   788  			oprange[ABHS] = oprange[r];
   789  			oprange[ABCC] = oprange[r];
   790  			oprange[ABLO] = oprange[r];
   791  			oprange[ABMI] = oprange[r];
   792  			oprange[ABPL] = oprange[r];
   793  			oprange[ABVS] = oprange[r];
   794  			oprange[ABVC] = oprange[r];
   795  			oprange[ABHI] = oprange[r];
   796  			oprange[ABLS] = oprange[r];
   797  			oprange[ABGE] = oprange[r];
   798  			oprange[ABLT] = oprange[r];
   799  			oprange[ABGT] = oprange[r];
   800  			oprange[ABLE] = oprange[r];
   801  			break;
   802  		case ASLL:
   803  			oprange[ASRL] = oprange[r];
   804  			oprange[ASRA] = oprange[r];
   805  			break;
   806  		case AMUL:
   807  			oprange[AMULU] = oprange[r];
   808  			break;
   809  		case ADIV:
   810  			oprange[AMOD] = oprange[r];
   811  			oprange[AMODU] = oprange[r];
   812  			oprange[ADIVU] = oprange[r];
   813  			break;
   814  		case AMOVW:
   815  		case AMOVB:
   816  		case AMOVBU:
   817  		case AMOVH:
   818  		case AMOVHU:
   819  			break;
   820  		case ASWPW:
   821  			oprange[ASWPBU] = oprange[r];
   822  			break;
   823  		case AB:
   824  		case ABL:
   825  		case ABX:
   826  		case ABXRET:
   827  		case ASWI:
   828  		case AWORD:
   829  		case AMOVM:
   830  		case ARFE:
   831  		case ATEXT:
   832  		case AUSEFIELD:
   833  		case ALOCALS:
   834  		case ACASE:
   835  		case ABCASE:
   836  		case ATYPE:
   837  			break;
   838  		case AADDF:
   839  			oprange[AADDD] = oprange[r];
   840  			oprange[ASUBF] = oprange[r];
   841  			oprange[ASUBD] = oprange[r];
   842  			oprange[AMULF] = oprange[r];
   843  			oprange[AMULD] = oprange[r];
   844  			oprange[ADIVF] = oprange[r];
   845  			oprange[ADIVD] = oprange[r];
   846  			oprange[ASQRTF] = oprange[r];
   847  			oprange[ASQRTD] = oprange[r];
   848  			oprange[AMOVFD] = oprange[r];
   849  			oprange[AMOVDF] = oprange[r];
   850  			oprange[AABSF] = oprange[r];
   851  			oprange[AABSD] = oprange[r];
   852  			break;
   853  
   854  		case ACMPF:
   855  			oprange[ACMPD] = oprange[r];
   856  			break;
   857  
   858  		case AMOVF:
   859  			oprange[AMOVD] = oprange[r];
   860  			break;
   861  
   862  		case AMOVFW:
   863  			oprange[AMOVDW] = oprange[r];
   864  			break;
   865  
   866  		case AMOVWF:
   867  			oprange[AMOVWD] = oprange[r];
   868  			break;
   869  
   870  		case AMULL:
   871  			oprange[AMULAL] = oprange[r];
   872  			oprange[AMULLU] = oprange[r];
   873  			oprange[AMULALU] = oprange[r];
   874  			break;
   875  
   876  		case AMULWT:
   877  			oprange[AMULWB] = oprange[r];
   878  			break;
   879  
   880  		case AMULAWT:
   881  			oprange[AMULAWB] = oprange[r];
   882  			break;
   883  
   884  		case AMULA:
   885  		case ALDREX:
   886  		case ASTREX:
   887  		case ALDREXD:
   888  		case ASTREXD:
   889  		case ATST:
   890  		case APLD:
   891  		case AUNDEF:
   892  		case ACLZ:
   893  			break;
   894  		}
   895  	}
   896  }
   897  
   898  /*
   899  void
   900  buildrep(int x, int as)
   901  {
   902  	Opcross *p;
   903  	Optab *e, *s, *o;
   904  	int a1, a2, a3, n;
   905  
   906  	if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
   907  		diag("assumptions fail in buildrep");
   908  		errorexit();
   909  	}
   910  	repop[as] = x;
   911  	p = (opcross + x);
   912  	s = oprange[as].start;
   913  	e = oprange[as].stop;
   914  	for(o=e-1; o>=s; o--) {
   915  		n = o-optab;
   916  		for(a2=0; a2<2; a2++) {
   917  			if(a2) {
   918  				if(o->a2 == C_NONE)
   919  					continue;
   920  			} else
   921  				if(o->a2 != C_NONE)
   922  					continue;
   923  			for(a1=0; a1<32; a1++) {
   924  				if(!xcmp[a1][o->a1])
   925  					continue;
   926  				for(a3=0; a3<32; a3++)
   927  					if(xcmp[a3][o->a3])
   928  						(*p)[a1][a2][a3] = n;
   929  			}
   930  		}
   931  	}
   932  	oprange[as].start = 0;
   933  }
   934  */