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