1 #include "l.h" 2 3 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 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 184 regoff(Adr *a) 185 { 186 187 instoffset = 0; 188 a->class = aclass(a) + 1; 189 return instoffset; 190 } 191 192 int 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 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* 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 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 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 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 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