github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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, *gmsym;
    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 && (p->as != AFUNCDATA && p->as != APCDATA)) {
   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 && (p->as != AFUNCDATA && p->as != APCDATA)) {
   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  	gmsym = S;
   241  	if(linkmode == LinkExternal)
   242  		gmsym = lookup("runtime.tlsgm", 0);
   243  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   244  		p = cursym->text;
   245  		if(p == P || p->link == P)
   246  		       continue;
   247  		autosize = p->to.offset + 4;
   248  		symgrow(cursym, cursym->size);
   249  	
   250  		bp = cursym->p;
   251  		for(p = p->link; p != P; p = p->link) {
   252  			pc = p->pc;
   253  			curp = p;
   254  			o = oplook(p);
   255  			asmout(p, o, out, gmsym);
   256  			for(i=0; i<o->size/4; i++) {
   257  				v = out[i];
   258  				*bp++ = v;
   259  				*bp++ = v>>8;
   260  				*bp++ = v>>16;
   261  				*bp++ = v>>24;
   262  			}
   263  		}
   264  	}
   265  	sect->vaddr = INITTEXT;
   266  	sect->len = c - INITTEXT;
   267  }
   268  
   269  /*
   270   * when the first reference to the literal pool threatens
   271   * to go out of range of a 12-bit PC-relative offset,
   272   * drop the pool now, and branch round it.
   273   * this happens only in extended basic blocks that exceed 4k.
   274   */
   275  int
   276  checkpool(Prog *p, int sz)
   277  {
   278  	if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
   279  		return flushpool(p, 1, 0);
   280  	else if(p->link == P)
   281  		return flushpool(p, 2, 0);
   282  	return 0;
   283  }
   284  
   285  int
   286  flushpool(Prog *p, int skip, int force)
   287  {
   288  	Prog *q;
   289  
   290  	if(blitrl) {
   291  		if(skip){
   292  			if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
   293  			q = prg();
   294  			q->as = AB;
   295  			q->to.type = D_BRANCH;
   296  			q->cond = p->link;
   297  			q->link = blitrl;
   298  			q->line = p->line;
   299  			blitrl = q;
   300  		}
   301  		else if(!force && (p->pc+pool.size-pool.start < 2048))
   302  			return 0;
   303  		elitrl->link = p->link;
   304  		p->link = blitrl;
   305  		// BUG(minux): how to correctly handle line number for constant pool entries?
   306  		// for now, we set line number to the last instruction preceding them at least
   307  		// this won't bloat the .debug_line tables
   308  		while(blitrl) {
   309  			blitrl->line = p->line;
   310  			blitrl = blitrl->link;
   311  		}
   312  		blitrl = 0;	/* BUG: should refer back to values until out-of-range */
   313  		elitrl = 0;
   314  		pool.size = 0;
   315  		pool.start = 0;
   316  		pool.extra = 0;
   317  		return 1;
   318  	}
   319  	return 0;
   320  }
   321  
   322  void
   323  addpool(Prog *p, Adr *a)
   324  {
   325  	Prog *q, t;
   326  	int c;
   327  
   328  	c = aclass(a);
   329  
   330  	t = zprg;
   331  	t.as = AWORD;
   332  
   333  	switch(c) {
   334  	default:
   335  		t.to = *a;
   336  		if(flag_shared && t.to.sym != S)
   337  			t.pcrel = p;
   338  		break;
   339  
   340  	case C_SROREG:
   341  	case C_LOREG:
   342  	case C_ROREG:
   343  	case C_FOREG:
   344  	case C_SOREG:
   345  	case C_HOREG:
   346  	case C_FAUTO:
   347  	case C_SAUTO:
   348  	case C_LAUTO:
   349  	case C_LACON:
   350  		t.to.type = D_CONST;
   351  		t.to.offset = instoffset;
   352  		break;
   353  	}
   354  
   355  	if(t.pcrel == P) {
   356  		for(q = blitrl; q != P; q = q->link)	/* could hash on t.t0.offset */
   357  			if(q->pcrel == P && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
   358  				p->cond = q;
   359  				return;
   360  			}
   361  	}
   362  
   363  	q = prg();
   364  	*q = t;
   365  	q->pc = pool.size;
   366  
   367  	if(blitrl == P) {
   368  		blitrl = q;
   369  		pool.start = p->pc;
   370  		q->align = 4;
   371  	} else
   372  		elitrl->link = q;
   373  	elitrl = q;
   374  	pool.size += 4;
   375  
   376  	p->cond = q;
   377  }
   378  
   379  void
   380  xdefine(char *p, int t, int32 v)
   381  {
   382  	Sym *s;
   383  
   384  	s = lookup(p, 0);
   385  	s->type = t;
   386  	s->value = v;
   387  	s->reachable = 1;
   388  	s->special = 1;
   389  }
   390  
   391  int32
   392  regoff(Adr *a)
   393  {
   394  
   395  	instoffset = 0;
   396  	aclass(a);
   397  	return instoffset;
   398  }
   399  
   400  int32
   401  immrot(uint32 v)
   402  {
   403  	int i;
   404  
   405  	for(i=0; i<16; i++) {
   406  		if((v & ~0xff) == 0)
   407  			return (i<<8) | v | (1<<25);
   408  		v = (v<<2) | (v>>30);
   409  	}
   410  	return 0;
   411  }
   412  
   413  int32
   414  immaddr(int32 v)
   415  {
   416  	if(v >= 0 && v <= 0xfff)
   417  		return (v & 0xfff) |
   418  			(1<<24) |	/* pre indexing */
   419  			(1<<23);	/* pre indexing, up */
   420  	if(v >= -0xfff && v < 0)
   421  		return (-v & 0xfff) |
   422  			(1<<24);	/* pre indexing */
   423  	return 0;
   424  }
   425  
   426  int
   427  immfloat(int32 v)
   428  {
   429  	return (v & 0xC03) == 0;	/* offset will fit in floating-point load/store */
   430  }
   431  
   432  int
   433  immhalf(int32 v)
   434  {
   435  	if(v >= 0 && v <= 0xff)
   436  		return v|
   437  			(1<<24)|	/* pre indexing */
   438  			(1<<23);	/* pre indexing, up */
   439  	if(v >= -0xff && v < 0)
   440  		return (-v & 0xff)|
   441  			(1<<24);	/* pre indexing */
   442  	return 0;
   443  }
   444  
   445  int32
   446  symaddr(Sym *s)
   447  {
   448  	if(!s->reachable)
   449  		diag("unreachable symbol in symaddr - %s", s->name);
   450  	return s->value;
   451  }
   452  
   453  int
   454  aclass(Adr *a)
   455  {
   456  	Sym *s;
   457  	int t;
   458  
   459  	switch(a->type) {
   460  	case D_NONE:
   461  		return C_NONE;
   462  
   463  	case D_REG:
   464  		return C_REG;
   465  
   466  	case D_REGREG:
   467  		return C_REGREG;
   468  
   469  	case D_REGREG2:
   470  		return C_REGREG2;
   471  
   472  	case D_SHIFT:
   473  		return C_SHIFT;
   474  
   475  	case D_FREG:
   476  		return C_FREG;
   477  
   478  	case D_FPCR:
   479  		return C_FCR;
   480  
   481  	case D_OREG:
   482  		switch(a->name) {
   483  		case D_EXTERN:
   484  		case D_STATIC:
   485  			if(a->sym == 0 || a->sym->name == 0) {
   486  				print("null sym external\n");
   487  				print("%D\n", a);
   488  				return C_GOK;
   489  			}
   490  			instoffset = 0;	// s.b. unused but just in case
   491  			return C_ADDR;
   492  
   493  		case D_AUTO:
   494  			instoffset = autosize + a->offset;
   495  			t = immaddr(instoffset);
   496  			if(t){
   497  				if(immhalf(instoffset))
   498  					return immfloat(t) ? C_HFAUTO : C_HAUTO;
   499  				if(immfloat(t))
   500  					return C_FAUTO;
   501  				return C_SAUTO;
   502  			}
   503  			return C_LAUTO;
   504  
   505  		case D_PARAM:
   506  			instoffset = autosize + a->offset + 4L;
   507  			t = immaddr(instoffset);
   508  			if(t){
   509  				if(immhalf(instoffset))
   510  					return immfloat(t) ? C_HFAUTO : C_HAUTO;
   511  				if(immfloat(t))
   512  					return C_FAUTO;
   513  				return C_SAUTO;
   514  			}
   515  			return C_LAUTO;
   516  		case D_NONE:
   517  			instoffset = a->offset;
   518  			t = immaddr(instoffset);
   519  			if(t) {
   520  				if(immhalf(instoffset))		 /* n.b. that it will also satisfy immrot */
   521  					return immfloat(t) ? C_HFOREG : C_HOREG;
   522  				if(immfloat(t))
   523  					return C_FOREG; /* n.b. that it will also satisfy immrot */
   524  				t = immrot(instoffset);
   525  				if(t)
   526  					return C_SROREG;
   527  				if(immhalf(instoffset))
   528  					return C_HOREG;
   529  				return C_SOREG;
   530  			}
   531  			t = immrot(instoffset);
   532  			if(t)
   533  				return C_ROREG;
   534  			return C_LOREG;
   535  		}
   536  		return C_GOK;
   537  
   538  	case D_PSR:
   539  		return C_PSR;
   540  
   541  	case D_OCONST:
   542  		switch(a->name) {
   543  		case D_EXTERN:
   544  		case D_STATIC:
   545  			instoffset = 0;	// s.b. unused but just in case
   546  			return C_ADDR;
   547  		}
   548  		return C_GOK;
   549  
   550  	case D_FCONST:
   551  		if(chipzero(&a->ieee) >= 0)
   552  			return C_ZFCON;
   553  		if(chipfloat(&a->ieee) >= 0)
   554  			return C_SFCON;
   555  		return C_LFCON;
   556  
   557  	case D_CONST:
   558  	case D_CONST2:
   559  		switch(a->name) {
   560  
   561  		case D_NONE:
   562  			instoffset = a->offset;
   563  			if(a->reg != NREG)
   564  				goto aconsize;
   565  
   566  			t = immrot(instoffset);
   567  			if(t)
   568  				return C_RCON;
   569  			t = immrot(~instoffset);
   570  			if(t)
   571  				return C_NCON;
   572  			return C_LCON;
   573  
   574  		case D_EXTERN:
   575  		case D_STATIC:
   576  			s = a->sym;
   577  			if(s == S)
   578  				break;
   579  			instoffset = 0;	// s.b. unused but just in case
   580  			return C_LCONADDR;
   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 AMOVBS:
   817  		case AMOVBU:
   818  		case AMOVH:
   819  		case AMOVHS:
   820  		case AMOVHU:
   821  			break;
   822  		case ASWPW:
   823  			oprange[ASWPBU] = oprange[r];
   824  			break;
   825  		case AB:
   826  		case ABL:
   827  		case ABX:
   828  		case ABXRET:
   829  		case ASWI:
   830  		case AWORD:
   831  		case AMOVM:
   832  		case ARFE:
   833  		case ATEXT:
   834  		case AUSEFIELD:
   835  		case ACASE:
   836  		case ABCASE:
   837  		case ATYPE:
   838  			break;
   839  		case AADDF:
   840  			oprange[AADDD] = oprange[r];
   841  			oprange[ASUBF] = oprange[r];
   842  			oprange[ASUBD] = oprange[r];
   843  			oprange[AMULF] = oprange[r];
   844  			oprange[AMULD] = oprange[r];
   845  			oprange[ADIVF] = oprange[r];
   846  			oprange[ADIVD] = oprange[r];
   847  			oprange[ASQRTF] = oprange[r];
   848  			oprange[ASQRTD] = oprange[r];
   849  			oprange[AMOVFD] = oprange[r];
   850  			oprange[AMOVDF] = oprange[r];
   851  			oprange[AABSF] = oprange[r];
   852  			oprange[AABSD] = oprange[r];
   853  			break;
   854  
   855  		case ACMPF:
   856  			oprange[ACMPD] = oprange[r];
   857  			break;
   858  
   859  		case AMOVF:
   860  			oprange[AMOVD] = oprange[r];
   861  			break;
   862  
   863  		case AMOVFW:
   864  			oprange[AMOVDW] = oprange[r];
   865  			break;
   866  
   867  		case AMOVWF:
   868  			oprange[AMOVWD] = oprange[r];
   869  			break;
   870  
   871  		case AMULL:
   872  			oprange[AMULAL] = oprange[r];
   873  			oprange[AMULLU] = oprange[r];
   874  			oprange[AMULALU] = oprange[r];
   875  			break;
   876  
   877  		case AMULWT:
   878  			oprange[AMULWB] = oprange[r];
   879  			break;
   880  
   881  		case AMULAWT:
   882  			oprange[AMULAWB] = oprange[r];
   883  			break;
   884  
   885  		case AMULA:
   886  		case ALDREX:
   887  		case ASTREX:
   888  		case ALDREXD:
   889  		case ASTREXD:
   890  		case ATST:
   891  		case APLD:
   892  		case AUNDEF:
   893  		case ACLZ:
   894  		case AFUNCDATA:
   895  		case APCDATA:
   896  			break;
   897  		}
   898  	}
   899  }
   900  
   901  /*
   902  void
   903  buildrep(int x, int as)
   904  {
   905  	Opcross *p;
   906  	Optab *e, *s, *o;
   907  	int a1, a2, a3, n;
   908  
   909  	if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
   910  		diag("assumptions fail in buildrep");
   911  		errorexit();
   912  	}
   913  	repop[as] = x;
   914  	p = (opcross + x);
   915  	s = oprange[as].start;
   916  	e = oprange[as].stop;
   917  	for(o=e-1; o>=s; o--) {
   918  		n = o-optab;
   919  		for(a2=0; a2<2; a2++) {
   920  			if(a2) {
   921  				if(o->a2 == C_NONE)
   922  					continue;
   923  			} else
   924  				if(o->a2 != C_NONE)
   925  					continue;
   926  			for(a1=0; a1<32; a1++) {
   927  				if(!xcmp[a1][o->a1])
   928  					continue;
   929  				for(a3=0; a3<32; a3++)
   930  					if(xcmp[a3][o->a3])
   931  						(*p)[a1][a2][a3] = n;
   932  			}
   933  		}
   934  	}
   935  	oprange[as].start = 0;
   936  }
   937  */