blob: ef77fa19fd08fb3bf23429a9d8ce5379c5355bee [file] [log] [blame]
Rob Pike0cafb9e2008-06-04 14:37:38 -07001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5#include "gg.h"
6
7void
8cgen(Node *n, Node *res)
9{
10 long lno;
11 Node *nl, *nr, *r;
12 Node n1, tmp;
13 int a;
14 Prog *p1, *p2, *p3;
15
16 if(debug['g']) {
17 dump("\ncgen-l", res);
18 dump("cgen-r", n);
19 }
20 if(n == N || n->type == T)
21 return;
22 if(res == N || res->type == T)
23 fatal("cgen: res nil");
24
Ken Thompson6b8bd352008-06-06 16:49:35 -070025 if(n->ullman >= UINF) {
26 if(n->op == OINDREG)
27 fatal("cgen: this is going to misscompile");
28 if(res->ullman >= UINF)
29 fatal("cgen: fun both sides");
30 }
31
Rob Pike0cafb9e2008-06-04 14:37:38 -070032 lno = dynlineno;
33 if(n->op != ONAME)
34 dynlineno = n->lineno; // for diagnostics
35
36 if(isfat(n->type)) {
37 sgen(n, res, n->type->width);
38 goto ret;
39 }
40
41 if(!res->addable) {
Ken Thompson6b8bd352008-06-06 16:49:35 -070042 if(n->ullman > res->ullman) {
Ken Thompsona93099c2008-06-06 17:01:33 -070043 regalloc(&n1, n->type, res);
Ken Thompson6b8bd352008-06-06 16:49:35 -070044 cgen(n, &n1);
45 cgen(&n1, res);
46 regfree(&n1);
47 return;
48 }
49
Rob Pike0cafb9e2008-06-04 14:37:38 -070050 igen(res, &n1, N);
51 cgen(n, &n1);
52 regfree(&n1);
53 goto ret;
54 }
55
56 if(n->addable) {
57 gmove(n, res);
58 goto ret;
59 }
60
61 nl = n->left;
62 nr = n->right;
63 if(nl != N && nl->ullman >= UINF)
64 if(nr != N && nr->ullman >= UINF) {
65 fatal("cgen: both sides functions");
66 goto ret;
67 }
68
69 switch(n->op) {
70 default:
71 dump("cgen", n);
72 fatal("cgen: unknown op %N", n);
73 break;
74
75 // these call bgen to get a bool value
76 case OOROR:
77 case OANDAND:
78 case OEQ:
79 case ONE:
80 case OLT:
81 case OLE:
82 case OGE:
83 case OGT:
84 case ONOT:
85 p1 = gbranch(AJMP, T);
86 p2 = pc;
87 gmove(booltrue, res);
88 p3 = gbranch(AJMP, T);
89 patch(p1, pc);
90 bgen(n, 1, p2);
91 gmove(boolfalse, res);
92 patch(p3, pc);
93 goto ret;
94
95 case OPLUS:
96 cgen(nl, res);
97 goto ret;
98
99 // unary
100 case OMINUS:
101 case OCOM:
102 a = optoas(n->op, nl->type);
103 goto uop;
104
105 // symmetric binary
106 case OAND:
107 case OOR:
108 case OXOR:
109 case OADD:
110 case OMUL:
111 a = optoas(n->op, nl->type);
112 goto sbop;
113
114 // asymmetric binary
115 case OMOD:
116 case OSUB:
117 case ODIV:
118 case OLSH:
119 case ORSH:
120 a = optoas(n->op, nl->type);
121 goto abop;
122
123 case OCONV:
124 if(eqtype(n->type, nl->type, 0)) {
125 cgen(nl, res);
126 break;
127 }
128 regalloc(&n1, nl->type, res);
129 cgen(nl, &n1);
130 gmove(&n1, res);
131 regfree(&n1);
132 break;
133
134// case OINDEXPTRSTR:
135// nl = n->left;
136// nr = n->right;
137// if(nl->addable) {
138// cgen(nr);
139// cgen(nl);
140// gopcode(P_LOADI, T_ADDR, N);
141// gopcodet(P_INDEXZ, nr->type, N);
142// break;
143// }
144// break;
145
146// case OINDEXSTR:
147// nl = n->left;
148// nr = n->right;
149// if(nl->addable) {
150// cgen(nr);
151// gopcodet(P_INDEXZ, nr->type, nl);
152// break;
153// }
154// cgen(nl);
155// r = tempname(nl->type);
156// gopcodet(P_STORE, nl->type, r);
157// cgen(nr);
158// gopcodet(P_INDEXZ, nr->type, r);
159// break;
160
161// case OSLICESTR:
162// case OSLICEPTRSTR:
163// nl = n->left; // name
164// nr = n->right;
165//
166// r = nr->right; // index2
167// if(!r->addable) {
168// cgen(r);
169// r = tempname(r->type);
170// gopcodet(P_STORE, r->type, r);
171// }
172//
173// // string into T_ADDR
174// if(!nl->addable) {
175// cgen(nl);
176// gconv(T_ADDR, nl->type->etype);
177// } else
178// gopcode(P_LOAD, T_ADDR, nl);
179//
180// if(n->op == OSLICEPTRSTR)
181// gopcode(P_LOADI, T_ADDR, N);
182//
183// // offset in int reg
184// cgen(nr->left);
185//
186// // index 2 addressed
187// gopcodet(P_SLICE, r->type, r);
188// break;
189
190 case OS2I:
191 case OI2I:
192 case OI2S:
193
194 case OINDEXPTR:
195 case OINDEX:
196 case ODOT:
197 case ODOTPTR:
198 case OIND:
199 igen(n, &n1, res);
200 gmove(&n1, res);
201 regfree(&n1);
202 break;
203
204 case OLEN:
205 if(isptrto(nl->type, TSTRING)) {
206 regalloc(&n1, types[tptr], res);
207 cgen(nl, res);
208 n1.op = OINDREG;
209 n1.type = types[TINT32];
210 gmove(&n1, res);
211 regfree(&n1);
212 break;
213 }
214 fatal("cgen: OLEN: unknown type %lT", nl->type);
215 break;
216
217// case ODOTMETH:
218// case ODOTINTER:
219// cgen(n->left);
220// break;
221
222 case OADDR:
223 agen(nl, res);
224 break;
225
226 case OCALLMETH:
227 cgen_callmeth(n);
228 cgen_callret(n, res);
229 break;
230
231 case OCALLINTER:
232 cgen_callinter(n, res);
233 cgen_callret(n, res);
234 break;
235
236 case OCALL:
237 cgen_call(n);
238 cgen_callret(n, res);
239 break;
240 }
241 goto ret;
242
243sbop: // symmetric binary
244 if(nl->ullman < nr->ullman) {
245 r = nl;
246 nl = nr;
247 nr = r;
248 }
249
250abop: // asymmetric binary
251 if(nr->addable) {
252 regalloc(&n1, nl->type, res);
253 cgen(nl, &n1);
254 gins(a, nr, &n1);
255 gmove(&n1, res);
256 regfree(&n1);
257 goto ret;
258 }
259
260 tempname(&tmp, nr->type);
261 regalloc(&n1, nr->type, res);
262 cgen(nr, &n1);
263 gmove(&n1, &tmp);
264 regfree(&n1);
265
266 regalloc(&n1, nl->type, res);
267 cgen(nl, &n1);
268 gins(a, &tmp, &n1);
269 gmove(&n1, res);
270 regfree(&n1);
271 goto ret;
272
273uop: // unary
274 regalloc(&n1, nl->type, res);
275 cgen(nl, &n1);
276 gins(a, N, &n1);
277 gmove(&n1, res);
278 regfree(&n1);
279 goto ret;
280
281ret:
282 dynlineno = lno;
283}
284
285void
286agen(Node *n, Node *res)
287{
288 Node *nl, *nr;
289 Node n1, n2, n3, tmp;
290 ulong w;
291 Type *t;
292
293 if(n == N || n->type == T)
294 return;
295
296 if(!isptr[res->type->etype])
297 fatal("agen: not tptr: %T", res->type);
298
299 if(n->addable) {
300 regalloc(&n1, types[tptr], res);
301 gins(ALEAQ, n, &n1);
302 gmove(&n1, res);
303 regfree(&n1);
304 return;
305 }
306
307 switch(n->op) {
308 default:
309 fatal("agen: unknown op %N", n);
310 break;
311
312// case ONAME:
313// regalloc(&n1, types[tptr], res);
314// gins(optoas(OADDR, types[tptr]), n, &n1);
315// gmove(&n1, res);
316// regfree(&n1);
317// break;
318
319 case OINDEXPTR:
320 nl = n->left;
321 nr = n->right;
322 w = n->type->width;
323 if(nr->addable)
324 goto iprad;
325 if(nl->addable) {
326 regalloc(&n1, nr->type, N);
327 cgen(nr, &n1);
328 cgen(nl, res);
329 goto index;
330 }
331 cgen(nr, res);
332 tempname(&tmp, nr->type);
333 gmove(res, &tmp);
334
335 iprad:
336 cgen(nl, res);
337 regalloc(&n1, nr->type, N);
338 cgen(nr, &n1);
339 goto index;
340
341 case OS2I:
342 case OI2I:
343 case OI2S:
344 agen_inter(n, res);
345 break;
346
347// case OINDREG:
348
349 case OINDEX:
350 nl = n->left;
351 nr = n->right;
352 w = n->type->width;
353 if(nr->addable)
354 goto irad;
355 if(nl->addable) {
356 regalloc(&n1, nr->type, N);
357 cgen(nr, &n1);
358 agen(nl, res);
359 goto index;
360 }
361 cgen(nr, res);
362 tempname(&tmp, nr->type);
363 gmove(res, &tmp);
364
365 irad:
366 agen(nl, res);
367 regalloc(&n1, nr->type, N);
368 cgen(nr, &n1);
369 goto index;
370
371 index:
372 // &a is in res
373 // i is in &n1
374 // w is width
375 if(issigned[n1.type->etype]) {
376 nodconst(&n3, types[TINT64], w); // w/tint64
377 regalloc(&n2, types[TINT64], &n1); // i/int64
378 gmove(&n1, &n2);
379 gins(optoas(OMUL, types[TINT64]), &n3, &n2);
380 gins(optoas(OADD, types[tptr]), &n2, res);
381 regfree(&n1);
382 regfree(&n2);
383 break;
384 }
385 // unsigned multiply is a pain in the ass
386 fatal("agen: unsigned index");
387 break;
388
389// case OIND:
390// nl = n->left;
391// if(nl->addable) {
392// gopcode(P_LOAD, T_ADDR, nl);
393// break;
394// }
395// cgen(nl);
396// gconv(T_ADDR, nl->type->etype);
397// break;
398
399 case ODOT:
400 nl = n->left;
401 t = nl->type;
402 agen(nl, res);
403 if(n->xoffset != 0) {
404 nodconst(&n1, types[TINT64], n->xoffset);
405 gins(optoas(OADD, types[tptr]), &n1, res);
406 }
407 break;
408
409 case ODOTPTR:
410 nl = n->left;
411 t = nl->type;
412 if(!isptr[t->etype])
413 fatal("agen: not ptr %N", n);
414 cgen(nl, res);
415 if(n->xoffset != 0) {
416 nodconst(&n1, types[TINT64], n->xoffset);
417 gins(optoas(OADD, types[tptr]), &n1, res);
418 }
419 break;
420 }
421}
422
423vlong
424fieldoffset(Type *t, Node *n)
425{
426 if(t->etype != TSTRUCT)
427 fatal("fieldoffset: not struct %lT", t);
428 if(n->op != ONAME)
429 fatal("fieldoffset: not field name %N", n);
430 return 0;
431}
432
433void
434igen(Node *n, Node *a, Node *res)
435{
436 regalloc(a, types[tptr], res);
437 agen(n, a);
438 a->op = OINDREG;
439 a->type = n->type;
440}
441
442void
443bgen(Node *n, int true, Prog *to)
444{
445 long lno;
446 int et, a, b;
447 Node *nl, *nr, *r;
448 Node n1, n2, tmp;
449 Prog *p1, *p2;
450
451 if(n == N)
452 n = booltrue;
453
454 lno = dynlineno;
455 if(n->op != ONAME)
456 dynlineno = n->lineno; // for diagnostics
457
458 if(n->type == T) {
459 convlit(n, types[TBOOL]);
460 if(n->type == T)
461 goto ret;
462 }
463
464 et = n->type->etype;
465 if(et != TBOOL) {
466 yyerror("cgen: bad type %T for %O", n->type, n->op);
467 patch(gins(AEND, N, N), to);
468 goto ret;
469 }
470 nl = N;
471 nr = N;
472
473 switch(n->op) {
474 default:
475 regalloc(&n1, n->type, N);
476 cgen(n, &n1);
477 nodconst(&n2, n->type, 0);
478 gins(optoas(OCMP, n->type), &n1, &n2);
479 a = AJNE;
480 if(!true)
481 a = AJEQ;
482 patch(gbranch(a, n->type), to);
483 regfree(&n1);
484 goto ret;
485
486 case OLITERAL:
487 if(!true == !n->val.vval)
488 patch(gbranch(AJMP, T), to);
489 goto ret;
490
491 case ONAME:
492 nodconst(&n1, n->type, 0);
493 gins(optoas(OCMP, n->type), n, &n1);
494 a = AJNE;
495 if(!true)
496 a = AJEQ;
497 patch(gbranch(a, n->type), to);
498 goto ret;
499
500 case OANDAND:
501 if(!true)
502 goto caseor;
503
504 caseand:
505 p1 = gbranch(AJMP, T);
506 p2 = gbranch(AJMP, T);
507 patch(p1, pc);
508 bgen(n->left, !true, p2);
509 bgen(n->right, !true, p2);
510 p1 = gbranch(AJMP, T);
511 patch(p1, to);
512 patch(p2, pc);
513 goto ret;
514
515 case OOROR:
516 if(!true)
517 goto caseand;
518
519 caseor:
520 bgen(n->left, true, to);
521 bgen(n->right, true, to);
522 goto ret;
523
524 case OEQ:
525 case ONE:
526 case OLT:
527 case OGT:
528 case OLE:
529 case OGE:
530 nr = n->right;
531 if(nr == N || nr->type == T)
532 goto ret;
533
534 case ONOT: // unary
535 nl = n->left;
536 if(nl == N || nl->type == T)
537 goto ret;
538 }
539
540 switch(n->op) {
541
542 case ONOT:
543 bgen(nl, !true, to);
544 goto ret;
545
546 case OEQ:
547 case ONE:
548 case OLT:
549 case OGT:
550 case OLE:
551 case OGE:
552 a = n->op;
553 if(!true)
554 a = brcom(a);
555
556 // make simplest on right
557 if(nl->ullman < nr->ullman) {
558 a = brrev(a);
559 r = nl;
560 nl = nr;
561 nr = r;
562 }
563 a = optoas(a, nr->type);
564
565 if(nr->addable) {
566 regalloc(&n1, nl->type, N);
567 cgen(nl, &n1);
568 b = optoas(OCMP, nr->type);
569
570 switch(b) {
571 case ACMPQ:
572 if(nr->op == OLITERAL)
573 if(nr->val.vval >= (1LL<<32))
574 goto dolit;
575
576 case AUCOMISS:
577 if(nr->op == OLITERAL)
578 goto dolit;
579 if(nr->op == ONAME)
580 goto dolit;
581 }
582
583 gins(b, &n1, nr);
584 patch(gbranch(a, nr->type), to);
585 regfree(&n1);
586 break;
587
588 dolit:
589 regalloc(&n2, nr->type, N);
590 cgen(nr, &n2);
591 gins(b, &n1, &n2);
592 patch(gbranch(a, nr->type), to);
593 regfree(&n2);
594 regfree(&n1);
595 break;
596 }
597
598 tempname(&tmp, nr->type);
599 cgen(nr, &tmp);
600
601 regalloc(&n1, nl->type, N);
602 cgen(nl, &n1);
603
604 gins(optoas(OCMP, nr->type), &n1, &tmp);
605 patch(gbranch(a, nr->type), to);
606 regfree(&n1);
607 break;
608 }
609 goto ret;
610
611ret:
612 dynlineno = lno;
613}
614
615void
616sgen(Node *n, Node *ns, ulong w)
617{
618 Node nodl, nodr;
619 long c;
620
621 if(w == 0)
622 return;
623 if(n->ullman >= UINF && ns->ullman >= UINF) {
624 fatal("sgen UINF");
625 }
626
627 nodreg(&nodl, types[tptr], D_DI);
628 nodreg(&nodr, types[tptr], D_SI);
629
630 if(n->ullman >= ns->ullman) {
631 agen(n, &nodr);
632 agen(ns, &nodl);
633 } else {
634 agen(ns, &nodl);
635 agen(n, &nodr);
636 }
637
638 gins(ACLD, N, N); // clear direction flag
639
640 c = w / 8;
641 if(c > 0) {
642 gconreg(AMOVQ, c, D_CX);
643 gins(AREP, N, N); // repeat
644 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
645 }
646
647 c = w % 8;
648 if(c > 0) {
649 gconreg(AMOVQ, c, D_CX);
650 gins(AREP, N, N); // repeat
651 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
652 }
653}