1 #include "l.h"
2
3 void
span(void)4 span(void)
5 {
6 Prog *p, *q;
7 Sym *setext, *s;
8 Optab *o;
9 int m, bflag, i, spass;
10 long c, otxt, v;
11
12 if(debug['v'])
13 Bprint(&bso, "%5.2f span\n", cputime());
14 Bflush(&bso);
15
16 bflag = 0;
17 c = 0;
18 otxt = c;
19 for(p = firstp; p != P; p = p->link) {
20 if(p->as == ATEXT)
21 c = (c + 3) & ~3;
22 p->pc = c;
23 o = oplook(p);
24 m = o->size;
25 if(!debug['c']){
26 if(o->ctype && asmout(p, o, 2) == 2){
27 bflag = 1;
28 p->mark |= COMPR;
29 m = 2;
30 }
31 }
32 if(m == 0) {
33 if(p->as == ATEXT) {
34 curtext = p;
35 autosize = p->to.offset + ptrsize;
36 if(p->from.sym != S)
37 p->from.sym->value = c;
38 /* need passes to resolve branches */
39 if(c-otxt >= 0x1000)
40 bflag = 1;
41 otxt = c;
42 continue;
43 }
44 diag("zero-width instruction\n%P", p);
45 continue;
46 }
47 c += m;
48 }
49
50 /*
51 * Multi-pass expansion of span dependent instructions
52 * Bcond JAL C.Bcond C.JAL C.JMP
53 */
54 spass = 0;
55 while(bflag) {
56 if(debug['v'])
57 Bprint(&bso, "%5.2f span1\n", cputime());
58 bflag = 0;
59 spass ^= SPASS;
60 c = 0;
61 for(p = firstp; p != P; p = p->link) {
62 o = oplook(p);
63 m = o->size;
64 if(p->mark&COMPR)
65 m = 2;
66 if((o->type == 3 || o->type == 4) && p->cond) {
67 if((p->cond->mark&SPASS) == spass)
68 p->pc = c;
69 if(m == 2){
70 /*
71 * If instruction was compressed, check again in case
72 * branch range is now too large.
73 */
74 m = asmout(p, o, 3);
75 if(m != 2){
76 p->mark &= ~COMPR;
77 bflag = 1;
78 }
79 }
80 otxt = p->cond->pc - p->pc;
81 if(otxt < 0)
82 otxt = -otxt;
83 if(o->type == 3){
84 /*
85 * If Bcond branch range exceeds 4K, replace it by the
86 * logically negated branch around a JMP.
87 */
88 if(otxt >= 0x1000) {
89 q = prg();
90 q->link = p->link;
91 q->line = p->line;
92 q->as = AJMP;
93 q->to.type = D_BRANCH;
94 q->cond = p->cond;
95 p->link = q;
96 p->as = relinv(p->as);
97 p->cond = q->link;
98 p->optab = 0;
99 o = oplook(p);
100 q->mark = spass ^ SPASS;
101 m = asmout(p, o, 2);
102 if(m == 2)
103 p->mark |= COMPR;
104 q->pc = p->pc + m;
105 bflag = 1;
106 }
107 }else{
108 /*
109 * If JAL branch range exceeds 1M, change address class
110 * and recalculate instruction length.
111 */
112 if(otxt >= 0x100000) {
113 p->to.class = C_LBRA + 1;
114 p->optab = 0;
115 o = oplook(p);
116 m = asmout(p, o, 3);
117 p->mark &= ~COMPR;
118 }
119 }
120 }
121 if(p->as == ATEXT)
122 c = (c + 3) & ~3;
123 p->pc = c;
124 p->mark ^= SPASS;
125 if(m == 0) {
126 if(p->as == ATEXT) {
127 curtext = p;
128 autosize = p->to.offset + ptrsize;
129 if(p->from.sym != S)
130 p->from.sym->value = c;
131 continue;
132 }
133 diag("zero-width instruction\n%P", p);
134 continue;
135 }
136 c += m;
137 }
138 }
139
140 if(debug['t']) {
141 /*
142 * add strings to text segment
143 */
144 c = rnd(c, 8);
145 for(i=0; i<NHASH; i++)
146 for(s = hash[i]; s != S; s = s->link) {
147 if(s->type != SSTRING)
148 continue;
149 v = s->value;
150 while(v & 3)
151 v++;
152 s->value = c;
153 c += v;
154 }
155 }
156
157 c = rnd(c, 8);
158
159 setext = lookup("etext", 0);
160 if(setext != S) {
161 setext->value = c;
162 textsize = c;
163 }
164 if(INITRND)
165 INITDAT = rnd(INITTEXT + c, INITRND);
166 if(debug['v'])
167 Bprint(&bso, "tsize = %lux\n", textsize);
168 Bflush(&bso);
169 }
170
171 void
xdefine(char * p,int t,long v)172 xdefine(char *p, int t, long v)
173 {
174 Sym *s;
175
176 s = lookup(p, 0);
177 if(s->type == 0 || s->type == SXREF) {
178 s->type = t;
179 s->value = v;
180 }
181 }
182
183 long
regoff(Adr * a)184 regoff(Adr *a)
185 {
186
187 instoffset = 0;
188 a->class = aclass(a) + 1;
189 return instoffset;
190 }
191
192 int
classreg(Adr * a)193 classreg(Adr *a)
194 {
195 if(a->reg == NREG) {
196 switch(a->class - 1) {
197 case C_SEXT:
198 case C_SECON:
199 case C_LECON:
200 return REGSB;
201 case C_SAUTO:
202 case C_LAUTO:
203 case C_SACON:
204 case C_LACON:
205 return REGSP;
206 }
207 }
208 return a->reg;
209 }
210
211 int
aclass(Adr * a)212 aclass(Adr *a)
213 {
214 Sym *s;
215 int t;
216
217 switch(a->type) {
218 case D_NONE:
219 return C_NONE;
220
221 case D_REG:
222 return C_REG;
223
224 case D_CTLREG:
225 return C_CTLREG;
226
227 case D_FREG:
228 return C_FREG;
229
230 case D_OREG:
231 switch(a->name) {
232 case D_EXTERN:
233 case D_STATIC:
234 if(a->sym == 0 || a->sym->name == 0) {
235 print("null sym external\n");
236 print("%D\n", a);
237 return C_GOK;
238 }
239 t = a->sym->type;
240 if(t == 0 || t == SXREF) {
241 diag("undefined external: %s in %s",
242 a->sym->name, TNAME);
243 a->sym->type = SDATA;
244 }
245 instoffset = a->sym->value + a->offset - BIG;
246 if(instoffset >= -BIG && instoffset < BIG)
247 return C_SEXT;
248 return C_LEXT;
249 case D_AUTO:
250 instoffset = autosize + a->offset;
251 if(instoffset >= -BIG && instoffset < BIG)
252 return C_SAUTO;
253 return C_LAUTO;
254
255 case D_PARAM:
256 instoffset = autosize + a->offset + ptrsize;
257 if(instoffset >= -BIG && instoffset < BIG)
258 return C_SAUTO;
259 return C_LAUTO;
260 case D_NONE:
261 instoffset = a->offset;
262 if(instoffset == 0)
263 return C_ZOREG;
264 if(instoffset >= -BIG && instoffset < BIG)
265 return C_SOREG;
266 return C_LOREG;
267 }
268 return C_GOK;
269
270 case D_FCONST:
271 return C_FCON;
272
273 case D_VCONST:
274 return C_VCON;
275
276 case D_CONST:
277 switch(a->name) {
278
279 case D_NONE:
280 instoffset = a->offset;
281 if(a->reg != NREG && a->reg != REGZERO){
282 if(instoffset >= -BIG && instoffset < BIG)
283 return C_SRCON;
284 return C_LRCON;
285 }
286 consize:
287 if(instoffset == 0)
288 return C_ZCON;
289 if(instoffset >= -0x800 && instoffset <= 0x7ff)
290 return C_SCON;
291 if((instoffset & 0xfff) == 0)
292 return C_UCON;
293 return C_LCON;
294
295 case D_EXTERN:
296 case D_STATIC:
297 instoffx = 0;
298 s = a->sym;
299 if(s == S)
300 break;
301 t = s->type;
302 switch(t) {
303 case 0:
304 case SXREF:
305 diag("undefined external: %s in %s",
306 s->name, TNAME);
307 s->type = SDATA;
308 break;
309 case SCONST:
310 instoffset = s->value + a->offset;
311 goto consize;
312 case STEXT:
313 case SLEAF:
314 case SSTRING:
315 instoffset = s->value + a->offset;
316 instoffx = INITTEXT;
317 return C_LECON;
318 }
319 instoffset = s->value + a->offset - BIG;
320 if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L)
321 return C_SECON;
322 instoffset = s->value + a->offset;
323 instoffx = INITDAT;
324 return C_LECON;
325
326 case D_AUTO:
327 instoffset = autosize + a->offset;
328 if(instoffset >= -BIG && instoffset < BIG)
329 return C_SACON;
330 return C_LACON;
331
332 case D_PARAM:
333 instoffset = autosize + a->offset + ptrsize;
334 if(instoffset >= -BIG && instoffset < BIG)
335 return C_SACON;
336 return C_LACON;
337 }
338 return C_GOK;
339
340 case D_BRANCH:
341 return C_SBRA;
342 }
343 return C_GOK;
344 }
345
346 Optab*
oplook(Prog * p)347 oplook(Prog *p)
348 {
349 int a1, a2, a3, r;
350 char *c1, *c3;
351 Optab *o, *e;
352
353 a1 = p->optab;
354 if(a1)
355 return optab+(a1-1);
356 a1 = p->from.class;
357 if(a1 == 0) {
358 a1 = aclass(&p->from) + 1;
359 p->from.class = a1;
360 }
361 a1--;
362 a3 = p->to.class;
363 if(a3 == 0) {
364 a3 = aclass(&p->to) + 1;
365 p->to.class = a3;
366 }
367 a3--;
368 a2 = C_NONE;
369 if(p->reg != NREG)
370 a2 = C_REG;
371 r = p->as;
372 o = oprange[r].start;
373 if(o == 0) {
374 a1 = opcross[repop[r]][a1][a3];
375 if(a1) {
376 p->optab = a1+1;
377 return optab+a1;
378 }
379 o = oprange[r].stop; /* just generate an error */
380 a1 = p->from.class - 1;
381 }
382 e = oprange[r].stop;
383
384 c1 = xcmp[a1];
385 c3 = xcmp[a3];
386 for(; o<e; o++)
387 if(c1[o->a1])
388 if(c3[o->a3]) {
389 p->optab = (o-optab)+1;
390 return o;
391 }
392 diag("illegal combination %A %d %d %d",
393 p->as, a1, a2, a3);
394 if(!debug['a'])
395 prasm(p);
396 o = optab;
397 p->optab = (o-optab)+1;
398 return o;
399 }
400
401 int
cmp(int a,int b)402 cmp(int a, int b)
403 {
404
405 if(a == b)
406 return 1;
407 switch(a) {
408 case C_LCON:
409 if(b == C_ZCON || b == C_SCON || b == C_UCON)
410 return 1;
411 break;
412 case C_UCON:
413 if(b == C_ZCON)
414 return 1;
415 break;
416 case C_SCON:
417 if(b == C_ZCON)
418 return 1;
419 break;
420 case C_LACON:
421 if(b == C_SACON)
422 return 1;
423 break;
424 case C_LRCON:
425 if(b == C_SRCON)
426 return 1;
427 break;
428 case C_LBRA:
429 if(b == C_SBRA)
430 return 1;
431 break;
432 case C_LEXT:
433 if(b == C_SEXT)
434 return 1;
435 break;
436 case C_LAUTO:
437 if(b == C_SAUTO)
438 return 1;
439 break;
440 case C_ZREG:
441 if(b == C_REG || b == C_ZCON)
442 return 1;
443 break;
444 case C_LOREG:
445 if(b == C_ZOREG || b == C_SOREG || b == C_SAUTO || b == C_LAUTO)
446 return 1;
447 break;
448 case C_SOREG:
449 if(b == C_ZOREG || b == C_SAUTO || b == C_SEXT)
450 return 1;
451 break;
452 }
453 return 0;
454 }
455
456 int
ocmp(void * a1,void * a2)457 ocmp(void *a1, void *a2)
458 {
459 Optab *p1, *p2;
460 int n;
461
462 p1 = (Optab*)a1;
463 p2 = (Optab*)a2;
464 n = p1->as - p2->as;
465 if(n)
466 return n;
467 n = p1->a1 - p2->a1;
468 if(n)
469 return n;
470 n = p1->a3 - p2->a3;
471 if(n)
472 return n;
473 return 0;
474 }
475
476 void
buildop(void)477 buildop(void)
478 {
479 int i, n, r;
480
481 for(i=0; i<32; i++)
482 for(n=0; n<32; n++)
483 xcmp[i][n] = cmp(n, i);
484 for(n=0; optab[n].as != AXXX; n++)
485 ;
486 qsort(optab, n, sizeof(optab[0]), ocmp);
487 for(i=0; i<n; i++) {
488 r = optab[i].as;
489 oprange[r].start = optab+i;
490 while(optab[i].as == r)
491 i++;
492 oprange[r].stop = optab+i;
493 i--;
494 }
495
496 buildrep(1, AMOVW);
497 }
498
499 void
buildrep(int x,int as)500 buildrep(int x, int as)
501 {
502 Opcross *p;
503 Optab *e, *s, *o;
504 int a1, a3, n;
505
506 if(C_GOK >= 32 || x >= nelem(opcross)) {
507 diag("assumptions fail in buildrep");
508 errorexit();
509 }
510 repop[as] = x;
511 p = (opcross + x);
512 s = oprange[as].start;
513 e = oprange[as].stop;
514 for(o=e-1; o>=s; o--) {
515 n = o-optab;
516 for(a1=0; a1<32; a1++) {
517 if(!xcmp[a1][o->a1])
518 continue;
519 for(a3=0; a3<32; a3++)
520 if(xcmp[a3][o->a3])
521 (*p)[a1][a3] = n;
522 }
523 }
524 oprange[as].start = 0;
525 }
526