]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/6c/peep.c
8c, 6c: native ROL (cyclic shift) instruction support, improve peephole optimizers
[plan9front.git] / sys / src / cmd / 6c / peep.c
1 #include "gc.h"
2
3 static int
4 needc(Prog *p)
5 {
6         while(p != P) {
7                 switch(p->as) {
8                 case AADCL:
9                 case AADCQ:
10                 case ASBBL:
11                 case ASBBQ:
12                 case ARCRL:
13                 case ARCRQ:
14                         return 1;
15                 case AADDL:
16                 case AADDQ:
17                 case ASUBL:
18                 case ASUBQ:
19                 case AJMP:
20                 case ARET:
21                 case ACALL:
22                         return 0;
23                 default:
24                         if(p->to.type == D_BRANCH)
25                                 return 0;
26                 }
27                 p = p->link;
28         }
29         return 0;
30 }
31
32 static Reg*
33 rnops(Reg *r)
34 {
35         Prog *p;
36         Reg *r1;
37
38         if(r != R)
39         for(;;){
40                 p = r->prog;
41                 if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
42                         break;
43                 r1 = uniqs(r);
44                 if(r1 == R)
45                         break;
46                 r = r1;
47         }
48         return r;
49 }
50
51 void
52 peep(void)
53 {
54         Reg *r, *r1, *r2;
55         Prog *p, *p1;
56         int t;
57
58         /*
59          * complete R structure
60          */
61         t = 0;
62         for(r=firstr; r!=R; r=r1) {
63                 r1 = r->link;
64                 if(r1 == R)
65                         break;
66                 p = r->prog->link;
67                 while(p != r1->prog)
68                 switch(p->as) {
69                 default:
70                         r2 = rega();
71                         r->link = r2;
72                         r2->link = r1;
73
74                         r2->prog = p;
75                         r2->p1 = r;
76                         r->s1 = r2;
77                         r2->s1 = r1;
78                         r1->p1 = r2;
79
80                         r = r2;
81                         t++;
82
83                 case ADATA:
84                 case AGLOBL:
85                 case ANAME:
86                 case ASIGNAME:
87                         p = p->link;
88                 }
89         }
90
91         pc = 0; /* speculating it won't kill */
92
93 loop1:
94
95         t = 0;
96         for(r=firstr; r!=R; r=r->link) {
97                 p = r->prog;
98                 switch(p->as) {
99                 case AMOVL:
100                 case AMOVQ:
101                 case AMOVSS:
102                 case AMOVSD:
103                         if(!regtyp(&p->to))
104                                 break;
105                         if(regtyp(&p->from)) {
106                                 if(copyprop(r)) {
107                                         excise(r);
108                                         t++;
109                                         break;
110                                 }
111                                 if(subprop(r) && copyprop(r)) {
112                                         excise(r);
113                                         t++;
114                                         break;
115                                 }
116                         }
117                         if(p->as != AMOVL)
118                                 break;
119                         r1 = rnops(uniqs(r));
120                         if(r1 != R){
121                                 p1 = r1->prog;
122                                 if(p1->as == AMOVLQZX && p1->from.type == p->to.type && p1->to.type == p->to.type){
123                                         excise(r1);
124                                         t++;
125                                 }
126                         }
127                         break;
128
129                 case AMOVBLZX:
130                 case AMOVWLZX:
131                 case AMOVBLSX:
132                 case AMOVWLSX:
133                         if(regtyp(&p->to)) {
134                                 r1 = rnops(uniqs(r));
135                                 if(r1 != R) {
136                                         p1 = r1->prog;
137                                         if(p->to.type != p1->from.type)
138                                                 break;
139                                         if((p->as == AMOVBLZX && p1->as == AMOVBQZX)
140                                         || (p->as == AMOVWLZX && p1->as == AMOVWQZX)
141                                         || (p->as == AMOVBLSX && p1->as == AMOVBQSX && p1->to.type == p->to.type)
142                                         || (p->as == AMOVWLSX && p1->as == AMOVWQSX && p1->to.type == p->to.type)) {
143                                                 p->as = p1->as;
144                                                 p1->as = AMOVQ;
145                                                 t++;
146                                         } else
147                                         if(p->as == p1->as) {
148                                                 p1->as = AMOVL;
149                                                 t++;
150                                         }
151                                 }
152                         }
153                         break;
154
155                 case AMOVBQSX:
156                 case AMOVBQZX:
157                 case AMOVWQSX:
158                 case AMOVWQZX:
159                 case AMOVLQSX:
160                 case AMOVLQZX:
161                         if(regtyp(&p->to)) {
162                                 r1 = rnops(uniqs(r));
163                                 if(r1 != R) {
164                                         p1 = r1->prog;
165                                         if(p->as == p1->as && p->to.type == p1->from.type){
166                                                 p1->as = AMOVQ;
167                                                 t++;
168                                         }
169                                 }
170                         }
171                         break;
172
173                 case AADDL:
174                 case AADDQ:
175                 case AADDW:
176                         if(p->from.type != D_CONST || needc(p->link))
177                                 break;
178                         if(p->from.offset == -1){
179                                 if(p->as == AADDQ)
180                                         p->as = ADECQ;
181                                 else if(p->as == AADDL)
182                                         p->as = ADECL;
183                                 else
184                                         p->as = ADECW;
185                                 p->from = zprog.from;
186                         }
187                         else if(p->from.offset == 1){
188                                 if(p->as == AADDQ)
189                                         p->as = AINCQ;
190                                 else if(p->as == AADDL)
191                                         p->as = AINCL;
192                                 else
193                                         p->as = AINCW;
194                                 p->from = zprog.from;
195                         }
196                         break;
197
198                 case ASUBL:
199                 case ASUBQ:
200                 case ASUBW:
201                         if(p->from.type != D_CONST || needc(p->link))
202                                 break;
203                         if(p->from.offset == -1) {
204                                 if(p->as == ASUBQ)
205                                         p->as = AINCQ;
206                                 else if(p->as == ASUBL)
207                                         p->as = AINCL;
208                                 else
209                                         p->as = AINCW;
210                                 p->from = zprog.from;
211                         }
212                         else if(p->from.offset == 1){
213                                 if(p->as == ASUBQ)
214                                         p->as = ADECQ;
215                                 else if(p->as == ASUBL)
216                                         p->as = ADECL;
217                                 else
218                                         p->as = ADECW;
219                                 p->from = zprog.from;
220                         }
221                         break;
222
223                 case ACMPL:
224                 case ACMPQ:
225                         if(p->to.type != D_CONST || p->to.offset != 0 || regtyp(&p->from) == 0)
226                                 break;
227                         if(p->link == P || (p->link->as != AJEQ && p->link->as != AJNE))
228                                 break;
229                         r1 = uniqp(r);
230                         while(r1 != R && r1->prog->as == ANOP)
231                                 r1 = uniqp(r1);
232                         if(r1 == R || r1->prog->to.type != p->from.type)
233                                 break;
234                         p1 = r1->prog;
235                         switch(p1->as){
236                         case ASHLQ:
237                         case ASHRQ:
238                         case ASALQ:
239                         case ASARQ:
240                                 /* shift doesnt affect ZF when shift count is zero */
241                                 if(p1->from.type != D_CONST || p1->from.offset == 0)
242                                         break;
243                         case AANDQ:
244                         case AORQ:
245                         case AXORQ:
246                         case ANEGQ:
247                         case AADDQ:
248                         case AADCQ:
249                         case ASUBQ:
250                         case ASBBQ:
251                         case AINCQ:
252                         case ADECQ:
253                                 if(p->as != ACMPQ)
254                                         break;
255                         case AANDL:
256                         case AORL:
257                         case AXORL:
258                         case ANEGL:
259                         case AADDL:
260                         case AADCL:
261                         case ASUBL:
262                         case ASBBL:
263                         case AINCL:
264                         case ADECL:
265                                 excise(r);
266                                 break;
267                         case ASHLL:
268                         case ASHRL:
269                         case ASALL:
270                         case ASARL:
271                                 /* shift doesnt affect ZF when shift count is zero */
272                                 if(p1->from.type != D_CONST || p1->from.offset == 0)
273                                         break;
274                                 excise(r);
275                         }
276                         break;
277                 }
278         }
279         if(t)
280                 goto loop1;
281 }
282
283 void
284 excise(Reg *r)
285 {
286         Prog *p;
287
288         p = r->prog;
289         p->as = ANOP;
290         p->from = zprog.from;
291         p->to = zprog.to;
292 }
293
294 Reg*
295 uniqp(Reg *r)
296 {
297         Reg *r1;
298
299         r1 = r->p1;
300         if(r1 == R) {
301                 r1 = r->p2;
302                 if(r1 == R || r1->p2link != R)
303                         return R;
304         } else
305                 if(r->p2 != R)
306                         return R;
307         return r1;
308 }
309
310 Reg*
311 uniqs(Reg *r)
312 {
313         Reg *r1;
314
315         r1 = r->s1;
316         if(r1 == R) {
317                 r1 = r->s2;
318                 if(r1 == R)
319                         return R;
320         } else
321                 if(r->s2 != R)
322                         return R;
323         return r1;
324 }
325
326 int
327 regtyp(Adr *a)
328 {
329         int t;
330
331         t = a->type;
332         if(t >= D_AX && t <= D_R15)
333                 return 1;
334         if(t >= D_X0 && t <= D_X0+15)
335                 return 1;
336         return 0;
337 }
338
339 /*
340  * the idea is to substitute
341  * one register for another
342  * from one MOV to another
343  *      MOV     a, R0
344  *      ADD     b, R0   / no use of R1
345  *      MOV     R0, R1
346  * would be converted to
347  *      MOV     a, R1
348  *      ADD     b, R1
349  *      MOV     R1, R0
350  * hopefully, then the former or latter MOV
351  * will be eliminated by copy propagation.
352  */
353 int
354 subprop(Reg *r0)
355 {
356         Prog *p;
357         Adr *v1, *v2;
358         Reg *r;
359         int t;
360
361         p = r0->prog;
362         v1 = &p->from;
363         if(!regtyp(v1))
364                 return 0;
365         v2 = &p->to;
366         if(!regtyp(v2))
367                 return 0;
368         for(r=uniqp(r0); r!=R; r=uniqp(r)) {
369                 if(uniqs(r) == R)
370                         break;
371                 p = r->prog;
372                 switch(p->as) {
373                 case AIMULL:
374                 case AIMULQ:
375                 case AIMULW:
376                         if(p->to.type != D_NONE)
377                                 break;
378                 case ADIVB:
379                 case ADIVL:
380                 case ADIVQ:
381                 case ADIVW:
382                 case AIDIVB:
383                 case AIDIVL:
384                 case AIDIVQ:
385                 case AIDIVW:
386                 case AIMULB:
387                 case AMULB:
388                 case AMULL:
389                 case AMULQ:
390                 case AMULW:
391
392                 case ACWD:
393                 case ACDQ:
394                 case ACQO:
395
396                 case AREP:
397                 case AREPN:
398                 case ALOOP:
399                 case ALOOPEQ:
400                 case ALOOPNE:
401
402                 case ACALL:
403                         return 0;
404
405                 case AROLB:
406                 case AROLL:
407                 case AROLQ:
408                 case AROLW:
409                 case ARORB:
410                 case ARORL:
411                 case ARORQ:
412                 case ARORW:
413                 case ASALB:
414                 case ASALL:
415                 case ASALQ:
416                 case ASALW:
417                 case ASARB:
418                 case ASARL:
419                 case ASARQ:
420                 case ASARW:
421                 case ASHLB:
422                 case ASHLL:
423                 case ASHLQ:
424                 case ASHLW:
425                 case ASHRB:
426                 case ASHRL:
427                 case ASHRQ:
428                 case ASHRW:
429                         if(p->from.type == D_CX && v1->type == D_CX)
430                                 return 0;
431                         break;
432
433                 case AORL:
434                 case AORQ:
435                 case AANDL:
436                 case AANDQ:
437                 case AXORL:
438                 case AXORQ:
439                 case AADDL:
440                 case AADDQ:
441                 case AADCL:
442                 case AADCQ:
443                         /*
444                          * can swap when:
445                          *  ADD R2, R1
446                          *  MOV R1, R2
447                          * convert to:
448                          *  ADD R1, R2
449                          *  MOV R2, R1  / no use for R1
450                          */
451                         if(p->to.type == v1->type && p->from.type == v2->type){
452                                 copysub(&p->from, v2, v1, 1);
453                                 goto gotit;
454                         }
455                         break;
456
457                 case AMOVL:
458                 case ALEAL:
459                 case AMOVSL:
460                 case AMOVBLZX:
461                 case AMOVBLSX:
462                 case AMOVWLZX:
463                 case AMOVWLSX:
464                 case AMOVQL:
465
466                 case AMOVQ:
467                 case ALEAQ:
468                 case AMOVSQ:
469                 case AMOVBQZX:
470                 case AMOVBQSX:
471                 case AMOVWQZX:
472                 case AMOVWQSX:
473                 case AMOVLQZX:
474                 case AMOVLQSX:
475                         if(p->to.type == v1->type)
476                                 goto gotit;
477                         break;
478                 }
479                 if(copyau(&p->from, v2) ||
480                    copyau(&p->to, v2))
481                         break;
482                 if(copysub(&p->from, v1, v2, 0) ||
483                    copysub(&p->to, v1, v2, 0))
484                         break;
485         }
486         return 0;
487
488 gotit:
489         copysub(&p->to, v1, v2, 1);
490         if(debug['P']) {
491                 print("gotit: %D->%D\n%P", v1, v2, r->prog);
492                 if(p->from.type == v2->type)
493                         print(" excise");
494                 print("\n");
495         }
496         for(r=uniqs(r); r!=r0; r=uniqs(r)) {
497                 p = r->prog;
498                 copysub(&p->from, v1, v2, 1);
499                 copysub(&p->to, v1, v2, 1);
500                 if(debug['P'])
501                         print("%P\n", r->prog);
502         }
503         t = v1->type;
504         v1->type = v2->type;
505         v2->type = t;
506         if(debug['P'])
507                 print("%P last\n", r->prog);
508         return 1;
509 }
510
511 /*
512  * The idea is to remove redundant copies.
513  *      v1->v2  F=0
514  *      (use v2 s/v2/v1/)*
515  *      set v1  F=1
516  *      use v2  return fail
517  *      -----------------
518  *      v1->v2  F=0
519  *      (use v2 s/v2/v1/)*
520  *      set v1  F=1
521  *      set v2  return success
522  */
523 int
524 copyprop(Reg *r0)
525 {
526         Prog *p;
527         Adr *v1, *v2;
528         Reg *r;
529
530         p = r0->prog;
531         v1 = &p->from;
532         v2 = &p->to;
533         if(copyas(v1, v2))
534                 return 1;
535         for(r=firstr; r!=R; r=r->link)
536                 r->active = 0;
537         return copy1(v1, v2, r0->s1, 0);
538 }
539
540 int
541 copy1(Adr *v1, Adr *v2, Reg *r, int f)
542 {
543         int t;
544         Prog *p;
545
546         if(r->active) {
547                 if(debug['P'])
548                         print("act set; return 1\n");
549                 return 1;
550         }
551         r->active = 1;
552         if(debug['P'])
553                 print("copy %D->%D f=%d\n", v1, v2, f);
554         for(; r != R; r = r->s1) {
555                 p = r->prog;
556                 if(debug['P'])
557                         print("%P", p);
558                 if(!f && uniqp(r) == R) {
559                         f = 1;
560                         if(debug['P'])
561                                 print("; merge; f=%d", f);
562                 }
563                 t = copyu(p, v2, A);
564                 switch(t) {
565                 case 2: /* rar, cant split */
566                         if(debug['P'])
567                                 print("; %D rar; return 0\n", v2);
568                         return 0;
569
570                 case 3: /* set */
571                         if(debug['P'])
572                                 print("; %D set; return 1\n", v2);
573                         return 1;
574
575                 case 1: /* used, substitute */
576                 case 4: /* use and set */
577                         if(f) {
578                                 if(!debug['P'])
579                                         return 0;
580                                 if(t == 4)
581                                         print("; %D used+set and f=%d; return 0\n", v2, f);
582                                 else
583                                         print("; %D used and f=%d; return 0\n", v2, f);
584                                 return 0;
585                         }
586                         if(copyu(p, v2, v1)) {
587                                 if(debug['P'])
588                                         print("; sub fail; return 0\n");
589                                 return 0;
590                         }
591                         if(debug['P'])
592                                 print("; sub %D/%D", v2, v1);
593                         if(t == 4) {
594                                 if(debug['P'])
595                                         print("; %D used+set; return 1\n", v2);
596                                 return 1;
597                         }
598                         break;
599                 }
600                 if(!f) {
601                         t = copyu(p, v1, A);
602                         if(!f && (t == 2 || t == 3 || t == 4)) {
603                                 f = 1;
604                                 if(debug['P'])
605                                         print("; %D set and !f; f=%d", v1, f);
606                         }
607                 }
608                 if(debug['P'])
609                         print("\n");
610                 if(r->s2)
611                         if(!copy1(v1, v2, r->s2, f))
612                                 return 0;
613         }
614         return 1;
615 }
616
617 /*
618  * return
619  * 1 if v only used (and substitute),
620  * 2 if read-alter-rewrite
621  * 3 if set
622  * 4 if set and used
623  * 0 otherwise (not touched)
624  */
625 int
626 copyu(Prog *p, Adr *v, Adr *s)
627 {
628
629         switch(p->as) {
630
631         default:
632                 if(debug['P'])
633                         print("unknown op %A\n", p->as);
634                 /* SBBL; ADCL; FLD1; SAHF */
635                 return 2;
636
637
638         case ANEGB:
639         case ANEGW:
640         case ANEGL:
641         case ANEGQ:
642         case ANOTB:
643         case ANOTW:
644         case ANOTL:
645         case ANOTQ:
646                 if(copyas(&p->to, v))
647                         return 2;
648                 break;
649
650         case ALEAL:     /* lhs addr, rhs store */
651         case ALEAQ:
652                 if(copyas(&p->from, v))
653                         return 2;
654
655
656         case ANOP:      /* rhs store */
657         case AMOVL:
658         case AMOVQ:
659         case AMOVBLSX:
660         case AMOVBLZX:
661         case AMOVBQSX:
662         case AMOVBQZX:
663         case AMOVLQSX:
664         case AMOVLQZX:
665         case AMOVWLSX:
666         case AMOVWLZX:
667         case AMOVWQSX:
668         case AMOVWQZX:
669         case AMOVQL:
670
671         case AMOVSS:
672         case AMOVSD:
673         case ACVTSD2SL:
674         case ACVTSD2SQ:
675         case ACVTSD2SS:
676         case ACVTSL2SD:
677         case ACVTSL2SS:
678         case ACVTSQ2SD:
679         case ACVTSQ2SS:
680         case ACVTSS2SD:
681         case ACVTSS2SL:
682         case ACVTSS2SQ:
683         case ACVTTSD2SL:
684         case ACVTTSD2SQ:
685         case ACVTTSS2SL:
686         case ACVTTSS2SQ:
687                 if(copyas(&p->to, v)) {
688                         if(s != A)
689                                 return copysub(&p->from, v, s, 1);
690                         if(copyau(&p->from, v))
691                                 return 4;
692                         return 3;
693                 }
694                 goto caseread;
695
696         case AROLB:
697         case AROLL:
698         case AROLQ:
699         case AROLW:
700         case ARORB:
701         case ARORL:
702         case ARORQ:
703         case ARORW:
704         case ASALB:
705         case ASALL:
706         case ASALQ:
707         case ASALW:
708         case ASARB:
709         case ASARL:
710         case ASARQ:
711         case ASARW:
712         case ASHLB:
713         case ASHLL:
714         case ASHLQ:
715         case ASHLW:
716         case ASHRB:
717         case ASHRL:
718         case ASHRQ:
719         case ASHRW:
720                 if(copyas(&p->to, v))
721                         return 2;
722                 if(copyas(&p->from, v))
723                         if(p->from.type == D_CX)
724                                 return 2;
725                 goto caseread;
726
727         case AADDB:     /* rhs rar */
728         case AADDL:
729         case AADDQ:
730         case AADDW:
731         case AANDB:
732         case AANDL:
733         case AANDQ:
734         case AANDW:
735         case ADECL:
736         case ADECQ:
737         case ADECW:
738         case AINCL:
739         case AINCQ:
740         case AINCW:
741         case ASUBB:
742         case ASUBL:
743         case ASUBQ:
744         case ASUBW:
745         case AORB:
746         case AORL:
747         case AORQ:
748         case AORW:
749         case AXORB:
750         case AXORL:
751         case AXORQ:
752         case AXORW:
753         case AMOVB:
754         case AMOVW:
755
756         case AADDSD:
757         case AADDSS:
758         case ACMPSD:
759         case ACMPSS:
760         case ADIVSD:
761         case ADIVSS:
762         case AMAXSD:
763         case AMAXSS:
764         case AMINSD:
765         case AMINSS:
766         case AMULSD:
767         case AMULSS:
768         case ARCPSS:
769         case ARSQRTSS:
770         case ASQRTSD:
771         case ASQRTSS:
772         case ASUBSD:
773         case ASUBSS:
774         case AXORPD:
775                 if(copyas(&p->to, v))
776                         return 2;
777                 goto caseread;
778
779         case ACMPL:     /* read only */
780         case ACMPW:
781         case ACMPB:
782         case ACMPQ:
783
784         case ACOMISD:
785         case ACOMISS:
786         case AUCOMISD:
787         case AUCOMISS:
788         caseread:
789                 if(s != A) {
790                         if(copysub(&p->from, v, s, 1))
791                                 return 1;
792                         return copysub(&p->to, v, s, 1);
793                 }
794                 if(copyau(&p->from, v))
795                         return 1;
796                 if(copyau(&p->to, v))
797                         return 1;
798                 break;
799
800         case AJGE:      /* no reference */
801         case AJNE:
802         case AJLE:
803         case AJEQ:
804         case AJHI:
805         case AJLS:
806         case AJMI:
807         case AJPL:
808         case AJGT:
809         case AJLT:
810         case AJCC:
811         case AJCS:
812
813         case AADJSP:
814         case AWAIT:
815         case ACLD:
816                 break;
817
818         case AIMULL:
819         case AIMULQ:
820         case AIMULW:
821                 if(p->to.type != D_NONE) {
822                         if(copyas(&p->to, v))
823                                 return 2;
824                         goto caseread;
825                 }
826
827         case ADIVB:
828         case ADIVL:
829         case ADIVQ:
830         case ADIVW:
831         case AIDIVB:
832         case AIDIVL:
833         case AIDIVQ:
834         case AIDIVW:
835         case AIMULB:
836         case AMULB:
837         case AMULL:
838         case AMULQ:
839         case AMULW:
840
841         case ACWD:
842         case ACDQ:
843         case ACQO:
844                 if(v->type == D_AX || v->type == D_DX)
845                         return 2;
846                 goto caseread;
847
848         case AMOVSL:
849         case AMOVSQ:
850         case AREP:
851         case AREPN:
852                 if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
853                         return 2;
854                 goto caseread;
855
856         case AJMP:      /* funny */
857                 if(s != A) {
858                         if(copysub(&p->to, v, s, 1))
859                                 return 1;
860                         return 0;
861                 }
862                 if(copyau(&p->to, v))
863                         return 1;
864                 return 0;
865
866         case ARET:      /* funny */
867                 if(v->type == REGRET || v->type == FREGRET)
868                         return 2;
869                 if(s != A)
870                         return 1;
871                 return 3;
872
873         case ACALL:     /* funny */
874                 if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
875                         return 2;
876                 if(REGARG && v->type == REGARG)
877                         return 2;
878
879                 if(s != A) {
880                         if(copysub(&p->to, v, s, 1))
881                                 return 1;
882                         return 0;
883                 }
884                 if(copyau(&p->to, v))
885                         return 4;
886                 return 3;
887
888         case ATEXT:     /* funny */
889                 if(REGARG && v->type == REGARG)
890                         return 3;
891                 return 0;
892         }
893         return 0;
894 }
895
896 /*
897  * direct reference,
898  * could be set/use depending on
899  * semantics
900  */
901 int
902 copyas(Adr *a, Adr *v)
903 {
904         if(a->type != v->type)
905                 return 0;
906         if(regtyp(v))
907                 return 1;
908         if(v->type == D_AUTO || v->type == D_PARAM)
909                 if(v->offset == a->offset)
910                         return 1;
911         return 0;
912 }
913
914 /*
915  * either direct or indirect
916  */
917 int
918 copyau(Adr *a, Adr *v)
919 {
920
921         if(copyas(a, v))
922                 return 1;
923         if(regtyp(v)) {
924                 if(a->type-D_INDIR == v->type)
925                         return 1;
926                 if(a->index == v->type)
927                         return 1;
928         }
929         return 0;
930 }
931
932 /*
933  * substitute s for v in a
934  * return failure to substitute
935  */
936 int
937 copysub(Adr *a, Adr *v, Adr *s, int f)
938 {
939         int t;
940
941         if(copyas(a, v)) {
942                 t = s->type;
943                 if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
944                         if(f)
945                                 a->type = t;
946                 }
947                 return 0;
948         }
949         if(regtyp(v)) {
950                 t = v->type;
951                 if(a->type == t+D_INDIR) {
952                         if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
953                                 return 1;       /* can't use BP-base with index */
954                         if(f)
955                                 a->type = s->type+D_INDIR;
956 //                      return 0;
957                 }
958                 if(a->index == t) {
959                         if(f)
960                                 a->index = s->type;
961                         return 0;
962                 }
963                 return 0;
964         }
965         return 0;
966 }