]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/5c/txt.c
merge
[plan9front.git] / sys / src / cmd / 5c / txt.c
1 #include "gc.h"
2
3 static  char    resvreg[nelem(reg)];
4
5 void
6 ginit(void)
7 {
8         Type *t;
9
10         thechar = '5';
11         thestring = "arm";
12         exregoffset = REGEXT;
13         exfregoffset = FREGEXT;
14         listinit();
15         nstring = 0;
16         mnstring = 0;
17         nrathole = 0;
18         pc = 0;
19         breakpc = -1;
20         continpc = -1;
21         cases = C;
22         firstp = P;
23         lastp = P;
24         tfield = types[TLONG];
25
26         zprog.link = P;
27         zprog.as = AGOK;
28         zprog.reg = NREG;
29         zprog.from.type = D_NONE;
30         zprog.from.name = D_NONE;
31         zprog.from.reg = NREG;
32         zprog.to = zprog.from;
33         zprog.scond = 0xE;  
34
35         regnode.op = OREGISTER;
36         regnode.class = CEXREG;
37         regnode.reg = REGTMP;
38         regnode.complex = 0;
39         regnode.addable = 11;
40         regnode.type = types[TLONG];
41
42         constnode.op = OCONST;
43         constnode.class = CXXX;
44         constnode.complex = 0;
45         constnode.addable = 20;
46         constnode.type = types[TLONG];
47
48         fconstnode.op = OCONST;
49         fconstnode.class = CXXX;
50         fconstnode.complex = 0;
51         fconstnode.addable = 20;
52         fconstnode.type = types[TDOUBLE];
53
54         nodsafe = new(ONAME, Z, Z);
55         nodsafe->sym = slookup(".safe");
56         nodsafe->type = types[TINT];
57         nodsafe->etype = types[TINT]->etype;
58         nodsafe->class = CAUTO;
59         complex(nodsafe);
60
61         t = typ(TARRAY, types[TCHAR]);
62         symrathole = slookup(".rathole");
63         symrathole->class = CGLOBL;
64         symrathole->type = t;
65
66         nodrat = new(ONAME, Z, Z);
67         nodrat->sym = symrathole;
68         nodrat->type = types[TIND];
69         nodrat->etype = TVOID;
70         nodrat->class = CGLOBL;
71         complex(nodrat);
72         nodrat->type = t;
73
74         nodret = new(ONAME, Z, Z);
75         nodret->sym = slookup(".ret");
76         nodret->type = types[TIND];
77         nodret->etype = TIND;
78         nodret->class = CPARAM;
79         nodret = new(OIND, nodret, Z);
80         complex(nodret);
81
82         com64init();
83
84         memset(reg, 0, sizeof(reg));
85         /* don't allocate */
86         reg[REGTMP] = 1;
87         reg[REGSB] = 1;
88         reg[REGSP] = 1;
89         reg[REGLINK] = 1;
90         reg[REGPC] = 1;
91         /* keep two external registers */
92         reg[REGEXT] = 1;
93         reg[REGEXT-1] = 1;
94         memmove(resvreg, reg, sizeof(reg));
95 }
96
97 void
98 gclean(void)
99 {
100         int i;
101         Sym *s;
102
103         for(i=0; i<NREG; i++)
104                 if(reg[i] && !resvreg[i])
105                         diag(Z, "reg %d left allocated", i);
106         for(i=NREG; i<NREG+NFREG; i++)
107                 if(reg[i] && !resvreg[i])
108                         diag(Z, "freg %d left allocated", i-NREG);
109         while(mnstring)
110                 outstring("", 1L);
111         symstring->type->width = nstring;
112         symrathole->type->width = nrathole;
113         for(i=0; i<NHASH; i++)
114         for(s = hash[i]; s != S; s = s->link) {
115                 if(s->type == T)
116                         continue;
117                 if(s->type->width == 0)
118                         continue;
119                 if(s->class != CGLOBL && s->class != CSTATIC)
120                         continue;
121                 if(s->type == types[TENUM])
122                         continue;
123                 gpseudo(AGLOBL, s, nodconst(s->type->width));
124         }
125         nextpc();
126         p->as = AEND;
127         outcode();
128 }
129
130 void
131 nextpc(void)
132 {
133
134         p = alloc(sizeof(*p));
135         *p = zprog;
136         p->lineno = nearln;
137         pc++;
138         if(firstp == P) {
139                 firstp = p;
140                 lastp = p;
141                 return;
142         }
143         lastp->link = p;
144         lastp = p;
145 }
146
147 void
148 gargs(Node *n, Node *tn1, Node *tn2)
149 {
150         long regs;
151         Node fnxargs[20], *fnxp;
152
153         regs = cursafe;
154
155         fnxp = fnxargs;
156         garg1(n, tn1, tn2, 0, &fnxp);   /* compile fns to temps */
157
158         curarg = 0;
159         fnxp = fnxargs;
160         garg1(n, tn1, tn2, 1, &fnxp);   /* compile normal args and temps */
161
162         cursafe = regs;
163 }
164
165 void
166 garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
167 {
168         Node nod;
169
170         if(n == Z)
171                 return;
172         if(n->op == OLIST) {
173                 garg1(n->left, tn1, tn2, f, fnxp);
174                 garg1(n->right, tn1, tn2, f, fnxp);
175                 return;
176         }
177         if(f == 0) {
178                 if(n->complex >= FNX) {
179                         regsalloc(*fnxp, n);
180                         nod = znode;
181                         nod.op = OAS;
182                         nod.left = *fnxp;
183                         nod.right = n;
184                         nod.type = n->type;
185                         cgen(&nod, Z);
186                         (*fnxp)++;
187                 }
188                 return;
189         }
190         if(typesuv[n->type->etype]) {
191                 regaalloc(tn2, n);
192                 if(n->complex >= FNX) {
193                         sugen(*fnxp, tn2, n->type->width);
194                         (*fnxp)++;
195                 } else
196                         sugen(n, tn2, n->type->width);
197                 return;
198         }
199         if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) {
200                 regaalloc1(tn1, n);
201                 if(n->complex >= FNX) {
202                         cgen(*fnxp, tn1);
203                         (*fnxp)++;
204                 } else
205                         cgen(n, tn1);
206                 return;
207         }
208         regalloc(tn1, n, Z);
209         if(n->complex >= FNX) {
210                 cgen(*fnxp, tn1);
211                 (*fnxp)++;
212         } else
213                 cgen(n, tn1);
214         regaalloc(tn2, n);
215         gopcode(OAS, tn1, Z, tn2);
216         regfree(tn1);
217 }
218
219 Node*
220 nodconst(long v)
221 {
222         constnode.vconst = v;
223         return &constnode;
224 }
225
226 Node*
227 nod32const(vlong v)
228 {
229         constnode.vconst = v & MASK(32);
230         return &constnode;
231 }
232
233 Node*
234 nodfconst(double d)
235 {
236         fconstnode.fconst = d;
237         return &fconstnode;
238 }
239
240 void
241 nodreg(Node *n, Node *nn, int reg)
242 {
243         *n = regnode;
244         n->reg = reg;
245         n->type = nn->type;
246         n->lineno = nn->lineno;
247 }
248
249 void
250 regret(Node *n, Node *nn)
251 {
252         int r;
253
254         r = REGRET;
255         if(typefd[nn->type->etype])
256                 r = FREGRET+NREG;
257         nodreg(n, nn, r);
258         reg[r]++;
259 }
260
261 int
262 tmpreg(void)
263 {
264         int i;
265
266         for(i=REGRET+1; i<NREG; i++)
267                 if(reg[i] == 0)
268                         return i;
269         diag(Z, "out of fixed registers");
270         return 0;
271 }
272
273 void
274 regalloc(Node *n, Node *tn, Node *o)
275 {
276         int i, j;
277         static int lasti;
278
279         switch(tn->type->etype) {
280         case TCHAR:
281         case TUCHAR:
282         case TSHORT:
283         case TUSHORT:
284         case TINT:
285         case TUINT:
286         case TLONG:
287         case TULONG:
288         case TIND:
289                 if(o != Z && o->op == OREGISTER) {
290                         i = o->reg;
291                         if(i >= 0 && i < NREG)
292                                 goto out;
293                 }
294                 j = lasti + REGRET+1;
295                 for(i=REGRET+1; i<NREG; i++) {
296                         if(j >= NREG)
297                                 j = REGRET+1;
298                         if(reg[j] == 0 && resvreg[j] == 0) {
299                                 i = j;
300                                 lasti = (i - REGRET) % 3;
301                                 goto out;
302                         }
303                         j++;
304                 }
305                 diag(tn, "out of fixed registers");
306                 goto err;
307
308         case TFLOAT:
309         case TDOUBLE:
310                 if(o != Z && o->op == OREGISTER) {
311                         i = o->reg;
312                         if(i >= NREG && i < NREG+NFREG)
313                                 goto out;
314                 }
315                 j = 0*2 + NREG;
316                 for(i=NREG; i<NREG+NFREG; i++) {
317                         if(j >= NREG+NFREG)
318                                 j = NREG;
319                         if(reg[j] == 0) {
320                                 i = j;
321                                 goto out;
322                         }
323                         j++;
324                 }
325                 diag(tn, "out of float registers");
326                 goto err;
327
328         case TVLONG:
329         case TUVLONG:
330                 n->op = OREGPAIR;
331                 n->complex = 0; /* already in registers */
332                 n->addable = 11;
333                 n->type = tn->type;
334                 n->lineno = nearln;
335                 n->left = alloc(sizeof(Node));
336                 n->right = alloc(sizeof(Node));
337                 if(o != Z && o->op == OREGPAIR) {
338                         regalloc(n->left, &regnode, o->left);
339                         regalloc(n->right, &regnode, o->right);
340                 } else {
341                         regalloc(n->left, &regnode, Z);
342                         regalloc(n->right, &regnode, Z);
343                 }
344                 if(n->left->reg > n->right->reg){
345                         j = n->left->reg;
346                         n->left->reg = n->right->reg;
347                         n->right->reg = j;
348                 }
349                 n->right->type = types[TULONG];
350                 if(tn->type->etype == TUVLONG)
351                         n->left->type = types[TULONG];
352                 return;
353         }
354         diag(tn, "unknown type in regalloc: %T", tn->type);
355 err:
356         nodreg(n, tn, 0);
357         return;
358 out:
359         reg[i]++;
360         nodreg(n, tn, i);
361 }
362
363 void
364 regialloc(Node *n, Node *tn, Node *o)
365 {
366         Node nod;
367
368         nod = *tn;
369         nod.type = types[TIND];
370         regalloc(n, &nod, o);
371 }
372
373 void
374 regfree(Node *n)
375 {
376         int i;
377
378         if(n->op == OREGPAIR) {
379                 regfree(n->left);
380                 regfree(n->right);
381                 return;
382         }
383         i = 0;
384         if(n->op != OREGISTER && n->op != OINDREG)
385                 goto err;
386         i = n->reg;
387         if(i < 0 || i >= sizeof(reg))
388                 goto err;
389         if(reg[i] <= 0)
390                 goto err;
391         reg[i]--;
392         return;
393 err:
394         diag(n, "error in regfree: %d", i);
395 }
396
397 void
398 regsalloc(Node *n, Node *nn)
399 {
400         cursafe = align(cursafe, nn->type, Aaut3);
401         maxargsafe = maxround(maxargsafe, cursafe+curarg);
402         *n = *nodsafe;
403         n->xoffset = -(stkoff + cursafe);
404         n->type = nn->type;
405         n->etype = nn->type->etype;
406         n->lineno = nn->lineno;
407 }
408
409 void
410 regaalloc1(Node *n, Node *nn)
411 {
412         nodreg(n, nn, REGARG);
413         reg[REGARG]++;
414         curarg = align(curarg, nn->type, Aarg1);
415         curarg = align(curarg, nn->type, Aarg2);
416         maxargsafe = maxround(maxargsafe, cursafe+curarg);
417 }
418
419 void
420 regaalloc(Node *n, Node *nn)
421 {
422         curarg = align(curarg, nn->type, Aarg1);
423         *n = *nn;
424         n->op = OINDREG;
425         n->reg = REGSP;
426         n->xoffset = curarg + SZ_LONG;
427         n->complex = 0;
428         n->addable = 20;
429         curarg = align(curarg, nn->type, Aarg2);
430         maxargsafe = maxround(maxargsafe, cursafe+curarg);
431 }
432
433 void
434 regind(Node *n, Node *nn)
435 {
436
437         if(n->op != OREGISTER) {
438                 diag(n, "regind not OREGISTER");
439                 return;
440         }
441         n->op = OINDREG;
442         n->type = nn->type;
443 }
444
445 void
446 raddr(Node *n, Prog *p)
447 {
448         Adr a;
449
450         naddr(n, &a);
451         if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
452                 a.type = D_REG;
453                 a.reg = 0;
454         }
455         if(a.type != D_REG && a.type != D_FREG) {
456                 if(n)
457                         diag(n, "bad in raddr: %O", n->op);
458                 else
459                         diag(n, "bad in raddr: <null>");
460                 p->reg = NREG;
461         } else
462                 p->reg = a.reg;
463 }
464
465 void
466 naddr(Node *n, Adr *a)
467 {
468         long v;
469
470         a->type = D_NONE;
471         if(n == Z)
472                 return;
473         switch(n->op) {
474         default:
475         bad:
476                 diag(n, "bad in naddr: %O", n->op);
477                 break;
478
479         case OREGISTER:
480                 a->type = D_REG;
481                 a->sym = S;
482                 a->reg = n->reg;
483                 if(a->reg >= NREG) {
484                         a->type = D_FREG;
485                         a->reg -= NREG;
486                 }
487                 break;
488
489         case OIND:
490                 naddr(n->left, a);
491                 if(a->type == D_REG) {
492                         a->type = D_OREG;
493                         break;
494                 }
495                 if(a->type == D_CONST) {
496                         a->type = D_OREG;
497                         break;
498                 }
499                 goto bad;
500
501         case OINDREG:
502                 a->type = D_OREG;
503                 a->sym = S;
504                 a->offset = n->xoffset;
505                 a->reg = n->reg;
506                 break;
507
508         case ONAME:
509                 a->etype = n->etype;
510                 a->type = D_OREG;
511                 a->name = D_STATIC;
512                 a->sym = n->sym;
513                 a->offset = n->xoffset;
514                 if(n->class == CSTATIC)
515                         break;
516                 if(n->class == CEXTERN || n->class == CGLOBL) {
517                         a->name = D_EXTERN;
518                         break;
519                 }
520                 if(n->class == CAUTO) {
521                         a->name = D_AUTO;
522                         break;
523                 }
524                 if(n->class == CPARAM) {
525                         a->name = D_PARAM;
526                         break;
527                 }
528                 goto bad;
529
530         case OCONST:
531                 a->sym = S;
532                 a->reg = NREG;
533                 if(typefd[n->type->etype]) {
534                         a->type = D_FCONST;
535                         a->dval = n->fconst;
536                 } else {
537                         a->type = D_CONST;
538                         a->offset = n->vconst;
539                 }
540                 break;
541
542         case OADDR:
543                 naddr(n->left, a);
544                 if(a->type == D_OREG) {
545                         a->type = D_CONST;
546                         break;
547                 }
548                 goto bad;
549
550         case OADD:
551                 if(n->left->op == OCONST) {
552                         naddr(n->left, a);
553                         v = a->offset;
554                         naddr(n->right, a);
555                 } else {
556                         naddr(n->right, a);
557                         v = a->offset;
558                         naddr(n->left, a);
559                 }
560                 a->offset += v;
561                 break;
562
563         }
564 }
565
566 void
567 fop(int as, int f1, int f2, Node *t)
568 {
569         Node nod1, nod2, nod3;
570
571         nodreg(&nod1, t, NREG+f1);
572         nodreg(&nod2, t, NREG+f2);
573         regalloc(&nod3, t, t);
574         gopcode(as, &nod1, &nod2, &nod3);
575         gmove(&nod3, t);
576         regfree(&nod3);
577 }
578
579 void
580 gmovm(Node *f, Node *t, int w)
581 {
582         gins(AMOVM, f, t);
583         p->scond |= C_UBIT;
584         if(w)
585                 p->scond |= C_WBIT;
586 }
587
588 void
589 gmove(Node *f, Node *t)
590 {
591         int ft, tt, a;
592         Node nod, nod1;
593         Prog *p1;
594
595         ft = f->type->etype;
596         tt = t->type->etype;
597         if(debug['M'])
598                 print("gop: %O %O[%s],%O[%s]\n", OAS,
599                         f->op, tnames[ft], t->op, tnames[tt]);
600
601         if(ft == TDOUBLE && f->op == OCONST) {
602         }
603         if(ft == TFLOAT && f->op == OCONST) {
604         }
605
606         /*
607          * a load --
608          * put it into a register then
609          * worry what to do with it.
610          */
611         if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
612                 switch(ft) {
613                 default:
614                         a = AMOVW;
615                         break;
616                 case TFLOAT:
617                         a = AMOVF;
618                         break;
619                 case TDOUBLE:
620                         a = AMOVD;
621                         break;
622                 case TCHAR:
623                         a = AMOVB;
624                         break;
625                 case TUCHAR:
626                         a = AMOVBU;
627                         break;
628                 case TSHORT:
629                         a = AMOVH;
630                         break;
631                 case TUSHORT:
632                         a = AMOVHU;
633                         break;
634                 }
635                 if(typev[ft]) {
636                         if(typev[tt]) {
637                                 nod1 = *f;
638                                 regalloc(&nod, f, t);
639                                 if(f->op == OINDREG && f->xoffset == 0 && nod.left->reg < nod.right->reg) {
640                                         gmovm(&nod1, nodconst((1<<nod.left->reg)|(1<<nod.right->reg)), 0);
641                                 } else {
642                                         /* low order first, because its value will be used first */
643                                         gins(AMOVW, &nod1, nod.left);
644                                         nod1.xoffset += SZ_LONG;
645                                         gins(AMOVW, &nod1, nod.right);
646                                 }
647                         } else {
648                                 /* assumed not float or double */
649                                 regalloc(&nod, &regnode, t);
650                                 gins(AMOVW, f, &nod);
651                         }
652                 } else {
653                         if(typechlp[ft] && typeilp[tt])
654                                 regalloc(&nod, t, t);
655                         else
656                                 regalloc(&nod, f, t);
657                         gins(a, f, &nod);
658                 }
659                 gmove(&nod, t);
660                 regfree(&nod);
661                 return;
662         }
663
664         /*
665          * a store --
666          * put it into a register then
667          * store it.
668          */
669         if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
670                 switch(tt) {
671                 default:
672                         a = AMOVW;
673                         break;
674                 case TUCHAR:
675                         a = AMOVBU;
676                         break;
677                 case TCHAR:
678                         a = AMOVB;
679                         break;
680                 case TUSHORT:
681                         a = AMOVHU;
682                         break;
683                 case TSHORT:
684                         a = AMOVH;
685                         break;
686                 case TFLOAT:
687                         a = AMOVF;
688                         break;
689                 case TDOUBLE:
690                         a = AMOVD;
691                         break;
692                 }
693                 if(ft == tt)
694                         regalloc(&nod, t, f);
695                 else
696                         regalloc(&nod, t, Z);
697                 gmove(f, &nod);
698                 if(typev[tt]) {
699                         nod1 = *t;
700                         if(t->op == OINDREG && t->xoffset == 0 && nod.left->reg < nod.right->reg){
701                                 gmovm(nodconst((1<<nod.left->reg)|(1<<nod.right->reg)), &nod1, 0);
702                         } else {
703                                 gins(a, nod.left, &nod1);
704                                 nod1.xoffset += SZ_LONG;
705                                 gins(a, nod.right, &nod1);
706                         }
707                 } else
708                         gins(a, &nod, t);
709                 regfree(&nod);
710                 return;
711         }
712
713         /*
714          * type x type cross table
715          */
716         a = AGOK;
717         switch(ft) {
718         case TDOUBLE:
719         case TFLOAT:
720                 switch(tt) {
721                 case TDOUBLE:
722                 case TVLONG:
723                         a = AMOVD;
724                         if(ft == TFLOAT)
725                                 a = AMOVFD;
726                         break;
727                 case TFLOAT:
728                         a = AMOVDF;
729                         if(ft == TFLOAT)
730                                 a = AMOVF;
731                         break;
732                 case TINT:
733                 case TUINT:
734                 case TLONG:
735                 case TULONG:
736                 case TIND:
737                         a = AMOVDW;
738                         if(ft == TFLOAT)
739                                 a = AMOVFW;
740                         break;
741                 case TSHORT:
742                 case TUSHORT:
743                 case TCHAR:
744                 case TUCHAR:
745                         a = AMOVDW;
746                         if(ft == TFLOAT)
747                                 a = AMOVFW;
748                         break;
749                 }
750                 break;
751         case TUINT:
752         case TULONG:
753                 if(tt == TFLOAT || tt == TDOUBLE) {
754                         // ugly and probably longer than necessary,
755                         // but vfp has a single instruction for this,
756                         // so hopefully it won't last long.
757                         //
758                         //      tmp = f
759                         //      tmp1 = tmp & 0x80000000
760                         //      tmp ^= tmp1
761                         //      t = float(int32(tmp))
762                         //      if(tmp1)
763                         //              t += 2147483648.
764                         //
765                         regalloc(&nod, f, Z);
766                         regalloc(&nod1, f, Z);
767                         gins(AMOVW, f, &nod);
768                         gins(AMOVW, &nod, &nod1);
769                         gins(AAND, nodconst(0x80000000), &nod1);
770                         gins(AEOR, &nod1, &nod);
771                         if(tt == TFLOAT)
772                                 gins(AMOVWF, &nod, t);
773                         else
774                                 gins(AMOVWD, &nod, t);
775                         gins(ACMP, nodconst(0), Z);
776                         raddr(&nod1, p);
777                         gins(ABEQ, Z, Z);
778                         regfree(&nod);
779                         regfree(&nod1);
780                         p1 = p;
781                         regalloc(&nod, t, Z);
782                         if(tt == TFLOAT) {
783                                 gins(AMOVF, nodfconst(2147483648.), &nod);
784                                 gins(AADDF, &nod, t);
785                         } else {
786                                 gins(AMOVD, nodfconst(2147483648.), &nod);
787                                 gins(AADDD, &nod, t);
788                         }
789                         regfree(&nod);
790                         patch(p1, pc);
791                         return;
792                 }
793                 // fall through
794
795         case TINT:
796         case TLONG:
797         case TIND:
798                 switch(tt) {
799                 case TDOUBLE:
800                         gins(AMOVWD, f, t);
801                         return;
802                 case TFLOAT:
803                         gins(AMOVWF, f, t);
804                         return;
805                 case TINT:
806                 case TUINT:
807                 case TLONG:
808                 case TULONG:
809                 case TIND:
810                 case TSHORT:
811                 case TUSHORT:
812                 case TCHAR:
813                 case TUCHAR:
814                         a = AMOVW;
815                         break;
816                 }
817                 break;
818         case TSHORT:
819                 switch(tt) {
820                 case TDOUBLE:
821                         regalloc(&nod, f, Z);
822                         gins(AMOVH, f, &nod);
823                         gins(AMOVWD, &nod, t);
824                         regfree(&nod);
825                         return;
826                 case TFLOAT:
827                         regalloc(&nod, f, Z);
828                         gins(AMOVH, f, &nod);
829                         gins(AMOVWF, &nod, t);
830                         regfree(&nod);
831                         return;
832                 case TUINT:
833                 case TINT:
834                 case TULONG:
835                 case TLONG:
836                 case TIND:
837                         a = AMOVH;
838                         break;
839                 case TSHORT:
840                 case TUSHORT:
841                 case TCHAR:
842                 case TUCHAR:
843                         a = AMOVW;
844                         break;
845                 }
846                 break;
847         case TUSHORT:
848                 switch(tt) {
849                 case TDOUBLE:
850                         regalloc(&nod, f, Z);
851                         gins(AMOVHU, f, &nod);
852                         gins(AMOVWD, &nod, t);
853                         regfree(&nod);
854                         return;
855                 case TFLOAT:
856                         regalloc(&nod, f, Z);
857                         gins(AMOVHU, f, &nod);
858                         gins(AMOVWF, &nod, t);
859                         regfree(&nod);
860                         return;
861                 case TINT:
862                 case TUINT:
863                 case TLONG:
864                 case TULONG:
865                 case TIND:
866                         a = AMOVHU;
867                         break;
868                 case TSHORT:
869                 case TUSHORT:
870                 case TCHAR:
871                 case TUCHAR:
872                         a = AMOVW;
873                         break;
874                 }
875                 break;
876         case TCHAR:
877                 switch(tt) {
878                 case TDOUBLE:
879                         regalloc(&nod, f, Z);
880                         gins(AMOVB, f, &nod);
881                         gins(AMOVWD, &nod, t);
882                         regfree(&nod);
883                         return;
884                 case TFLOAT:
885                         regalloc(&nod, f, Z);
886                         gins(AMOVB, f, &nod);
887                         gins(AMOVWF, &nod, t);
888                         regfree(&nod);
889                         return;
890                 case TINT:
891                 case TUINT:
892                 case TLONG:
893                 case TULONG:
894                 case TIND:
895                 case TSHORT:
896                 case TUSHORT:
897                         a = AMOVB;
898                         break;
899                 case TCHAR:
900                 case TUCHAR:
901                         a = AMOVW;
902                         break;
903                 }
904                 break;
905         case TUCHAR:
906                 switch(tt) {
907                 case TDOUBLE:
908                         regalloc(&nod, f, Z);
909                         gins(AMOVBU, f, &nod);
910                         gins(AMOVWD, &nod, t);
911                         regfree(&nod);
912                         return;
913                 case TFLOAT:
914                         regalloc(&nod, f, Z);
915                         gins(AMOVBU, f, &nod);
916                         gins(AMOVWF, &nod, t);
917                         regfree(&nod);
918                         return;
919                 case TINT:
920                 case TUINT:
921                 case TLONG:
922                 case TULONG:
923                 case TIND:
924                 case TSHORT:
925                 case TUSHORT:
926                         a = AMOVBU;
927                         break;
928                 case TCHAR:
929                 case TUCHAR:
930                         a = AMOVW;
931                         break;
932                 }
933                 break;
934         case TVLONG:
935         case TUVLONG:
936                 switch(tt) {
937                 case TVLONG:
938                 case TUVLONG:
939                         a = AMOVW;
940                         break;
941                 }
942                 break;
943         }
944         if(a == AGOK)
945                 diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
946         if(a == AMOVW || a == AMOVF || a == AMOVD)
947         if(samaddr(f, t))
948                 return;
949         if(typev[ft]) {
950                 if(f->op != OREGPAIR || t->op != OREGPAIR)
951                         diag(Z, "bad vlong in gmove (%O->%O)", f->op, t->op);
952                 gins(a, f->left, t->left);
953                 gins(a, f->right, t->right);
954         } else
955                 gins(a, f, t);
956 }
957
958 void
959 gmover(Node *f, Node *t)
960 {
961         int ft, tt, a;
962
963         ft = f->type->etype;
964         tt = t->type->etype;
965         a = AGOK;
966         if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){
967                 switch(tt){
968                 case TSHORT:
969                         a = AMOVH;
970                         break;
971                 case TUSHORT:
972                         a = AMOVHU;
973                         break;
974                 case TCHAR:
975                         a = AMOVB;
976                         break;
977                 case TUCHAR:
978                         a = AMOVBU;
979                         break;
980                 }
981         }
982         if(a == AGOK)
983                 gmove(f, t);
984         else
985                 gins(a, f, t);
986 }
987
988 void
989 gins(int a, Node *f, Node *t)
990 {
991
992         nextpc();
993         p->as = a;
994         if(f != Z)
995                 naddr(f, &p->from);
996         if(t != Z)
997                 naddr(t, &p->to);
998         if(debug['g'])
999                 print("%P\n", p);
1000 }
1001
1002 void
1003 gopcode(int o, Node *f1, Node *f2, Node *t)
1004 {
1005         int a, et, true;
1006         Adr ta;
1007
1008         et = TLONG;
1009         if(f1 != Z && f1->type != T)
1010                 et = f1->type->etype;
1011         true = o & BTRUE;
1012         o &= ~BTRUE;
1013         a = AGOK;
1014         switch(o) {
1015         case OAS:
1016                 gmove(f1, t);
1017                 return;
1018
1019         case OASADD:
1020         case OADD:
1021                 a = AADD;
1022                 if(et == TFLOAT)
1023                         a = AADDF;
1024                 else
1025                 if(et == TDOUBLE || et == TVLONG)
1026                         a = AADDD;
1027                 break;
1028
1029         case OASSUB:
1030         case OSUB:
1031                 if(f2 && f2->op == OCONST) {
1032                         Node *t = f1;
1033                         f1 = f2;
1034                         f2 = t;
1035                         a = ARSB;
1036                 } else
1037                         a = ASUB;
1038                 if(et == TFLOAT)
1039                         a = ASUBF;
1040                 else
1041                 if(et == TDOUBLE || et == TVLONG)
1042                         a = ASUBD;
1043                 break;
1044
1045         case OASOR:
1046         case OOR:
1047                 a = AORR;
1048                 break;
1049
1050         case OASAND:
1051         case OAND:
1052                 a = AAND;
1053                 break;
1054
1055         case OASXOR:
1056         case OXOR:
1057                 a = AEOR;
1058                 break;
1059
1060         case OASLSHR:
1061         case OLSHR:
1062                 a = ASRL;
1063                 break;
1064
1065         case OASASHR:
1066         case OASHR:
1067                 a = ASRA;
1068                 break;
1069
1070         case OASASHL:
1071         case OASHL:
1072                 a = ASLL;
1073                 break;
1074
1075         case OROL:
1076                 assert(f1->op == OCONST);
1077                 f1->vconst = 32-f1->vconst;
1078                 a = AROR;
1079                 break;
1080
1081         case OFUNC:
1082                 a = ABL;
1083                 break;
1084
1085         case OASMUL:
1086         case OMUL:
1087                 a = AMUL;
1088                 if(et == TFLOAT)
1089                         a = AMULF;
1090                 else
1091                 if(et == TDOUBLE || et == TVLONG)
1092                         a = AMULD;
1093                 break;
1094
1095         case OASDIV:
1096         case ODIV:
1097                 a = ADIV;
1098                 if(et == TFLOAT)
1099                         a = ADIVF;
1100                 else
1101                 if(et == TDOUBLE || et == TVLONG)
1102                         a = ADIVD;
1103                 break;
1104
1105         case OASMOD:
1106         case OMOD:
1107                 a = AMOD;
1108                 break;
1109
1110         case OASLMUL:
1111         case OLMUL:
1112                 a = AMULU;
1113                 break;
1114
1115         case OASLMOD:
1116         case OLMOD:
1117                 a = AMODU;
1118                 break;
1119
1120         case OASLDIV:
1121         case OLDIV:
1122                 a = ADIVU;
1123                 break;
1124
1125         case OCASE:
1126         case OEQ:
1127         case ONE:
1128         case OLT:
1129         case OLE:
1130         case OGE:
1131         case OGT:
1132         case OLO:
1133         case OLS:
1134         case OHS:
1135         case OHI:
1136                 a = ACMP;
1137                 if(et == TFLOAT)
1138                         a = ACMPF;
1139                 else
1140                 if(et == TDOUBLE || et == TVLONG)
1141                         a = ACMPD;
1142                 nextpc();
1143                 p->as = a;
1144                 naddr(f1, &p->from);
1145                 if(a == ACMP && f1->op == OCONST && p->from.offset < 0 &&
1146                     p->from.offset != 0x80000000) {
1147                         p->as = ACMN;
1148                         p->from.offset = -p->from.offset;
1149                 }
1150                 raddr(f2, p);
1151                 switch(o) {
1152                 case OEQ:
1153                         a = ABEQ;
1154                         break;
1155                 case ONE:
1156                         a = ABNE;
1157                         break;
1158                 case OLT:
1159                         a = ABLT;
1160                         /* ensure NaN comparison is always false */
1161                         if(typefd[et] && !true)
1162                                 a = ABMI;
1163                         break;
1164                 case OLE:
1165                         a = ABLE;
1166                         if(typefd[et] && !true)
1167                                 a = ABLS;
1168                         break;
1169                 case OGE:
1170                         a = ABGE;
1171                         if(typefd[et] && true)
1172                                 a = ABPL;
1173                         break;
1174                 case OGT:
1175                         a = ABGT;
1176                         if(typefd[et] && true)
1177                                 a = ABHI;
1178                         break;
1179                 case OLO:
1180                         a = ABLO;
1181                         break;
1182                 case OLS:
1183                         a = ABLS;
1184                         break;
1185                 case OHS:
1186                         a = ABHS;
1187                         break;
1188                 case OHI:
1189                         a = ABHI;
1190                         break;
1191                 case OCASE:
1192                         nextpc();
1193                         p->as = ACASE;
1194                         p->scond = 0x9;
1195                         naddr(f2, &p->from);
1196                         a = ABHI;
1197                         break;
1198                 }
1199                 f1 = Z;
1200                 f2 = Z;
1201                 break;
1202         }
1203         if(a == AGOK)
1204                 diag(Z, "bad in gopcode %O", o);
1205         nextpc();
1206         p->as = a;
1207         if(f1 != Z)
1208                 naddr(f1, &p->from);
1209         if(f2 != Z) {
1210                 naddr(f2, &ta);
1211                 p->reg = ta.reg;
1212         }
1213         if(t != Z)
1214                 naddr(t, &p->to);
1215         if(debug['g'])
1216                 print("%P\n", p);
1217 }
1218
1219 samaddr(Node *f, Node *t)
1220 {
1221
1222         if(f->op != t->op)
1223                 return 0;
1224         switch(f->op) {
1225
1226         case OREGISTER:
1227                 if(f->reg != t->reg)
1228                         break;
1229                 return 1;
1230
1231         case OREGPAIR:
1232                 return samaddr(f->left, t->left) && samaddr(f->right, t->right);
1233         }
1234         return 0;
1235 }
1236
1237 void
1238 gbranch(int o)
1239 {
1240         int a;
1241
1242         a = AGOK;
1243         switch(o) {
1244         case ORETURN:
1245                 a = ARET;
1246                 break;
1247         case OGOTO:
1248                 a = AB;
1249                 break;
1250         }
1251         nextpc();
1252         if(a == AGOK) {
1253                 diag(Z, "bad in gbranch %O",  o);
1254                 nextpc();
1255         }
1256         p->as = a;
1257 }
1258
1259 void
1260 patch(Prog *op, long pc)
1261 {
1262
1263         op->to.offset = pc;
1264         op->to.type = D_BRANCH;
1265 }
1266
1267 void
1268 gpseudo(int a, Sym *s, Node *n)
1269 {
1270
1271         nextpc();
1272         p->as = a;
1273         p->from.type = D_OREG;
1274         p->from.sym = s;
1275         p->from.name = D_EXTERN;
1276         if(a == ATEXT)
1277                 p->reg = (profileflg ? 0 : NOPROF);
1278         if(s->class == CSTATIC)
1279                 p->from.name = D_STATIC;
1280         naddr(n, &p->to);
1281         if(a == ADATA || a == AGLOBL)
1282                 pc--;
1283 }
1284
1285 int
1286 sconst(Node *n)
1287 {
1288         vlong vv;
1289
1290         if(n->op == OCONST) {
1291                 if(!typefd[n->type->etype]) {
1292                         vv = n->vconst;
1293                         if(vv >= (vlong)(-32766) && vv < (vlong)32766)
1294                                 return 1;
1295                         /*
1296                          * should be specialised for constant values which will
1297                          * fit in different instructionsl; for now, let 5l
1298                          * sort it out
1299                          */
1300                         return 1;
1301                 }
1302         }
1303         return 0;
1304 }
1305
1306 int
1307 sval(long v)
1308 {
1309         int i;
1310
1311         for(i=0; i<16; i++) {
1312                 if((v & ~0xff) == 0)
1313                         return 1;
1314                 if((~v & ~0xff) == 0)
1315                         return 1;
1316                 v = (v<<2) | ((ulong)v>>30);
1317         }
1318         return 0;
1319 }
1320
1321 long
1322 exreg(Type *t)
1323 {
1324         long o;
1325
1326         if(typechlp[t->etype]) {
1327                 if(exregoffset <= REGEXT-2)
1328                         return 0;
1329                 o = exregoffset;
1330                 if(reg[o] && !resvreg[o])
1331                         return 0;
1332                 resvreg[o] = reg[o] = 1;
1333                 exregoffset--;
1334                 return o;
1335         }
1336         if(typefd[t->etype]) {
1337                 if(exfregoffset <= NFREG-1)
1338                         return 0;
1339                 o = exfregoffset + NREG;
1340                 if(reg[o] && !resvreg[o])
1341                         return 0;
1342                 resvreg[o] = reg[o] = 1;
1343                 exfregoffset--;
1344                 return o;
1345         }
1346         return 0;
1347 }
1348
1349 schar   ewidth[NTYPE] =
1350 {
1351         -1,             /* [TXXX] */
1352         SZ_CHAR,        /* [TCHAR] */
1353         SZ_CHAR,        /* [TUCHAR] */
1354         SZ_SHORT,       /* [TSHORT] */
1355         SZ_SHORT,       /* [TUSHORT] */
1356         SZ_INT,         /* [TINT] */
1357         SZ_INT,         /* [TUINT] */
1358         SZ_LONG,        /* [TLONG] */
1359         SZ_LONG,        /* [TULONG] */
1360         SZ_VLONG,       /* [TVLONG] */
1361         SZ_VLONG,       /* [TUVLONG] */
1362         SZ_FLOAT,       /* [TFLOAT] */
1363         SZ_DOUBLE,      /* [TDOUBLE] */
1364         SZ_IND,         /* [TIND] */
1365         0,              /* [TFUNC] */
1366         -1,             /* [TARRAY] */
1367         0,              /* [TVOID] */
1368         -1,             /* [TSTRUCT] */
1369         -1,             /* [TUNION] */
1370         SZ_INT,         /* [TENUM] */
1371 };
1372
1373 long    ncast[NTYPE] =
1374 {
1375         0,                              /* [TXXX] */
1376         BCHAR|BUCHAR,                   /* [TCHAR] */
1377         BCHAR|BUCHAR,                   /* [TUCHAR] */
1378         BSHORT|BUSHORT,                 /* [TSHORT] */
1379         BSHORT|BUSHORT,                 /* [TUSHORT] */
1380         BINT|BUINT|BLONG|BULONG|BIND,   /* [TINT] */
1381         BINT|BUINT|BLONG|BULONG|BIND,   /* [TUINT] */
1382         BINT|BUINT|BLONG|BULONG|BIND,   /* [TLONG] */
1383         BINT|BUINT|BLONG|BULONG|BIND,   /* [TULONG] */
1384         BVLONG|BUVLONG,                 /* [TVLONG] */
1385         BVLONG|BUVLONG,                 /* [TUVLONG] */
1386         BFLOAT,                         /* [TFLOAT] */
1387         BDOUBLE,                        /* [TDOUBLE] */
1388         BLONG|BULONG|BIND,              /* [TIND] */
1389         0,                              /* [TFUNC] */
1390         0,                              /* [TARRAY] */
1391         0,                              /* [TVOID] */
1392         BSTRUCT,                        /* [TSTRUCT] */
1393         BUNION,                         /* [TUNION] */
1394         0,                              /* [TENUM] */
1395 };