Commit | Line | Data |
---|---|---|
f101f434 TL |
1 | # |
2 | char C21[] = {"@(#)c21.c 1.59 79/01/20 11:07:52"}; /* sccs ident */ | |
3 | /* | |
4 | * C object code improver-- second part | |
5 | */ | |
6 | ||
7 | #include "c2.h" | |
8 | #include <stdio.h> | |
9 | #include <ctype.h> | |
10 | ||
11 | #define NUSE 6 | |
12 | int ioflag; | |
13 | int biti[NUSE] = {1,2,4,8,16,32}; | |
14 | int bitsize[4] = {0,8,16,32}; /* index by type codes */ | |
15 | int pos,siz; long f; /* for bit field communication */ | |
16 | struct node *uses[NUSE]; /* for backwards flow analysis */ | |
17 | char *lastrand; /* last operand of instruction */ | |
18 | struct node *bflow(); | |
19 | struct node *bicopt(); | |
20 | char *findcon(); | |
21 | ||
22 | redun3(p,split) register struct node *p; int split; { | |
23 | /* check for 3 addr instr which should be 2 addr */ | |
24 | if (OP3==((p->subop>>4)&0xF)) { | |
25 | if (split) splitrand(p); | |
26 | if (equstr(regs[RT1],regs[RT3]) | |
27 | && (p->op==ADD || p->op==MUL || p->op==BIS || p->op==XOR)) { | |
28 | register char *t=regs[RT1]; regs[RT1]=regs[RT2]; regs[RT2]=t; | |
29 | } | |
30 | if (equstr(regs[RT2],regs[RT3])) { | |
31 | p->subop=(p->subop&0xF)|(OP2<<4); p->pop=0; | |
32 | lastrand=regs[RT2]; *regs[RT3]=0; return(1); | |
33 | } | |
34 | } return(0); | |
35 | } | |
36 | ||
37 | bmove() { | |
38 | register struct node *p, *lastp; register char *cp1,*cp2; register int r; | |
39 | refcount(); | |
40 | for (p=lastp= &first; 0!=(p=p->forw); lastp=p); | |
41 | clearreg(); clearuse(); | |
42 | for (p=lastp; p!= &first; p=p->back) { | |
43 | if (debug) { | |
44 | for (r=NUSE;--r>=0;) if (uses[r]) printf("%d: %s\n",r,uses[r]->code); | |
45 | printf("-\n"); | |
46 | } | |
47 | if (OP3==((p->subop>>4)&0xF) && 0!=redun3(p,1)) {newcode(p); redunm++;} | |
48 | switch (p->op) { | |
49 | case LABEL: case DLABEL: | |
50 | if (p->back && p->back->op==JBR && p->back->subop!=RET) | |
51 | for (r=NUSE; --r>=0;) if (uses[r] && regs[r][0]!= -1) | |
52 | p->ref=(struct node *) (((int)p->ref)|biti[r]); | |
53 | case CALLS: case 0: | |
54 | clearuse(); break; | |
55 | case SUB: | |
56 | if ((p->subop&0xF)!=LONG) goto std; cp1=p->code; | |
57 | if (*cp1++!='$') goto std; splitrand(p); | |
58 | if (equstr(regs[RT2],"fp") && !indexa(regs[RT1])) {/* address comp. */ | |
59 | char buf[50]; cp2=buf; *cp2++='-'; | |
60 | cp1=regs[RT1]+1; while (*cp2++= *cp1++); --cp2; | |
61 | cp1="(fp),"; while (*cp2++= *cp1++); --cp2; | |
62 | cp1=regs[RT3]; while (*cp2++= *cp1++); | |
63 | p->code=copy(buf); p->combop=T(MOVA,LONG); p->pop=0; | |
64 | } else if (*cp1++=='-' && 0<=(r=getnum(cp1))) { | |
65 | p->op=ADD; p->pop=0; *--cp1='$'; p->code=cp1; | |
66 | } goto std; | |
67 | case ADD: | |
68 | if ((p->subop&0xF)!=LONG) goto std; cp1=p->code; | |
69 | if (*cp1++!='$') goto std; splitrand(p); | |
70 | if (equstr(regs[RT2],"fp") && !indexa(regs[RT1])) {/* address comp. */ | |
71 | cp2=cp1-1; cp1=regs[RT1]+1; while (*cp2++= *cp1++); --cp2; | |
72 | cp1="(fp)"; while (*cp2++= *cp1++); *--cp2=','; | |
73 | p->combop=T(MOVA,LONG); p->pop=0; | |
74 | } else if (*cp1++=='-' && 0<=(r=getnum(cp1))) { | |
75 | p->op=SUB; p->pop=0; *--cp1='$'; p->code=cp1; | |
76 | } | |
77 | case CASE: | |
78 | default: std: | |
79 | p=bflow(p); break; | |
80 | case JBR: | |
81 | if (p->subop==RET) {uses[0]=p; regs[0][0]= -1; break;} | |
82 | else if (p->ref->ref!=0) for (r=NUSE;--r>=0;) | |
83 | if (biti[r] & (int)p->ref->ref) {uses[r]=p; regs[r][0]= -1;} | |
84 | case CBR: case JMP: case EROU: case JSW: | |
85 | case TEXT: case DATA: case BSS: case ALIGN: case WGEN: case END: ; | |
86 | } | |
87 | } | |
88 | } | |
89 | ||
90 | rmove() | |
91 | { | |
92 | register struct node *p, *lastp; | |
93 | register int r; | |
94 | int r1; | |
95 | ||
96 | clearreg(); | |
97 | for (p=first.forw; p!=0; p = p->forw) { | |
98 | lastp=p; | |
99 | if (debug) { | |
100 | for (r=0; r<NREG; r++) | |
101 | if (regs[r][0]) { | |
102 | r1=regs[r][0]; | |
103 | printf("%d: %d%d %s\n", r, r1&0xF, r1>>4, regs[r]+1); | |
104 | } | |
105 | printf("-\n"); | |
106 | } | |
107 | switch (p->op) { | |
108 | ||
109 | case CVT: | |
110 | splitrand(p); goto mov; | |
111 | ||
112 | case MOV: | |
113 | splitrand(p); | |
114 | if ((r = findrand(regs[RT1],p->subop)) >= 0) { | |
115 | if (r == isreg(regs[RT2]) && p->forw->op!=CBR) { | |
116 | delnode(p); redunm++; break; | |
117 | } | |
118 | } | |
119 | mov: | |
120 | repladdr(p); | |
121 | r = isreg(regs[RT1]); | |
122 | r1 = isreg(regs[RT2]); | |
123 | dest(regs[RT2],p->subop); | |
124 | if (r >= 0) | |
125 | if (r1 >= 0) savereg(r1, regs[r]+1, p->subop); | |
126 | else savereg(r, regs[RT2], p->subop); | |
127 | else | |
128 | if (r1 >= 0) savereg(r1, regs[RT1], p->subop); | |
129 | else setcon(regs[RT1], regs[RT2], p->subop); | |
130 | break; | |
131 | ||
132 | /* .rx,.wx */ | |
133 | case COM: | |
134 | case NEG: | |
135 | /* .rx,.wx or .rx,.rx,.wx */ | |
136 | case ADD: | |
137 | case SUB: | |
138 | case BIC: | |
139 | case BIS: | |
140 | case XOR: | |
141 | case MUL: | |
142 | case DIV: | |
143 | case ASH: | |
144 | case MOVZ: | |
145 | /* .rx,.rx,.rx,.wx */ | |
146 | case EXTV: | |
147 | case EXTZV: | |
148 | case INSV: | |
149 | splitrand(p); | |
150 | repladdr(p); | |
151 | dest(lastrand,p->subop); | |
152 | if (p->op==INSV) ccloc[0]=0; | |
153 | break; | |
154 | ||
155 | /* .mx or .wx */ | |
156 | case CLR: | |
157 | case INC: | |
158 | case DEC: | |
159 | splitrand(p); | |
160 | dest(lastrand,p->subop); | |
161 | if (p->op==CLR) | |
162 | if ((r = isreg(regs[RT1])) >= 0) | |
163 | savereg(r, "$0", p->subop); | |
164 | else | |
165 | setcon("$0", regs[RT1], p->subop); | |
166 | break; | |
167 | ||
168 | /* .rx */ | |
169 | case TST: | |
170 | case PUSH: | |
171 | splitrand(p); | |
172 | lastrand=regs[RT1+1]; /* fool repladdr into doing 1 operand */ | |
173 | repladdr(p); | |
174 | if (p->op==TST && equstr(lastrand=regs[RT1], ccloc+1) | |
175 | && equtype(ccloc[0],p->subop) &&!source(lastrand)) { | |
176 | delnode(p); p = p->back; nrtst++; nchange++; | |
177 | } | |
178 | setcc(lastrand,p->subop); | |
179 | break; | |
180 | ||
181 | /* .rx,.rx,.rx */ | |
182 | case CASE: | |
183 | /* .rx,.rx */ | |
184 | case CALLS: | |
185 | case CMP: | |
186 | case BIT: | |
187 | splitrand(p); | |
188 | /* fool repladdr into doing right number of operands */ | |
189 | if (p->op!=CASE) lastrand=regs[RT3]; else lastrand=regs[RT4]; | |
190 | repladdr(p); | |
191 | if (p->op==CALLS) clearreg(); | |
192 | if (p->op==BIT) bitopt(p); | |
193 | ccloc[0]=0; break; | |
194 | ||
195 | case CBR: | |
196 | if (p->subop>=JBC) {/* 2 operands can be optimized */ | |
197 | splitrand(p); lastrand=regs[RT3]; repladdr(p); | |
198 | } | |
199 | ccloc[0] = 0; | |
200 | break; | |
201 | ||
202 | case JBR: | |
203 | redunbr(p); | |
204 | ||
205 | /* .wx,.bb */ | |
206 | case SOB: | |
207 | ||
208 | default: | |
209 | clearreg(); | |
210 | } | |
211 | } | |
212 | } | |
213 | ||
214 | char * | |
215 | byondrd(p) register struct node *p; { | |
216 | /* return pointer to register which is "beyond last read/modify operand" */ | |
217 | if (OP2==(p->subop>>4)) return(regs[RT3]); | |
218 | switch (p->op) { | |
219 | case PUSHA: | |
220 | case TST: case INC: case DEC: case PUSH: return(regs[RT2]); | |
221 | case BIT: case CMP: case CALLS: return(regs[RT3]); | |
222 | case CASE: return(regs[RT4]); | |
223 | } | |
224 | return(lastrand); | |
225 | } | |
226 | ||
227 | struct node * | |
228 | bflow(p) register struct node *p; { | |
229 | register char *cp1,*cp2,**preg; register int r; | |
230 | splitrand(p); | |
231 | if (0<=(r=isreg(lastrand)) && r<NUSE && p->op!=PUSH && | |
232 | uses[r]==p->forw && p->subop && equtype(regs[r][0],p->subop)) { | |
233 | if (regs[r][1]!=0) {/* send directly to destination */ | |
234 | if (p->op==INC || p->op==DEC) { | |
235 | if (p->op==DEC) p->op=SUB; else p->op=ADD; | |
236 | p->subop=(OP2<<4)+(p->subop&0xF); /* use 2 now, convert to 3 later */ | |
237 | p->pop=0; | |
238 | cp1=lastrand; cp2=regs[RT2]; while (*cp2++= *cp1++); /* copy reg */ | |
239 | cp1=lastrand; *cp1++='$'; *cp1++='1'; *cp1=0; | |
240 | } | |
241 | cp1=regs[r]+1; cp2=lastrand; | |
242 | if (OP2==(p->subop>>4)) {/* use 3 operand form of instruction */ | |
243 | p->pop=0; | |
244 | p->subop += (OP3-OP2)<<4; lastrand=cp2=regs[RT3]; | |
245 | } | |
246 | while (*cp2++= *cp1++); | |
247 | if (p->op==MOVA && p->forw->op==PUSH) { | |
248 | p->op=PUSHA; *regs[RT2]=0; p->pop=0; | |
249 | } | |
250 | delnode(p->forw); | |
251 | redun3(p,0); | |
252 | newcode(p); redunm++; uses[r]=0; *(short *)(regs[r])=0; | |
253 | } else if (p->op==MOV && p->forw->op!=EXTV && p->forw->op!=EXTZV) { | |
254 | /* superfluous fetch */ | |
255 | int nmatch; | |
256 | char src[20]; cp2=src; cp1=regs[RT1]; while (*cp2++= *cp1++); | |
257 | splitrand(p->forw); lastrand=byondrd(p->forw); nmatch=0; | |
258 | for (preg=regs+RT1;*preg!=lastrand;preg++) if (r==isreg(*preg)) { | |
259 | cp2= *preg; cp1=src; while (*cp2++= *cp1++); ++nmatch; | |
260 | } | |
261 | if (nmatch==1) { | |
262 | if (OP2==(p->forw->subop>>4) && equstr(src,regs[RT2])) { | |
263 | p->forw->pop=0; | |
264 | p->forw->subop += (OP3-OP2)<<4; cp1=regs[RT3]; | |
265 | *cp1++='r'; *cp1++=r+'0'; *cp1=0; | |
266 | } | |
267 | delnode(p); p=p->forw; | |
268 | redun3(p,0); | |
269 | newcode(p); redunm++; uses[r]=0; *(short *)(regs[r])=0; | |
270 | } | |
271 | } | |
272 | } | |
273 | /* adjust 'lastrand' past any 'read' or 'modify' operands. */ | |
274 | lastrand=byondrd(p); | |
275 | /* a 'write' clobbers the register. */ | |
276 | if (0<=(r=isreg(lastrand)) && r<NUSE | |
277 | || OP2==(p->subop>>4) && 0<=(r=isreg(regs[RT2])) && r<NUSE) | |
278 | {uses[r]=0; *(short *)(regs[r])=0;} | |
279 | if (p->op==BIC) {p=bicopt(p); splitrand(p); lastrand=byondrd(p);} | |
280 | if (p->op==BIS) bixprep(p,JBSS); | |
281 | /* now look for 'read' or 'modify' (read & write) uses */ | |
282 | preg=regs+RT1; | |
283 | while (*(cp1= *preg++)) { | |
284 | /* check for r */ | |
285 | if (lastrand!=cp1 && 0<=(r=isreg(cp1)) && r<NUSE && uses[r]==0) { | |
286 | uses[r]=p; cp2=regs[r]; *cp2++=p->subop; | |
287 | if (p->op==MOV || p->op==PUSH) { | |
288 | if (p->op==PUSH) cp1="-(sp)"; else cp1=regs[RT2]; | |
289 | while (*cp2++= *cp1++); | |
290 | } else *cp2++=0; | |
291 | continue; | |
292 | } | |
293 | /* check for (r),(r)+,-(r),[r] */ | |
294 | do if (*cp1=='(' || *cp1=='[') {/* get register number */ | |
295 | char t; | |
296 | cp2= ++cp1; while (*++cp1!=')' && *cp1!=']'); t= *cp1; *cp1=0; | |
297 | if (0<=(r=isreg(cp2)) && r<NUSE && (uses[r]==0 || uses[r]==p)) { | |
298 | uses[r]=p; regs[r][0]=(*--cp2=='[' ? OPX<<4 : OPB<<4); | |
299 | } | |
300 | *cp1=t; | |
301 | } while (*++cp1); | |
302 | } | |
303 | /* pushax or movax possibility? */ | |
304 | cp1=regs[RT1]; | |
305 | if (*cp1++=='$' | |
306 | && (*cp1=='_' || *cp1=='L' || (*cp1++=='v' && *cp1=='.')) | |
307 | && natural(regs[RT1])) { | |
308 | if (p->combop==T(MOV,LONG)) { | |
309 | if (regs[RT1][1]=='L' && 0!=(p->labno=getnum(regs[RT1]+2))) { | |
310 | cp1=p->code; while (*cp1++!=','); p->code= --cp1; | |
311 | } | |
312 | p->combop=T(MOVA,LONG); ++p->code; p->pop=0; | |
313 | } else if (p->combop==T(PUSH,LONG)) { | |
314 | p->combop=T(PUSHA,LONG); ++p->code; p->pop=0; | |
315 | } else if ((p->combop&0xFFFF)==T(ADD,U(LONG,OP3)) | |
316 | && 0<=(r=isreg(regs[RT2]))) { | |
317 | cp1=cp2=p->code; ++cp1; | |
318 | do *cp2++= *cp1; while (*cp1++!=','); cp2[-1]='['; | |
319 | do *cp2++= *cp1; while (*cp1++!=','); cp2[-1]=']'; | |
320 | if (!equstr(regs[RT3],"-(sp)")) p->combop=T(MOVA,BYTE); | |
321 | else {p->combop=T(PUSHA,BYTE); *cp2=0;} | |
322 | if (uses[r]==0) {uses[r]=p; regs[r][0]=OPX<<4;} | |
323 | p->pop=0; | |
324 | } | |
325 | } | |
326 | return(p); | |
327 | } | |
328 | ||
329 | ispow2(n) register long n; {/* -1 -> no; else -> log to base 2 */ | |
330 | register int log; | |
331 | if (n==0 || n&(n-1)) return(-1); log=0; | |
332 | for (;;) {n >>= 1; if (n==0) return(log); ++log; if (n== -1) return(log);} | |
333 | } | |
334 | ||
335 | bitopt(p) register struct node *p; { | |
336 | /* change "bitx $<power_of_2>,a" followed by JEQ or JNE | |
337 | /* into JBC or JBS. watch out for I/O registers. (?) | |
338 | /* assumes that 'splitrand' has already been called. | |
339 | */ | |
340 | register char *cp1,*cp2; int b; | |
341 | cp1=regs[RT1]; cp2=regs[RT2]; | |
342 | if (*cp1++!='$' || !okio(cp2) || p->forw->op!=CBR || p->forw->subop&-2 || | |
343 | 0>(b=ispow2(getnum(cp1))) || p->subop!=BYTE && indexa(cp2)) return; | |
344 | if (b>=bitsize[p->subop]) {/* you dummy! */ | |
345 | if (source(cp2)) {/* side effect: auto increment or decrement */ | |
346 | p->pop=0; | |
347 | p->op=TST; --cp1; while (*cp1++= *cp2++); | |
348 | regs[RT2][0]=0; newcode(p); | |
349 | } else delnode(p); | |
350 | p = p->forw; | |
351 | if (p->subop==JEQ) {p->combop=JBR; p->pop=0;} | |
352 | else delnode(p); | |
353 | nchange++; nbj++; return; | |
354 | } | |
355 | if (cp1=p->forw->code) {/* destination is not an internal label */ | |
356 | cp2=regs[RT3]; while (*cp2++= *cp1++); | |
357 | } | |
358 | if (b==0 && (p->subop==LONG || !indexa(regs[RT2]))) {/* JLB optimization, ala BLISS */ | |
359 | cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++); | |
360 | cp2=regs[RT2]; cp1=regs[RT3]; while (*cp2++= *cp1++); | |
361 | *(regs[RT3])=0; p->forw->subop += JLBC-JBC; | |
362 | p->forw->pop=0; | |
363 | } else { | |
364 | cp1=regs[RT1]+1; | |
365 | if (b>9) *cp1++= b/10 +'0'; *cp1++= b%10 +'0'; *cp1=0; /* $<bit_number> */ | |
366 | } | |
367 | nbj++; newcode(p); p->combop = p->forw->combop+((JBC-JEQ)<<8); | |
368 | p->labno = p->forw->labno; delnode(p->forw); | |
369 | p->pop=0; | |
370 | } | |
371 | ||
372 | isfield(n) register long n; {/* -1 -> no; else -> position of low bit */ | |
373 | register int pos; register long t; | |
374 | t= ((n-1)|n) +1; | |
375 | if (n!=0 && (0==t || 0==n || 0<=ispow2(t))) { | |
376 | pos=0; while(!(n&1)) {n >>= 1; ++pos;} return(pos); | |
377 | } else return(-1); | |
378 | } | |
379 | ||
380 | bixprep(p,bix) register struct node *p; { | |
381 | /* initial setup, single-bit checking for bisopt, bicopt. | |
382 | /* return: 0->don't bother any more; 1->worthwhile trying | |
383 | */ | |
384 | register char *cp1,*cp2; | |
385 | splitrand(p); cp1=regs[RT1]; cp2=regs[RT2]; | |
386 | if (*cp1++!='$' || 0>(pos=isfield(f=getnum(cp1))) | |
387 | || !okio(cp2) || indexa(cp2) || source(cp2) || !okio(lastrand)) return(0); | |
388 | f |= f-1; if (++f==0) siz=32-pos; else siz=ispow2(f)-pos; | |
389 | if (siz==1 && pos>5 && (p->subop>>4)==OP2 && (p->subop&0xF)!=BYTE | |
390 | && pos<bitsize[p->subop&0xF]) { | |
391 | p->ref = insertl(p->forw); p->combop = CBR | (bix<<8); | |
392 | p->pop=0; | |
393 | p->labno = p->ref->labno; | |
394 | if (pos>9) {*cp1++= pos/10 +'0'; pos %= 10;} | |
395 | *cp1++=pos+'0'; *cp1=0; newcode(p); nbj++; return(0); | |
396 | } | |
397 | return(1); | |
398 | } | |
399 | ||
400 | ||
401 | struct node * | |
402 | bicopt(p) register struct node *p; { | |
403 | /* use field operations or MOVZ if possible. done as part of 'bflow'. | |
404 | */ | |
405 | register char *cp1,*cp2; int r; | |
406 | char src[50]; | |
407 | if (!bixprep(p,JBCC)) return(p); | |
408 | if (f<=0) {/* the BIC isolates low order bits */ | |
409 | siz=pos; pos=0; | |
410 | if ((p->subop&0xF)==LONG && *(regs[RT2])!='$') {/* result of EXTZV is long */ | |
411 | /* save source of BICL in 'src' */ | |
412 | cp1=regs[RT2]; cp2=src; while (*cp2++= *cp1++); | |
413 | if (p->back->op==ASH) {/* try for more */ | |
414 | splitrand(p->back); cp1=regs[RT1]; cp2=regs[RT3]; | |
415 | if (*cp1++=='$' && *(regs[RT2])!='$' && !indexa(regs[RT2]) | |
416 | && 0>(f=getnum(cp1)) && equstr(src,cp2) | |
417 | && 0<=(r=isreg(cp2)) && r<NUSE && uses[r]==0) {/* a good ASH */ | |
418 | pos -= f; cp1=regs[RT2]; cp2=src; while (*cp2++= *cp1++); | |
419 | delnode(p->back); | |
420 | } | |
421 | } | |
422 | if (p->back->op==CVT || p->back->op==MOVZ) {/* greedy, aren't we? */ | |
423 | splitrand(p->back); cp1=regs[RT1]; cp2=regs[RT2]; | |
424 | if (equstr(src,cp2) && okio(cp1) && !indexa(cp1) | |
425 | && 0<=(r=isreg(cp2)) && r<NUSE && uses[r]==0 | |
426 | && bitsize[p->back->subop&0xF]>=(pos+siz) | |
427 | && bitsize[p->back->subop>>4]>=(pos+siz)) {/* good CVT */ | |
428 | cp1=regs[RT1]; cp2=src; while (*cp2++= *cp1++); | |
429 | delnode(p->back); | |
430 | } | |
431 | } | |
432 | /* 'pos', 'siz' known; source of field is in 'src' */ | |
433 | splitrand(p); /* retrieve destination of BICL */ | |
434 | if (siz==8 && pos==0) { | |
435 | p->combop = T(MOVZ,U(BYTE,LONG)); | |
436 | sprintf(line,"%s,%s",src,lastrand); | |
437 | } else { | |
438 | p->combop = T(EXTZV,LONG); | |
439 | sprintf(line,"$%d,$%d,%s,%s",pos,siz,src,lastrand); | |
440 | } | |
441 | p->pop=0; | |
442 | p->code = copy(line); nfield++; return(p); | |
443 | }/* end EXTZV possibility */ | |
444 | }/* end low order bits */ | |
445 | /* unfortunately, INSV clears the condition codes, thus cannot be used */ | |
446 | /* else {/* see if BICL2 of positive field should be INSV $0 */ | |
447 | /* if (p->subop==(LONG | (OP2<<4)) && 6<=(pos+siz)) { | |
448 | /* p->combop = INSV; | |
449 | /* sprintf(line,"$0,$%d,$%d,%s",pos,siz,lastrand); | |
450 | /* p->code = copy(line); nfield++; return(p); | |
451 | /* } | |
452 | /* } | |
453 | */ | |
454 | return(p); | |
455 | } | |
456 | ||
457 | jumpsw() | |
458 | { | |
459 | register struct node *p, *p1; | |
460 | register t; | |
461 | int nj; | |
462 | ||
463 | t = 0; | |
464 | nj = 0; | |
465 | for (p=first.forw; p!=0; p = p->forw) | |
466 | p->seq = ++t; | |
467 | for (p=first.forw; p!=0; p = p1) { | |
468 | p1 = p->forw; | |
469 | if (p->op == CBR && p1->op==JBR && p->ref && p1->ref | |
470 | && abs(p->seq - p->ref->seq) > abs(p1->seq - p1->ref->seq)) { | |
471 | if (p->ref==p1->ref) | |
472 | continue; | |
473 | p->subop = revbr[p->subop]; | |
474 | p->pop=0; | |
475 | t = p1->ref; | |
476 | p1->ref = p->ref; | |
477 | p->ref = t; | |
478 | t = p1->labno; | |
479 | p1->labno = p->labno; | |
480 | p->labno = t; | |
481 | nrevbr++; | |
482 | nj++; | |
483 | } | |
484 | } | |
485 | return(nj); | |
486 | } | |
487 | ||
488 | addsob() | |
489 | { | |
490 | register struct node *p, *p1, *p2, *p3; | |
491 | ||
492 | for (p = &first; (p1 = p->forw)!=0; p = p1) { | |
493 | if (p->combop==T(DEC,LONG) && p1->op==CBR) { | |
494 | if (abs(p->seq - p1->ref->seq) > 12) continue; | |
495 | if (p1->subop==JGE || p1->subop==JGT) { | |
496 | if (p1->subop==JGE) p->combop=SOBGEQ; else p->combop=SOBGTR; | |
497 | p->pop=0; | |
498 | p->labno = p1->labno; delnode(p1); nsob++; | |
499 | } | |
500 | } else if (p->combop==T(INC,LONG)) { | |
501 | if (p1->op==LABEL && p1->refc==1 && p1->forw->combop==T(CMP,LONG) | |
502 | && (p2=p1->forw->forw)->combop==T(CBR,JLE) | |
503 | && (p3=p2->ref->back)->combop==JBR && p3->ref==p1 | |
504 | && p3->forw->op==LABEL && p3->forw==p2->ref) { | |
505 | /* change INC LAB: CMP to LAB: INC CMP */ | |
506 | p->back->forw=p1; p1->back=p->back; | |
507 | p->forw=p1->forw; p1->forw->back=p; | |
508 | p->back=p1; p1->forw=p; | |
509 | p1=p->forw; | |
510 | /* adjust beginning value by 1 */ | |
511 | p2=alloc(sizeof first); p2->combop=T(DEC,LONG); | |
512 | p2->pop=0; | |
513 | p2->forw=p3; p2->back=p3->back; p3->back->forw=p2; | |
514 | p3->back=p2; p2->code=p->code; p2->labno=0; | |
515 | } | |
516 | if (p1->combop==T(CMP,LONG) && (p2=p1->forw)->op==CBR) { | |
517 | register char *cp1,*cp2; | |
518 | splitrand(p1); if (!equstr(p->code,regs[RT1])) continue; | |
519 | if (abs(p->seq - p2->ref->seq)>12) {/* outside byte displ range */ | |
520 | if (p2->subop!=JLE) continue; | |
521 | p->combop=T(ACB,LONG); | |
522 | cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++); /* limit */ | |
523 | cp2=regs[RT2]; cp1="$1"; while (*cp2++= *cp1++); /* increment */ | |
524 | cp2=regs[RT3]; cp1=p->code; while (*cp2++= *cp1++); /* index */ | |
525 | p->pop=0; newcode(p); | |
526 | p->labno = p2->labno; delnode(p2); delnode(p1); nsob++; | |
527 | } else if (p2->subop==JLE || p2->subop==JLT) { | |
528 | if (p2->subop==JLE) p->combop=AOBLEQ; else p->combop=AOBLSS; | |
529 | cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++); /* limit */ | |
530 | cp2=regs[RT2]; cp1=p->code; while (*cp2++= *cp1++); /* index */ | |
531 | p->pop=0; newcode(p); | |
532 | p->labno = p2->labno; delnode(p2); delnode(p1); nsob++; | |
533 | } | |
534 | } | |
535 | } | |
536 | } | |
537 | } | |
538 | ||
539 | abs(x) | |
540 | { | |
541 | return(x<0? -x: x); | |
542 | } | |
543 | ||
544 | equop(p1, p2) | |
545 | register struct node *p1; | |
546 | struct node *p2; | |
547 | { | |
548 | register char *cp1, *cp2; | |
549 | ||
550 | if (p1->combop != p2->combop) | |
551 | return(0); | |
552 | if (p1->op>0 && p1->op<MOV) | |
553 | return(0); | |
554 | if (p1->op==MOVA && p1->labno!=p2->labno) return(0); | |
555 | cp1 = p1->code; | |
556 | cp2 = p2->code; | |
557 | if (cp1==0 && cp2==0) | |
558 | return(1); | |
559 | if (cp1==0 || cp2==0) | |
560 | return(0); | |
561 | while (*cp1 == *cp2++) | |
562 | if (*cp1++ == 0) | |
563 | return(1); | |
564 | return(0); | |
565 | } | |
566 | ||
567 | delnode(p) register struct node *p; { | |
568 | p->back->forw = p->forw; | |
569 | p->forw->back = p->back; | |
570 | } | |
571 | ||
572 | decref(p) | |
573 | register struct node *p; | |
574 | { | |
575 | if (p && --p->refc <= 0) { | |
576 | nrlab++; | |
577 | delnode(p); | |
578 | } | |
579 | } | |
580 | ||
581 | struct node * | |
582 | nonlab(ap) | |
583 | struct node *ap; | |
584 | { | |
585 | register struct node *p; | |
586 | ||
587 | p = ap; | |
588 | while (p && p->op==LABEL) | |
589 | p = p->forw; | |
590 | return(p); | |
591 | } | |
592 | ||
593 | clearuse() { | |
594 | register struct node **i; | |
595 | for (i=uses+NUSE; i>uses;) *--i=0; | |
596 | } | |
597 | ||
598 | clearreg() { | |
599 | register short **i; | |
600 | for (i=regs+NREG; i>regs;) **--i=0; | |
601 | conloc[0] = 0; ccloc[0] = 0; | |
602 | } | |
603 | ||
604 | savereg(ai, s, type) | |
605 | register char *s; | |
606 | { | |
607 | register char *p, *sp; | |
608 | ||
609 | sp = p = regs[ai]; | |
610 | if (source(s)) /* side effects in addressing */ | |
611 | return; | |
612 | /* if any indexing, must be parameter or local */ | |
613 | /* indirection (as in "*-4(fp)") is ok, however */ | |
614 | *p++ = type; | |
615 | while (*p++ = *s) | |
616 | if (*s=='[' || *s++=='(' && *s!='a' && *s!='f') {*sp = 0; return;} | |
617 | } | |
618 | ||
619 | dest(s,type) | |
620 | register char *s; | |
621 | { | |
622 | register int i; | |
623 | ||
624 | source(s); /* handle addressing side effects */ | |
625 | if ((i = isreg(s)) >= 0) { | |
626 | *(short *)(regs[i]) = 0; /* if register destination, that reg is a goner */ | |
627 | if (DOUBLE==(type&0xF) || DOUBLE==((type>>4)&0xF)) | |
628 | *(short *)(regs[i+1]) = 0; /* clobber two at once */ | |
629 | } | |
630 | for (i=NREG; --i>=0;) | |
631 | if (regs[i][1]=='*' && equstr(s, regs[i]+2)) | |
632 | *(short *)(regs[i]) = 0; /* previous indirection through destination is invalid */ | |
633 | while ((i = findrand(s,0)) >= 0) /* previous values of destination are invalid */ | |
634 | *(short *)(regs[i]) = 0; | |
635 | if (!natural(s)) {/* wild store, everything except constants vanishes */ | |
636 | for (i=NREG; --i>=0;) if (regs[i][1] != '$') *(short *)(regs[i]) = 0; | |
637 | conloc[0] = 0; ccloc[0] = 0; | |
638 | } else setcc(s,type); /* natural destinations set condition codes */ | |
639 | } | |
640 | ||
641 | splitrand(p) struct node *p; { | |
642 | /* separate operands at commas, set up 'regs' and 'lastrand' */ | |
643 | register char *p1, *p2; register char **preg; | |
644 | preg=regs+RT1; | |
645 | if (p1=p->code) while (*p1) { | |
646 | lastrand=p2= *preg++; | |
647 | while (*p1) if (','==(*p2++= *p1++)) {--p2; break;} | |
648 | *p2=0; | |
649 | } | |
650 | while (preg<(regs+RT1+5)) *(*preg++)=0; | |
651 | } | |
652 | ||
653 | compat(have, want) { | |
654 | register int hsrc, hdst; | |
655 | if (0==(want &= 0xF)) return(1); /* anything satisfies a wildcard want */ | |
656 | hsrc=have&0xF; if (0==(hdst=((have>>4)&0xF)) || hdst>=OP2) hdst=hsrc; | |
657 | /* last term prevents floats, doubles from satisfying a request for an int */ | |
658 | return(hsrc>=want && hdst>=want && !((want>=FLOAT) ^ (hdst>=FLOAT))); | |
659 | } | |
660 | ||
661 | equtype(t1,t2) {return(compat(t1,t2) && compat(t2,t1));} | |
662 | ||
663 | findrand(as, type) | |
664 | char *as; | |
665 | { | |
666 | register char **i; | |
667 | for (i = regs+NREG; --i>=regs;) { | |
668 | if (**i && equstr(*i+1, as) && compat(**i,type)) | |
669 | return(i-regs); | |
670 | } | |
671 | return(-1); | |
672 | } | |
673 | ||
674 | isreg(s) | |
675 | register char *s; | |
676 | { | |
677 | if (*s++!='r' || !isdigit(*s++)) return(-1); | |
678 | if (*s==0) return(*--s-'0'); | |
679 | if (*(s-1)=='1' && isdigit(*s++) && *s==0) return(10+*--s-'0'); | |
680 | return(-1); | |
681 | } | |
682 | ||
683 | check() | |
684 | { | |
685 | register struct node *p, *lp; | |
686 | ||
687 | lp = &first; | |
688 | for (p=first.forw; p!=0; p = p->forw) { | |
689 | if (p->back != lp) | |
690 | abort(-1); | |
691 | lp = p; | |
692 | } | |
693 | } | |
694 | ||
695 | source(ap) | |
696 | char *ap; | |
697 | { | |
698 | register char *p1, *p2; | |
699 | ||
700 | p1 = ap; | |
701 | p2 = p1; | |
702 | if (*p1==0) | |
703 | return(0); | |
704 | while (*p2++ && *(p2-1)!='['); | |
705 | if (*p1=='-' && *(p1+1)=='(' | |
706 | || *p1=='*' && *(p1+1)=='-' && *(p1+2)=='(' | |
707 | || *(p2-2)=='+') { | |
708 | while (*p1 && *p1++!='r'); | |
709 | if (isdigit(*p1++)) | |
710 | if (isdigit(*p1)) *(short *)(regs[10+*p1-'0'])=0; | |
711 | else *(short *)(regs[*--p1-'0'])=0; | |
712 | return(1); | |
713 | } | |
714 | return(0); | |
715 | } | |
716 | ||
717 | newcode(p) struct node *p; { | |
718 | register char *p1,*p2,**preg; | |
719 | preg=regs+RT1; p2=line; | |
720 | while (*(p1= *preg++)) {while (*p2++= *p1++); *(p2-1)=',';} | |
721 | *--p2=0; | |
722 | p->code=copy(line); | |
723 | } | |
724 | ||
725 | repladdr(p) | |
726 | struct node *p; | |
727 | { | |
728 | register r; | |
729 | register char *p1, *p2; | |
730 | char **preg; int nrepl; | |
731 | ||
732 | preg=regs+RT1; nrepl=0; | |
733 | while (lastrand!=(p1= *preg++)) | |
734 | if (!source(p1) && 0<=(r=findrand(p1,p->subop))) { | |
735 | *p1++='r'; if (r>9) {*p1++='1'; r -= 10;} *p1++=r+'0'; *p1=0; | |
736 | nrepl++; nsaddr++; | |
737 | } | |
738 | if (nrepl) newcode(p); | |
739 | } | |
740 | ||
741 | /* movedat() | |
742 | /* { | |
743 | /* register struct node *p1, *p2; | |
744 | /* struct node *p3; | |
745 | /* register seg; | |
746 | /* struct node data; | |
747 | /* struct node *datp; | |
748 | /* | |
749 | /* if (first.forw == 0) | |
750 | /* return; | |
751 | /* datp = &data; | |
752 | /* for (p1 = first.forw; p1!=0; p1 = p1->forw) { | |
753 | /* if (p1->op == DATA) { | |
754 | /* p2 = p1->forw; | |
755 | /* while (p2 && p2->op!=TEXT) | |
756 | /* p2 = p2->forw; | |
757 | /* if (p2==0) | |
758 | /* break; | |
759 | /* p3 = p1->back; | |
760 | /* p1->back->forw = p2->forw; | |
761 | /* p2->forw->back = p3; | |
762 | /* p2->forw = 0; | |
763 | /* datp->forw = p1; | |
764 | /* p1->back = datp; | |
765 | /* p1 = p3; | |
766 | /* datp = p2; | |
767 | /* } | |
768 | /* } | |
769 | /* if (data.forw) { | |
770 | /* datp->forw = first.forw; | |
771 | /* first.forw->back = datp; | |
772 | /* data.forw->back = &first; | |
773 | /* first.forw = data.forw; | |
774 | /* } | |
775 | /* seg = -1; | |
776 | /* for (p1 = first.forw; p1!=0; p1 = p1->forw) { | |
777 | /* if (p1->op==TEXT||p1->op==DATA||p1->op==BSS) { | |
778 | /* if (p1->op == seg || p1->forw&&p1->forw->op==seg) { | |
779 | /* p1->back->forw = p1->forw; | |
780 | /* p1->forw->back = p1->back; | |
781 | /* p1 = p1->back; | |
782 | /* continue; | |
783 | /* } | |
784 | /* seg = p1->op; | |
785 | /* } | |
786 | /* } | |
787 | /* } | |
788 | */ | |
789 | ||
790 | redunbr(p) | |
791 | register struct node *p; | |
792 | { | |
793 | register struct node *p1; | |
794 | register char *ap1; | |
795 | char *ap2; | |
796 | ||
797 | if ((p1 = p->ref) == 0) | |
798 | return; | |
799 | p1 = nonlab(p1); | |
800 | if (p1->op==TST) { | |
801 | splitrand(p1); | |
802 | savereg(RT2, "$0", p1->subop); | |
803 | } else if (p1->op==CMP) | |
804 | splitrand(p1); | |
805 | else | |
806 | return; | |
807 | if (p1->forw->op==CBR) { | |
808 | ap1 = findcon(RT1, p1->subop); | |
809 | ap2 = findcon(RT2, p1->subop); | |
810 | p1 = p1->forw; | |
811 | if (compare(p1->subop, ap1, ap2)) { | |
812 | nredunj++; | |
813 | nchange++; | |
814 | decref(p->ref); | |
815 | p->ref = p1->ref; | |
816 | p->labno = p1->labno; | |
817 | p->ref->refc++; | |
818 | } | |
819 | } else if (p1->op==TST && equstr(regs[RT1],ccloc+1) && | |
820 | equtype(ccloc[0],p1->subop)) { | |
821 | p1=insertl(p1->forw); decref(p->ref); p->ref=p1; | |
822 | nrtst++; nchange++; | |
823 | } | |
824 | } | |
825 | ||
826 | char * | |
827 | findcon(i, type) | |
828 | { | |
829 | register char *p; | |
830 | register r; | |
831 | ||
832 | p = regs[i]; | |
833 | if (*p=='$') | |
834 | return(p); | |
835 | if ((r = isreg(p)) >= 0 && compat(regs[r][0],type)) | |
836 | return(regs[r]+1); | |
837 | if (equstr(p, conloc)) | |
838 | return(conval+1); | |
839 | return(p); | |
840 | } | |
841 | ||
842 | compare(op, acp1, acp2) | |
843 | char *acp1, *acp2; | |
844 | { | |
845 | register char *cp1, *cp2; | |
846 | register n1; | |
847 | int n2; int sign; | |
848 | ||
849 | cp1 = acp1; | |
850 | cp2 = acp2; | |
851 | if (*cp1++ != '$' || *cp2++ != '$') | |
852 | return(0); | |
853 | n1 = 0; sign=1; if (*cp2=='-') {++cp2; sign= -1;} | |
854 | while (isdigit(*cp2)) {n1 *= 10; n1 += (*cp2++ - '0')*sign;} | |
855 | n2 = n1; | |
856 | n1 = 0; sign=1; if (*cp1=='-') {++cp1; sign= -1;} | |
857 | while (isdigit(*cp1)) {n1 *= 10; n1 += (*cp1++ - '0')*sign;} | |
858 | if (*cp1=='+') | |
859 | cp1++; | |
860 | if (*cp2=='+') | |
861 | cp2++; | |
862 | do { | |
863 | if (*cp1++ != *cp2) | |
864 | return(0); | |
865 | } while (*cp2++); | |
866 | cp1 = n1; | |
867 | cp2 = n2; | |
868 | switch(op) { | |
869 | ||
870 | case JEQ: | |
871 | return(cp1 == cp2); | |
872 | case JNE: | |
873 | return(cp1 != cp2); | |
874 | case JLE: | |
875 | return(((int)cp1) <= ((int)cp2)); | |
876 | case JGE: | |
877 | return(((int)cp1) >= ((int)cp2)); | |
878 | case JLT: | |
879 | return(((int)cp1) < ((int)cp2)); | |
880 | case JGT: | |
881 | return(((int)cp1) > ((int)cp2)); | |
882 | case JLO: | |
883 | return(cp1 < cp2); | |
884 | case JHI: | |
885 | return(cp1 > cp2); | |
886 | case JLOS: | |
887 | return(cp1 <= cp2); | |
888 | case JHIS: | |
889 | return(cp1 >= cp2); | |
890 | } | |
891 | return(0); | |
892 | } | |
893 | ||
894 | setcon(cv, cl, type) | |
895 | register char *cv, *cl; | |
896 | { | |
897 | register char *p; | |
898 | ||
899 | if (*cv != '$') | |
900 | return; | |
901 | if (!natural(cl)) | |
902 | return; | |
903 | p = conloc; | |
904 | while (*p++ = *cl++); | |
905 | p = conval; | |
906 | *p++ = type; | |
907 | while (*p++ = *cv++); | |
908 | } | |
909 | ||
910 | equstr(p1, p2) | |
911 | register char *p1, *p2; | |
912 | { | |
913 | do { | |
914 | if (*p1++ != *p2) | |
915 | return(0); | |
916 | } while (*p2++); | |
917 | return(1); | |
918 | } | |
919 | ||
920 | setcc(ap,type) | |
921 | char *ap; | |
922 | { | |
923 | register char *p, *p1; | |
924 | ||
925 | p = ap; | |
926 | if (!natural(p)) { | |
927 | ccloc[0] = 0; | |
928 | return; | |
929 | } | |
930 | p1 = ccloc; | |
931 | *p1++ = type; | |
932 | while (*p1++ = *p++); | |
933 | } | |
934 | ||
935 | okio(p) register char *p; {/* 0->probable I/O space address; 1->not */ | |
936 | if (ioflag && (!natural(p) || 0>getnum(p))) return(0); | |
937 | return(1); | |
938 | } | |
939 | ||
940 | indexa(p) register char *p; {/* 1-> uses [r] addressing mode; 0->doesn't */ | |
941 | while (*p) if (*p++=='[') return(1); | |
942 | return(0); | |
943 | } | |
944 | ||
945 | natural(p) | |
946 | register char *p; | |
947 | {/* 1->simple local, parameter, global, or register; 0->otherwise */ | |
948 | if (*p=='*' || *p=='(' || *p=='-'&&*(p+1)=='(' || *p=='$'&&getnum(p+1)) | |
949 | return(0); | |
950 | while (*p++); | |
951 | p--; | |
952 | if (*--p=='+' || *p==']' || *p==')' && *(p-2)!='a' && *(p-2)!='f') | |
953 | return(0); | |
954 | return(1); | |
955 | } |