| 1 | static char sccsid[] = "@(#)c21.c 4.2 %G%"; |
| 2 | /* char C21[] = {"@(#)c21.c 1.83 80/10/16 21:18:22 JFR"}; /* sccs ident */ |
| 3 | |
| 4 | /* |
| 5 | * C object code improver-- second part |
| 6 | */ |
| 7 | |
| 8 | #include "c2.h" |
| 9 | #include <stdio.h> |
| 10 | #include <ctype.h> |
| 11 | |
| 12 | #define NUSE 6 |
| 13 | int ioflag; |
| 14 | int biti[NUSE] = {1,2,4,8,16,32}; |
| 15 | int bitsize[4] = {0,8,16,32}; /* index by type codes */ |
| 16 | int pos,siz; long f; /* for bit field communication */ |
| 17 | struct node *uses[NUSE]; /* for backwards flow analysis */ |
| 18 | char *lastrand; /* last operand of instruction */ |
| 19 | struct node *bflow(); |
| 20 | struct node *bicopt(); |
| 21 | char *findcon(); |
| 22 | |
| 23 | redun3(p,split) register struct node *p; int split; { |
| 24 | /* check for 3 addr instr which should be 2 addr */ |
| 25 | if (OP3==((p->subop>>4)&0xF)) { |
| 26 | if (split) splitrand(p); |
| 27 | if (equstr(regs[RT1],regs[RT3]) |
| 28 | && (p->op==ADD || p->op==MUL || p->op==BIS || p->op==XOR)) { |
| 29 | register char *t=regs[RT1]; regs[RT1]=regs[RT2]; regs[RT2]=t; |
| 30 | } |
| 31 | if (equstr(regs[RT2],regs[RT3])) { |
| 32 | p->subop=(p->subop&0xF)|(OP2<<4); p->pop=0; |
| 33 | lastrand=regs[RT2]; *regs[RT3]=0; return(1); |
| 34 | } |
| 35 | } return(0); |
| 36 | } |
| 37 | |
| 38 | bmove() { |
| 39 | register struct node *p, *lastp; register char *cp1,*cp2; register int r; |
| 40 | refcount(); |
| 41 | for (p=lastp= &first; 0!=(p=p->forw); lastp=p); |
| 42 | clearreg(); clearuse(); |
| 43 | for (p=lastp; p!= &first; p=p->back) { |
| 44 | if (debug) { |
| 45 | printf("Uses:\n"); |
| 46 | for (r=NUSE;--r>=0;) if (uses[r]) |
| 47 | printf("%d: %s\n",r,uses[r]->code? uses[r]->code:""); |
| 48 | printf("-\n"); |
| 49 | } |
| 50 | r=(p->subop>>4)&0xF; |
| 51 | if (OP2==r && (cp1=p->code, *cp1++)=='$' && *cp1++=='0' && *cp1++==',' && |
| 52 | !source(cp1)) {/* a no-op unless MUL or DIV */ |
| 53 | if (p->op==MUL) {p->op=MOV; p->subop&=0xF; p->pop=0;} |
| 54 | else if (p->op==DIV) fprintf(stderr,"c2: zero divide\n"); |
| 55 | else {delnode(p); redunm++; continue;} |
| 56 | } |
| 57 | if (OP3==r && 0!=redun3(p,1)) {newcode(p); redunm++;} |
| 58 | switch (p->op) { |
| 59 | case LABEL: case DLABEL: |
| 60 | for (r=NUSE; --r>=0;) |
| 61 | if (uses[r]) p->ref=(struct node *) (((int)p->ref)|biti[r]); |
| 62 | break; |
| 63 | case CALLS: |
| 64 | clearuse(); goto std; |
| 65 | case 0: |
| 66 | clearuse(); break; |
| 67 | case SUB: |
| 68 | if ((p->subop&0xF)!=LONG) goto std; cp1=p->code; |
| 69 | if (*cp1++!='$') goto std; splitrand(p); |
| 70 | if (equstr(regs[RT2],"fp") && !indexa(regs[RT1])) {/* address comp. */ |
| 71 | char buf[50]; cp2=buf; *cp2++='-'; |
| 72 | cp1=regs[RT1]+1; while (*cp2++= *cp1++); --cp2; |
| 73 | cp1="(fp),"; while (*cp2++= *cp1++); --cp2; |
| 74 | cp1=regs[RT3]; while (*cp2++= *cp1++); |
| 75 | p->code=copy(buf); p->combop=T(MOVA,LONG); p->pop=0; |
| 76 | } else if (*cp1++=='-' && 0<=(r=getnum(cp1))) { |
| 77 | p->op=ADD; p->pop=0; *--cp1='$'; p->code=cp1; |
| 78 | } goto std; |
| 79 | case ADD: |
| 80 | if ((p->subop&0xF)!=LONG) goto std; cp1=p->code; |
| 81 | if (*cp1++!='$') goto std; splitrand(p); |
| 82 | if (isstatic(cp1) && (r=isreg(regs[RT2]))>=0 && r<NUSE && uses[r]==p->forw) |
| 83 | { |
| 84 | /* address comp: |
| 85 | ** addl2 $_foo,r0 \ movab _foo[r0],bar |
| 86 | ** movl r0,bar / |
| 87 | */ |
| 88 | register struct node *pnext = p->forw; |
| 89 | char buf[50]; |
| 90 | |
| 91 | if (pnext->op == MOV && pnext->subop == LONG) |
| 92 | { |
| 93 | cp1 = ®s[RT1][1]; cp2 = &buf[0]; |
| 94 | while (*cp2++ = *cp1++) ; cp2--; |
| 95 | splitrand(pnext); |
| 96 | if (r == isreg(regs[RT1])) |
| 97 | { |
| 98 | delnode(p); p = pnext; |
| 99 | p->op = MOVA; p->subop = BYTE; |
| 100 | p->pop = 0; |
| 101 | cp1 = regs[RT1]; *cp2++ = '['; |
| 102 | while (*cp2++ = *cp1++) ; cp2--; |
| 103 | *cp2++ = ']'; *cp2++ = ','; |
| 104 | cp1 = regs[RT2]; |
| 105 | while (*cp2++ = *cp1++) ; |
| 106 | p->code = copy(buf); |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | else |
| 111 | if (equstr(regs[RT2],"fp") && !indexa(regs[RT1])) {/* address comp. */ |
| 112 | cp2=cp1-1; cp1=regs[RT1]+1; while (*cp2++= *cp1++); --cp2; |
| 113 | cp1="(fp)"; while (*cp2++= *cp1++); *--cp2=','; |
| 114 | p->combop=T(MOVA,LONG); p->pop=0; |
| 115 | } else if (*cp1++=='-' && 0<=(r=getnum(cp1))) { |
| 116 | p->op=SUB; p->pop=0; *--cp1='$'; p->code=cp1; |
| 117 | } |
| 118 | /* fall thru ... */ |
| 119 | case CASE: |
| 120 | default: std: |
| 121 | p=bflow(p); break; |
| 122 | case MUL: |
| 123 | { |
| 124 | /* |
| 125 | ** Change multiplication by constant powers of 2 to |
| 126 | ** shifts. |
| 127 | */ |
| 128 | splitrand(p); |
| 129 | if (regs[RT1][0] != '$' || regs[RT1][1] == '-') goto std; |
| 130 | if ((r = ispow2(getnum(®s[RT1][1]))) < 0) goto std; |
| 131 | switch (r) |
| 132 | { |
| 133 | case 0: /* mull3 $1,x,y */ |
| 134 | if (p->subop == U(LONG,OP3)) |
| 135 | { |
| 136 | if (equstr(regs[RT2], regs[RT3])) |
| 137 | { |
| 138 | delnode(p); p = p->forw; |
| 139 | } |
| 140 | else |
| 141 | { |
| 142 | p->op = MOV; p->subop = LONG; |
| 143 | p->pop = 0; newcode(p); nchange++; |
| 144 | } |
| 145 | } |
| 146 | else |
| 147 | if (p->subop == U(LONG,OP2)) |
| 148 | { |
| 149 | delnode(p); p = p->forw; |
| 150 | } |
| 151 | goto std; |
| 152 | |
| 153 | case 1: /* mull2 $2,x */ |
| 154 | if (p->subop == U(LONG, OP2) && !source(regs[RT2])) |
| 155 | { |
| 156 | strcpy(regs[RT1], regs[RT2]); |
| 157 | p->op = ADD; p->pop = 0; newcode(p); nchange++; |
| 158 | } |
| 159 | goto std; |
| 160 | } |
| 161 | if(p->subop==U(LONG,OP3)||(p->subop==U(LONG,OP2)&&!source(regs[RT2]))) |
| 162 | { |
| 163 | if (p->subop == U(LONG,OP2)) |
| 164 | strcpy(regs[RT3], regs[RT2]); |
| 165 | sprintf(regs[RT1], "$%d", r); |
| 166 | p->op = ASH; p->subop = LONG; |
| 167 | p->pop = 0; newcode(p); nchange++; |
| 168 | } |
| 169 | goto std; |
| 170 | } |
| 171 | case ASH: |
| 172 | { |
| 173 | /* address comp: |
| 174 | ** ashl $1,bar,r0 \ movl bar,r0 |
| 175 | ** movab _foo[r0] / movaw _foo[r0] |
| 176 | ** |
| 177 | ** ashl $2,r0,r0 \ moval _foo[r0] |
| 178 | ** movab _foo[r0] / |
| 179 | */ |
| 180 | register struct node *pf; |
| 181 | register int shfrom, shto; |
| 182 | long shcnt; |
| 183 | char *regfrom; |
| 184 | |
| 185 | splitrand(p); |
| 186 | if (regs[RT1][0] != '$') goto std; |
| 187 | if ((shcnt = getnum(®s[RT1][1])) < 1 || shcnt > 3) goto std; |
| 188 | if ((shfrom = isreg(regs[RT2])) >= 0) |
| 189 | regfrom = copy(regs[RT2],"]"); |
| 190 | if ((shto = isreg(regs[RT3])) >= 0 && shto<NUSE) |
| 191 | { |
| 192 | int regnum; |
| 193 | |
| 194 | if (uses[shto] != (pf = p->forw)) goto ashadd; |
| 195 | if (pf->op != MOVA && pf->op != PUSHA) goto ashadd; |
| 196 | if (pf->subop != BYTE) goto ashadd; |
| 197 | splitrand(pf); |
| 198 | if (!indexa(regs[RT1])) goto std; |
| 199 | cp2 = regs[RT1]; |
| 200 | if(!isstatic(cp2)) goto std; |
| 201 | while (*cp2++ != '[') ; |
| 202 | if (*cp2++ != 'r' || !isdigit(*cp2)) goto std; |
| 203 | regnum = *cp2++ - '0'; |
| 204 | if (isdigit(*cp2)) |
| 205 | { |
| 206 | if (cp2[1] != ']') goto std; |
| 207 | regnum *= 10; regnum += *cp2 - '0'; |
| 208 | } |
| 209 | if (regnum != shto) goto std; |
| 210 | if (shfrom >= 0) /* ashl $N,r*,r0 */ |
| 211 | { |
| 212 | delnode(p); |
| 213 | if (shfrom != shto) |
| 214 | { |
| 215 | uses[shto] = NULL; splitrand(pf); |
| 216 | cp2=regs[RT1]; while (*cp2++!='['); |
| 217 | cp1=regfrom; while (*cp2++= *cp1++); |
| 218 | newcode(pf); |
| 219 | } |
| 220 | } |
| 221 | else |
| 222 | { |
| 223 | p->op = MOV; splitrand(p); |
| 224 | strcpy(regs[RT1], regs[RT2]); |
| 225 | strcpy(regs[RT2], regs[RT3]); |
| 226 | regs[RT3][0] = '\0'; |
| 227 | p->pop = 0; newcode(p); |
| 228 | } |
| 229 | switch (shcnt) |
| 230 | { |
| 231 | case 1: pf->subop = WORD; break; |
| 232 | case 2: pf->subop = LONG; break; |
| 233 | case 3: pf->subop = QUAD; break; |
| 234 | } |
| 235 | redunm++; nsaddr++; nchange++; |
| 236 | } |
| 237 | goto std; |
| 238 | ashadd: |
| 239 | /* at this point, RT2 and RT3 are guaranteed to be simple regs*/ |
| 240 | if (shcnt == 1 && equstr(regs[RT2], regs[RT3])) |
| 241 | { |
| 242 | /* |
| 243 | ** quickie: |
| 244 | ** ashl $1,A,A > addl2 A,A |
| 245 | */ |
| 246 | p->op = ADD; p->subop = U(LONG,OP2); p->pop = 0; |
| 247 | strcpy(regs[RT1], regs[RT2]); regs[RT3][0] = '\0'; |
| 248 | newcode(p); nchange++; |
| 249 | } |
| 250 | goto std; |
| 251 | } |
| 252 | |
| 253 | case EXTV: |
| 254 | case EXTZV: |
| 255 | { |
| 256 | /* bit tests: |
| 257 | ** extv A,$1,B,rC \ |
| 258 | ** tstl rC > jbc A,B,D |
| 259 | ** jeql D / |
| 260 | ** |
| 261 | ** also byte- and word-size fields: |
| 262 | ** extv $n*8,$8,A,B > cvtbl n+A,B |
| 263 | ** extv $n*16,$16,A,B > cvtwl n+A,B |
| 264 | ** extzv $n*8,$8,A,B > movzbl n+A,B |
| 265 | ** extzv $n*16,$16,A,B > movzwl n+A,B |
| 266 | */ |
| 267 | register struct node *pf; /* forward node */ |
| 268 | register struct node *pn; /* next node (after pf) */ |
| 269 | int flen; /* field length */ |
| 270 | |
| 271 | splitrand(p); |
| 272 | if (regs[RT2][0] != '$') goto std; |
| 273 | if ((flen = getnum(®s[RT2][1])) < 0) goto std; |
| 274 | if (flen == 1) |
| 275 | { |
| 276 | register int extreg; /* reg extracted to */ |
| 277 | |
| 278 | extreg = isreg(regs[RT4]); |
| 279 | if (extreg < 0 || extreg >= NUSE) goto std; |
| 280 | if ((pf = p->forw)->op != TST) goto std; |
| 281 | if (uses[extreg] && uses[extreg] != pf) goto std; |
| 282 | splitrand(pf); |
| 283 | if (extreg != isreg(regs[RT1])) goto std; |
| 284 | if ((pn = pf->forw)->op != CBR) goto std; |
| 285 | if (pn->subop != JEQ && pn->subop != JNE) goto std; |
| 286 | delnode(p); delnode(pf); |
| 287 | pn->subop = (pn->subop == JEQ) ? JBC : JBS; |
| 288 | for(cp2=p->code; *cp2++!=',';); |
| 289 | for(cp1=cp2; *cp1++!=',';); |
| 290 | while (*cp1!=',') *cp2++= *cp1++; *cp2='\0'; |
| 291 | pn->code = p->code; pn->pop = NULL; |
| 292 | uses[extreg] = NULL; |
| 293 | } |
| 294 | else |
| 295 | if (flen == 8 || flen == 16) |
| 296 | { |
| 297 | register int boff; /* bit offset */ |
| 298 | register int coff; /* chunk (byte or word) offset*/ |
| 299 | |
| 300 | if (regs[RT1][0] != '$') goto std; |
| 301 | if ((boff = getnum(®s[RT1][1])) < 0) goto std; |
| 302 | coff = boff / flen; |
| 303 | if (coff && (isreg(regs[RT3]) >= 0)) goto std; |
| 304 | if (boff < 0 || (boff % flen) != 0) goto std; |
| 305 | p->op = (p->op == EXTV) ? CVT : MOVZ; |
| 306 | p->subop = U((flen == 8 ? BYTE : WORD), LONG); |
| 307 | if (coff == 0) |
| 308 | strcpy(regs[RT1], regs[RT3]); |
| 309 | else |
| 310 | sprintf(regs[RT1], "%d%s%s", coff, regs[RT3][0]=='(' ? "":"+", |
| 311 | regs[RT3]); |
| 312 | strcpy(regs[RT2], regs[RT4]); |
| 313 | regs[RT3][0] = '\0'; regs[RT4][0] = '\0'; |
| 314 | p->pop = 0; newcode(p); |
| 315 | } |
| 316 | nchange++; |
| 317 | goto std; |
| 318 | } |
| 319 | |
| 320 | case CMP: |
| 321 | { |
| 322 | /* comparison to -63 to -1: |
| 323 | ** cmpl r0,$-1 > incl r0 |
| 324 | ** jeql ... |
| 325 | ** |
| 326 | ** cmpl r0,$-63 > addl2 $63,r0 |
| 327 | ** jeql ... |
| 328 | */ |
| 329 | register int num; |
| 330 | register int reg; |
| 331 | register struct node *regp = p->back; |
| 332 | |
| 333 | if (p->forw->op != CBR) goto std; |
| 334 | if (p->forw->subop != JEQ && p->forw->subop != JNE) goto std; |
| 335 | splitrand(p); |
| 336 | if (strncmp(regs[RT2], "$-", 2) != 0) goto std; |
| 337 | reg = r = isreg(regs[RT1]); |
| 338 | if (r < 0) goto std; |
| 339 | if (r < NUSE && uses[r] != 0) goto std; |
| 340 | if (r >= NUSE && regp->op == MOV && p->subop == regp->subop) |
| 341 | { |
| 342 | if (*regp->code != 'r') goto std; |
| 343 | reg = regp->code[1] - '0'; |
| 344 | if (isdigit(regp->code[2]) || reg >= NUSE || uses[reg]) |
| 345 | goto std; |
| 346 | } |
| 347 | if (r >= NUSE) goto std; |
| 348 | if (reg != r) |
| 349 | sprintf(regs[RT1], "r%d", reg); |
| 350 | if ((num = getnum(®s[RT2][2])) <= 0 || num > 63) goto std; |
| 351 | if (num == 1) |
| 352 | { |
| 353 | p->op = INC; regs[RT2][0] = '\0'; |
| 354 | } |
| 355 | else |
| 356 | { |
| 357 | register char *t; |
| 358 | |
| 359 | t=regs[RT1];regs[RT1]=regs[RT2];regs[RT2]=t; |
| 360 | p->op = ADD; p->subop = U(p->subop, OP2); |
| 361 | for (t = ®s[RT1][2]; t[-1] = *t; t++) ; |
| 362 | } |
| 363 | p->pop = 0; newcode(p); |
| 364 | nchange++; |
| 365 | goto std; |
| 366 | } |
| 367 | |
| 368 | case JSB: |
| 369 | if (equstr(p->code,"mcount")) {uses[0]=p; regs[0][0]= -1;} |
| 370 | goto std; |
| 371 | case JBR: case JMP: |
| 372 | clearuse(); |
| 373 | if (p->subop==RET || p->subop==RSB) {uses[0]=p; regs[0][0]= -1; break;} |
| 374 | if (p->ref==0) goto std; /* jmp (r0) */ |
| 375 | /* fall through */ |
| 376 | case CBR: |
| 377 | if (p->ref->ref!=0) for (r=NUSE;--r>=0;) |
| 378 | if (biti[r] & (int)p->ref->ref) {uses[r]=p; regs[r][0]= -1;} |
| 379 | case EROU: case JSW: |
| 380 | case TEXT: case DATA: case BSS: case ALIGN: case WGEN: case END: ; |
| 381 | } |
| 382 | } |
| 383 | for (p= &first; p!=0; p=p->forw) |
| 384 | if (p->op==LABEL || p->op==DLABEL) p->ref=0; /* erase our tracks */ |
| 385 | } |
| 386 | |
| 387 | rmove() |
| 388 | { |
| 389 | register struct node *p, *lastp; |
| 390 | register int r; |
| 391 | int r1; |
| 392 | |
| 393 | clearreg(); |
| 394 | for (p=first.forw; p!=0; p = p->forw) { |
| 395 | lastp=p; |
| 396 | if (debug) { |
| 397 | printf("Regs:\n"); |
| 398 | for (r=0; r<NREG; r++) |
| 399 | if (regs[r][0]) { |
| 400 | r1=regs[r][0]; |
| 401 | printf("%d: %d%d %s\n", r, r1&0xF, r1>>4, regs[r]+1); |
| 402 | } |
| 403 | printf("-\n"); |
| 404 | } |
| 405 | switch (p->op) { |
| 406 | |
| 407 | case CVT: |
| 408 | splitrand(p); goto mov; |
| 409 | |
| 410 | case MOV: |
| 411 | splitrand(p); |
| 412 | if ((r = findrand(regs[RT1],p->subop)) >= 0) { |
| 413 | if (r == isreg(regs[RT2]) && p->forw->op!=CBR) { |
| 414 | delnode(p); redunm++; break; |
| 415 | } |
| 416 | } |
| 417 | mov: |
| 418 | repladdr(p); |
| 419 | r = isreg(regs[RT1]); |
| 420 | r1 = isreg(regs[RT2]); |
| 421 | dest(regs[RT2],p->subop); |
| 422 | if (r>=0) { |
| 423 | if (r1>=0) savereg(r1, regs[r]+1, p->subop); |
| 424 | else if (p->op!=CVT) savereg(r, regs[RT2], p->subop); |
| 425 | } else if (r1>=0) savereg(r1, regs[RT1], p->subop); |
| 426 | else if (p->op!=CVT) setcon(regs[RT1], regs[RT2], p->subop); |
| 427 | break; |
| 428 | |
| 429 | /* .rx,.wx */ |
| 430 | case MFPR: |
| 431 | case COM: |
| 432 | case NEG: |
| 433 | /* .rx,.wx or .rx,.rx,.wx */ |
| 434 | case ADD: |
| 435 | case SUB: |
| 436 | case BIC: |
| 437 | case BIS: |
| 438 | case XOR: |
| 439 | case MUL: |
| 440 | case DIV: |
| 441 | case ASH: |
| 442 | case MOVZ: |
| 443 | /* .rx,.rx,.rx,.wx */ |
| 444 | case EXTV: |
| 445 | case EXTZV: |
| 446 | case INSV: |
| 447 | splitrand(p); |
| 448 | repladdr(p); |
| 449 | dest(lastrand,p->subop); |
| 450 | if (p->op==INSV) ccloc[0]=0; |
| 451 | break; |
| 452 | |
| 453 | /* .mx or .wx */ |
| 454 | case CLR: |
| 455 | case INC: |
| 456 | case DEC: |
| 457 | splitrand(p); |
| 458 | dest(lastrand,p->subop); |
| 459 | if (p->op==CLR) |
| 460 | if ((r = isreg(regs[RT1])) >= 0) |
| 461 | savereg(r, "$0", p->subop); |
| 462 | else |
| 463 | setcon("$0", regs[RT1], p->subop); |
| 464 | break; |
| 465 | |
| 466 | /* .rx */ |
| 467 | case TST: |
| 468 | case PUSH: |
| 469 | splitrand(p); |
| 470 | lastrand=regs[RT1+1]; /* fool repladdr into doing 1 operand */ |
| 471 | repladdr(p); |
| 472 | if (p->op==TST && equstr(lastrand=regs[RT1], ccloc+1) |
| 473 | && ((0xf&(ccloc[0]>>4))==p->subop || equtype(ccloc[0],p->subop)) |
| 474 | &&!source(lastrand)) { |
| 475 | delnode(p); p = p->back; nrtst++; nchange++; |
| 476 | } |
| 477 | setcc(lastrand,p->subop); |
| 478 | break; |
| 479 | |
| 480 | /* .rx,.rx,.rx */ |
| 481 | case PROBER: |
| 482 | case PROBEW: |
| 483 | case CASE: |
| 484 | case MOVC3: |
| 485 | /* .rx,.rx */ |
| 486 | case MTPR: |
| 487 | case CALLS: |
| 488 | case CMP: |
| 489 | case BIT: |
| 490 | splitrand(p); |
| 491 | /* fool repladdr into doing right number of operands */ |
| 492 | if (p->op==CASE || p->op==MOVC3 || p->op==PROBER || p->op==PROBEW) |
| 493 | lastrand=regs[RT4]; |
| 494 | else lastrand=regs[RT3]; |
| 495 | repladdr(p); |
| 496 | if (p->op==CALLS || p->op==MOVC3) clearreg(); |
| 497 | if (p->op==BIT) bitopt(p); |
| 498 | ccloc[0]=0; break; |
| 499 | |
| 500 | case CBR: |
| 501 | if (p->subop>=JBC) { |
| 502 | splitrand(p); |
| 503 | if (p->subop<JBCC) lastrand=regs[RT3]; /* 2 operands can be optimized */ |
| 504 | else lastrand=regs[RT2]; /* .mb destinations lose */ |
| 505 | repladdr(p); |
| 506 | } |
| 507 | ccloc[0] = 0; |
| 508 | break; |
| 509 | |
| 510 | case JBR: |
| 511 | redunbr(p); |
| 512 | |
| 513 | /* .wx,.bb */ |
| 514 | case SOB: |
| 515 | |
| 516 | default: |
| 517 | clearreg(); |
| 518 | } |
| 519 | } |
| 520 | } |
| 521 | |
| 522 | char * |
| 523 | byondrd(p) register struct node *p; { |
| 524 | /* return pointer to register which is "beyond last read/modify operand" */ |
| 525 | if (OP2==(p->subop>>4)) return(regs[RT3]); |
| 526 | switch (p->op) { |
| 527 | case MFPR: |
| 528 | case JSB: |
| 529 | case PUSHA: |
| 530 | case TST: case INC: case DEC: case PUSH: return(regs[RT2]); |
| 531 | case MTPR: |
| 532 | case BIT: case CMP: case CALLS: return(regs[RT3]); |
| 533 | case PROBER: case PROBEW: |
| 534 | case CASE: case MOVC3: return(regs[RT4]); |
| 535 | } |
| 536 | return(lastrand); |
| 537 | } |
| 538 | |
| 539 | struct node * |
| 540 | bflow(p) |
| 541 | register struct node *p; |
| 542 | { |
| 543 | register char *cp1,*cp2,**preg; register int r; |
| 544 | int flow= -1; |
| 545 | struct node *olduse=0; |
| 546 | splitrand(p); |
| 547 | if (p->op!=PUSH && p->subop && 0<=(r=isreg(lastrand)) && r<NUSE && uses[r]==p->forw) { |
| 548 | if (equtype(p->subop,regs[r][0]) |
| 549 | || ((p->op==CVT || p->op==MOVZ) |
| 550 | && 0xf®s[r][0] && compat(0xf&(p->subop>>4),regs[r][0]))) { |
| 551 | register int r2; |
| 552 | if (regs[r][1]!=0) {/* send directly to destination */ |
| 553 | if (p->op==INC || p->op==DEC) { |
| 554 | if (p->op==DEC) p->op=SUB; else p->op=ADD; |
| 555 | p->subop=(OP2<<4)+(p->subop&0xF); /* use 2 now, convert to 3 later */ |
| 556 | p->pop=0; |
| 557 | cp1=lastrand; cp2=regs[RT2]; while (*cp2++= *cp1++); /* copy reg */ |
| 558 | cp1=lastrand; *cp1++='$'; *cp1++='1'; *cp1=0; |
| 559 | } |
| 560 | cp1=regs[r]+1; cp2=lastrand; |
| 561 | if (OP2==(p->subop>>4)) {/* use 3 operand form of instruction */ |
| 562 | p->pop=0; |
| 563 | p->subop += (OP3-OP2)<<4; lastrand=cp2=regs[RT3]; |
| 564 | } |
| 565 | while (*cp2++= *cp1++); |
| 566 | if (p->op==MOVA && p->forw->op==PUSH) { |
| 567 | p->op=PUSHA; *regs[RT2]=0; p->pop=0; |
| 568 | } else if (p->op==MOV && p->forw->op==PUSH) { |
| 569 | p->op=PUSH ; *regs[RT2]=0; p->pop=0; |
| 570 | } |
| 571 | delnode(p->forw); |
| 572 | if (0<=(r2=isreg(lastrand)) && r2<NUSE) { |
| 573 | uses[r2]=uses[r]; uses[r]=0; |
| 574 | } |
| 575 | redun3(p,0); |
| 576 | newcode(p); redunm++; flow=r; |
| 577 | } else if (p->op==MOV && p->forw->op!=EXTV && p->forw->op!=EXTZV) { |
| 578 | /* superfluous fetch */ |
| 579 | int nmatch; |
| 580 | char src[20]; |
| 581 | movit: |
| 582 | cp2=src; cp1=regs[RT1]; while (*cp2++= *cp1++); |
| 583 | splitrand(p->forw); |
| 584 | if (p->forw->op != INC && p->forw->op != DEC) |
| 585 | lastrand=byondrd(p->forw); |
| 586 | nmatch=0; |
| 587 | for (preg=regs+RT1;*preg!=lastrand;preg++) |
| 588 | if (r==isreg(*preg)) { |
| 589 | cp2= *preg; cp1=src; while (*cp2++= *cp1++); ++nmatch; |
| 590 | } |
| 591 | if (nmatch==1) { |
| 592 | if (OP2==(p->forw->subop>>4) && equstr(src,regs[RT2])) { |
| 593 | p->forw->pop=0; |
| 594 | p->forw->subop += (OP3-OP2)<<4; cp1=regs[RT3]; |
| 595 | *cp1++='r'; *cp1++=r+'0'; *cp1=0; |
| 596 | } |
| 597 | delnode(p); p=p->forw; |
| 598 | if (0<=(r2=isreg(src)) && r2<NUSE) { |
| 599 | uses[r2]=uses[r]; uses[r]=0; |
| 600 | } |
| 601 | redun3(p,0); |
| 602 | newcode(p); redunm++; flow=r; |
| 603 | } else splitrand(p); |
| 604 | } |
| 605 | } else if (p->op==MOV && (p->forw->op==CVT || p->forw->op==MOVZ) |
| 606 | && p->forw->subop&0xf /* if base or index, then forget it */ |
| 607 | && compat(p->subop,p->forw->subop) && !source(cp1=regs[RT1]) |
| 608 | && !indexa(cp1)) goto movit; |
| 609 | } |
| 610 | /* adjust 'lastrand' past any 'read' or 'modify' operands. */ |
| 611 | lastrand=byondrd(p); |
| 612 | /* a 'write' clobbers the register. */ |
| 613 | if (0<=(r=isreg(lastrand)) && r<NUSE |
| 614 | || OP2==(p->subop>>4) && 0<=(r=isreg(regs[RT2])) && r<NUSE && uses[r]==0) { |
| 615 | /* writing a dead register is useless, but watch side effects */ |
| 616 | switch (p->op) { |
| 617 | case ACB: |
| 618 | case AOBLEQ: case AOBLSS: case SOBGTR: case SOBGEQ: break; |
| 619 | default: |
| 620 | if (uses[r]==0) {/* no direct uses, check for use of condition codes */ |
| 621 | register struct node *q=p; |
| 622 | while ((q=nonlab(q->forw))->combop==JBR) q=q->ref; /* cc unused, unchanged */ |
| 623 | if (q->op!=CBR) {/* ... and destroyed */ |
| 624 | preg=regs+RT1; |
| 625 | while (cp1= *preg++) { |
| 626 | if (cp1==lastrand) {redunm++; delnode(p); return(p->forw);} |
| 627 | if (source(cp1) || equstr(cp1,lastrand)) break; |
| 628 | } |
| 629 | } |
| 630 | } |
| 631 | flow=r; |
| 632 | } |
| 633 | } |
| 634 | if (0<=(r=flow)) {olduse=uses[r]; uses[r]=0; *(short *)(regs[r])=0;} |
| 635 | /* these two are here, rather than in bmove(), |
| 636 | /* because I decided that it was better to go for 3-address code |
| 637 | /* (save time) rather than fancy jbxx (save 1 byte) |
| 638 | /* on sequences like bisl2 $64,r0; movl r0,foo |
| 639 | */ |
| 640 | if (p->op==BIC) {p=bicopt(p); splitrand(p); lastrand=byondrd(p);} |
| 641 | if (p->op==BIS) {bixprep(p,JBSS); lastrand=byondrd(p);} |
| 642 | /* now look for 'read' or 'modify' (read & write) uses */ |
| 643 | preg=regs+RT1; |
| 644 | while (*(cp1= *preg++)) { |
| 645 | /* check for r */ |
| 646 | if (lastrand!=cp1 && 0<=(r=isreg(cp1)) && r<NUSE && uses[r]==0) { |
| 647 | uses[r]=p; cp2=regs[r]; *cp2++=p->subop; |
| 648 | if (p->op==ASH && preg==(regs+RT1+1)) cp2[-1]=BYTE; /* stupid DEC */ |
| 649 | if (p->op==MOV || p->op==PUSH || p->op==CVT || p->op==MOVZ || p->op==COM || p->op==NEG) { |
| 650 | if (p->op==PUSH) cp1="-(sp)"; |
| 651 | else { |
| 652 | cp1=regs[RT2]; |
| 653 | if (0<=(r=isreg(cp1)) && r<NUSE && uses[r]==0) |
| 654 | uses[r]=olduse; /* reincarnation!! */ |
| 655 | /* as in addl2 r0,r1; movl r1,r0; ret */ |
| 656 | if (p->op!=MOV) cp1=0; |
| 657 | } |
| 658 | if (cp1) while (*cp2++= *cp1++); |
| 659 | else *cp2=0; |
| 660 | } else *cp2=0; |
| 661 | continue; |
| 662 | } |
| 663 | /* check for (r),(r)+,-(r),[r] */ |
| 664 | do if (*cp1=='(' || *cp1=='[') {/* get register number */ |
| 665 | char t; |
| 666 | cp2= ++cp1; while (*++cp1!=')' && *cp1!=']'); t= *cp1; *cp1=0; |
| 667 | if (0<=(r=isreg(cp2)) && r<NUSE && (uses[r]==0 || uses[r]==p)) { |
| 668 | uses[r]=p; regs[r][0]=(*--cp2=='[' ? OPX<<4 : OPB<<4); |
| 669 | } |
| 670 | *cp1=t; |
| 671 | } while (*++cp1); |
| 672 | } |
| 673 | /* pushax or movax possibility? */ |
| 674 | cp1=regs[RT1]; |
| 675 | if (*cp1++=='$' && isstatic(cp1) && natural(regs[RT1])) { |
| 676 | if (p->combop==T(MOV,LONG)) { |
| 677 | if (regs[RT1][1]=='L' && 0!=(p->labno=getnum(regs[RT1]+2))) { |
| 678 | cp1=p->code; while (*cp1++!=','); p->code= --cp1; |
| 679 | } |
| 680 | p->combop=T(MOVA,LONG); ++p->code; p->pop=0; |
| 681 | } else if (p->combop==T(PUSH,LONG)) { |
| 682 | p->combop=T(PUSHA,LONG); ++p->code; p->pop=0; |
| 683 | } else if ((p->combop&0xFFFF)==T(ADD,U(LONG,OP3)) |
| 684 | && 0<=(r=isreg(regs[RT2]))) { |
| 685 | cp1=cp2=p->code; ++cp1; |
| 686 | do *cp2++= *cp1; while (*cp1++!=','); cp2[-1]='['; |
| 687 | do *cp2++= *cp1; while (*cp1++!=','); cp2[-1]=']'; |
| 688 | if (!equstr(regs[RT3],"-(sp)")) p->combop=T(MOVA,BYTE); |
| 689 | else {p->combop=T(PUSHA,BYTE); *cp2=0;} |
| 690 | if (uses[r]==0) {uses[r]=p; regs[r][0]=OPX<<4;} |
| 691 | p->pop=0; |
| 692 | } |
| 693 | } |
| 694 | return(p); |
| 695 | } |
| 696 | |
| 697 | ispow2(n) register long n; {/* -1 -> no; else -> log to base 2 */ |
| 698 | register int log; |
| 699 | if (n==0 || n&(n-1)) return(-1); log=0; |
| 700 | for (;;) {n >>= 1; if (n==0) return(log); ++log; if (n== -1) return(log);} |
| 701 | } |
| 702 | |
| 703 | bitopt(p) register struct node *p; { |
| 704 | /* change "bitx $<power_of_2>,a" followed by JEQ or JNE |
| 705 | /* into JBC or JBS. watch out for I/O registers. (?) |
| 706 | /* assumes that 'splitrand' has already been called. |
| 707 | */ |
| 708 | register char *cp1,*cp2; int b; |
| 709 | cp1=regs[RT1]; cp2=regs[RT2]; |
| 710 | if (*cp1++!='$' || !okio(cp2) || p->forw->op!=CBR || p->forw->subop&-2 || |
| 711 | 0>(b=ispow2(getnum(cp1))) || |
| 712 | p->subop!=BYTE && (source(cp2) || indexa(cp2))) return; |
| 713 | if (b>=bitsize[p->subop]) {/* you dummy! */ |
| 714 | if (source(cp2)) {/* side effect: auto increment or decrement */ |
| 715 | p->pop=0; |
| 716 | p->op=TST; --cp1; while (*cp1++= *cp2++); |
| 717 | regs[RT2][0]=0; newcode(p); |
| 718 | } else delnode(p); |
| 719 | p = p->forw; |
| 720 | if (p->subop==JEQ) {p->combop=JBR; p->pop=0;} |
| 721 | else delnode(p); |
| 722 | nchange++; nbj++; return; |
| 723 | } |
| 724 | if (cp1=p->forw->code) {/* destination is not an internal label */ |
| 725 | cp2=regs[RT3]; while (*cp2++= *cp1++); |
| 726 | } |
| 727 | if (b==0 && (p->subop==LONG || !indexa(regs[RT2]))) {/* JLB optimization, ala BLISS */ |
| 728 | cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++); |
| 729 | cp2=regs[RT2]; cp1=regs[RT3]; while (*cp2++= *cp1++); |
| 730 | *(regs[RT3])=0; p->forw->subop += JLBC-JBC; |
| 731 | p->forw->pop=0; |
| 732 | } else { |
| 733 | cp1=regs[RT1]+1; |
| 734 | if (b>9) *cp1++= b/10 +'0'; *cp1++= b%10 +'0'; *cp1=0; /* $<bit_number> */ |
| 735 | } |
| 736 | nbj++; newcode(p); p->combop = p->forw->combop+((JBC-JEQ)<<8); |
| 737 | p->labno = p->forw->labno; delnode(p->forw); |
| 738 | p->pop=0; |
| 739 | } |
| 740 | |
| 741 | isfield(n) register long n; {/* -1 -> no; else -> position of low bit */ |
| 742 | register int pos; register long t; |
| 743 | t= ((n-1)|n) +1; |
| 744 | if (n!=0 && (0==t || 0==n || 0<=ispow2(t))) { |
| 745 | pos=0; while(!(n&1)) {n >>= 1; ++pos;} return(pos); |
| 746 | } else return(-1); |
| 747 | } |
| 748 | |
| 749 | bixprep(p,bix) register struct node *p; { |
| 750 | /* initial setup, single-bit checking for bisopt, bicopt. |
| 751 | /* return: 0->don't bother any more; 1->worthwhile trying |
| 752 | */ |
| 753 | register char *cp1,*cp2; |
| 754 | splitrand(p); cp1=regs[RT1]; cp2=regs[RT2]; |
| 755 | if (*cp1++!='$' || 0>(pos=isfield(f=getnum(cp1))) |
| 756 | || !okio(cp2) || indexa(cp2) || source(cp2) || !okio(lastrand)) return(0); |
| 757 | f |= f-1; if (++f==0) siz=32-pos; else siz=ispow2(f)-pos; |
| 758 | if (siz==1 && pos>5 && (p->subop>>4)==OP2 && (p->subop&0xF)!=BYTE |
| 759 | && pos<bitsize[p->subop&0xF]) { |
| 760 | p->ref = insertl(p->forw); p->combop = CBR | (bix<<8); |
| 761 | p->pop=0; |
| 762 | p->labno = p->ref->labno; |
| 763 | if (pos>9) {*cp1++= pos/10 +'0'; pos %= 10;} |
| 764 | *cp1++=pos+'0'; *cp1=0; newcode(p); nbj++; return(0); |
| 765 | } |
| 766 | return(1); |
| 767 | } |
| 768 | |
| 769 | |
| 770 | struct node * |
| 771 | bicopt(p) register struct node *p; { |
| 772 | /* use field operations or MOVZ if possible. done as part of 'bflow'. |
| 773 | */ |
| 774 | register char *cp1,*cp2; int r; |
| 775 | char src[50]; |
| 776 | if (!bixprep(p,JBCC)) return(p); |
| 777 | if (f==0) {/* the BIC isolates low order bits */ |
| 778 | siz=pos; pos=0; |
| 779 | if ((p->subop&0xF)==LONG && *(regs[RT2])!='$') {/* result of EXTZV is long */ |
| 780 | /* save source of BICL in 'src' */ |
| 781 | cp1=regs[RT2]; cp2=src; while (*cp2++= *cp1++); |
| 782 | if (p->back->op==ASH) {/* try for more */ |
| 783 | splitrand(p->back); cp1=regs[RT1]; cp2=regs[RT3]; |
| 784 | if (*cp1++=='$' && *(regs[RT2])!='$' && !indexa(regs[RT2]) |
| 785 | && 0>(f=getnum(cp1)) && equstr(src,cp2) |
| 786 | && 0<=(r=isreg(cp2)) && r<NUSE) {/* a good ASH */ |
| 787 | pos -= f; cp1=regs[RT2]; cp2=src; while (*cp2++= *cp1++); |
| 788 | delnode(p->back); |
| 789 | } |
| 790 | } |
| 791 | if (p->back->op==CVT || p->back->op==MOVZ) {/* greedy, aren't we? */ |
| 792 | splitrand(p->back); cp1=regs[RT1]; cp2=regs[RT2]; |
| 793 | if (equstr(src,cp2) && okio(cp1) && !indexa(cp1) |
| 794 | && 0<=(r=isreg(cp2)) && r<NUSE |
| 795 | && bitsize[p->back->subop&0xF]>=(pos+siz) |
| 796 | && bitsize[p->back->subop>>4]>=(pos+siz)) {/* good CVT */ |
| 797 | cp1=regs[RT1]; cp2=src; while (*cp2++= *cp1++); |
| 798 | delnode(p->back); |
| 799 | } |
| 800 | } |
| 801 | /* 'pos', 'siz' known; source of field is in 'src' */ |
| 802 | splitrand(p); /* retrieve destination of BICL */ |
| 803 | if (siz==8 && pos==0) { |
| 804 | p->combop = T(MOVZ,U(BYTE,LONG)); |
| 805 | sprintf(line,"%s,%s",src,lastrand); |
| 806 | } else { |
| 807 | p->combop = T(EXTZV,LONG); |
| 808 | sprintf(line,"$%d,$%d,%s,%s",pos,siz,src,lastrand); |
| 809 | } |
| 810 | p->pop=0; |
| 811 | p->code = copy(line); nfield++; return(p); |
| 812 | }/* end EXTZV possibility */ |
| 813 | }/* end low order bits */ |
| 814 | /* unfortunately, INSV clears the condition codes, thus cannot be used */ |
| 815 | /* else {/* see if BICL2 of positive field should be INSV $0 */ |
| 816 | /* if (p->subop==(LONG | (OP2<<4)) && 6<=(pos+siz)) { |
| 817 | /* p->combop = INSV; |
| 818 | /* sprintf(line,"$0,$%d,$%d,%s",pos,siz,lastrand); |
| 819 | /* p->code = copy(line); nfield++; return(p); |
| 820 | /* } |
| 821 | /* } |
| 822 | */ |
| 823 | return(p); |
| 824 | } |
| 825 | |
| 826 | jumpsw() |
| 827 | { |
| 828 | register struct node *p, *p1; |
| 829 | register t; |
| 830 | int nj; |
| 831 | |
| 832 | t = 0; |
| 833 | nj = 0; |
| 834 | for (p=first.forw; p!=0; p = p->forw) |
| 835 | p->seq = ++t; |
| 836 | for (p=first.forw; p!=0; p = p1) { |
| 837 | p1 = p->forw; |
| 838 | if (p->op == CBR && p1->op==JBR && p->ref && p1->ref |
| 839 | && abs(p->seq - p->ref->seq) > abs(p1->seq - p1->ref->seq)) { |
| 840 | if (p->ref==p1->ref) |
| 841 | continue; |
| 842 | p->subop = revbr[p->subop]; |
| 843 | p->pop=0; |
| 844 | t = p1->ref; |
| 845 | p1->ref = p->ref; |
| 846 | p->ref = t; |
| 847 | t = p1->labno; |
| 848 | p1->labno = p->labno; |
| 849 | p->labno = t; |
| 850 | #ifdef COPYCODE |
| 851 | if (p->labno == 0) { |
| 852 | t = p1->code; p1->code = p->code; p->code = t; |
| 853 | } |
| 854 | #endif |
| 855 | nrevbr++; |
| 856 | nj++; |
| 857 | } |
| 858 | } |
| 859 | return(nj); |
| 860 | } |
| 861 | |
| 862 | addsob() |
| 863 | { |
| 864 | register struct node *p, *p1, *p2, *p3; |
| 865 | |
| 866 | for (p = &first; (p1 = p->forw)!=0; p = p1) { |
| 867 | if (p->combop==T(DEC,LONG) && p1->op==CBR) { |
| 868 | if (abs(p->seq - p1->ref->seq) > 12) continue; |
| 869 | if (p1->subop==JGE || p1->subop==JGT) { |
| 870 | if (p1->subop==JGE) p->combop=SOBGEQ; else p->combop=SOBGTR; |
| 871 | p->pop=0; |
| 872 | p->labno = p1->labno; delnode(p1); nsob++; |
| 873 | } |
| 874 | } else if (p->combop==T(INC,LONG)) { |
| 875 | if (p1->op==LABEL && p1->refc==1 && p1->forw->combop==T(CMP,LONG) |
| 876 | && (p2=p1->forw->forw)->combop==T(CBR,JLE) |
| 877 | && (p3=p2->ref->back)->combop==JBR && p3->ref==p1 |
| 878 | && p3->forw->op==LABEL && p3->forw==p2->ref) { |
| 879 | /* change INC LAB: CMP to LAB: INC CMP */ |
| 880 | p->back->forw=p1; p1->back=p->back; |
| 881 | p->forw=p1->forw; p1->forw->back=p; |
| 882 | p->back=p1; p1->forw=p; |
| 883 | p1=p->forw; |
| 884 | /* adjust beginning value by 1 */ |
| 885 | p2=alloc(sizeof first); p2->combop=T(DEC,LONG); |
| 886 | p2->pop=0; |
| 887 | p2->forw=p3; p2->back=p3->back; p3->back->forw=p2; |
| 888 | p3->back=p2; p2->code=p->code; p2->labno=0; |
| 889 | } |
| 890 | if (p1->combop==T(CMP,LONG) && (p2=p1->forw)->op==CBR) { |
| 891 | register char *cp1,*cp2; |
| 892 | splitrand(p1); if (!equstr(p->code,regs[RT1])) continue; |
| 893 | if (abs(p->seq - p2->ref->seq)>12) {/* outside byte displ range */ |
| 894 | if (p2->subop!=JLE) continue; |
| 895 | p->combop=T(ACB,LONG); |
| 896 | cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++); /* limit */ |
| 897 | cp2=regs[RT2]; cp1="$1"; while (*cp2++= *cp1++); /* increment */ |
| 898 | cp2=regs[RT3]; cp1=p->code; while (*cp2++= *cp1++); /* index */ |
| 899 | p->pop=0; newcode(p); |
| 900 | p->labno = p2->labno; delnode(p2); delnode(p1); nsob++; |
| 901 | } else if (p2->subop==JLE || p2->subop==JLT) { |
| 902 | if (p2->subop==JLE) p->combop=AOBLEQ; else p->combop=AOBLSS; |
| 903 | cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++); /* limit */ |
| 904 | cp2=regs[RT2]; cp1=p->code; while (*cp2++= *cp1++); /* index */ |
| 905 | p->pop=0; newcode(p); |
| 906 | p->labno = p2->labno; delnode(p2); delnode(p1); nsob++; |
| 907 | } |
| 908 | } |
| 909 | } |
| 910 | } |
| 911 | } |
| 912 | |
| 913 | abs(x) |
| 914 | { |
| 915 | return(x<0? -x: x); |
| 916 | } |
| 917 | |
| 918 | equop(p1, p2) |
| 919 | register struct node *p1; |
| 920 | struct node *p2; |
| 921 | { |
| 922 | register char *cp1, *cp2; |
| 923 | |
| 924 | if (p1->combop != p2->combop) |
| 925 | return(0); |
| 926 | if (p1->op>0 && p1->op<MOV) |
| 927 | return(0); |
| 928 | if (p1->op==MOVA && p1->labno!=p2->labno) return(0); |
| 929 | cp1 = p1->code; |
| 930 | cp2 = p2->code; |
| 931 | if (cp1==0 && cp2==0) |
| 932 | return(1); |
| 933 | if (cp1==0 || cp2==0) |
| 934 | return(0); |
| 935 | while (*cp1 == *cp2++) |
| 936 | if (*cp1++ == 0) |
| 937 | return(1); |
| 938 | return(0); |
| 939 | } |
| 940 | |
| 941 | delnode(p) register struct node *p; { |
| 942 | p->back->forw = p->forw; |
| 943 | p->forw->back = p->back; |
| 944 | } |
| 945 | |
| 946 | decref(p) |
| 947 | register struct node *p; |
| 948 | { |
| 949 | if (p && --p->refc <= 0) { |
| 950 | nrlab++; |
| 951 | delnode(p); |
| 952 | } |
| 953 | } |
| 954 | |
| 955 | struct node * |
| 956 | nonlab(ap) |
| 957 | struct node *ap; |
| 958 | { |
| 959 | register struct node *p; |
| 960 | |
| 961 | p = ap; |
| 962 | while (p && p->op==LABEL) |
| 963 | p = p->forw; |
| 964 | return(p); |
| 965 | } |
| 966 | |
| 967 | clearuse() { |
| 968 | register struct node **i; |
| 969 | for (i=uses+NUSE; i>uses;) *--i=0; |
| 970 | } |
| 971 | |
| 972 | clearreg() { |
| 973 | register short **i; |
| 974 | for (i=regs+NREG; i>regs;) **--i=0; |
| 975 | conloc[0] = 0; ccloc[0] = 0; |
| 976 | } |
| 977 | |
| 978 | savereg(ai, s, type) |
| 979 | register char *s; |
| 980 | { |
| 981 | register char *p, *sp; |
| 982 | |
| 983 | sp = p = regs[ai]; |
| 984 | if (source(s)) /* side effects in addressing */ |
| 985 | return; |
| 986 | /* if any indexing, must be parameter or local */ |
| 987 | /* indirection (as in "*-4(fp)") is ok, however */ |
| 988 | *p++ = type; |
| 989 | while (*p++ = *s) |
| 990 | if (*s=='[' || *s++=='(' && *s!='a' && *s!='f') {*sp = 0; return;} |
| 991 | } |
| 992 | |
| 993 | dest(s,type) |
| 994 | register char *s; |
| 995 | { |
| 996 | register int i; |
| 997 | |
| 998 | source(s); /* handle addressing side effects */ |
| 999 | if ((i = isreg(s)) >= 0) { |
| 1000 | *(short *)(regs[i]) = 0; /* if register destination, that reg is a goner */ |
| 1001 | if (DOUBLE==(type&0xF) || DOUBLE==((type>>4)&0xF)) |
| 1002 | *(short *)(regs[i+1]) = 0; /* clobber two at once */ |
| 1003 | } |
| 1004 | for (i=NREG; --i>=0;) |
| 1005 | if (regs[i][1]=='*' && equstr(s, regs[i]+2)) |
| 1006 | *(short *)(regs[i]) = 0; /* previous indirection through destination is invalid */ |
| 1007 | while ((i = findrand(s,0)) >= 0) /* previous values of destination are invalid */ |
| 1008 | *(short *)(regs[i]) = 0; |
| 1009 | if (!natural(s)) {/* wild store, everything except constants vanishes */ |
| 1010 | for (i=NREG; --i>=0;) if (regs[i][1] != '$') *(short *)(regs[i]) = 0; |
| 1011 | conloc[0] = 0; ccloc[0] = 0; |
| 1012 | } else setcc(s,type); /* natural destinations set condition codes */ |
| 1013 | } |
| 1014 | |
| 1015 | splitrand(p) struct node *p; { |
| 1016 | /* separate operands at commas, set up 'regs' and 'lastrand' */ |
| 1017 | register char *p1, *p2; register char **preg; |
| 1018 | preg=regs+RT1; |
| 1019 | if (p1=p->code) while (*p1) { |
| 1020 | lastrand=p2= *preg++; |
| 1021 | while (*p1) if (','==(*p2++= *p1++)) {--p2; break;} |
| 1022 | *p2=0; |
| 1023 | } |
| 1024 | while (preg<(regs+RT1+5)) *(*preg++)=0; |
| 1025 | } |
| 1026 | |
| 1027 | compat(have, want) { |
| 1028 | register int hsrc, hdst; |
| 1029 | if (0==(want &= 0xF)) return(1); /* anything satisfies a wildcard want */ |
| 1030 | hsrc=have&0xF; if (0==(hdst=((have>>4)&0xF)) || hdst>=OP2) hdst=hsrc; |
| 1031 | if (want>=FLOAT) return(hdst==want && hsrc==want); |
| 1032 | /* FLOAT, DOUBLE not compat: rounding */ |
| 1033 | return(hsrc>=want && hdst>=want && hdst<FLOAT); |
| 1034 | } |
| 1035 | |
| 1036 | equtype(t1,t2) {return(compat(t1,t2) && compat(t2,t1));} |
| 1037 | |
| 1038 | findrand(as, type) |
| 1039 | char *as; |
| 1040 | { |
| 1041 | register char **i; |
| 1042 | for (i = regs+NREG; --i>=regs;) { |
| 1043 | if (**i && equstr(*i+1, as) && compat(**i,type)) |
| 1044 | return(i-regs); |
| 1045 | } |
| 1046 | return(-1); |
| 1047 | } |
| 1048 | |
| 1049 | isreg(s) |
| 1050 | register char *s; |
| 1051 | { |
| 1052 | if (*s++!='r' || !isdigit(*s++)) return(-1); |
| 1053 | if (*s==0) return(*--s-'0'); |
| 1054 | if (*(s-1)=='1' && isdigit(*s++) && *s==0) return(10+*--s-'0'); |
| 1055 | return(-1); |
| 1056 | } |
| 1057 | |
| 1058 | check() |
| 1059 | { |
| 1060 | register struct node *p, *lp; |
| 1061 | |
| 1062 | lp = &first; |
| 1063 | for (p=first.forw; p!=0; p = p->forw) { |
| 1064 | if (p->back != lp) |
| 1065 | abort(-1); |
| 1066 | lp = p; |
| 1067 | } |
| 1068 | } |
| 1069 | |
| 1070 | source(ap) |
| 1071 | char *ap; |
| 1072 | { |
| 1073 | register char *p1, *p2; |
| 1074 | |
| 1075 | p1 = ap; |
| 1076 | p2 = p1; |
| 1077 | if (*p1==0) |
| 1078 | return(0); |
| 1079 | while (*p2++ && *(p2-1)!='['); |
| 1080 | if (*p1=='-' && *(p1+1)=='(' |
| 1081 | || *p1=='*' && *(p1+1)=='-' && *(p1+2)=='(' |
| 1082 | || *(p2-2)=='+') { |
| 1083 | while (*p1 && *p1++!='r'); |
| 1084 | if (isdigit(*p1++)) |
| 1085 | if (isdigit(*p1)) *(short *)(regs[10+*p1-'0'])=0; |
| 1086 | else *(short *)(regs[*--p1-'0'])=0; |
| 1087 | return(1); |
| 1088 | } |
| 1089 | return(0); |
| 1090 | } |
| 1091 | |
| 1092 | newcode(p) struct node *p; { |
| 1093 | register char *p1,*p2,**preg; |
| 1094 | preg=regs+RT1; p2=line; |
| 1095 | while (*(p1= *preg++)) {while (*p2++= *p1++); *(p2-1)=',';} |
| 1096 | *--p2=0; |
| 1097 | p->code=copy(line); |
| 1098 | } |
| 1099 | |
| 1100 | repladdr(p) |
| 1101 | struct node *p; |
| 1102 | { |
| 1103 | register r; |
| 1104 | register char *p1, *p2; |
| 1105 | char **preg; int nrepl; |
| 1106 | |
| 1107 | preg=regs+RT1; nrepl=0; |
| 1108 | while (lastrand!=(p1= *preg++)) |
| 1109 | if (!source(p1) && 0<=(r=findrand(p1,p->subop))) { |
| 1110 | *p1++='r'; if (r>9) {*p1++='1'; r -= 10;} *p1++=r+'0'; *p1=0; |
| 1111 | nrepl++; nsaddr++; |
| 1112 | } |
| 1113 | if (nrepl) newcode(p); |
| 1114 | } |
| 1115 | |
| 1116 | /* movedat() |
| 1117 | /* { |
| 1118 | /* register struct node *p1, *p2; |
| 1119 | /* struct node *p3; |
| 1120 | /* register seg; |
| 1121 | /* struct node data; |
| 1122 | /* struct node *datp; |
| 1123 | /* |
| 1124 | /* if (first.forw == 0) |
| 1125 | /* return; |
| 1126 | /* datp = &data; |
| 1127 | /* for (p1 = first.forw; p1!=0; p1 = p1->forw) { |
| 1128 | /* if (p1->op == DATA) { |
| 1129 | /* p2 = p1->forw; |
| 1130 | /* while (p2 && p2->op!=TEXT) |
| 1131 | /* p2 = p2->forw; |
| 1132 | /* if (p2==0) |
| 1133 | /* break; |
| 1134 | /* p3 = p1->back; |
| 1135 | /* p1->back->forw = p2->forw; |
| 1136 | /* p2->forw->back = p3; |
| 1137 | /* p2->forw = 0; |
| 1138 | /* datp->forw = p1; |
| 1139 | /* p1->back = datp; |
| 1140 | /* p1 = p3; |
| 1141 | /* datp = p2; |
| 1142 | /* } |
| 1143 | /* } |
| 1144 | /* if (data.forw) { |
| 1145 | /* datp->forw = first.forw; |
| 1146 | /* first.forw->back = datp; |
| 1147 | /* data.forw->back = &first; |
| 1148 | /* first.forw = data.forw; |
| 1149 | /* } |
| 1150 | /* seg = -1; |
| 1151 | /* for (p1 = first.forw; p1!=0; p1 = p1->forw) { |
| 1152 | /* if (p1->op==TEXT||p1->op==DATA||p1->op==BSS) { |
| 1153 | /* if (p1->op == seg || p1->forw&&p1->forw->op==seg) { |
| 1154 | /* p1->back->forw = p1->forw; |
| 1155 | /* p1->forw->back = p1->back; |
| 1156 | /* p1 = p1->back; |
| 1157 | /* continue; |
| 1158 | /* } |
| 1159 | /* seg = p1->op; |
| 1160 | /* } |
| 1161 | /* } |
| 1162 | /* } |
| 1163 | */ |
| 1164 | |
| 1165 | redunbr(p) |
| 1166 | register struct node *p; |
| 1167 | { |
| 1168 | register struct node *p1; |
| 1169 | register char *ap1; |
| 1170 | char *ap2; |
| 1171 | |
| 1172 | if ((p1 = p->ref) == 0) |
| 1173 | return; |
| 1174 | p1 = nonlab(p1); |
| 1175 | if (p1->op==TST) { |
| 1176 | splitrand(p1); |
| 1177 | savereg(RT2, "$0", p1->subop); |
| 1178 | } else if (p1->op==CMP) |
| 1179 | splitrand(p1); |
| 1180 | else |
| 1181 | return; |
| 1182 | if (p1->forw->op==CBR) { |
| 1183 | ap1 = findcon(RT1, p1->subop); |
| 1184 | ap2 = findcon(RT2, p1->subop); |
| 1185 | p1 = p1->forw; |
| 1186 | if (compare(p1->subop, ap1, ap2)) { |
| 1187 | nredunj++; |
| 1188 | nchange++; |
| 1189 | decref(p->ref); |
| 1190 | p->ref = p1->ref; |
| 1191 | p->labno = p1->labno; |
| 1192 | #ifdef COPYCODE |
| 1193 | if (p->labno == 0) |
| 1194 | p->code = p1->code; |
| 1195 | if (p->ref) |
| 1196 | #endif |
| 1197 | p->ref->refc++; |
| 1198 | } |
| 1199 | } else if (p1->op==TST && equstr(regs[RT1],ccloc+1) && |
| 1200 | equtype(ccloc[0],p1->subop)) { |
| 1201 | p1=insertl(p1->forw); decref(p->ref); p->ref=p1; |
| 1202 | nrtst++; nchange++; |
| 1203 | } |
| 1204 | } |
| 1205 | |
| 1206 | char * |
| 1207 | findcon(i, type) |
| 1208 | { |
| 1209 | register char *p; |
| 1210 | register r; |
| 1211 | |
| 1212 | p = regs[i]; |
| 1213 | if (*p=='$') |
| 1214 | return(p); |
| 1215 | if ((r = isreg(p)) >= 0 && compat(regs[r][0],type)) |
| 1216 | return(regs[r]+1); |
| 1217 | if (equstr(p, conloc)) |
| 1218 | return(conval+1); |
| 1219 | return(p); |
| 1220 | } |
| 1221 | |
| 1222 | compare(op, acp1, acp2) |
| 1223 | char *acp1, *acp2; |
| 1224 | { |
| 1225 | register char *cp1, *cp2; |
| 1226 | register n1; |
| 1227 | int n2; int sign; |
| 1228 | |
| 1229 | cp1 = acp1; |
| 1230 | cp2 = acp2; |
| 1231 | if (*cp1++ != '$' || *cp2++ != '$') |
| 1232 | return(0); |
| 1233 | n1 = 0; sign=1; if (*cp2=='-') {++cp2; sign= -1;} |
| 1234 | while (isdigit(*cp2)) {n1 *= 10; n1 += (*cp2++ - '0')*sign;} |
| 1235 | n2 = n1; |
| 1236 | n1 = 0; sign=1; if (*cp1=='-') {++cp1; sign= -1;} |
| 1237 | while (isdigit(*cp1)) {n1 *= 10; n1 += (*cp1++ - '0')*sign;} |
| 1238 | if (*cp1=='+') |
| 1239 | cp1++; |
| 1240 | if (*cp2=='+') |
| 1241 | cp2++; |
| 1242 | do { |
| 1243 | if (*cp1++ != *cp2) |
| 1244 | return(0); |
| 1245 | } while (*cp2++); |
| 1246 | cp1 = n1; |
| 1247 | cp2 = n2; |
| 1248 | switch(op) { |
| 1249 | |
| 1250 | case JEQ: |
| 1251 | return(cp1 == cp2); |
| 1252 | case JNE: |
| 1253 | return(cp1 != cp2); |
| 1254 | case JLE: |
| 1255 | return(((int)cp1) <= ((int)cp2)); |
| 1256 | case JGE: |
| 1257 | return(((int)cp1) >= ((int)cp2)); |
| 1258 | case JLT: |
| 1259 | return(((int)cp1) < ((int)cp2)); |
| 1260 | case JGT: |
| 1261 | return(((int)cp1) > ((int)cp2)); |
| 1262 | case JLO: |
| 1263 | return(cp1 < cp2); |
| 1264 | case JHI: |
| 1265 | return(cp1 > cp2); |
| 1266 | case JLOS: |
| 1267 | return(cp1 <= cp2); |
| 1268 | case JHIS: |
| 1269 | return(cp1 >= cp2); |
| 1270 | } |
| 1271 | return(0); |
| 1272 | } |
| 1273 | |
| 1274 | setcon(cv, cl, type) |
| 1275 | register char *cv, *cl; |
| 1276 | { |
| 1277 | register char *p; |
| 1278 | |
| 1279 | if (*cv != '$') |
| 1280 | return; |
| 1281 | if (!natural(cl)) |
| 1282 | return; |
| 1283 | p = conloc; |
| 1284 | while (*p++ = *cl++); |
| 1285 | p = conval; |
| 1286 | *p++ = type; |
| 1287 | while (*p++ = *cv++); |
| 1288 | } |
| 1289 | |
| 1290 | equstr(p1, p2) |
| 1291 | register char *p1, *p2; |
| 1292 | { |
| 1293 | do { |
| 1294 | if (*p1++ != *p2) |
| 1295 | return(0); |
| 1296 | } while (*p2++); |
| 1297 | return(1); |
| 1298 | } |
| 1299 | |
| 1300 | setcc(ap,type) |
| 1301 | char *ap; |
| 1302 | { |
| 1303 | register char *p, *p1; |
| 1304 | |
| 1305 | p = ap; |
| 1306 | if (!natural(p)) { |
| 1307 | ccloc[0] = 0; |
| 1308 | return; |
| 1309 | } |
| 1310 | p1 = ccloc; |
| 1311 | *p1++ = type; |
| 1312 | while (*p1++ = *p++); |
| 1313 | } |
| 1314 | |
| 1315 | okio(p) register char *p; {/* 0->probable I/O space address; 1->not */ |
| 1316 | if (ioflag && (!natural(p) || 0>getnum(p))) return(0); |
| 1317 | return(1); |
| 1318 | } |
| 1319 | |
| 1320 | indexa(p) register char *p; {/* 1-> uses [r] addressing mode; 0->doesn't */ |
| 1321 | while (*p) if (*p++=='[') return(1); |
| 1322 | return(0); |
| 1323 | } |
| 1324 | |
| 1325 | natural(p) |
| 1326 | register char *p; |
| 1327 | {/* 1->simple local, parameter, global, or register; 0->otherwise */ |
| 1328 | if (*p=='*' || *p=='(' || *p=='-'&&*(p+1)=='(' || *p=='$'&&getnum(p+1)) |
| 1329 | return(0); |
| 1330 | while (*p++); |
| 1331 | p--; |
| 1332 | if (*--p=='+' || *p==']' || *p==')' && *(p-2)!='a' && *(p-2)!='f') |
| 1333 | return(0); |
| 1334 | return(1); |
| 1335 | } |
| 1336 | |
| 1337 | /* |
| 1338 | ** Tell if an argument is most likely static. |
| 1339 | */ |
| 1340 | |
| 1341 | isstatic(cp) |
| 1342 | register char *cp; |
| 1343 | { |
| 1344 | if (*cp == '_' || *cp == 'L' || (*cp++ == 'v' && *cp == '.')) |
| 1345 | return (1); |
| 1346 | return (0); |
| 1347 | } |