blob: 412d3fa09b0cfacd949b12f958293fd4c90f11aa [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{
Rob Pike0cafb9e2008-06-04 14:37:38 -070010 Node *nl, *nr, *r;
Ken Thompsonf7753f12008-06-07 15:21:02 -070011 Node n1, n2;
Rob Pike0cafb9e2008-06-04 14:37:38 -070012 int a;
13 Prog *p1, *p2, *p3;
14
15 if(debug['g']) {
Ken Thompson36bfd2a2008-06-08 16:11:14 -070016 dump("\ncgen-res", res);
Rob Pike0cafb9e2008-06-04 14:37:38 -070017 dump("cgen-r", n);
18 }
19 if(n == N || n->type == T)
20 return;
Ken Thompson78c8dec2008-06-24 10:30:33 -070021
Rob Pike0cafb9e2008-06-04 14:37:38 -070022 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");
Ken Thompson78c8dec2008-06-24 10:30:33 -070028 if(res->ullman >= UINF) {
Ken Thompsonca029d32008-06-27 17:53:23 -070029 tempname(&n1, n->type);
30 cgen(n, &n1);
31 cgen(&n1, res);
32 goto ret;
Ken Thompson78c8dec2008-06-24 10:30:33 -070033 }
Ken Thompson6b8bd352008-06-06 16:49:35 -070034 }
35
Rob Pike0cafb9e2008-06-04 14:37:38 -070036 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);
Ken Thompsonca029d32008-06-27 17:53:23 -070047 goto ret;
Ken Thompson6b8bd352008-06-06 16:49:35 -070048 }
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) {
Ken Thompson390d5fe2008-06-27 16:59:14 -070065 tempname(&n1, nr->type);
66 cgen(nr, &n1);
67 n2 = *n;
68 n2.right = &n1;
69 cgen(&n2, res);
Rob Pike0cafb9e2008-06-04 14:37:38 -070070 goto ret;
71 }
72
73 switch(n->op) {
74 default:
75 dump("cgen", n);
76 fatal("cgen: unknown op %N", n);
77 break;
78
79 // these call bgen to get a bool value
80 case OOROR:
81 case OANDAND:
82 case OEQ:
83 case ONE:
84 case OLT:
85 case OLE:
86 case OGE:
87 case OGT:
88 case ONOT:
89 p1 = gbranch(AJMP, T);
90 p2 = pc;
91 gmove(booltrue, res);
92 p3 = gbranch(AJMP, T);
93 patch(p1, pc);
94 bgen(n, 1, p2);
95 gmove(boolfalse, res);
96 patch(p3, pc);
97 goto ret;
98
99 case OPLUS:
100 cgen(nl, res);
101 goto ret;
102
103 // unary
104 case OMINUS:
105 case OCOM:
106 a = optoas(n->op, nl->type);
107 goto uop;
108
109 // symmetric binary
110 case OAND:
111 case OOR:
112 case OXOR:
113 case OADD:
114 case OMUL:
115 a = optoas(n->op, nl->type);
116 goto sbop;
117
118 // asymmetric binary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700119 case OSUB:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700120 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
Rob Pike0cafb9e2008-06-04 14:37:38 -0700134 case OS2I:
135 case OI2I:
136 case OI2S:
137
138 case OINDEXPTR:
139 case OINDEX:
140 case ODOT:
141 case ODOTPTR:
142 case OIND:
143 igen(n, &n1, res);
144 gmove(&n1, res);
145 regfree(&n1);
146 break;
147
148 case OLEN:
149 if(isptrto(nl->type, TSTRING)) {
150 regalloc(&n1, types[tptr], res);
Ken Thompsonb6eca352008-06-08 17:46:28 -0700151 cgen(nl, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700152 n1.op = OINDREG;
153 n1.type = types[TINT32];
154 gmove(&n1, res);
155 regfree(&n1);
156 break;
157 }
Ken Thompson87dae022008-06-24 14:11:20 -0700158 if(isptrto(nl->type, TMAP)) {
159 regalloc(&n1, types[tptr], res);
160 cgen(nl, &n1);
161 n1.op = OINDREG;
162 n1.type = types[TINT32];
163 gmove(&n1, res);
164 regfree(&n1);
165 break;
166 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700167 fatal("cgen: OLEN: unknown type %lT", nl->type);
168 break;
169
Rob Pike0cafb9e2008-06-04 14:37:38 -0700170 case OADDR:
171 agen(nl, res);
172 break;
173
174 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700175 cgen_callmeth(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700176 cgen_callret(n, res);
177 break;
178
179 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700180 cgen_callinter(n, res, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700181 cgen_callret(n, res);
182 break;
183
184 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700185 cgen_call(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700186 cgen_callret(n, res);
187 break;
Ken Thompsond83b9942008-06-06 20:43:29 -0700188
189 case OMOD:
190 case ODIV:
Ken Thompson6a659eb2008-06-09 13:16:50 -0700191 if(isfloat[n->type->etype]) {
192 a = optoas(n->op, nl->type);
193 goto abop;
194 }
Ken Thompsond83b9942008-06-06 20:43:29 -0700195 cgen_div(n->op, nl, nr, res);
196 break;
Ken Thompson610644a2008-06-08 17:21:46 -0700197
Ken Thompsonf7753f12008-06-07 15:21:02 -0700198 case OLSH:
199 case ORSH:
200 cgen_shift(n->op, nl, nr, res);
201 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700202 }
203 goto ret;
204
205sbop: // symmetric binary
206 if(nl->ullman < nr->ullman) {
207 r = nl;
208 nl = nr;
209 nr = r;
210 }
211
212abop: // asymmetric binary
Ken Thompsonf7753f12008-06-07 15:21:02 -0700213 if(nl->ullman >= nr->ullman) {
Rob Pike0cafb9e2008-06-04 14:37:38 -0700214 regalloc(&n1, nl->type, res);
215 cgen(nl, &n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700216 regalloc(&n2, nr->type, N);
217 cgen(nr, &n2);
218 } else {
219 regalloc(&n2, nr->type, N);
220 cgen(nr, &n2);
221 regalloc(&n1, nl->type, res);
222 cgen(nl, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700223 }
Ken Thompsonf7753f12008-06-07 15:21:02 -0700224 gins(a, &n2, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700225 gmove(&n1, res);
226 regfree(&n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700227 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700228 goto ret;
229
230uop: // unary
231 regalloc(&n1, nl->type, res);
232 cgen(nl, &n1);
233 gins(a, N, &n1);
234 gmove(&n1, res);
235 regfree(&n1);
236 goto ret;
237
238ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700239 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700240}
241
242void
243agen(Node *n, Node *res)
244{
245 Node *nl, *nr;
246 Node n1, n2, n3, tmp;
Russ Cox9aad9fe2008-08-03 17:25:15 -0700247 uint32 w;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700248 Type *t;
Ken Thompson54abac62008-06-21 15:11:29 -0700249
250 if(debug['g']) {
251 dump("\nagen-res", res);
252 dump("agen-r", n);
253 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700254 if(n == N || n->type == T)
255 return;
256
257 if(!isptr[res->type->etype])
258 fatal("agen: not tptr: %T", res->type);
259
260 if(n->addable) {
261 regalloc(&n1, types[tptr], res);
262 gins(ALEAQ, n, &n1);
263 gmove(&n1, res);
264 regfree(&n1);
Ken Thompson610644a2008-06-08 17:21:46 -0700265 goto ret;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700266 }
267
Ken Thompson610644a2008-06-08 17:21:46 -0700268 nl = n->left;
269 nr = n->right;
270
Rob Pike0cafb9e2008-06-04 14:37:38 -0700271 switch(n->op) {
272 default:
273 fatal("agen: unknown op %N", n);
274 break;
275
276// case ONAME:
277// regalloc(&n1, types[tptr], res);
278// gins(optoas(OADDR, types[tptr]), n, &n1);
279// gmove(&n1, res);
280// regfree(&n1);
281// break;
282
Ken Thompson54abac62008-06-21 15:11:29 -0700283 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700284 cgen_callmeth(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700285 cgen_aret(n, res);
286 break;
287
288 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700289 cgen_callinter(n, res, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700290 cgen_aret(n, res);
291 break;
292
293 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700294 cgen_call(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700295 cgen_aret(n, res);
296 break;
297
Rob Pike0cafb9e2008-06-04 14:37:38 -0700298 case OINDEXPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700299 w = n->type->width;
300 if(nr->addable)
301 goto iprad;
302 if(nl->addable) {
303 regalloc(&n1, nr->type, N);
304 cgen(nr, &n1);
305 cgen(nl, res);
306 goto index;
307 }
308 cgen(nr, res);
309 tempname(&tmp, nr->type);
310 gmove(res, &tmp);
311
312 iprad:
313 cgen(nl, res);
314 regalloc(&n1, nr->type, N);
315 cgen(nr, &n1);
316 goto index;
317
318 case OS2I:
319 case OI2I:
320 case OI2S:
321 agen_inter(n, res);
322 break;
323
324// case OINDREG:
325
326 case OINDEX:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700327 w = n->type->width;
328 if(nr->addable)
329 goto irad;
330 if(nl->addable) {
331 regalloc(&n1, nr->type, N);
332 cgen(nr, &n1);
333 agen(nl, res);
334 goto index;
335 }
336 cgen(nr, res);
337 tempname(&tmp, nr->type);
338 gmove(res, &tmp);
339
340 irad:
341 agen(nl, res);
342 regalloc(&n1, nr->type, N);
343 cgen(nr, &n1);
344 goto index;
345
346 index:
347 // &a is in res
348 // i is in &n1
349 // w is width
Ken Thompsonf7753f12008-06-07 15:21:02 -0700350 nodconst(&n3, types[TINT64], w); // w/tint64
351 if(issigned[n1.type->etype])
Rob Pike0cafb9e2008-06-04 14:37:38 -0700352 regalloc(&n2, types[TINT64], &n1); // i/int64
Ken Thompsonf7753f12008-06-07 15:21:02 -0700353 else
354 regalloc(&n2, types[TUINT64], &n1); // i/uint64
355 gmove(&n1, &n2);
356 gins(optoas(OMUL, types[TINT64]), &n3, &n2);
357 gins(optoas(OADD, types[tptr]), &n2, res);
358 regfree(&n1);
359 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700360 break;
361
Ken Thompsone1a06cc2008-06-15 20:24:30 -0700362 case OIND:
363 cgen(nl, res);
364 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700365
366 case ODOT:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700367 t = nl->type;
368 agen(nl, res);
369 if(n->xoffset != 0) {
370 nodconst(&n1, types[TINT64], n->xoffset);
371 gins(optoas(OADD, types[tptr]), &n1, res);
372 }
373 break;
374
375 case ODOTPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700376 t = nl->type;
377 if(!isptr[t->etype])
378 fatal("agen: not ptr %N", n);
379 cgen(nl, res);
380 if(n->xoffset != 0) {
381 nodconst(&n1, types[TINT64], n->xoffset);
382 gins(optoas(OADD, types[tptr]), &n1, res);
383 }
384 break;
385 }
Ken Thompson610644a2008-06-08 17:21:46 -0700386
387ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700388 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700389}
390
391vlong
392fieldoffset(Type *t, Node *n)
393{
394 if(t->etype != TSTRUCT)
395 fatal("fieldoffset: not struct %lT", t);
396 if(n->op != ONAME)
397 fatal("fieldoffset: not field name %N", n);
398 return 0;
399}
400
401void
402igen(Node *n, Node *a, Node *res)
403{
404 regalloc(a, types[tptr], res);
405 agen(n, a);
406 a->op = OINDREG;
407 a->type = n->type;
408}
409
410void
411bgen(Node *n, int true, Prog *to)
412{
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700413 int et, a;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700414 Node *nl, *nr, *r;
Ken Thompson610644a2008-06-08 17:21:46 -0700415 Node n1, n2, tmp;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700416 Prog *p1, *p2;
417
Ken Thompson54abac62008-06-21 15:11:29 -0700418 if(debug['g']) {
419 dump("\nbgen", n);
420 }
Ken Thompsond3237f92008-06-28 17:27:39 -0700421
Rob Pike0cafb9e2008-06-04 14:37:38 -0700422 if(n == N)
423 n = booltrue;
424
Ken Thompson610644a2008-06-08 17:21:46 -0700425 nl = n->left;
426 nr = n->right;
427
Rob Pike0cafb9e2008-06-04 14:37:38 -0700428 if(n->type == T) {
429 convlit(n, types[TBOOL]);
430 if(n->type == T)
431 goto ret;
432 }
433
434 et = n->type->etype;
435 if(et != TBOOL) {
436 yyerror("cgen: bad type %T for %O", n->type, n->op);
437 patch(gins(AEND, N, N), to);
438 goto ret;
439 }
440 nl = N;
441 nr = N;
442
443 switch(n->op) {
444 default:
445 regalloc(&n1, n->type, N);
446 cgen(n, &n1);
447 nodconst(&n2, n->type, 0);
448 gins(optoas(OCMP, n->type), &n1, &n2);
449 a = AJNE;
450 if(!true)
451 a = AJEQ;
452 patch(gbranch(a, n->type), to);
453 regfree(&n1);
454 goto ret;
455
456 case OLITERAL:
457 if(!true == !n->val.vval)
458 patch(gbranch(AJMP, T), to);
459 goto ret;
460
461 case ONAME:
462 nodconst(&n1, n->type, 0);
463 gins(optoas(OCMP, n->type), n, &n1);
464 a = AJNE;
465 if(!true)
466 a = AJEQ;
467 patch(gbranch(a, n->type), to);
468 goto ret;
469
470 case OANDAND:
471 if(!true)
472 goto caseor;
473
474 caseand:
475 p1 = gbranch(AJMP, T);
476 p2 = gbranch(AJMP, T);
477 patch(p1, pc);
478 bgen(n->left, !true, p2);
479 bgen(n->right, !true, p2);
480 p1 = gbranch(AJMP, T);
481 patch(p1, to);
482 patch(p2, pc);
483 goto ret;
484
485 case OOROR:
486 if(!true)
487 goto caseand;
488
489 caseor:
490 bgen(n->left, true, to);
491 bgen(n->right, true, to);
492 goto ret;
493
494 case OEQ:
495 case ONE:
496 case OLT:
497 case OGT:
498 case OLE:
499 case OGE:
500 nr = n->right;
501 if(nr == N || nr->type == T)
502 goto ret;
503
504 case ONOT: // unary
505 nl = n->left;
506 if(nl == N || nl->type == T)
507 goto ret;
508 }
509
510 switch(n->op) {
511
512 case ONOT:
513 bgen(nl, !true, to);
514 goto ret;
515
516 case OEQ:
517 case ONE:
518 case OLT:
519 case OGT:
520 case OLE:
521 case OGE:
522 a = n->op;
523 if(!true)
524 a = brcom(a);
525
526 // make simplest on right
527 if(nl->ullman < nr->ullman) {
528 a = brrev(a);
529 r = nl;
530 nl = nr;
531 nr = r;
532 }
Ken Thompson610644a2008-06-08 17:21:46 -0700533
Rob Pike0cafb9e2008-06-04 14:37:38 -0700534 a = optoas(a, nr->type);
535
Ken Thompson610644a2008-06-08 17:21:46 -0700536 if(nr->ullman >= UINF) {
537 regalloc(&n1, nr->type, N);
538 cgen(nr, &n1);
539
540 tempname(&tmp, nr->type);
541 gmove(&n1, &tmp);
542 regfree(&n1);
543
544 regalloc(&n1, nl->type, N);
545 cgen(nl, &n1);
546
547 regalloc(&n2, nr->type, &n2);
548 cgen(&tmp, &n2);
549
550 gins(optoas(OCMP, nr->type), &n1, &n2);
551 patch(gbranch(a, nr->type), to);
552
553 regfree(&n1);
554 regfree(&n2);
555 break;
556 }
557
558
Rob Pike0cafb9e2008-06-04 14:37:38 -0700559 regalloc(&n1, nl->type, N);
560 cgen(nl, &n1);
561
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700562 regalloc(&n2, nr->type, N);
563 cgen(nr, &n2);
564
565 gins(optoas(OCMP, nr->type), &n1, &n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700566 patch(gbranch(a, nr->type), to);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700567
Rob Pike0cafb9e2008-06-04 14:37:38 -0700568 regfree(&n1);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700569 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700570 break;
571 }
572 goto ret;
573
574ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700575 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700576}
577
578void
Russ Cox9aad9fe2008-08-03 17:25:15 -0700579sgen(Node *n, Node *ns, uint32 w)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700580{
581 Node nodl, nodr;
Russ Cox9aad9fe2008-08-03 17:25:15 -0700582 int32 c;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700583
Ken Thompson54abac62008-06-21 15:11:29 -0700584 if(debug['g']) {
585 dump("\nsgen-res", ns);
586 dump("sgen-r", n);
587 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700588 if(w == 0)
589 return;
590 if(n->ullman >= UINF && ns->ullman >= UINF) {
591 fatal("sgen UINF");
592 }
593
594 nodreg(&nodl, types[tptr], D_DI);
595 nodreg(&nodr, types[tptr], D_SI);
596
597 if(n->ullman >= ns->ullman) {
598 agen(n, &nodr);
599 agen(ns, &nodl);
600 } else {
601 agen(ns, &nodl);
602 agen(n, &nodr);
603 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700604 gins(ACLD, N, N); // clear direction flag
605
606 c = w / 8;
607 if(c > 0) {
608 gconreg(AMOVQ, c, D_CX);
609 gins(AREP, N, N); // repeat
610 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
611 }
612
613 c = w % 8;
614 if(c > 0) {
615 gconreg(AMOVQ, c, D_CX);
616 gins(AREP, N, N); // repeat
617 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
618 }
Ken Thompson75937c22008-06-26 17:54:44 -0700619
Rob Pike0cafb9e2008-06-04 14:37:38 -0700620}