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