blob: b8c49b4f928ff421a4eaa165966211bddf0e151d [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;
Ken Thompsonf7753f12008-06-07 15:21:02 -070012 Node n1, n2;
Rob Pike0cafb9e2008-06-04 14:37:38 -070013 int a;
14 Prog *p1, *p2, *p3;
15
16 if(debug['g']) {
Ken Thompson36bfd2a2008-06-08 16:11:14 -070017 dump("\ncgen-res", res);
Rob Pike0cafb9e2008-06-04 14:37:38 -070018 dump("cgen-r", n);
19 }
20 if(n == N || n->type == T)
21 return;
Ken Thompson78c8dec2008-06-24 10:30:33 -070022
Ken Thompson75937c22008-06-26 17:54:44 -070023 lno = setlineno(n);
Ken Thompson78c8dec2008-06-24 10:30:33 -070024
Rob Pike0cafb9e2008-06-04 14:37:38 -070025 if(res == N || res->type == T)
26 fatal("cgen: res nil");
27
Ken Thompson6b8bd352008-06-06 16:49:35 -070028 if(n->ullman >= UINF) {
29 if(n->op == OINDREG)
30 fatal("cgen: this is going to misscompile");
Ken Thompson78c8dec2008-06-24 10:30:33 -070031 if(res->ullman >= UINF) {
Ken Thompsonca029d32008-06-27 17:53:23 -070032 tempname(&n1, n->type);
33 cgen(n, &n1);
34 cgen(&n1, res);
35 goto ret;
Ken Thompson78c8dec2008-06-24 10:30:33 -070036 }
Ken Thompson6b8bd352008-06-06 16:49:35 -070037 }
38
Rob Pike0cafb9e2008-06-04 14:37:38 -070039 if(isfat(n->type)) {
40 sgen(n, res, n->type->width);
41 goto ret;
42 }
43
44 if(!res->addable) {
Ken Thompson6b8bd352008-06-06 16:49:35 -070045 if(n->ullman > res->ullman) {
Ken Thompsona93099c2008-06-06 17:01:33 -070046 regalloc(&n1, n->type, res);
Ken Thompson6b8bd352008-06-06 16:49:35 -070047 cgen(n, &n1);
48 cgen(&n1, res);
49 regfree(&n1);
Ken Thompsonca029d32008-06-27 17:53:23 -070050 goto ret;
Ken Thompson6b8bd352008-06-06 16:49:35 -070051 }
52
Rob Pike0cafb9e2008-06-04 14:37:38 -070053 igen(res, &n1, N);
54 cgen(n, &n1);
55 regfree(&n1);
56 goto ret;
57 }
58
59 if(n->addable) {
60 gmove(n, res);
61 goto ret;
62 }
63
64 nl = n->left;
65 nr = n->right;
66 if(nl != N && nl->ullman >= UINF)
67 if(nr != N && nr->ullman >= UINF) {
Ken Thompson390d5fe2008-06-27 16:59:14 -070068 tempname(&n1, nr->type);
69 cgen(nr, &n1);
70 n2 = *n;
71 n2.right = &n1;
72 cgen(&n2, res);
Rob Pike0cafb9e2008-06-04 14:37:38 -070073 goto ret;
74 }
75
76 switch(n->op) {
77 default:
78 dump("cgen", n);
79 fatal("cgen: unknown op %N", n);
80 break;
81
82 // these call bgen to get a bool value
83 case OOROR:
84 case OANDAND:
85 case OEQ:
86 case ONE:
87 case OLT:
88 case OLE:
89 case OGE:
90 case OGT:
91 case ONOT:
92 p1 = gbranch(AJMP, T);
93 p2 = pc;
94 gmove(booltrue, res);
95 p3 = gbranch(AJMP, T);
96 patch(p1, pc);
97 bgen(n, 1, p2);
98 gmove(boolfalse, res);
99 patch(p3, pc);
100 goto ret;
101
102 case OPLUS:
103 cgen(nl, res);
104 goto ret;
105
106 // unary
107 case OMINUS:
108 case OCOM:
109 a = optoas(n->op, nl->type);
110 goto uop;
111
112 // symmetric binary
113 case OAND:
114 case OOR:
115 case OXOR:
116 case OADD:
117 case OMUL:
118 a = optoas(n->op, nl->type);
119 goto sbop;
120
121 // asymmetric binary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700122 case OSUB:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700123 a = optoas(n->op, nl->type);
124 goto abop;
125
126 case OCONV:
127 if(eqtype(n->type, nl->type, 0)) {
128 cgen(nl, res);
129 break;
130 }
131 regalloc(&n1, nl->type, res);
132 cgen(nl, &n1);
133 gmove(&n1, res);
134 regfree(&n1);
135 break;
136
Rob Pike0cafb9e2008-06-04 14:37:38 -0700137 case OS2I:
138 case OI2I:
139 case OI2S:
140
141 case OINDEXPTR:
142 case OINDEX:
143 case ODOT:
144 case ODOTPTR:
145 case OIND:
146 igen(n, &n1, res);
147 gmove(&n1, res);
148 regfree(&n1);
149 break;
150
151 case OLEN:
152 if(isptrto(nl->type, TSTRING)) {
153 regalloc(&n1, types[tptr], res);
Ken Thompsonb6eca352008-06-08 17:46:28 -0700154 cgen(nl, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700155 n1.op = OINDREG;
156 n1.type = types[TINT32];
157 gmove(&n1, res);
158 regfree(&n1);
159 break;
160 }
Ken Thompson87dae022008-06-24 14:11:20 -0700161 if(isptrto(nl->type, TMAP)) {
162 regalloc(&n1, types[tptr], res);
163 cgen(nl, &n1);
164 n1.op = OINDREG;
165 n1.type = types[TINT32];
166 gmove(&n1, res);
167 regfree(&n1);
168 break;
169 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700170 fatal("cgen: OLEN: unknown type %lT", nl->type);
171 break;
172
Rob Pike0cafb9e2008-06-04 14:37:38 -0700173 case OADDR:
174 agen(nl, res);
175 break;
176
177 case OCALLMETH:
178 cgen_callmeth(n);
179 cgen_callret(n, res);
180 break;
181
182 case OCALLINTER:
183 cgen_callinter(n, res);
184 cgen_callret(n, res);
185 break;
186
187 case OCALL:
188 cgen_call(n);
189 cgen_callret(n, res);
190 break;
Ken Thompsond83b9942008-06-06 20:43:29 -0700191
192 case OMOD:
193 case ODIV:
Ken Thompson6a659eb2008-06-09 13:16:50 -0700194 if(isfloat[n->type->etype]) {
195 a = optoas(n->op, nl->type);
196 goto abop;
197 }
Ken Thompsond83b9942008-06-06 20:43:29 -0700198 cgen_div(n->op, nl, nr, res);
199 break;
Ken Thompson610644a2008-06-08 17:21:46 -0700200
Ken Thompsonf7753f12008-06-07 15:21:02 -0700201 case OLSH:
202 case ORSH:
203 cgen_shift(n->op, nl, nr, res);
204 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700205 }
206 goto ret;
207
208sbop: // symmetric binary
209 if(nl->ullman < nr->ullman) {
210 r = nl;
211 nl = nr;
212 nr = r;
213 }
214
215abop: // asymmetric binary
Ken Thompsonf7753f12008-06-07 15:21:02 -0700216 if(nl->ullman >= nr->ullman) {
Rob Pike0cafb9e2008-06-04 14:37:38 -0700217 regalloc(&n1, nl->type, res);
218 cgen(nl, &n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700219 regalloc(&n2, nr->type, N);
220 cgen(nr, &n2);
221 } else {
222 regalloc(&n2, nr->type, N);
223 cgen(nr, &n2);
224 regalloc(&n1, nl->type, res);
225 cgen(nl, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700226 }
Ken Thompsonf7753f12008-06-07 15:21:02 -0700227 gins(a, &n2, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700228 gmove(&n1, res);
229 regfree(&n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700230 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700231 goto ret;
232
233uop: // unary
234 regalloc(&n1, nl->type, res);
235 cgen(nl, &n1);
236 gins(a, N, &n1);
237 gmove(&n1, res);
238 regfree(&n1);
239 goto ret;
240
241ret:
Ken Thompson75937c22008-06-26 17:54:44 -0700242 lineno = lno;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700243}
244
245void
246agen(Node *n, Node *res)
247{
248 Node *nl, *nr;
249 Node n1, n2, n3, tmp;
Ken Thompson75937c22008-06-26 17:54:44 -0700250 ulong w;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700251 Type *t;
Ken Thompson75937c22008-06-26 17:54:44 -0700252 long lno;
Ken Thompson54abac62008-06-21 15:11:29 -0700253
254 if(debug['g']) {
255 dump("\nagen-res", res);
256 dump("agen-r", n);
257 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700258 if(n == N || n->type == T)
259 return;
260
Ken Thompson75937c22008-06-26 17:54:44 -0700261 lno = setlineno(n);
262
Rob Pike0cafb9e2008-06-04 14:37:38 -0700263 if(!isptr[res->type->etype])
264 fatal("agen: not tptr: %T", res->type);
265
266 if(n->addable) {
267 regalloc(&n1, types[tptr], res);
268 gins(ALEAQ, n, &n1);
269 gmove(&n1, res);
270 regfree(&n1);
Ken Thompson610644a2008-06-08 17:21:46 -0700271 goto ret;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700272 }
273
Ken Thompson610644a2008-06-08 17:21:46 -0700274 nl = n->left;
275 nr = n->right;
276
Rob Pike0cafb9e2008-06-04 14:37:38 -0700277 switch(n->op) {
278 default:
279 fatal("agen: unknown op %N", n);
280 break;
281
282// case ONAME:
283// regalloc(&n1, types[tptr], res);
284// gins(optoas(OADDR, types[tptr]), n, &n1);
285// gmove(&n1, res);
286// regfree(&n1);
287// break;
288
Ken Thompson54abac62008-06-21 15:11:29 -0700289 case OCALLMETH:
290 cgen_callmeth(n);
291 cgen_aret(n, res);
292 break;
293
294 case OCALLINTER:
295 cgen_callinter(n, res);
296 cgen_aret(n, res);
297 break;
298
299 case OCALL:
300 cgen_call(n);
301 cgen_aret(n, res);
302 break;
303
Rob Pike0cafb9e2008-06-04 14:37:38 -0700304 case OINDEXPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700305 w = n->type->width;
306 if(nr->addable)
307 goto iprad;
308 if(nl->addable) {
309 regalloc(&n1, nr->type, N);
310 cgen(nr, &n1);
311 cgen(nl, res);
312 goto index;
313 }
314 cgen(nr, res);
315 tempname(&tmp, nr->type);
316 gmove(res, &tmp);
317
318 iprad:
319 cgen(nl, res);
320 regalloc(&n1, nr->type, N);
321 cgen(nr, &n1);
322 goto index;
323
324 case OS2I:
325 case OI2I:
326 case OI2S:
327 agen_inter(n, res);
328 break;
329
330// case OINDREG:
331
332 case OINDEX:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700333 w = n->type->width;
334 if(nr->addable)
335 goto irad;
336 if(nl->addable) {
337 regalloc(&n1, nr->type, N);
338 cgen(nr, &n1);
339 agen(nl, res);
340 goto index;
341 }
342 cgen(nr, res);
343 tempname(&tmp, nr->type);
344 gmove(res, &tmp);
345
346 irad:
347 agen(nl, res);
348 regalloc(&n1, nr->type, N);
349 cgen(nr, &n1);
350 goto index;
351
352 index:
353 // &a is in res
354 // i is in &n1
355 // w is width
Ken Thompsonf7753f12008-06-07 15:21:02 -0700356 nodconst(&n3, types[TINT64], w); // w/tint64
357 if(issigned[n1.type->etype])
Rob Pike0cafb9e2008-06-04 14:37:38 -0700358 regalloc(&n2, types[TINT64], &n1); // i/int64
Ken Thompsonf7753f12008-06-07 15:21:02 -0700359 else
360 regalloc(&n2, types[TUINT64], &n1); // i/uint64
361 gmove(&n1, &n2);
362 gins(optoas(OMUL, types[TINT64]), &n3, &n2);
363 gins(optoas(OADD, types[tptr]), &n2, res);
364 regfree(&n1);
365 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700366 break;
367
Ken Thompsone1a06cc2008-06-15 20:24:30 -0700368 case OIND:
369 cgen(nl, res);
370 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700371
372 case ODOT:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700373 t = nl->type;
374 agen(nl, res);
375 if(n->xoffset != 0) {
376 nodconst(&n1, types[TINT64], n->xoffset);
377 gins(optoas(OADD, types[tptr]), &n1, res);
378 }
379 break;
380
381 case ODOTPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700382 t = nl->type;
383 if(!isptr[t->etype])
384 fatal("agen: not ptr %N", n);
385 cgen(nl, res);
386 if(n->xoffset != 0) {
387 nodconst(&n1, types[TINT64], n->xoffset);
388 gins(optoas(OADD, types[tptr]), &n1, res);
389 }
390 break;
391 }
Ken Thompson610644a2008-06-08 17:21:46 -0700392
393ret:
Ken Thompson75937c22008-06-26 17:54:44 -0700394 lineno = lno;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700395}
396
397vlong
398fieldoffset(Type *t, Node *n)
399{
400 if(t->etype != TSTRUCT)
401 fatal("fieldoffset: not struct %lT", t);
402 if(n->op != ONAME)
403 fatal("fieldoffset: not field name %N", n);
404 return 0;
405}
406
407void
408igen(Node *n, Node *a, Node *res)
409{
410 regalloc(a, types[tptr], res);
411 agen(n, a);
412 a->op = OINDREG;
413 a->type = n->type;
414}
415
416void
417bgen(Node *n, int true, Prog *to)
418{
419 long lno;
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700420 int et, a;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700421 Node *nl, *nr, *r;
Ken Thompson610644a2008-06-08 17:21:46 -0700422 Node n1, n2, tmp;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700423 Prog *p1, *p2;
424
Ken Thompson54abac62008-06-21 15:11:29 -0700425 if(debug['g']) {
426 dump("\nbgen", n);
427 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700428 if(n == N)
429 n = booltrue;
430
Ken Thompson75937c22008-06-26 17:54:44 -0700431 lno = setlineno(n);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700432
Ken Thompson610644a2008-06-08 17:21:46 -0700433 nl = n->left;
434 nr = n->right;
435
Rob Pike0cafb9e2008-06-04 14:37:38 -0700436 if(n->type == T) {
437 convlit(n, types[TBOOL]);
438 if(n->type == T)
439 goto ret;
440 }
441
442 et = n->type->etype;
443 if(et != TBOOL) {
444 yyerror("cgen: bad type %T for %O", n->type, n->op);
445 patch(gins(AEND, N, N), to);
446 goto ret;
447 }
448 nl = N;
449 nr = N;
450
451 switch(n->op) {
452 default:
453 regalloc(&n1, n->type, N);
454 cgen(n, &n1);
455 nodconst(&n2, n->type, 0);
456 gins(optoas(OCMP, n->type), &n1, &n2);
457 a = AJNE;
458 if(!true)
459 a = AJEQ;
460 patch(gbranch(a, n->type), to);
461 regfree(&n1);
462 goto ret;
463
464 case OLITERAL:
465 if(!true == !n->val.vval)
466 patch(gbranch(AJMP, T), to);
467 goto ret;
468
469 case ONAME:
470 nodconst(&n1, n->type, 0);
471 gins(optoas(OCMP, n->type), n, &n1);
472 a = AJNE;
473 if(!true)
474 a = AJEQ;
475 patch(gbranch(a, n->type), to);
476 goto ret;
477
478 case OANDAND:
479 if(!true)
480 goto caseor;
481
482 caseand:
483 p1 = gbranch(AJMP, T);
484 p2 = gbranch(AJMP, T);
485 patch(p1, pc);
486 bgen(n->left, !true, p2);
487 bgen(n->right, !true, p2);
488 p1 = gbranch(AJMP, T);
489 patch(p1, to);
490 patch(p2, pc);
491 goto ret;
492
493 case OOROR:
494 if(!true)
495 goto caseand;
496
497 caseor:
498 bgen(n->left, true, to);
499 bgen(n->right, true, to);
500 goto ret;
501
502 case OEQ:
503 case ONE:
504 case OLT:
505 case OGT:
506 case OLE:
507 case OGE:
508 nr = n->right;
509 if(nr == N || nr->type == T)
510 goto ret;
511
512 case ONOT: // unary
513 nl = n->left;
514 if(nl == N || nl->type == T)
515 goto ret;
516 }
517
518 switch(n->op) {
519
520 case ONOT:
521 bgen(nl, !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 a = n->op;
531 if(!true)
532 a = brcom(a);
533
534 // make simplest on right
535 if(nl->ullman < nr->ullman) {
536 a = brrev(a);
537 r = nl;
538 nl = nr;
539 nr = r;
540 }
Ken Thompson610644a2008-06-08 17:21:46 -0700541
Rob Pike0cafb9e2008-06-04 14:37:38 -0700542 a = optoas(a, nr->type);
543
Ken Thompson610644a2008-06-08 17:21:46 -0700544 if(nr->ullman >= UINF) {
545 regalloc(&n1, nr->type, N);
546 cgen(nr, &n1);
547
548 tempname(&tmp, nr->type);
549 gmove(&n1, &tmp);
550 regfree(&n1);
551
552 regalloc(&n1, nl->type, N);
553 cgen(nl, &n1);
554
555 regalloc(&n2, nr->type, &n2);
556 cgen(&tmp, &n2);
557
558 gins(optoas(OCMP, nr->type), &n1, &n2);
559 patch(gbranch(a, nr->type), to);
560
561 regfree(&n1);
562 regfree(&n2);
563 break;
564 }
565
566
Rob Pike0cafb9e2008-06-04 14:37:38 -0700567 regalloc(&n1, nl->type, N);
568 cgen(nl, &n1);
569
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700570 regalloc(&n2, nr->type, N);
571 cgen(nr, &n2);
572
573 gins(optoas(OCMP, nr->type), &n1, &n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700574 patch(gbranch(a, nr->type), to);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700575
Rob Pike0cafb9e2008-06-04 14:37:38 -0700576 regfree(&n1);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700577 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700578 break;
579 }
580 goto ret;
581
582ret:
Ken Thompson75937c22008-06-26 17:54:44 -0700583 lineno = lno;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700584}
585
586void
587sgen(Node *n, Node *ns, ulong w)
588{
589 Node nodl, nodr;
Ken Thompson75937c22008-06-26 17:54:44 -0700590 long c, lno;
591
592 lno = setlineno(n);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700593
Ken Thompson54abac62008-06-21 15:11:29 -0700594 if(debug['g']) {
595 dump("\nsgen-res", ns);
596 dump("sgen-r", n);
597 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700598 if(w == 0)
599 return;
600 if(n->ullman >= UINF && ns->ullman >= UINF) {
601 fatal("sgen UINF");
602 }
603
604 nodreg(&nodl, types[tptr], D_DI);
605 nodreg(&nodr, types[tptr], D_SI);
606
607 if(n->ullman >= ns->ullman) {
608 agen(n, &nodr);
609 agen(ns, &nodl);
610 } else {
611 agen(ns, &nodl);
612 agen(n, &nodr);
613 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700614 gins(ACLD, N, N); // clear direction flag
615
616 c = w / 8;
617 if(c > 0) {
618 gconreg(AMOVQ, c, D_CX);
619 gins(AREP, N, N); // repeat
620 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
621 }
622
623 c = w % 8;
624 if(c > 0) {
625 gconreg(AMOVQ, c, D_CX);
626 gins(AREP, N, N); // repeat
627 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
628 }
Ken Thompson75937c22008-06-26 17:54:44 -0700629
630 lineno = lno;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700631}