changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/cmd/7c/txt.c

changeset 7169: 94fca26a23d8
parent: 4e09a9199097
child: 8eca5306b6d9
author: cinap_lenrek@felloff.net
date: Wed, 17 Apr 2019 23:38:00 +0200
permissions: -rw-r--r--
description: 7c: fix long to vlong/pointer conversion, avoid negative immediate offsets

we have to explicitely convert to vlong by sign or
zero extending as not every operation leaves a proper
zero/sign extended result in the register. for example
NEGW will zero extend, breaking negative int offsets
on pointers.

we explicitely insert SXTW or MOVWU instructions which
the peephole optimizer takes out again when it is safe
todo so.

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