]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/5c/peep.c
merge
[plan9front.git] / sys / src / cmd / 5c / peep.c
1 #include "gc.h"
2
3 int xtramodes(Reg*, Adr*);
4
5 void
6 peep(void)
7 {
8         Reg *r, *r1, *r2;
9         Prog *p, *p1;
10         int t;
11 /*
12  * complete R structure
13  */
14         t = 0;
15         for(r=firstr; r!=R; r=r1) {
16                 r1 = r->link;
17                 if(r1 == R)
18                         break;
19                 p = r->prog->link;
20                 while(p != r1->prog)
21                 switch(p->as) {
22                 default:
23                         r2 = rega();
24                         r->link = r2;
25                         r2->link = r1;
26
27                         r2->prog = p;
28                         r2->p1 = r;
29                         r->s1 = r2;
30                         r2->s1 = r1;
31                         r1->p1 = r2;
32
33                         r = r2;
34                         t++;
35
36                 case ADATA:
37                 case AGLOBL:
38                 case ANAME:
39                 case ASIGNAME:
40                         p = p->link;
41                 }
42         }
43
44 loop1:
45         t = 0;
46         for(r=firstr; r!=R; r=r->link) {
47                 p = r->prog;
48                 if(p->as == ASLL || p->as == ASRL || p->as == ASRA) {
49                         /*
50                          * elide shift into D_SHIFT operand of subsequent instruction
51                          */
52                         if(shiftprop(r)) {
53                                 excise(r);
54                                 t++;
55                         }
56                 }
57                 if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
58                 if(regtyp(&p->to)) {
59                         if(p->from.type == D_CONST)
60                                 constprop(&p->from, &p->to, r->s1);
61                         else if(regtyp(&p->from))
62                         if(p->from.type == p->to.type) {
63                                 if(copyprop(r)) {
64                                         excise(r);
65                                         t++;
66                                 } else
67                                 if(subprop(r) && copyprop(r)) {
68                                         excise(r);
69                                         t++;
70                                 }
71                         }
72                 }
73         }
74         if(t)
75                 goto loop1;
76         /*
77          * look for MOVB x,R; MOVB R,R
78          */
79         for(r=firstr; r!=R; r=r->link) {
80                 p = r->prog;
81                 switch(p->as) {
82                 default:
83                         continue;
84                 case AEOR:
85                         /*
86                          * EOR -1,x,y => MVN x,y
87                          */
88                         if(p->from.type == D_CONST && p->from.offset == -1) {
89                                 p->as = AMVN;
90                                 p->from.type = D_REG;
91                                 if(p->reg != NREG)
92                                         p->from.reg = p->reg;
93                                 else
94                                         p->from.reg = p->to.reg;
95                                 p->reg = NREG;
96                         }
97                         continue;
98                 case AMOVH:
99                 case AMOVHU:
100                 case AMOVB:
101                 case AMOVBU:
102                         if(p->to.type != D_REG)
103                                 continue;
104                         break;
105                 }
106                 r1 = r->link;
107                 if(r1 == R)
108                         continue;
109                 p1 = r1->prog;
110                 if(p1->as != p->as)
111                         continue;
112                 if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
113                         continue;
114                 if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
115                         continue;
116                 excise(r1);
117         }
118
119         for(r=firstr; r!=R; r=r->link) {
120                 p = r->prog;
121                 switch(p->as) {
122                 case AMOVW:
123                 case AMOVB:
124                 case AMOVBU:
125                         if(p->from.type == D_OREG && p->from.offset == 0)
126                                 xtramodes(r, &p->from);
127                         else if(p->to.type == D_OREG && p->to.offset == 0)
128                                 xtramodes(r, &p->to);
129                         else
130                                 continue;
131                         break;
132                 case ACMP:
133                         /*
134                          * elide CMP $0,x if calculation of x can set condition codes
135                          */
136                         if(p->from.type != D_CONST || p->from.offset != 0)
137                                 continue;
138                         r2 = r->s1;
139                         if(r2 == R)
140                                 continue;
141                         t = r2->prog->as;
142                         switch(t) {
143                         default:
144                                 continue;
145                         case ABEQ:
146                         case ABNE:
147                         case ABMI:
148                         case ABPL:
149                                 break;
150                         case ABGE:
151                                 t = ABPL;
152                                 break;
153                         case ABLT:
154                                 t = ABMI;
155                                 break;
156                         case ABHI:
157                                 t = ABNE;
158                                 break;
159                         case ABLS:
160                                 t = ABEQ;
161                                 break;
162                         }
163                         r1 = r;
164                         do
165                                 r1 = uniqp(r1);
166                         while (r1 != R && r1->prog->as == ANOP);
167                         if(r1 == R)
168                                 continue;
169                         p1 = r1->prog;
170                         if(p1->to.type != D_REG)
171                                 continue;
172                         if(p1->to.reg != p->reg)
173                         if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
174                                 continue;
175                         switch(p1->as) {
176                         default:
177                                 continue;
178                         case AMOVW:
179                                 if(p1->from.type != D_REG)
180                                         continue;
181                         case AAND:
182                         case AEOR:
183                         case AORR:
184                         case ABIC:
185                         case AMVN:
186                         case ASUB:
187                         case ARSB:
188                         case AADD:
189                         case AADC:
190                         case ASBC:
191                         case ARSC:
192                                 break;
193                         }
194                         p1->scond |= C_SBIT;
195                         r2->prog->as = t;
196                         excise(r);
197                         continue;
198                 }
199         }
200
201         predicate();
202 }
203
204 void
205 excise(Reg *r)
206 {
207         Prog *p;
208
209         p = r->prog;
210         p->as = ANOP;
211         p->scond = zprog.scond;
212         p->from = zprog.from;
213         p->to = zprog.to;
214         p->reg = zprog.reg; /**/
215 }
216
217 Reg*
218 uniqp(Reg *r)
219 {
220         Reg *r1;
221
222         r1 = r->p1;
223         if(r1 == R) {
224                 r1 = r->p2;
225                 if(r1 == R || r1->p2link != R)
226                         return R;
227         } else
228                 if(r->p2 != R)
229                         return R;
230         return r1;
231 }
232
233 Reg*
234 uniqs(Reg *r)
235 {
236         Reg *r1;
237
238         r1 = r->s1;
239         if(r1 == R) {
240                 r1 = r->s2;
241                 if(r1 == R)
242                         return R;
243         } else
244                 if(r->s2 != R)
245                         return R;
246         return r1;
247 }
248
249 int
250 regtyp(Adr *a)
251 {
252
253         if(a->type == D_REG)
254                 return 1;
255         if(a->type == D_FREG)
256                 return 1;
257         return 0;
258 }
259
260 /*
261  * the idea is to substitute
262  * one register for another
263  * from one MOV to another
264  *      MOV     a, R0
265  *      ADD     b, R0   / no use of R1
266  *      MOV     R0, R1
267  * would be converted to
268  *      MOV     a, R1
269  *      ADD     b, R1
270  *      MOV     R1, R0
271  * hopefully, then the former or latter MOV
272  * will be eliminated by copy propagation.
273  */
274 int
275 subprop(Reg *r0)
276 {
277         Prog *p;
278         Adr *v1, *v2;
279         Reg *r;
280         int t;
281
282         p = r0->prog;
283         v1 = &p->from;
284         if(!regtyp(v1))
285                 return 0;
286         v2 = &p->to;
287         if(!regtyp(v2))
288                 return 0;
289         for(r=uniqp(r0); r!=R; r=uniqp(r)) {
290                 if(uniqs(r) == R)
291                         break;
292                 p = r->prog;
293                 switch(p->as) {
294                 case ABL:
295                         return 0;
296
297                 case ACMP:
298                 case ACMN:
299                 case AADD:
300                 case ASUB:
301                 case ARSB:
302                 case ASLL:
303                 case ASRL:
304                 case ASRA:
305                 case AORR:
306                 case AAND:
307                 case AEOR:
308                 case AMUL:
309                 case ADIV:
310                 case ADIVU:
311
312                 case ACMPF:
313                 case ACMPD:
314                 case AADDD:
315                 case AADDF:
316                 case ASUBD:
317                 case ASUBF:
318                 case AMULD:
319                 case AMULF:
320                 case ADIVD:
321                 case ADIVF:
322                         if(p->to.type == v1->type)
323                         if(p->to.reg == v1->reg) {
324                                 if(p->reg == NREG)
325                                         p->reg = p->to.reg;
326                                 goto gotit;
327                         }
328                         break;
329
330                 case AMOVF:
331                 case AMOVD:
332                 case AMOVW:
333                         if(p->to.type == v1->type)
334                         if(p->to.reg == v1->reg)
335                                 goto gotit;
336                         break;
337
338                 case AMOVM:
339                         t = 1<<v2->reg;
340                         if((p->from.type == D_CONST && (p->from.offset&t)) ||
341                            (p->to.type == D_CONST && (p->to.offset&t)))
342                                 return 0;
343                         break;
344                 }
345                 if(copyau(&p->from, v2) ||
346                    copyau1(p, v2) ||
347                    copyau(&p->to, v2))
348                         break;
349                 if(copysub(&p->from, v1, v2, 0) ||
350                    copysub1(p, v1, v2, 0) ||
351                    copysub(&p->to, v1, v2, 0))
352                         break;
353         }
354         return 0;
355
356 gotit:
357         copysub(&p->to, v1, v2, 1);
358         if(debug['P']) {
359                 print("gotit: %D->%D\n%P", v1, v2, r->prog);
360                 if(p->from.type == v2->type)
361                         print(" excise");
362                 print("\n");
363         }
364         for(r=uniqs(r); r!=r0; r=uniqs(r)) {
365                 p = r->prog;
366                 copysub(&p->from, v1, v2, 1);
367                 copysub1(p, v1, v2, 1);
368                 copysub(&p->to, v1, v2, 1);
369                 if(debug['P'])
370                         print("%P\n", r->prog);
371         }
372         t = v1->reg;
373         v1->reg = v2->reg;
374         v2->reg = t;
375         if(debug['P'])
376                 print("%P last\n", r->prog);
377         return 1;
378 }
379
380 /*
381  * The idea is to remove redundant copies.
382  *      v1->v2  F=0
383  *      (use v2 s/v2/v1/)*
384  *      set v1  F=1
385  *      use v2  return fail
386  *      -----------------
387  *      v1->v2  F=0
388  *      (use v2 s/v2/v1/)*
389  *      set v1  F=1
390  *      set v2  return success
391  */
392 int
393 copyprop(Reg *r0)
394 {
395         Prog *p;
396         Adr *v1, *v2;
397         Reg *r;
398
399         p = r0->prog;
400         v1 = &p->from;
401         v2 = &p->to;
402         if(copyas(v1, v2))
403                 return 1;
404         for(r=firstr; r!=R; r=r->link)
405                 r->active = 0;
406         return copy1(v1, v2, r0->s1, 0);
407 }
408
409 int
410 copy1(Adr *v1, Adr *v2, Reg *r, int f)
411 {
412         int t;
413         Prog *p;
414
415         if(r->active) {
416                 if(debug['P'])
417                         print("act set; return 1\n");
418                 return 1;
419         }
420         r->active = 1;
421         if(debug['P'])
422                 print("copy %D->%D f=%d\n", v1, v2, f);
423         for(; r != R; r = r->s1) {
424                 p = r->prog;
425                 if(debug['P'])
426                         print("%P", p);
427                 if(!f && uniqp(r) == R) {
428                         f = 1;
429                         if(debug['P'])
430                                 print("; merge; f=%d", f);
431                 }
432                 t = copyu(p, v2, A);
433                 switch(t) {
434                 case 2: /* rar, cant split */
435                         if(debug['P'])
436                                 print("; %Drar; return 0\n", v2);
437                         return 0;
438
439                 case 3: /* set */
440                         if(debug['P'])
441                                 print("; %Dset; return 1\n", v2);
442                         return 1;
443
444                 case 1: /* used, substitute */
445                 case 4: /* use and set */
446                         if(f) {
447                                 if(!debug['P'])
448                                         return 0;
449                                 if(t == 4)
450                                         print("; %Dused+set and f=%d; return 0\n", v2, f);
451                                 else
452                                         print("; %Dused and f=%d; return 0\n", v2, f);
453                                 return 0;
454                         }
455                         if(copyu(p, v2, v1)) {
456                                 if(debug['P'])
457                                         print("; sub fail; return 0\n");
458                                 return 0;
459                         }
460                         if(debug['P'])
461                                 print("; sub%D/%D", v2, v1);
462                         if(t == 4) {
463                                 if(debug['P'])
464                                         print("; %Dused+set; return 1\n", v2);
465                                 return 1;
466                         }
467                         break;
468                 }
469                 if(!f) {
470                         t = copyu(p, v1, A);
471                         if(!f && (t == 2 || t == 3 || t == 4)) {
472                                 f = 1;
473                                 if(debug['P'])
474                                         print("; %Dset and !f; f=%d", v1, f);
475                         }
476                 }
477                 if(debug['P'])
478                         print("\n");
479                 if(r->s2)
480                         if(!copy1(v1, v2, r->s2, f))
481                                 return 0;
482         }
483         return 1;
484 }
485
486 /*
487  * The idea is to remove redundant constants.
488  *      $c1->v1
489  *      ($c1->v2 s/$c1/v1)*
490  *      set v1  return
491  * The v1->v2 should be eliminated by copy propagation.
492  */
493 void
494 constprop(Adr *c1, Adr *v1, Reg *r)
495 {
496         Prog *p;
497
498         if(debug['C'])
499                 print("constprop %D->%D\n", c1, v1);
500         for(; r != R; r = r->s1) {
501                 p = r->prog;
502                 if(debug['C'])
503                         print("%P", p);
504                 if(uniqp(r) == R) {
505                         if(debug['C'])
506                                 print("; merge; return\n");
507                         return;
508                 }
509                 if(p->as == AMOVW && copyas(&p->from, c1)) {
510                                 if(debug['C'])
511                                         print("; sub%D/%D", &p->from, v1);
512                                 p->from = *v1;
513                 } else if(copyu(p, v1, A) > 1) {
514                         if(debug['C'])
515                                 print("; %Dset; return\n", v1);
516                         return;
517                 }
518                 if(debug['C'])
519                         print("\n");
520                 if(r->s2)
521                         constprop(c1, v1, r->s2);
522         }
523 }
524
525 /*
526  * ASLL x,y,w
527  * .. (not use w, not set x y w)
528  * AXXX w,a,b (a != w)
529  * .. (not use w)
530  * (set w)
531  * ----------- changed to
532  * ..
533  * AXXX (x<<y),a,b
534  * ..
535  */
536 #define FAIL(msg) { if(debug['H']) print("\t%s; FAILURE\n", msg); return 0; }
537 int
538 shiftprop(Reg *r)
539 {
540         Reg *r1;
541         Prog *p, *p1, *p2;
542         int n, o;
543         Adr a;
544
545         p = r->prog;
546         if(p->to.type != D_REG)
547                 FAIL("BOTCH: result not reg");
548         n = p->to.reg;
549         a = zprog.from;
550         if(p->reg != NREG && p->reg != p->to.reg) {
551                 a.type = D_REG;
552                 a.reg = p->reg;
553         }
554         if(debug['H'])
555                 print("shiftprop\n%P", p);
556         r1 = r;
557         for(;;) {
558                 /* find first use of shift result; abort if shift operands or result are changed */
559                 r1 = uniqs(r1);
560                 if(r1 == R)
561                         FAIL("branch");
562                 if(uniqp(r1) == R)
563                         FAIL("merge");
564                 p1 = r1->prog;
565                 if(debug['H'])
566                         print("\n%P", p1);
567                 switch(copyu(p1, &p->to, A)) {
568                 case 0: /* not used or set */
569                         if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
570                            (a.type == D_REG && copyu(p1, &a, A) > 1))
571                                 FAIL("args modified");
572                         continue;
573                 case 3: /* set, not used */
574                         FAIL("BOTCH: noref");
575                 }
576                 break;
577         }
578         /* check whether substitution can be done */
579         switch(p1->as) {
580         default:
581                 FAIL("non-dpi");
582         case AAND:
583         case AEOR:
584         case AADD:
585         case AADC:
586         case AORR:
587         case ASUB:
588         case ARSB:
589         case ASBC:
590         case ARSC:
591                 if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
592                         if(p1->from.type != D_REG)
593                                 FAIL("can't swap");
594                         p1->reg = p1->from.reg;
595                         p1->from.reg = n;
596                         switch(p1->as) {
597                         case ASUB:
598                                 p1->as = ARSB;
599                                 break;
600                         case ARSB:
601                                 p1->as = ASUB;
602                                 break;
603                         case ASBC:
604                                 p1->as = ARSC;
605                                 break;
606                         case ARSC:
607                                 p1->as = ASBC;
608                                 break;
609                         }
610                         if(debug['H'])
611                                 print("\t=>%P", p1);
612                 }
613         case ABIC:
614         case ACMP:
615         case ACMN:
616                 if(p1->reg == n)
617                         FAIL("can't swap");
618                 if(p1->reg == NREG && p1->to.reg == n)
619                         FAIL("shift result used twice");
620         case AMVN:
621                 if(p1->from.type == D_SHIFT)
622                         FAIL("shift result used in shift");
623                 if(p1->from.type != D_REG || p1->from.reg != n)
624                         FAIL("BOTCH: where is it used?");
625                 break;
626         }
627         /* check whether shift result is used subsequently */
628         p2 = p1;
629         if(p1->to.reg != n)
630         for (;;) {
631                 r1 = uniqs(r1);
632                 if(r1 == R)
633                         FAIL("inconclusive");
634                 p1 = r1->prog;
635                 if(debug['H'])
636                         print("\n%P", p1);
637                 switch(copyu(p1, &p->to, A)) {
638                 case 0: /* not used or set */
639                         continue;
640                 case 3: /* set, not used */
641                         break;
642                 default:/* used */
643                         FAIL("reused");
644                 }
645                 break;
646         }
647         /* make the substitution */
648         p2->from.type = D_SHIFT;
649         p2->from.reg = NREG;
650         o = p->reg;
651         if(o == NREG)
652                 o = p->to.reg;
653         switch(p->from.type){
654         case D_CONST:
655                 o |= (p->from.offset&0x1f)<<7;
656                 break;
657         case D_REG:
658                 o |= (1<<4) | (p->from.reg<<8);
659                 break;
660         }
661         switch(p->as){
662         case ASLL:
663                 o |= 0<<5;
664                 break;
665         case ASRL:
666                 o |= 1<<5;
667                 break;
668         case ASRA:
669                 o |= 2<<5;
670                 break;
671         }
672         p2->from.offset = o;
673         if(debug['H'])
674                 print("\t=>%P\tSUCCEED\n", p2);
675         return 1;
676 }
677
678 Reg*
679 findpre(Reg *r, Adr *v)
680 {
681         Reg *r1;
682
683         for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
684                 if(uniqs(r1) != r)
685                         return R;
686                 switch(copyu(r1->prog, v, A)) {
687                 case 1: /* used */
688                 case 2: /* read-alter-rewrite */
689                         return R;
690                 case 3: /* set */
691                 case 4: /* set and used */
692                         return r1;
693                 }
694         }
695         return R;
696 }
697
698 Reg*
699 findinc(Reg *r, Reg *r2, Adr *v)
700 {
701         Reg *r1;
702         Prog *p;
703
704
705         for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
706                 if(uniqp(r1) != r)
707                         return R;
708                 switch(copyu(r1->prog, v, A)) {
709                 case 0: /* not touched */
710                         continue;
711                 case 4: /* set and used */
712                         p = r1->prog;
713                         if(p->as == AADD)
714                         if(p->from.type == D_CONST)
715                         if(p->from.offset > -4096 && p->from.offset < 4096)
716                                 return r1;
717                 default:
718                         return R;
719                 }
720         }
721         return R;
722 }
723
724 int
725 nochange(Reg *r, Reg *r2, Prog *p)
726 {
727         Adr a[3];
728         int i, n;
729
730         if(r == r2)
731                 return 1;
732         n = 0;
733         if(p->reg != NREG && p->reg != p->to.reg) {
734                 a[n].type = D_REG;
735                 a[n++].reg = p->reg;
736         }
737         switch(p->from.type) {
738         case D_SHIFT:
739                 a[n].type = D_REG;
740                 a[n++].reg = p->from.offset&0xf;
741         case D_REG:
742                 a[n].type = D_REG;
743                 a[n++].reg = p->from.reg;
744         }
745         if(n == 0)
746                 return 1;
747         for(; r!=R && r!=r2; r=uniqs(r)) {
748                 p = r->prog;
749                 for(i=0; i<n; i++)
750                         if(copyu(p, &a[i], A) > 1)
751                                 return 0;
752         }
753         return 1;
754 }
755
756 int
757 findu1(Reg *r, Adr *v)
758 {
759         for(; r != R; r = r->s1) {
760                 if(r->active)
761                         return 0;
762                 r->active = 1;
763                 switch(copyu(r->prog, v, A)) {
764                 case 1: /* used */
765                 case 2: /* read-alter-rewrite */
766                 case 4: /* set and used */
767                         return 1;
768                 case 3: /* set */
769                         return 0;
770                 }
771                 if(r->s2)
772                         if (findu1(r->s2, v))
773                                 return 1;
774         }
775         return 0;
776 }
777
778 int
779 finduse(Reg *r, Adr *v)
780 {
781         Reg *r1;
782
783         for(r1=firstr; r1!=R; r1=r1->link)
784                 r1->active = 0;
785         return findu1(r, v);
786 }
787
788 int
789 xtramodes(Reg *r, Adr *a)
790 {
791         Reg *r1, *r2, *r3;
792         Prog *p, *p1;
793         Adr v;
794
795         p = r->prog;
796         if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG)      /* byte load */
797                 return 0;
798         v = *a;
799         v.type = D_REG;
800         r1 = findpre(r, &v);
801         if(r1 != R) {
802                 p1 = r1->prog;
803                 if(p1->to.type == D_REG && p1->to.reg == v.reg)
804                 switch(p1->as) {
805                 case AADD:
806                         if(p1->from.type == D_REG ||
807                            (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
808                             (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
809                            (p1->from.type == D_CONST && 
810                             p1->from.offset > -4096 && p1->from.offset < 4096))
811                         if(nochange(uniqs(r1), r, p1)) {
812                                 if(a != &p->from || v.reg != p->to.reg)
813                                 if (finduse(r->s1, &v)) {
814                                         if(p1->reg == NREG || p1->reg == v.reg)
815                                                 /* pre-indexing */
816                                                 p->scond |= C_WBIT;
817                                         else return 0;  
818                                 }
819                                 switch (p1->from.type) {
820                                 case D_REG:
821                                         /* register offset */
822                                         a->type = D_SHIFT;
823                                         a->offset = p1->from.reg;
824                                         break;
825                                 case D_SHIFT:
826                                         /* scaled register offset */
827                                         a->type = D_SHIFT;
828                                 case D_CONST:
829                                         /* immediate offset */
830                                         a->offset = p1->from.offset;
831                                         break;
832                                 }
833                                 if(p1->reg != NREG)
834                                         a->reg = p1->reg;
835                                 excise(r1);
836                                 return 1;
837                         }
838                         break;
839                 case AMOVW:
840                         if(p1->from.type == D_REG)
841                         if((r2 = findinc(r1, r, &p1->from)) != R) {
842                         for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
843                                 ;
844                         if(r3 == r) {
845                                 /* post-indexing */
846                                 p1 = r2->prog;
847                                 a->reg = p1->to.reg;
848                                 a->offset = p1->from.offset;
849                                 p->scond |= C_PBIT;
850                                 if(!finduse(r, &r1->prog->to))
851                                         excise(r1);
852                                 excise(r2);
853                                 return 1;
854                         }
855                         }
856                         break;
857                 }
858         }
859         if(a != &p->from || a->reg != p->to.reg)
860         if((r1 = findinc(r, R, &v)) != R) {
861                 /* post-indexing */
862                 p1 = r1->prog;
863                 a->offset = p1->from.offset;
864                 p->scond |= C_PBIT;
865                 excise(r1);
866                 return 1;
867         }
868         return 0;
869 }
870
871 /*
872  * return
873  * 1 if v only used (and substitute),
874  * 2 if read-alter-rewrite
875  * 3 if set
876  * 4 if set and used
877  * 0 otherwise (not touched)
878  */
879 int
880 copyu(Prog *p, Adr *v, Adr *s)
881 {
882
883         switch(p->as) {
884
885         default:
886                 if(debug['P'])
887                         print(" (???)");
888                 return 2;
889
890         case AMOVM:
891                 if(v->type != D_REG)
892                         return 0;
893                 if(p->from.type == D_CONST) {   /* read reglist, read/rar */
894                         if(s != A) {
895                                 if(p->from.offset&(1<<v->reg))
896                                         return 1;
897                                 if(copysub(&p->to, v, s, 1))
898                                         return 1;
899                                 return 0;
900                         }
901                         if(copyau(&p->to, v)) {
902                                 if(p->scond&C_WBIT)
903                                         return 2;
904                                 return 1;
905                         }
906                         if(p->from.offset&(1<<v->reg))
907                                 return 1;
908                 } else {                        /* read/rar, write reglist */
909                         if(s != A) {
910                                 if(p->to.offset&(1<<v->reg))
911                                         return 1;
912                                 if(copysub(&p->from, v, s, 1))
913                                         return 1;
914                                 return 0;
915                         }
916                         if(copyau(&p->from, v)) {
917                                 if(p->scond&C_WBIT)
918                                         return 2;
919                                 if(p->to.offset&(1<<v->reg))
920                                         return 4;
921                                 return 1;
922                         }
923                         if(p->to.offset&(1<<v->reg))
924                                 return 3;
925                 }
926                 return 0;
927                 
928         case ANOP:      /* read, write */
929         case AMOVW:
930         case AMOVF:
931         case AMOVD:
932         case AMOVH:
933         case AMOVHU:
934         case AMOVB:
935         case AMOVBU:
936         case AMOVDW:
937         case AMOVWD:
938         case AMOVFD:
939         case AMOVDF:
940                 if(p->scond&(C_WBIT|C_PBIT))
941                 if(v->type == D_REG) {
942                         if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
943                                 if(p->from.reg == v->reg)
944                                         return 2;
945                         } else {
946                                 if(p->to.reg == v->reg)
947                                 return 2;
948                         }
949                 }
950                 if(s != A) {
951                         if(copysub(&p->from, v, s, 1))
952                                 return 1;
953                         if(!copyas(&p->to, v))
954                                 if(copysub(&p->to, v, s, 1))
955                                         return 1;
956                         return 0;
957                 }
958                 if(copyas(&p->to, v)) {
959                         if(copyau(&p->from, v))
960                                 return 4;
961                         return 3;
962                 }
963                 if(copyau(&p->from, v))
964                         return 1;
965                 if(copyau(&p->to, v))
966                         return 1;
967                 return 0;
968
969
970         case AADD:      /* read, read, write */
971         case ASUB:
972         case ARSB:
973         case ASLL:
974         case ASRL:
975         case ASRA:
976         case AORR:
977         case AAND:
978         case AEOR:
979         case AMUL:
980         case ADIV:
981         case ADIVU:
982         case AADDF:
983         case AADDD:
984         case ASUBF:
985         case ASUBD:
986         case AMULF:
987         case AMULD:
988         case ADIVF:
989         case ADIVD:
990
991         case ACMPF:
992         case ACMPD:
993         case ACMP:
994         case ACMN:
995         case ACASE:
996                 if(s != A) {
997                         if(copysub(&p->from, v, s, 1))
998                                 return 1;
999                         if(copysub1(p, v, s, 1))
1000                                 return 1;
1001                         if(!copyas(&p->to, v))
1002                                 if(copysub(&p->to, v, s, 1))
1003                                         return 1;
1004                         return 0;
1005                 }
1006                 if(copyas(&p->to, v)) {
1007                         if(p->reg == NREG)
1008                                 p->reg = p->to.reg;
1009                         if(copyau(&p->from, v))
1010                                 return 4;
1011                         if(copyau1(p, v))
1012                                 return 4;
1013                         return 3;
1014                 }
1015                 if(copyau(&p->from, v))
1016                         return 1;
1017                 if(copyau1(p, v))
1018                         return 1;
1019                 if(copyau(&p->to, v))
1020                         return 1;
1021                 return 0;
1022
1023         case ABEQ:      /* read, read */
1024         case ABNE:
1025         case ABCS:
1026         case ABHS:
1027         case ABCC:
1028         case ABLO:
1029         case ABMI:
1030         case ABPL:
1031         case ABVS:
1032         case ABVC:
1033         case ABHI:
1034         case ABLS:
1035         case ABGE:
1036         case ABLT:
1037         case ABGT:
1038         case ABLE:
1039                 if(s != A) {
1040                         if(copysub(&p->from, v, s, 1))
1041                                 return 1;
1042                         return copysub1(p, v, s, 1);
1043                 }
1044                 if(copyau(&p->from, v))
1045                         return 1;
1046                 if(copyau1(p, v))
1047                         return 1;
1048                 return 0;
1049
1050         case AB:        /* funny */
1051                 if(s != A) {
1052                         if(copysub(&p->to, v, s, 1))
1053                                 return 1;
1054                         return 0;
1055                 }
1056                 if(copyau(&p->to, v))
1057                         return 1;
1058                 return 0;
1059
1060         case ARET:      /* funny */
1061                 if(v->type == D_REG)
1062                 if(v->reg == REGRET)
1063                         return 2;
1064                 if(v->type == D_FREG)
1065                 if(v->reg == FREGRET)
1066                         return 2;
1067
1068         case ABL:       /* funny */
1069                 if(v->type == D_REG) {
1070                         if(v->reg <= REGEXT && v->reg > exregoffset)
1071                                 return 2;
1072                         if(v->reg == (uchar)REGARG)
1073                                 return 2;
1074                 }
1075                 if(v->type == D_FREG)
1076                         if(v->reg <= FREGEXT && v->reg > exfregoffset)
1077                                 return 2;
1078
1079                 if(s != A) {
1080                         if(copysub(&p->to, v, s, 1))
1081                                 return 1;
1082                         return 0;
1083                 }
1084                 if(copyau(&p->to, v))
1085                         return 4;
1086                 return 3;
1087
1088         case ATEXT:     /* funny */
1089                 if(v->type == D_REG)
1090                         if(v->reg == (uchar)REGARG)
1091                                 return 3;
1092                 return 0;
1093         }
1094 }
1095
1096 int
1097 a2type(Prog *p)
1098 {
1099
1100         switch(p->as) {
1101
1102         case ACMP:
1103         case ACMN:
1104
1105         case AADD:
1106         case ASUB:
1107         case ARSB:
1108         case ASLL:
1109         case ASRL:
1110         case ASRA:
1111         case AORR:
1112         case AAND:
1113         case AEOR:
1114         case AMUL:
1115         case ADIV:
1116         case ADIVU:
1117                 return D_REG;
1118
1119         case ACMPF:
1120         case ACMPD:
1121
1122         case AADDF:
1123         case AADDD:
1124         case ASUBF:
1125         case ASUBD:
1126         case AMULF:
1127         case AMULD:
1128         case ADIVF:
1129         case ADIVD:
1130                 return D_FREG;
1131         }
1132         return D_NONE;
1133 }
1134
1135 /*
1136  * direct reference,
1137  * could be set/use depending on
1138  * semantics
1139  */
1140 int
1141 copyas(Adr *a, Adr *v)
1142 {
1143
1144         if(regtyp(v)) {
1145                 if(a->type == v->type)
1146                 if(a->reg == v->reg)
1147                         return 1;
1148         } else if(v->type == D_CONST) {         /* for constprop */
1149                 if(a->type == v->type)
1150                 if(a->name == v->name)
1151                 if(a->sym == v->sym)
1152                 if(a->reg == v->reg)
1153                 if(a->offset == v->offset)
1154                         return 1;
1155         }
1156         return 0;
1157 }
1158
1159 /*
1160  * either direct or indirect
1161  */
1162 int
1163 copyau(Adr *a, Adr *v)
1164 {
1165
1166         if(copyas(a, v))
1167                 return 1;
1168         if(v->type == D_REG) {
1169                 if(a->type == D_OREG) {
1170                         if(v->reg == a->reg)
1171                                 return 1;
1172                 } else if(a->type == D_SHIFT) {
1173                         if((a->offset&0xf) == v->reg)
1174                                 return 1;
1175                         if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
1176                                 return 1;
1177                 }
1178         }
1179         return 0;
1180 }
1181
1182 int
1183 copyau1(Prog *p, Adr *v)
1184 {
1185
1186         if(regtyp(v)) {
1187                 if(a2type(p) == v->type)
1188                 if(p->reg == v->reg) {
1189                         if(a2type(p) != v->type)
1190                                 print("botch a2type %P\n", p);
1191                         return 1;
1192                 }
1193         }
1194         return 0;
1195 }
1196
1197 /*
1198  * substitute s for v in a
1199  * return failure to substitute
1200  */
1201 int
1202 copysub(Adr *a, Adr *v, Adr *s, int f)
1203 {
1204
1205         if(f)
1206         if(copyau(a, v)) {
1207                 if(a->type == D_SHIFT) {
1208                         if((a->offset&0xf) == v->reg)
1209                                 a->offset = (a->offset&~0xf)|s->reg;
1210                         if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
1211                                 a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
1212                 } else
1213                         a->reg = s->reg;
1214         }
1215         return 0;
1216 }
1217
1218 int
1219 copysub1(Prog *p1, Adr *v, Adr *s, int f)
1220 {
1221
1222         if(f)
1223         if(copyau1(p1, v))
1224                 p1->reg = s->reg;
1225         return 0;
1226 }
1227
1228 struct {
1229         int opcode;
1230         int notopcode;
1231         int scond; 
1232         int notscond; 
1233 } predinfo[]  = { 
1234         { ABEQ, ABNE,   0x0,    0x1, }, 
1235         { ABNE, ABEQ,   0x1,    0x0, }, 
1236         { ABCS, ABCC,   0x2,    0x3, }, 
1237         { ABHS, ABLO,   0x2,    0x3, }, 
1238         { ABCC, ABCS,   0x3,    0x2, }, 
1239         { ABLO, ABHS,   0x3,    0x2, }, 
1240         { ABMI, ABPL,   0x4,    0x5, }, 
1241         { ABPL, ABMI,   0x5,    0x4, }, 
1242         { ABVS, ABVC,   0x6,    0x7, }, 
1243         { ABVC, ABVS,   0x7,    0x6, }, 
1244         { ABHI, ABLS,   0x8,    0x9, }, 
1245         { ABLS, ABHI,   0x9,    0x8, }, 
1246         { ABGE, ABLT,   0xA,    0xB, }, 
1247         { ABLT, ABGE,   0xB,    0xA, }, 
1248         { ABGT, ABLE,   0xC,    0xD, }, 
1249         { ABLE, ABGT,   0xD,    0xC, }, 
1250 }; 
1251
1252 typedef struct {
1253         Reg *start;
1254         Reg *last;
1255         Reg *end;
1256         int len;
1257 } Joininfo;
1258
1259 enum {
1260         Join,
1261         Split,
1262         End,
1263         Branch,
1264         Setcond,
1265         Toolong
1266 };
1267         
1268 enum {
1269         Falsecond,
1270         Truecond,
1271         Delbranch,
1272         Keepbranch
1273 };
1274
1275 int 
1276 isbranch(Prog *p)
1277 {
1278         return (ABEQ <= p->as) && (p->as <= ABLE); 
1279 }
1280
1281 int
1282 predicable(Prog *p)
1283 {
1284         if (isbranch(p)
1285                 || p->as == ANOP
1286                 || p->as == AXXX
1287                 || p->as == ADATA
1288                 || p->as == AGLOBL
1289                 || p->as == AGOK
1290                 || p->as == AHISTORY
1291                 || p->as == ANAME
1292                 || p->as == ASIGNAME
1293                 || p->as == ATEXT
1294                 || p->as == AWORD
1295                 || p->as == ADYNT
1296                 || p->as == AINIT
1297                 || p->as == ABCASE
1298                 || p->as == ACASE)
1299                 return 0; 
1300         return 1; 
1301 }
1302
1303 /* 
1304  * Depends on an analysis of the encodings performed by 5l. 
1305  * These seem to be all of the opcodes that lead to the "S" bit
1306  * being set in the instruction encodings. 
1307  * 
1308  * C_SBIT may also have been set explicitly in p->scond.
1309  */ 
1310 int
1311 modifiescpsr(Prog *p)
1312 {
1313         return (p->scond&C_SBIT)
1314                 || p->as == ATST 
1315                 || p->as == ATEQ 
1316                 || p->as == ACMN
1317                 || p->as == ACMP
1318                 || p->as == AMULU
1319                 || p->as == ADIVU
1320                 || p->as == AMUL
1321                 || p->as == ADIV
1322                 || p->as == AMOD
1323                 || p->as == AMODU
1324                 || p->as == ABL;
1325
1326
1327 /*
1328  * Find the maximal chain of instructions starting with r which could
1329  * be executed conditionally
1330  */
1331 int
1332 joinsplit(Reg *r, Joininfo *j)
1333 {
1334         j->start = r;
1335         j->last = r;
1336         j->len = 0;
1337         do {
1338                 if (r->p2 && (r->p1 || r->p2->p2link)) {
1339                         j->end = r;
1340                         return Join;
1341                 }
1342                 if (r->s1 && r->s2) {
1343                         j->end = r;
1344                         return Split;
1345                 }
1346                 j->last = r;
1347                 if (r->prog->as != ANOP)
1348                         j->len++;
1349                 if (!r->s1 && !r->s2) {
1350                         j->end = r->link;
1351                         return End;
1352                 }
1353                 if (r->s2) {
1354                         j->end = r->s2;
1355                         return Branch;
1356                 }
1357                 if (modifiescpsr(r->prog)) {
1358                         j->end = r->s1;
1359                         return Setcond;
1360                 }
1361                 r = r->s1;
1362         } while (j->len < 4);
1363         j->end = r;
1364         return Toolong;
1365 }
1366
1367 Reg *
1368 successor(Reg *r)
1369 {
1370         if (r->s1)
1371                 return r->s1; 
1372         else
1373                 return r->s2; 
1374 }
1375
1376 void
1377 applypred(Reg *rstart, Joininfo *j, int cond, int branch)
1378 {
1379         int pred; 
1380         Reg *r; 
1381
1382         if(j->len == 0)
1383                 return;
1384         if (cond == Truecond)
1385                 pred = predinfo[rstart->prog->as - ABEQ].scond;
1386         else
1387                 pred = predinfo[rstart->prog->as - ABEQ].notscond; 
1388         
1389         for (r = j->start; ; r = successor(r)) {
1390                 if (r->prog->as == AB) {
1391                         if (r != j->last || branch == Delbranch)
1392                                 excise(r);
1393                         else {
1394                           if (cond == Truecond)
1395                                 r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
1396                           else
1397                                 r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
1398                         }
1399                 }
1400                 else if (predicable(r->prog)) 
1401                         r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
1402                 if (r->s1 != r->link) {
1403                         r->s1 = r->link;
1404                         r->link->p1 = r;
1405                 }
1406                 if (r == j->last)
1407                         break;
1408         }
1409 }
1410
1411 void
1412 predicate(void)
1413 {       
1414         Reg *r;
1415         int t1, t2;
1416         Joininfo j1, j2;
1417
1418         for(r=firstr; r!=R; r=r->link) {
1419                 if (isbranch(r->prog)) {
1420                         t1 = joinsplit(r->s1, &j1);
1421                         t2 = joinsplit(r->s2, &j2);
1422                         if(j1.last->link != j2.start)
1423                                 continue;
1424                         if(j1.end == j2.end)
1425                         if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
1426                            (t2 == Join && (t1 == Join || t1 == Setcond))) {
1427                                 applypred(r, &j1, Falsecond, Delbranch);
1428                                 applypred(r, &j2, Truecond, Delbranch);
1429                                 excise(r);
1430                                 continue;
1431                         }
1432                         if(t1 == End || t1 == Branch) {
1433                                 applypred(r, &j1, Falsecond, Keepbranch);
1434                                 excise(r);
1435                                 continue;
1436                         }
1437                 } 
1438         } 
1439 }