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