Commit | Line | Data |
---|---|---|
3347ccab | 1 | #ifndef lint |
6e32ca3e | 2 | static char sccsid[] = "@(#)c21.c 1.5 (Berkeley/CCI) %G%"; |
3347ccab SL |
3 | #endif |
4 | ||
5 | /* | |
6 | * C object code improver-- second part | |
7 | */ | |
8 | ||
9 | #include "c2.h" | |
10 | #include <stdio.h> | |
11 | #include <ctype.h> | |
12 | ||
13 | int bitsize[] = {0,8,16,32,64,32,64}; /* index by type codes */ | |
14 | ||
15 | redun3(p) register struct node *p; { | |
16 | /* check for 3 addr instr which should be 2 addr */ | |
864f1f35 | 17 | if (has3ops(p)) { |
3347ccab SL |
18 | if (equstr(regs[RT1],regs[RT3]) |
19 | && (p->op==ADD || p->op==MUL || p->op==AND || p->op==OR || p->op==XOR)) { | |
20 | register char *t=regs[RT1]; regs[RT1]=regs[RT2]; regs[RT2]=t; | |
21 | } | |
22 | if (equstr(regs[RT2],regs[RT3])) { | |
23 | p->subop=(p->subop&0xF)|(OP2<<4); p->pop=0; | |
24 | lastrand=regs[RT2]; *regs[RT3]=0; return(1); | |
25 | } | |
26 | } return(0); | |
27 | } | |
28 | ||
29 | bmove() { | |
30 | register struct node *p, *lastp; register char *cp1,*cp2; register int r; | |
31 | struct node *flops(); | |
32 | ||
33 | refcount(); | |
34 | for (p=lastp= &first; 0!=(p=p->forw); lastp=p); | |
35 | clearreg(); clearuse(); | |
36 | for (p=lastp; p!= &first; p=p->back) { | |
37 | if (debug) { | |
38 | printf("Uses: "); | |
39 | if (useacc) | |
40 | printf("acc: %s\n",useacc->code? useacc->code:""); | |
41 | for (r=NUSE;--r>=0;) if (uses[r]) | |
42 | printf("%d: %s\n",r,uses[r]->code? uses[r]->code:""); | |
43 | printf("-\n"); | |
44 | } | |
45 | r=(p->subop>>4)&0xF; | |
46 | splitrand(p); | |
47 | if (OP3==r && 0!=redun3(p)) {newcode(p); redunm++;} | |
48 | /* ops that do nothing */ | |
49 | if(p->op==MOV && equstr(regs[RT1], regs[RT2])) | |
50 | if(p->forw->op!=CBR) { | |
51 | delnode(p); redunm++; continue; | |
52 | } else { | |
53 | p->op=TST; p->pop=0; | |
54 | while(*p->code++ != ','); | |
55 | redunm++; | |
56 | } | |
57 | else if((cp1=p->code, *cp1++)=='$' && | |
58 | (*cp1=='0' || *cp1=='1' || *cp1++=='-' && *cp1=='1') && cp1[1]==',') { | |
864f1f35 SL |
59 | switch((p->code[1]<<8)|ord(p->op)) { |
60 | case (('0'<<8)|ord(ADD)): | |
61 | case (('0'<<8)|ord(SUB)): | |
62 | case (('-'<<8)|ord(AND)): | |
63 | case (('0'<<8)|ord(OR)): | |
64 | case (('0'<<8)|ord(XOR)): | |
65 | case (('1'<<8)|ord(MUL)): | |
66 | case (('1'<<8)|ord(DIV)): | |
67 | case (('0'<<8)|ord(SHAL)): | |
68 | case (('0'<<8)|ord(SHAR)): | |
69 | case (('0'<<8)|ord(SHL)): | |
70 | case (('0'<<8)|ord(SHR)): | |
3347ccab SL |
71 | if(r == OP2) { |
72 | if(p->forw->op!=CBR) { | |
73 | delnode(p); redunm++; continue; | |
74 | } else { | |
75 | p->op=TST; p->subop&=0xF; p->pop=0; | |
76 | while(*p->code++ != ','); | |
77 | redunm++; | |
78 | } | |
79 | } else { /* OP3 or shift */ | |
80 | p->op=MOV; p->subop&=0xF; p->pop=0; | |
81 | while(*p->code++ != ','); | |
82 | p = p->forw; redunm++; continue; | |
83 | } | |
84 | break; | |
864f1f35 SL |
85 | case (('0'<<8)|ord(MUL)): |
86 | case (('0'<<8)|ord(AND)): | |
3347ccab SL |
87 | p->op=CLR; p->subop&=0xF; p->pop=0; |
88 | while(*p->code++ != ','); | |
89 | if(r == OP3) | |
90 | while(*p->code++ != ','); | |
91 | redunm++; | |
92 | } | |
93 | } | |
94 | switch (p->op) { | |
95 | case LABEL: case DLABEL: | |
96 | for (r=NUSE; --r>=0;) | |
97 | if (uses[r]) p->ref=(struct node *) (((int)p->ref)|(1<<r)); | |
98 | if (useacc) p->ref=(struct node *) (((int)p->ref)|(1<<NUSE)); | |
99 | break; | |
100 | case CALLS: | |
101 | case CALLF: | |
102 | clearuse(); goto std; | |
864f1f35 | 103 | case NIL: |
3347ccab SL |
104 | clearuse(); break; |
105 | case CVT: | |
106 | { long n; | |
107 | if ((p->subop&0xF)!=LONG) goto std; cp1=p->code; | |
108 | if (*cp1++!='$') goto std; splitrand(p); | |
109 | n = getnum(®s[RT1][1]); | |
110 | if(r==BYTE && (n<-128 || n>127)) goto std; | |
111 | if(r==WORD && (n<-32768 || n>32767)) goto std; | |
112 | p->op = MOV; p->subop = r; p->pop = 0; | |
113 | } goto std; | |
114 | ||
115 | case SUB: | |
116 | if ((p->subop&0xF)!=LONG) goto std; cp1=p->code; | |
117 | if (*cp1++!='$') goto std; splitrand(p); | |
118 | #ifdef MOVAFASTER | |
119 | if (equstr(regs[RT2],"fp") && !indexa(regs[RT1])) {/* address comp. */ | |
120 | char buf[C2_ASIZE]; cp2=buf; *cp2++='-'; | |
121 | cp1=regs[RT1]+1; while (*cp2++= *cp1++); --cp2; | |
122 | cp1="(fp),"; while (*cp2++= *cp1++); --cp2; | |
123 | cp1=regs[RT3]; while (*cp2++= *cp1++); | |
124 | p->code=copy(buf); p->op = MOVA; p->subop = BYTE; p->pop=0; | |
125 | } else | |
126 | #endif MOVAFASTER | |
e6c8f4f3 SL |
127 | if (*cp1++=='-' && 0==(r=getnum(cp1)) && |
128 | !checkexpr(cp1)) { | |
3347ccab SL |
129 | p->op=ADD; p->pop=0; *--cp1='$'; p->code=cp1; |
130 | } goto std; | |
131 | case ADD: | |
132 | if ((p->subop&0xF)!=LONG) goto std; cp1=p->code; | |
133 | if (*cp1++!='$') goto std; splitrand(p); | |
864f1f35 | 134 | if (isstatic(cp1) && tempreg(regs[RT2],r) && uses[r]==p->forw) |
3347ccab SL |
135 | { |
136 | /* address comp: | |
137 | ** addl2 $_foo,r0 \ movab _foo[r0],bar | |
138 | ** movl r0,bar / | |
139 | */ | |
140 | register struct node *pnext = p->forw; | |
141 | char buf[C2_ASIZE]; | |
142 | ||
143 | if (pnext->op == MOV && pnext->subop == LONG) | |
144 | { | |
145 | cp1 = ®s[RT1][1]; cp2 = &buf[0]; | |
146 | while (*cp2++ = *cp1++) ; cp2--; | |
147 | splitrand(pnext); | |
148 | if (r == isreg(regs[RT1])) | |
149 | { | |
150 | delnode(p); p = pnext; | |
151 | p->op = MOVA; p->subop = BYTE; | |
152 | p->pop = 0; | |
153 | cp1 = regs[RT1]; *cp2++ = '['; | |
154 | while (*cp2++ = *cp1++) ; cp2--; | |
155 | *cp2++ = ']'; *cp2++ = ','; | |
156 | cp1 = regs[RT2]; | |
157 | while (*cp2++ = *cp1++) ; | |
158 | p->code = copy(buf); | |
159 | } | |
160 | } | |
161 | } | |
162 | else | |
163 | #ifdef MOVAFASTER | |
164 | if (equstr(regs[RT2],"fp") && !indexa(regs[RT1])) {/* address comp. */ | |
165 | cp2=cp1-1; cp1=regs[RT1]+1; while (*cp2++= *cp1++); --cp2; | |
166 | cp1="(fp)"; while (*cp2++= *cp1++); *--cp2=','; | |
167 | p->op = MOVA; p->subop = BYTE; p->pop=0; | |
168 | } else | |
169 | #endif MOVAFASTER | |
e6c8f4f3 SL |
170 | if (*cp1++=='-' && 0==(r=getnum(cp1)) && |
171 | !checkexpr(cp1)) { | |
3347ccab SL |
172 | p->op=SUB; p->pop=0; *--cp1='$'; p->code=cp1; |
173 | } | |
174 | /* fall thru ... */ | |
175 | case CASE: | |
176 | default: std: | |
177 | p=bflow(p); break; | |
178 | ||
179 | case MUL: | |
180 | /* | |
181 | ** Change multiplication | |
182 | ** by constant powers of 2 to shifts. | |
183 | */ | |
184 | splitrand(p); | |
185 | if (regs[RT1][0] != '$' || regs[RT1][1] == '-') goto std; | |
186 | if ((r = ispow2(getnum(®s[RT1][1]))) <= 0) goto std; | |
187 | /* mull2 $2,x */ | |
188 | if(r == 1 && p->subop == U(LONG, OP2)) { | |
189 | strcpy(regs[RT1], regs[RT2]); | |
190 | p->op = ADD; p->pop = 0; newcode(p); | |
191 | goto std; | |
192 | } | |
193 | if (p->subop == U(LONG,OP2)) | |
194 | strcpy(regs[RT3], regs[RT2]); | |
195 | sprintf(regs[RT1], "$%d", r); | |
196 | p->op = SHL; p->subop = LONG; | |
197 | p->pop = 0; newcode(p); | |
198 | goto std; | |
199 | ||
200 | case SHAL: | |
201 | case SHL: | |
202 | { | |
203 | /* bit tests: | |
204 | ** shll A,$1,rC \ | |
205 | ** bitl B,rC > jbc A,B,D | |
206 | ** jeql D / | |
207 | ** | |
208 | ** address comp: | |
209 | ** shll $1,bar,r0 \ movl bar,r0 | |
210 | ** movab _foo[r0] / movaw _foo[r0] | |
211 | ** | |
212 | ** shll $2,r0,r0 \ moval _foo[r0] | |
213 | ** movab _foo[r0] / | |
214 | */ | |
215 | register struct node *pf; | |
216 | register struct node *pn; | |
217 | register int shfrom, shto; | |
218 | long shcnt; | |
219 | char *regfrom; | |
220 | ||
221 | splitrand(p); | |
222 | if (regs[RT1][0] != '$') { | |
223 | if(isreg(regs[RT1]) < 0) goto std; /* alignment */ | |
224 | if (regs[RT2][0] != '$') goto std; | |
225 | if (getnum(®s[RT2][1]) != 1) goto std; | |
864f1f35 | 226 | if (!tempreg(regs[RT3],r)) goto std; |
3347ccab SL |
227 | if ((pf = p->forw)->op != BIT && pf->op!=AND) goto std; |
228 | if (uses[r] && uses[r] != pf) goto std; | |
229 | splitrand(pf); | |
230 | if (r == isreg(regs[RT1])) cp2 = regs[RT2]; | |
231 | else if (r == isreg(regs[RT2])) cp2 = regs[RT1]; | |
232 | else goto std; | |
233 | if (*cp2 == '$') goto std; | |
234 | if ((pn = pf->forw)->op != CBR) goto std; | |
235 | if (pn->subop != JEQ && pn->subop != JNE) goto std; | |
236 | delnode(p); delnode(pf); | |
237 | pn->subop = (pn->subop == JEQ) ? JBC : JBS; | |
238 | for(cp1=p->code; *cp1++!=',';); | |
239 | while (*cp1++= *cp2++); | |
240 | pn->code = p->code; pn->pop = NULL; | |
241 | uses[r] = NULL; | |
242 | nbj++; | |
243 | p = pn; | |
244 | goto std; | |
245 | } | |
246 | if ((shcnt = getnum(®s[RT1][1])) < 1 || shcnt > 2) goto std; | |
247 | if ((shfrom = isreg(regs[RT2])) >= 0) | |
248 | regfrom = copy(regs[RT2]); | |
864f1f35 | 249 | if (tempreg(regs[RT3],shto)) |
3347ccab SL |
250 | { |
251 | int regnum; | |
252 | ||
253 | if (uses[shto] != (pf = p->forw)) goto ashadd; | |
254 | if (pf->op != MOVA && pf->op != PUSHA) goto ashadd; | |
255 | if (pf->subop != BYTE) goto ashadd; | |
256 | splitrand(pf); | |
257 | if (!indexa(regs[RT1])) goto std; | |
258 | cp2 = regs[RT1]; | |
259 | if(!isstatic(cp2)) goto std; | |
260 | while (*cp2++ != '[') ; | |
261 | if (*cp2++ != 'r' || !isdigit(*cp2)) goto std; | |
262 | regnum = *cp2++ - '0'; | |
263 | if (isdigit(*cp2)) | |
264 | { | |
265 | if (cp2[1] != ']') goto std; | |
266 | regnum *= 10; regnum += *cp2 - '0'; | |
267 | } | |
268 | if (regnum != shto) goto std; | |
269 | if (shfrom >= 0) /* shll $N,r*,r0 */ | |
270 | { | |
271 | delnode(p); | |
272 | p = pf; | |
273 | if (shfrom != shto) | |
274 | { | |
275 | uses[shto] = NULL; splitrand(pf); | |
276 | cp2=regs[RT1]; while (*cp2++!='['); | |
277 | cp1=regfrom; while (*cp2++= *cp1++); | |
278 | cp2[-1] = ']'; *cp2 = 0; | |
279 | newcode(pf); | |
280 | } | |
281 | } | |
282 | else | |
283 | { | |
284 | p->op = MOV; splitrand(p); | |
285 | strcpy(regs[RT1], regs[RT2]); | |
286 | strcpy(regs[RT2], regs[RT3]); | |
287 | regs[RT3][0] = '\0'; | |
288 | p->pop = 0; newcode(p); | |
289 | } | |
290 | switch (shcnt) | |
291 | { | |
292 | case 1: pf->subop = WORD; break; | |
293 | case 2: pf->subop = LONG; break; | |
294 | } | |
295 | redunm++; nsaddr++; | |
296 | } | |
297 | goto std; | |
298 | ashadd: | |
299 | /* at this point, RT2 and RT3 are guaranteed to be simple regs*/ | |
300 | if (shcnt == 1) { | |
301 | /* | |
302 | ** quickie: | |
303 | ** shll $1,A,A > addl2 A,A | |
304 | ** shll $1,A,B > addl3 A,A,B | |
305 | */ | |
306 | p->op = ADD; | |
307 | strcpy(regs[RT1], regs[RT2]); | |
308 | if(equstr(regs[RT2], regs[RT3])) { | |
309 | p->subop = U(LONG,OP2); | |
310 | regs[RT3][0] = '\0'; | |
311 | } else | |
312 | p->subop = U(LONG,OP3); | |
313 | p->pop = 0; | |
314 | newcode(p); | |
315 | } | |
316 | goto std; | |
317 | } | |
318 | ||
319 | case SHAR: | |
320 | case SHR: | |
321 | { | |
322 | /* bit tests: | |
323 | ** shrl A,B,rC \ | |
324 | ** bitl $1,rC > jbc A,B,D | |
325 | ** jeql D / | |
326 | */ | |
327 | register struct node *pf; /* forward node */ | |
328 | register struct node *pn; /* next node (after pf) */ | |
329 | register int extreg; /* reg extracted to */ | |
330 | ||
331 | splitrand(p); | |
332 | if(isreg(regs[RT1]) < 0) goto std; /* alignment */ | |
864f1f35 | 333 | if (!tempreg(regs[RT3],extreg)) goto std; |
3347ccab SL |
334 | if ((pf = p->forw)->op != BIT) goto std; |
335 | if (uses[extreg] && uses[extreg] != pf) goto std; | |
336 | splitrand(pf); | |
337 | if (regs[RT1][0] != '$') goto std; | |
338 | if (getnum(®s[RT1][1]) != 1) goto std; | |
339 | if (extreg != isreg(regs[RT2])) goto std; | |
340 | if ((pn = pf->forw)->op != CBR) goto std; | |
341 | if (pn->subop != JEQ && pn->subop != JNE) goto std; | |
342 | delnode(p); delnode(pf); | |
343 | pn->subop = (pn->subop == JEQ) ? JBC : JBS; | |
344 | for(cp1=p->code; *cp1++!=',';); | |
345 | while (*cp1!=',') cp1++; *cp1='\0'; | |
346 | pn->code = p->code; pn->pop = NULL; | |
347 | uses[extreg] = NULL; nbj++; | |
348 | p = pn; | |
349 | goto std; | |
350 | } | |
351 | ||
352 | case AND: | |
353 | { | |
354 | /* unsigned conversion: | |
355 | ** cvtbl A,B; andl2 $255,B > movzbl A,B | |
356 | ** | |
357 | ** also byte- and word-size fields: | |
358 | ** shrl $(3-n)*8,A,B; andl2 $255,B > movzbl n+A,B | |
359 | ** shrl $(1-n)*16,A,B; andl2 $65535,B > movzwl n+A,B | |
360 | */ | |
361 | char src[C2_ASIZE]; | |
362 | register int f; /* field length */ | |
363 | register struct node *pb = p->back; /* backward node */ | |
364 | ||
365 | if (p->subop != U(LONG,OP2)) | |
366 | goto std; | |
367 | splitrand(p); cp1=regs[RT1]; | |
368 | if (*cp1++!='$' || (f=getnum(cp1))!=0xff && f!=0xffff) | |
369 | goto std; | |
370 | f = f==0xff ? 8 : 16; | |
371 | if (pb->op!=CVT && pb->op!=MOVZ && pb->op!=SHAR && pb->op!=SHR) | |
372 | goto std; | |
373 | /* save source of ANDL in 'src' */ | |
374 | strcpy(src, regs[RT2]); | |
375 | splitrand(pb); | |
376 | if (!equstr(src,lastrand)) | |
377 | goto std; | |
378 | if (pb->op==CVT || pb->op==MOVZ) { | |
379 | if (!(bitsize[pb->subop&0xF]==f | |
380 | && bitsize[pb->subop>>4]>=f)) /* good CVT */ | |
381 | goto std; | |
382 | strcpy(src, regs[RT1]); | |
383 | } else { | |
384 | register int boff; /* bit offset */ | |
385 | ||
386 | if (regs[RT1][0] != '$') goto std; | |
387 | if ((boff = getnum(®s[RT1][1])) < 0) goto std; | |
388 | if (isreg(regs[RT2])>=0 || !natural(regs[RT2])) goto std; | |
389 | if ((boff & (f-1)) != 0) goto std; | |
390 | boff = (32-boff-f) / 8; | |
391 | if (boff == 0) | |
392 | strcpy(src, regs[RT2]); | |
393 | else | |
394 | sprintf(src, "%d%s%s", boff, regs[RT2][0]=='(' ? "":"+", | |
395 | regs[RT2]); | |
396 | } | |
397 | delnode(pb); | |
398 | p->op = MOVZ; | |
399 | p->subop = U((f==8 ? BYTE : WORD), LONG); | |
400 | sprintf(line,"%s,%s",src,lastrand); | |
401 | p->pop=0; | |
402 | p->code = copy(line); | |
403 | goto std; | |
404 | } | |
405 | ||
406 | case CMP: | |
407 | { | |
408 | /* comparison to -63 to -1: | |
409 | ** cmpl r0,$-1 > incl r0 | |
410 | ** jeql ... | |
411 | ** | |
412 | ** cmpl r0,$-63 > addl2 $63,r0 | |
413 | ** jeql ... | |
414 | */ | |
415 | register int num; | |
416 | register int reg; | |
417 | register struct node *regp = p->back; | |
418 | ||
419 | if (p->forw->op != CBR) goto std; | |
420 | if (p->forw->subop != JEQ && p->forw->subop != JNE) goto std; | |
421 | splitrand(p); | |
422 | if (strncmp(regs[RT2], "$-", 2) != 0) goto std; | |
423 | reg = r = isreg(regs[RT1]); | |
424 | if (r < 0) goto std; | |
425 | if (r < NUSE && uses[r] != 0) goto std; | |
426 | if (r >= NUSE && regp->op == MOV && p->subop == regp->subop) | |
427 | { | |
428 | if (*regp->code != 'r') goto std; | |
429 | reg = regp->code[1] - '0'; | |
430 | if (isdigit(regp->code[2]) || reg >= NUSE || uses[reg]) | |
431 | goto std; | |
432 | } | |
433 | if (r >= NUSE) goto std; | |
434 | if (reg != r) | |
435 | sprintf(regs[RT1], "r%d", reg); | |
436 | if ((num = getnum(®s[RT2][2])) <= 0 || num > 63) goto std; | |
437 | if (num == 1) | |
438 | { | |
439 | p->op = INC; regs[RT2][0] = '\0'; | |
440 | } | |
441 | else | |
442 | { | |
443 | register char *t; | |
444 | ||
445 | t=regs[RT1];regs[RT1]=regs[RT2];regs[RT2]=t; | |
446 | p->op = ADD; p->subop = U(p->subop, OP2); | |
447 | for (t = ®s[RT1][2]; t[-1] = *t; t++) ; | |
448 | } | |
449 | p->pop = 0; newcode(p); | |
450 | goto std; | |
451 | } | |
452 | ||
453 | case JBR: case JMP: | |
454 | clearuse(); | |
455 | if ((p->subop&0xF)==RET) { | |
456 | switch((p->subop>>4)&0xF) { | |
457 | case 2: uses[1]=p; regs[1][0]= -1; | |
458 | case 1: uses[0]=p; regs[0][0]= -1; | |
459 | } | |
460 | break; | |
461 | } | |
462 | if (p->ref==0) goto std; /* jmp (r0) */ | |
463 | /* fall through */ | |
464 | case CBR: | |
465 | if (p->ref->ref!=0) { | |
466 | for (r=NUSE;--r>=0;) | |
467 | if ((1<<r) & (int)p->ref->ref) {uses[r]=p; regs[r][0]= -1;} | |
468 | if ((1<<NUSE) & (int)p->ref->ref) useacc=p; | |
469 | } | |
470 | break; | |
471 | case LNF: | |
472 | /* lnf a; addf b ==> ldf b; subf a */ | |
473 | { register struct node *pf = p->forw; | |
474 | if(pf->op==ADDF && p->subop==pf->subop) { | |
475 | p->op = LDF; | |
476 | p->pop = 0; | |
477 | pf->op = SUBF; | |
478 | pf->pop = 0; | |
479 | cp1 = p->code; | |
480 | p->code = pf->code; | |
481 | pf->code = cp1; | |
482 | p = pf->forw; | |
483 | break; | |
484 | }} | |
485 | case LDF: case LDFD: case CVLF: /* destroy acc */ | |
486 | useacc = 0; | |
487 | goto std; | |
488 | case STF: | |
489 | { register struct node *pf; | |
490 | if((pf=flops(p)) != p) { | |
491 | p = pf; /* usually p->forw; */ | |
492 | break; | |
493 | }} | |
494 | if(ldmov(p)) { | |
495 | p = p->forw; | |
496 | break; | |
497 | } | |
498 | if(useacc == 0) | |
499 | useacc = p; | |
500 | goto std; | |
501 | case ADDF: case MULF: /* commutatives - create clients for flops */ | |
502 | /* stf a; ldf b; addf a => stf a; ldf a; addf b */ | |
503 | { register struct node *pb = p->back; | |
504 | register struct node *pbb = pb->back; | |
505 | if(pb->op==LDF && pb->subop==p->subop && | |
506 | pbb && pbb->op==STF && pbb->subop==p->subop && | |
507 | equstr(pbb->code, p->code)) { | |
508 | cp1 = p->code; | |
509 | p->code = pb->code; | |
510 | pb->code = cp1; | |
511 | }} | |
512 | /* use acc and regs */ | |
513 | case CMPF: case CVFL: case SUBF: case DIVF: | |
514 | if(useacc == 0) | |
515 | useacc = p; | |
516 | goto std; | |
e6c8f4f3 SL |
517 | case TSTF: |
518 | break; | |
519 | case PUSHD: | |
3347ccab SL |
520 | if(ldmov(p)) { |
521 | p = p->forw; | |
522 | break; | |
523 | } | |
524 | case CVDF: case NEGF: /* use only acc */ | |
525 | case SINF: case COSF: case ATANF: case LOGF: case SQRTF: case EXPF: | |
526 | if(useacc == 0) | |
527 | useacc = p; | |
528 | case EROU: case JSW: | |
529 | case TEXT: case DATA: case BSS: case ALIGN: case WGEN: case END: ; | |
530 | } | |
531 | } | |
532 | for (p= &first; p!=0; p=p->forw) | |
533 | if (p->op==LABEL || p->op==DLABEL) p->ref=0; /* erase our tracks */ | |
534 | } | |
535 | ||
536 | char * | |
537 | byondrd(p) register struct node *p; { | |
538 | /* return pointer to register which is "beyond last read/modify operand" */ | |
864f1f35 | 539 | if (has2ops(p)) return(regs[RT3]); |
3347ccab SL |
540 | switch (p->op) { |
541 | case MFPR: | |
542 | case PUSHA: | |
543 | case TST: case INC: case DEC: case PUSH: | |
544 | case LDF: case LNF: case CVLF: case LDFD: | |
545 | case ADDF: case SUBF: case MULF: case DIVF: | |
546 | case CMPF: | |
547 | return(regs[RT2]); | |
548 | case MTPR: | |
549 | #ifndef EMOD | |
550 | case EDIV: | |
551 | #endif EMOD | |
552 | case CBR: /* must be JBC/JBS */ | |
553 | case BIT: case CMP: case CALLS: case CALLF: | |
554 | case CMPF2: | |
555 | return(regs[RT3]); | |
556 | case EMUL: | |
557 | case PROBE: | |
558 | case MOVBLK: | |
559 | case CASE: | |
560 | return(regs[RT4]); | |
561 | } | |
562 | return(lastrand); | |
563 | } | |
564 | ||
565 | struct node * | |
566 | bflow(p) | |
864f1f35 | 567 | register struct node *p; |
3347ccab SL |
568 | { |
569 | register char *cp1,*cp2,**preg; | |
570 | register int r, fr, dblflg=0; | |
571 | int flow= -1; | |
572 | struct node *olduse=0, *olduse1=0; | |
573 | ||
864f1f35 | 574 | if (p->subop==QUAD || p->subop==DOUBLE || (p->subop&0xF0)==DOUBLE<<4) |
3347ccab | 575 | dblflg |= 1; /* double dest */ |
864f1f35 | 576 | if ((p->subop&0xF)==DOUBLE || p->subop==QUAD) |
3347ccab SL |
577 | dblflg |= 2; /* double src */ |
578 | splitrand(p); | |
864f1f35 | 579 | if (p->op!=PUSH && |
3347ccab | 580 | #ifndef EMOD |
864f1f35 | 581 | p->op!=EDIV && |
3347ccab | 582 | #endif EMOD |
864f1f35 SL |
583 | p->op!=EMUL && |
584 | p->subop && tempreg(lastrand,r) && uses[r]==p->forw) { | |
585 | if (equtype(p->subop,regs[r][0]) || | |
586 | ((p->op==CVT || p->op==MOVZ || p->op==CVFL) && | |
587 | (regs[r][0]&0xf) && compat((p->subop>>4)&0xf,regs[r][0])) || | |
588 | p->op==MOVA && compat(LONG, regs[r][0])) { | |
3347ccab | 589 | register int r2; |
864f1f35 SL |
590 | |
591 | if (regs[r][1]!=0) { /* send directly to destination */ | |
3347ccab | 592 | if (p->op==INC || p->op==DEC) { |
864f1f35 SL |
593 | p->op = (p->op==DEC) ? SUB : ADD; |
594 | /* use 2 now, convert to 3 later */ | |
595 | p->subop=(OP2<<4)+(p->subop&0xF); | |
3347ccab | 596 | p->pop=0; |
864f1f35 SL |
597 | cp1=lastrand; cp2=regs[RT2]; |
598 | while (*cp2++= *cp1++) /* copy reg */ | |
599 | ; | |
3347ccab SL |
600 | cp1=lastrand; *cp1++='$'; *cp1++='1'; *cp1=0; |
601 | } | |
602 | cp1=regs[r]+1; cp2=lastrand; | |
864f1f35 SL |
603 | if (has2ops(p)) { |
604 | /* use 3 operand form of instruction */ | |
3347ccab | 605 | p->pop=0; |
864f1f35 SL |
606 | p->subop += (OP3-OP2)<<4; |
607 | lastrand = cp2 = regs[RT3]; | |
3347ccab | 608 | } |
864f1f35 SL |
609 | while (*cp2++= *cp1++) |
610 | ; | |
3347ccab SL |
611 | if (p->op==MOVA && p->forw->op==PUSH) { |
612 | p->op=PUSHA; | |
613 | *regs[RT2]=0; p->pop=0; | |
864f1f35 SL |
614 | } else if ((p->op==MOV || p->op==CVT) && |
615 | p->forw->op==PUSH) { | |
3347ccab SL |
616 | p->op=PUSH; p->subop &= 0xF; |
617 | *regs[RT2]=0; p->pop=0; | |
618 | } | |
619 | delnode(p->forw); | |
864f1f35 SL |
620 | if (tempreg(lastrand,r2)) |
621 | uses[r2]=uses[r], uses[r]=0; | |
3347ccab SL |
622 | redun3(p); |
623 | newcode(p); redunm++; flow=r; | |
864f1f35 | 624 | } else if (p->op==MOV) { /* superfluous fetch */ |
3347ccab SL |
625 | int nmatch; |
626 | char src[C2_ASIZE]; | |
627 | movit: | |
864f1f35 SL |
628 | for (cp2=src, cp1=regs[RT1]; *cp2++= *cp1++;) |
629 | ; | |
3347ccab SL |
630 | splitrand(p->forw); |
631 | if (p->forw->op != INC && p->forw->op != DEC) | |
632 | lastrand=byondrd(p->forw); | |
633 | nmatch=0; | |
634 | for (preg=regs+RT1;*preg!=lastrand;preg++) | |
635 | if (r==isreg(*preg)) { | |
864f1f35 SL |
636 | cp2= *preg; cp1=src; |
637 | while (*cp2++= *cp1++) | |
638 | ; | |
639 | ++nmatch; | |
3347ccab SL |
640 | } |
641 | if (nmatch==1) { | |
864f1f35 | 642 | if (has2ops(p->forw) && equstr(src,regs[RT2])) { |
3347ccab | 643 | p->forw->pop=0; |
864f1f35 SL |
644 | p->forw->subop += (OP3-OP2)<<4; |
645 | cp1=regs[RT3]; | |
646 | *cp1++ = 'r'; *cp1++ = r+'0'; *cp1=0; | |
3347ccab | 647 | } |
864f1f35 SL |
648 | delnode(p); |
649 | p=p->forw; | |
650 | if (tempreg(src,r2)) | |
651 | uses[r2]=uses[r], uses[r]=0; | |
3347ccab SL |
652 | redun3(p); |
653 | newcode(p); redunm++; flow=r; | |
864f1f35 SL |
654 | } else |
655 | splitrand(p); | |
3347ccab | 656 | } |
864f1f35 SL |
657 | } else if (p->op==MOV && (p->forw->op==CVT || p->forw->op==MOVZ) && |
658 | p->forw->subop&0xf && /* if base or index, then forget it */ | |
659 | compat(p->subop,p->forw->subop) && !indexa(cp1=regs[RT1])) | |
660 | goto movit; | |
3347ccab SL |
661 | } |
662 | /* adjust 'lastrand' past any 'read' or 'modify' operands. */ | |
663 | lastrand=byondrd(p); | |
664 | /* a 'write' clobbers the register. */ | |
864f1f35 SL |
665 | if (tempreg(lastrand,r) || |
666 | (has2ops(p) && tempreg(regs[RT2],r) && uses[r]==0)) { | |
667 | /* | |
668 | * Writing a dead register is useless, | |
669 | * but watch side effects | |
670 | */ | |
3347ccab SL |
671 | switch (p->op) { |
672 | #ifndef EMOD | |
673 | case EDIV: | |
674 | #endif EMOD | |
675 | case EMUL: | |
864f1f35 SL |
676 | case AOBLEQ: case AOBLSS: |
677 | break; | |
3347ccab | 678 | default: |
864f1f35 SL |
679 | /* |
680 | * If no direct uses, check for | |
681 | * use of condition codes | |
682 | */ | |
3347ccab | 683 | if (uses[r]==0 && ((dblflg&1)==0 || uses[r+1]==0)) { |
864f1f35 SL |
684 | register struct node *q = p; |
685 | ||
686 | while ((q = nonlab(q->forw))->op==JBR && | |
687 | q->subop==0) | |
688 | q=q->ref; /* cc unused, unchanged */ | |
689 | if (q->op!=CBR && q->op!=ADDA && q->op!=SUBA) { | |
690 | /* ... and destroyed */ | |
3347ccab | 691 | preg=regs+RT1; |
864f1f35 SL |
692 | while (cp1 = *preg++) { |
693 | if (cp1==lastrand && | |
694 | p->op != CLR && | |
695 | p->op != CVFL) { | |
696 | redunm++; | |
697 | delnode(p); | |
698 | return(p->forw); | |
699 | } | |
700 | if (equstr(cp1,lastrand)) | |
701 | break; | |
3347ccab SL |
702 | } |
703 | } | |
704 | } | |
705 | flow=r; | |
706 | } | |
707 | } | |
864f1f35 SL |
708 | if ((r=flow) >= 0) { |
709 | olduse=uses[r], uses[r]=0; | |
710 | *(short *)(regs[r])=0; | |
3347ccab | 711 | /* if r0 destroyed, dont keep r1 */ |
864f1f35 SL |
712 | if (dblflg&1) { |
713 | olduse1=uses[++r], uses[r]=0; | |
714 | *(short *)(regs[r])=0; | |
3347ccab SL |
715 | } |
716 | } | |
717 | /* now look for 'read' or 'modify' (read & write) uses */ | |
718 | preg=regs+RT1; | |
719 | while (*(cp1= *preg++)) { | |
720 | /* check for r */ | |
6e32ca3e DS |
721 | if (lastrand!=cp1 && tempreg(cp1,r)) { |
722 | int isunused; | |
723 | if (isunused=(uses[r]==0)) { | |
724 | uses[r]=p; | |
725 | cp2=regs[r]; *cp2++=p->subop; | |
726 | if ((p->op==SHAL || p->op==SHAR || | |
727 | p->op==SHL || p->op==SHR) && | |
728 | cp1==regs[RT1]) | |
729 | cp2[-1] = BYTE; | |
730 | if (p->op==CBR && (p->subop==JBC || p->subop==JBS)) | |
731 | cp2[-1] = LONG; | |
732 | if (p->op==MOVA && cp1==regs[RT2]) | |
733 | cp2[-1]=LONG; | |
734 | } | |
3347ccab | 735 | /* ediv/emod's 2nd operand is quad */ |
864f1f35 | 736 | if (((p->op==EDIV |
3347ccab | 737 | #ifdef EMOD |
864f1f35 | 738 | || p->op==EMOD |
3347ccab | 739 | #endif EMOD |
864f1f35 SL |
740 | ) && cp1==regs[RT2] || (dblflg&2)) && |
741 | ++r<NUSE && uses[r]==0) { | |
6e32ca3e DS |
742 | if (isunused) |
743 | *cp2=0; | |
864f1f35 SL |
744 | uses[r]=p; |
745 | cp2=regs[r]; *cp2++=p->subop; | |
6e32ca3e DS |
746 | if (!isunused) |
747 | *cp2=0; | |
3347ccab | 748 | } |
6e32ca3e DS |
749 | if (!isunused) |
750 | continue; | |
864f1f35 SL |
751 | if (p->op==MOV || p->op==PUSH || p->op==CVT || |
752 | p->op==MOVZ || p->op==COM || p->op==NEG || | |
753 | p->op==STF) { | |
754 | if (p->op!=PUSH) { | |
3347ccab | 755 | cp1=regs[RT2]; |
864f1f35 SL |
756 | if (tempreg(cp1,r)) { |
757 | /* | |
758 | * reincarnation!! | |
759 | * (as in addl2 r0,r1; | |
760 | * movl r1,r0; ret) | |
761 | */ | |
762 | if (uses[r]==0) | |
3347ccab | 763 | uses[r]=olduse; |
864f1f35 | 764 | if ((dblflg&1) && uses[r+1]==0) |
3347ccab SL |
765 | uses[r+1]=olduse1; |
766 | } | |
864f1f35 SL |
767 | if (p->op!=MOV) |
768 | cp1=0; | |
769 | } else | |
770 | cp1="-(sp)"; | |
771 | if (cp1) | |
772 | while (*cp2++= *cp1++) | |
773 | ; | |
774 | else | |
775 | *cp2=0; | |
776 | } else | |
777 | *cp2=0; | |
3347ccab SL |
778 | continue; |
779 | } | |
780 | /* check for (r),[r] */ | |
864f1f35 SL |
781 | do { |
782 | if (*cp1=='(' || *cp1=='[') { /* get register number */ | |
783 | char t; | |
784 | for (cp2= ++cp1; *++cp1!=')' && *cp1!=']';) | |
785 | ; | |
786 | t= *cp1; *cp1=0; | |
787 | if (tempreg(cp2,r) && | |
788 | (uses[r]==0 || uses[r]==p)) { | |
789 | uses[r]=p; | |
790 | regs[r][0] = | |
791 | (*--cp2=='[' ? OPX<<4 : OPB<<4); | |
792 | } | |
793 | *cp1=t; | |
3347ccab | 794 | } |
3347ccab SL |
795 | } while (*++cp1); |
796 | } | |
797 | #ifdef MOVAFASTER | |
798 | /* pushax or movax possibility? */ | |
799 | cp1=regs[RT1]; | |
800 | if (*cp1++=='$' && isstatic(cp1)) { | |
801 | if (p->op==MOV && p->subop==LONG) { | |
802 | if (regs[RT1][1]=='L' && 0!=(p->labno=getnum(regs[RT1]+2))) { | |
803 | cp1=p->code; while (*cp1++!=','); p->code= --cp1; | |
804 | } | |
805 | p->op = MOVA; p->subop = BYTE; ++p->code; p->pop=0; | |
806 | } else if (p->op==PUSH && p->subop==LONG) { | |
807 | p->op = PUSHA; p->subop = BYTE; ++p->code; p->pop=0; | |
808 | } else if (p->op==ADD && p->subop==U(LONG,OP3) | |
809 | && 0<=(r=isreg(regs[RT2]))) { | |
810 | cp1=cp2=p->code; ++cp1; | |
811 | do *cp2++= *cp1; while (*cp1++!=','); cp2[-1]='['; | |
812 | do *cp2++= *cp1; while (*cp1++!=','); cp2[-1]=']'; | |
813 | if (!equstr(regs[RT3],"-(sp)")){ p->op = MOVA; p->subop = BYTE;} | |
814 | else {p->op = PUSHA; p->subop = BYTE; *cp2=0;} | |
815 | if (uses[r]==0) {uses[r]=p; regs[r][0]=OPX<<4;} | |
816 | p->pop=0; | |
817 | } | |
818 | } | |
819 | #endif MOVAFASTER | |
864f1f35 | 820 | return (p); |
3347ccab SL |
821 | } |
822 | ||
823 | /* try to eliminate STF's */ | |
824 | struct node * | |
825 | flops(q) | |
826 | register struct node *q; | |
827 | { | |
828 | register struct node *p; | |
829 | register int r; | |
830 | ||
864f1f35 | 831 | if(q->op!=STF || !tempreg(q->code,r)) |
3347ccab SL |
832 | return(q); |
833 | if(uses[r]) { | |
834 | /* see if anyone destroys acc between us */ | |
835 | for(p=q->forw; p!=uses[r]; p=p->forw) | |
836 | switch(p->op) { | |
837 | case LABEL: | |
838 | case LDF: case LNF: case CVLF: case LDFD: | |
839 | case CVDF: case NEGF: case ADDF: case SUBF: | |
840 | case MULF: case DIVF: case SINF: case COSF: | |
841 | case ATANF: case LOGF: case SQRTF: case EXPF: | |
842 | return(q); | |
843 | } | |
844 | ||
845 | if(q->subop == p->subop) | |
846 | switch(p->op) { /* do it in the accumulator */ | |
847 | case LDF: /* redundant load */ | |
848 | delnode(p); nld++; | |
849 | p = p->forw; | |
850 | break; | |
851 | case LNF: /* stf r; lnf r ==> negf */ | |
852 | p->op = NEGF; | |
853 | p->pop = 0; | |
854 | p->code = 0; | |
855 | break; | |
856 | case CMPF2: /* stf r; cmpf2 r,x ==> cmpf x */ | |
857 | { register char *s; | |
858 | register struct node *p1=p->forw; | |
859 | for(s=p->code; *s!=','; s++); | |
860 | *s = 0; | |
861 | if(isreg(p->code) == r) | |
862 | p->code = s+1; | |
863 | else { | |
864 | if(p1->op != CBR || isreg(s+1) != r) { | |
865 | *s = ','; | |
866 | return(q); | |
867 | } | |
868 | if(p1->subop > JNE) { | |
869 | p1->subop ^= 1; | |
870 | p1->pop = 0; | |
871 | nrevbr++; | |
872 | } | |
873 | } | |
874 | p->op = CMPF; | |
875 | p->pop = 0; | |
876 | } | |
877 | break; | |
878 | default: | |
879 | return(q); | |
880 | } | |
881 | else if(p->subop==LONG) { | |
882 | switch(p->op) { | |
883 | case TST: /* stf r; tstl r ==> tstf */ | |
884 | p->op = TSTF; | |
885 | p->code = 0; | |
886 | break; | |
887 | /* send directly to destination */ | |
888 | case MOV: /* stf r; movl r,x ==> stf x */ | |
889 | case PUSH: /* stf r; pushl r ==> stf -(sp)/pushd */ | |
890 | if(q->subop == DOUBLE) { | |
891 | register struct node *b = p->back; | |
892 | /* assume b's 2nd arg is ok */ | |
893 | if(!(b==uses[r+1] && b->op==p->op && b->subop==LONG)) | |
894 | return(q); | |
895 | delnode(b); redunm++; | |
896 | } | |
897 | if(p->op==PUSH) { | |
898 | if(q->subop == DOUBLE) { | |
899 | p->op = PUSHD; | |
900 | p->code = 0; | |
901 | } else { | |
902 | p->op = q->op; | |
903 | p->code = copy("-(sp)"); | |
904 | } | |
905 | } else { | |
906 | p->op = q->op; | |
907 | while(*p->code++ != ','); | |
908 | } | |
909 | break; | |
910 | default: | |
911 | return(q); | |
912 | } | |
913 | p->pop = 0; | |
914 | p->subop = q->subop; | |
915 | } else | |
916 | return(q); | |
917 | uses[r] = 0; | |
918 | if(q->subop == DOUBLE) | |
919 | uses[r+1] = 0; | |
920 | { /* undo any effect on uses in the area between p and q, | |
921 | * as we are going over it again */ | |
922 | register struct node *b; | |
923 | for(b=p; b!=q; b=b->back) { | |
924 | for(r=0; r<NUSE; r++) { | |
925 | if(uses[r] == b) | |
926 | uses[r] = 0; | |
927 | if(useacc == b) | |
928 | useacc = 0; | |
929 | } | |
930 | } | |
931 | } | |
932 | return(p->forw); /* make p the next for bflow */ | |
933 | } | |
934 | /* it's a store to reg which isnt used elsewhere */ | |
935 | if((p=q->forw)->op == CBR) { | |
936 | q->op = TSTF; | |
937 | q->pop = 0; | |
938 | q->code = 0; | |
939 | } else { | |
940 | delnode(q); nst++; | |
941 | if(p->op ==STF || p->op==TSTF || p->op==PUSHD) { | |
942 | if(useacc == p) | |
943 | useacc = 0; | |
944 | return(p->forw); /* so ldmov can be used on p */ | |
945 | } | |
946 | } | |
947 | return(p); | |
948 | } | |
949 | ||
950 | /* try to change load/store sequences to movl */ | |
951 | ldmov(q) | |
952 | register struct node *q; | |
953 | { | |
954 | register struct node *p; | |
955 | register char *s, *pcod, *cp; | |
956 | char *dlsw(); | |
957 | ||
958 | p = q->back; | |
959 | if(!(useacc==0 && (q->op==STF || q->op==TSTF || q->op==PUSHD) | |
960 | && ((p->op==LDF && p->subop==q->subop) || (p->op==LDFD && q->subop==DOUBLE)))) | |
961 | return(0); | |
962 | pcod = p->code; | |
963 | cp = p->code; | |
964 | /* prepare args for movl/pushl */ | |
965 | if(q->op!=TSTF && q->subop==DOUBLE) { | |
966 | if(p->op == LDF) { | |
967 | if((s = dlsw(p->code)) == NULL) | |
968 | return(0); | |
e6c8f4f3 | 969 | |
3347ccab SL |
970 | strcpy(line, s); |
971 | if(q->op == STF) { | |
972 | strcat(line, ","); | |
973 | if((s = dlsw(q->code)) == NULL) | |
974 | return(0); | |
975 | strcat(line, s); | |
976 | p->op = MOV; | |
977 | } else | |
978 | p->op = PUSH; | |
979 | } else { /* LDFD */ | |
980 | if(q->op == STF) { | |
981 | if((s = dlsw(q->code)) == NULL) | |
982 | return(0); | |
983 | } else | |
984 | s = "-(sp)"; | |
985 | strcpy(line, s); | |
986 | p->op = CLR; | |
987 | } | |
988 | p->pop = 0; | |
989 | p->subop = LONG; | |
990 | p->code = copy(line); | |
991 | } else | |
992 | { | |
993 | if ((p->op == LDF) && (p->subop == DOUBLE) && | |
994 | (indexa(cp))) return(0); | |
995 | delnode(p); | |
996 | } | |
997 | strcpy(line, pcod); | |
998 | if(q->op == STF) { /* ldf x; stf y ==> movl x,y */ | |
999 | strcat(line, ","); | |
1000 | strcat(line, q->code); | |
1001 | q->op = MOV; | |
1002 | nst++; | |
1003 | } else if(q->op == TSTF) /* ldf x; tstf ==> tstl x */ | |
1004 | q->op = TST; | |
1005 | else /* ldd x; pushd ==> pushl x+4; pushl x */ | |
1006 | q->op = PUSH; | |
1007 | q->pop = 0; | |
1008 | q->subop = LONG; | |
1009 | q->code = copy(line); | |
1010 | nld++; | |
1011 | return(1); | |
1012 | } | |
1013 | ||
1014 | /* reconstruct the address of l.s.w. of a double operand */ | |
1015 | char * | |
1016 | dlsw(d) | |
1017 | register char *d; | |
1018 | { | |
e6c8f4f3 | 1019 | register char *s, *t, *c; |
3347ccab SL |
1020 | register int r; |
1021 | static char lsw[C2_ASIZE]; | |
1022 | ||
1023 | if(d[0] == '*' || d[0] == '$') | |
1024 | return(NULL); | |
e6c8f4f3 SL |
1025 | if (((strncmp(d, "(r", 2)) == 0) && isdigit(d[2])) |
1026 | return(NULL); | |
3347ccab SL |
1027 | t = lsw; |
1028 | if((r=isreg(d)) >= 0) | |
1029 | sprintf(t, "r%d", r+1); | |
1030 | else { | |
1031 | for(s=d; *s && *s!='('; *t++ = *s++) | |
1032 | if(*s == '[') | |
1033 | return(NULL); | |
e6c8f4f3 SL |
1034 | if(s!=d) |
1035 | *t++ = '+'; | |
1036 | *t++ = '4'; | |
3347ccab | 1037 | while(*t++ = *s) |
e6c8f4f3 SL |
1038 | if(*s++ == '[' ) |
1039 | { | |
3347ccab | 1040 | return(NULL); |
e6c8f4f3 | 1041 | } |
3347ccab SL |
1042 | } |
1043 | return(lsw); | |
1044 | } | |
e6c8f4f3 SL |
1045 | checkexpr(p) |
1046 | register char *p; | |
1047 | { | |
1048 | ||
1049 | while(*p && *p != ','){ | |
1050 | if ((*p == '+' ) || (*p == '-')) | |
1051 | return(1); | |
1052 | *p++; | |
1053 | } | |
1054 | return(0); | |
1055 | } |