blob: de54756de8b2ac7612414421c227c93d16f27ecf [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
Rob Pike0cafb9e2008-06-04 14:37:38 -0700104 case OCOM:
Ken Thompsonb89c5382008-08-10 14:35:02 -0700105 a = optoas(OXOR, nl->type);
106 regalloc(&n1, nl->type, N);
107 cgen(nl, &n1);
108 nodconst(&n2, nl->type, -1);
109 gins(a, &n2, &n1);
110 gmove(&n1, res);
111 regfree(&n1);
112 goto ret;
113
114 case OMINUS:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700115 a = optoas(n->op, nl->type);
116 goto uop;
117
118 // symmetric binary
119 case OAND:
120 case OOR:
121 case OXOR:
122 case OADD:
123 case OMUL:
124 a = optoas(n->op, nl->type);
Ken Thompsondc78c642008-11-07 14:20:32 -0800125 if(a != AIMULB)
126 goto sbop;
127 cgen_bmul(n->op, nl, nr, res);
128 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700129
130 // asymmetric binary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700131 case OSUB:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700132 a = optoas(n->op, nl->type);
133 goto abop;
134
135 case OCONV:
136 if(eqtype(n->type, nl->type, 0)) {
137 cgen(nl, res);
138 break;
139 }
140 regalloc(&n1, nl->type, res);
141 cgen(nl, &n1);
Ken Thompsonc6130e92008-08-28 15:17:37 -0700142 if(isptrarray(n->type) && isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700143 // convert dynamic array to static array
144 n2 = n1;
145 n2.op = OINDREG;
146 n2.xoffset = offsetof(Array,array);
147 n2.type = types[tptr];
148 gins(AMOVQ, &n2, &n1);
149 }
Ken Thompsonc6130e92008-08-28 15:17:37 -0700150 if(isptrdarray(n->type) && isptrarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700151 // conver static array to dynamic array
152 // it is assumed that the dope is just before the array
153 nodconst(&n2, types[tptr], offsetof(Array,b));
154 gins(ASUBQ, &n2, &n1);
155 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700156 gmove(&n1, res);
157 regfree(&n1);
158 break;
159
Rob Pike0cafb9e2008-06-04 14:37:38 -0700160 case OINDEXPTR:
161 case OINDEX:
162 case ODOT:
163 case ODOTPTR:
164 case OIND:
165 igen(n, &n1, res);
166 gmove(&n1, res);
167 regfree(&n1);
168 break;
169
170 case OLEN:
171 if(isptrto(nl->type, TSTRING)) {
172 regalloc(&n1, types[tptr], res);
Ken Thompsonb6eca352008-06-08 17:46:28 -0700173 cgen(nl, &n1);
Ken Thompson193eac72008-09-04 17:15:15 -0700174
175 nodconst(&n2, types[tptr], 0);
176 gins(optoas(OCMP, types[tptr]), &n1, &n2);
177 p1 = gbranch(optoas(OEQ, types[tptr]), T);
178
Ken Thompsone081f252008-11-22 17:58:53 -0800179 n2 = n1;
180 n2.op = OINDREG;
181 n2.type = types[TINT32];
182 gmove(&n2, &n1);
Ken Thompson193eac72008-09-04 17:15:15 -0700183
184 patch(p1, pc);
185
Ken Thompsone081f252008-11-22 17:58:53 -0800186 gmove(&n1, res);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700187 regfree(&n1);
188 break;
189 }
Ken Thompson87dae022008-06-24 14:11:20 -0700190 if(isptrto(nl->type, TMAP)) {
191 regalloc(&n1, types[tptr], res);
192 cgen(nl, &n1);
193 n1.op = OINDREG;
194 n1.type = types[TINT32];
195 gmove(&n1, res);
196 regfree(&n1);
197 break;
198 }
Ken Thompsonc6130e92008-08-28 15:17:37 -0700199 if(isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700200 regalloc(&n1, types[tptr], res);
201 cgen(nl, &n1);
202 n1.op = OINDREG;
203 n1.type = types[TUINT32];
204 n1.xoffset = offsetof(Array,nel);
205 gmove(&n1, res);
206 regfree(&n1);
207 break;
208 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700209 fatal("cgen: OLEN: unknown type %lT", nl->type);
210 break;
211
Ken Thompson66a603c2008-08-27 17:28:30 -0700212 case OCAP:
Ken Thompsonc6130e92008-08-28 15:17:37 -0700213 if(isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700214 regalloc(&n1, types[tptr], res);
215 cgen(nl, &n1);
216 n1.op = OINDREG;
217 n1.type = types[TUINT32];
218 n1.xoffset = offsetof(Array,cap);
219 gmove(&n1, res);
220 regfree(&n1);
221 break;
222 }
223 fatal("cgen: OCAP: unknown type %lT", nl->type);
224 break;
225
Rob Pike0cafb9e2008-06-04 14:37:38 -0700226 case OADDR:
227 agen(nl, res);
228 break;
229
230 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700231 cgen_callmeth(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700232 cgen_callret(n, res);
233 break;
234
235 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700236 cgen_callinter(n, res, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700237 cgen_callret(n, res);
238 break;
239
240 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700241 cgen_call(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700242 cgen_callret(n, res);
243 break;
Ken Thompsond83b9942008-06-06 20:43:29 -0700244
245 case OMOD:
246 case ODIV:
Ken Thompson6a659eb2008-06-09 13:16:50 -0700247 if(isfloat[n->type->etype]) {
248 a = optoas(n->op, nl->type);
249 goto abop;
250 }
Ken Thompsond83b9942008-06-06 20:43:29 -0700251 cgen_div(n->op, nl, nr, res);
252 break;
Ken Thompson610644a2008-06-08 17:21:46 -0700253
Ken Thompsonf7753f12008-06-07 15:21:02 -0700254 case OLSH:
255 case ORSH:
256 cgen_shift(n->op, nl, nr, res);
257 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700258 }
259 goto ret;
260
261sbop: // symmetric binary
262 if(nl->ullman < nr->ullman) {
263 r = nl;
264 nl = nr;
265 nr = r;
266 }
267
268abop: // asymmetric binary
Ken Thompsonf7753f12008-06-07 15:21:02 -0700269 if(nl->ullman >= nr->ullman) {
Rob Pike0cafb9e2008-06-04 14:37:38 -0700270 regalloc(&n1, nl->type, res);
271 cgen(nl, &n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700272 regalloc(&n2, nr->type, N);
273 cgen(nr, &n2);
274 } else {
275 regalloc(&n2, nr->type, N);
276 cgen(nr, &n2);
277 regalloc(&n1, nl->type, res);
278 cgen(nl, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700279 }
Ken Thompsonf7753f12008-06-07 15:21:02 -0700280 gins(a, &n2, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700281 gmove(&n1, res);
282 regfree(&n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700283 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700284 goto ret;
285
286uop: // unary
287 regalloc(&n1, nl->type, res);
288 cgen(nl, &n1);
289 gins(a, N, &n1);
290 gmove(&n1, res);
291 regfree(&n1);
292 goto ret;
293
294ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700295 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700296}
297
298void
299agen(Node *n, Node *res)
300{
301 Node *nl, *nr;
302 Node n1, n2, n3, tmp;
Ken Thompson66a603c2008-08-27 17:28:30 -0700303 Prog *p1;
Russ Cox9aad9fe2008-08-03 17:25:15 -0700304 uint32 w;
Ken Thompson904d4042008-09-12 16:48:35 -0700305 uint64 v;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700306 Type *t;
Ken Thompson54abac62008-06-21 15:11:29 -0700307
308 if(debug['g']) {
309 dump("\nagen-res", res);
310 dump("agen-r", n);
311 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700312 if(n == N || n->type == T)
313 return;
314
315 if(!isptr[res->type->etype])
316 fatal("agen: not tptr: %T", res->type);
317
318 if(n->addable) {
319 regalloc(&n1, types[tptr], res);
320 gins(ALEAQ, n, &n1);
321 gmove(&n1, res);
322 regfree(&n1);
Ken Thompson610644a2008-06-08 17:21:46 -0700323 goto ret;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700324 }
325
Ken Thompson610644a2008-06-08 17:21:46 -0700326 nl = n->left;
327 nr = n->right;
328
Rob Pike0cafb9e2008-06-04 14:37:38 -0700329 switch(n->op) {
330 default:
331 fatal("agen: unknown op %N", n);
332 break;
333
Ken Thompson54abac62008-06-21 15:11:29 -0700334 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700335 cgen_callmeth(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700336 cgen_aret(n, res);
337 break;
338
339 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700340 cgen_callinter(n, res, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700341 cgen_aret(n, res);
342 break;
343
344 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700345 cgen_call(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700346 cgen_aret(n, res);
347 break;
348
Rob Pike0cafb9e2008-06-04 14:37:38 -0700349 case OINDEXPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700350 w = n->type->width;
351 if(nr->addable)
352 goto iprad;
353 if(nl->addable) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800354 if(whatis(nr) != Wlitint) {
355 regalloc(&n1, nr->type, N);
356 cgen(nr, &n1);
357 }
358 regalloc(&n3, types[tptr], res);
359 cgen(nl, &n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700360 goto index;
361 }
362 cgen(nr, res);
363 tempname(&tmp, nr->type);
364 gmove(res, &tmp);
365
366 iprad:
Ken Thompsona6182da2008-11-23 17:26:49 -0800367 regalloc(&n3, types[tptr], res);
368 cgen(nl, &n3);
369 if(whatis(nr) != Wlitint) {
370 regalloc(&n1, nr->type, N);
371 cgen(nr, &n1);
372 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700373 goto index;
374
Rob Pike0cafb9e2008-06-04 14:37:38 -0700375 case OINDEX:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700376 w = n->type->width;
377 if(nr->addable)
378 goto irad;
379 if(nl->addable) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800380 if(whatis(nr) != Wlitint) {
381 regalloc(&n1, nr->type, N);
382 cgen(nr, &n1);
383 }
384 regalloc(&n3, types[tptr], res);
385 agen(nl, &n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700386 goto index;
387 }
388 cgen(nr, res);
389 tempname(&tmp, nr->type);
390 gmove(res, &tmp);
391
392 irad:
Ken Thompsona6182da2008-11-23 17:26:49 -0800393 regalloc(&n3, types[tptr], res);
394 agen(nl, &n3);
395 if(whatis(nr) != Wlitint) {
396 regalloc(&n1, nr->type, N);
397 cgen(nr, &n1);
398 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700399 goto index;
400
401 index:
Ken Thompsona6182da2008-11-23 17:26:49 -0800402 // &a is in &n3 (allocated in res)
403 // i is in &n1 (if not constant)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700404 // w is width
Ken Thompson66a603c2008-08-27 17:28:30 -0700405
Ken Thompson85457002008-09-26 17:41:23 -0700406 if(w == 0)
407 fatal("index is zero width");
408
Ken Thompson8e3fe102008-11-24 14:01:12 -0800409 // constant index
Ken Thompson904d4042008-09-12 16:48:35 -0700410 if(whatis(nr) == Wlitint) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800411 v = mpgetfix(nr->val.u.xval);
Ken Thompsona6182da2008-11-23 17:26:49 -0800412 if(isptrdarray(nl->type)) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800413
414 if(!debug['B']) {
415 n1 = n3;
416 n1.op = OINDREG;
417 n1.type = types[tptr];
418 n1.xoffset = offsetof(Array, nel);
419 nodconst(&n2, types[TUINT64], v);
420 gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
421 p1 = gbranch(optoas(OGT, types[TUINT32]), T);
422 gins(ACALL, N, throwindex);
423 patch(p1, pc);
424 }
425
Ken Thompsona6182da2008-11-23 17:26:49 -0800426 n1 = n3;
427 n1.op = OINDREG;
428 n1.type = types[tptr];
429 n1.xoffset = offsetof(Array, array);
430 gmove(&n1, &n3);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800431 } else
432 if(!debug['B']) {
433 if(v < 0)
434 yyerror("out of bounds on array");
435 else
436 if(isptrarray(nl->type)) {
437 if(v >= nl->type->type->bound)
438 yyerror("out of bounds on array");
439 } else
440 if(v >= nl->type->bound)
441 yyerror("out of bounds on array");
Ken Thompsona6182da2008-11-23 17:26:49 -0800442 }
Ken Thompson8e3fe102008-11-24 14:01:12 -0800443
Ken Thompson904d4042008-09-12 16:48:35 -0700444 nodconst(&n2, types[tptr], v*w);
Ken Thompsona6182da2008-11-23 17:26:49 -0800445 gins(optoas(OADD, types[tptr]), &n2, &n3);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800446
Ken Thompsona6182da2008-11-23 17:26:49 -0800447 gmove(&n3, res);
448 regfree(&n3);
Ken Thompson904d4042008-09-12 16:48:35 -0700449 break;
450 }
451
Ken Thompsona6182da2008-11-23 17:26:49 -0800452 // type of the index
Ken Thompson66a603c2008-08-27 17:28:30 -0700453 t = types[TUINT64];
Ken Thompsonf7753f12008-06-07 15:21:02 -0700454 if(issigned[n1.type->etype])
Ken Thompson66a603c2008-08-27 17:28:30 -0700455 t = types[TINT64];
456
457 regalloc(&n2, t, &n1); // i
Ken Thompsonf7753f12008-06-07 15:21:02 -0700458 gmove(&n1, &n2);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700459 regfree(&n1);
Ken Thompson66a603c2008-08-27 17:28:30 -0700460
Ken Thompsona6182da2008-11-23 17:26:49 -0800461 if(!debug['B']) {
462 // check bounds
463 if(isptrdarray(nl->type)) {
464 n1 = n3;
465 n1.op = OINDREG;
466 n1.type = types[tptr];
467 n1.xoffset = offsetof(Array, nel);
468 } else {
469 nodconst(&n1, types[TUINT64], nl->type->bound);
470 if(isptrarray(nl->type))
471 nodconst(&n1, types[TUINT64], nl->type->type->bound);
472 }
Ken Thompson8e3fe102008-11-24 14:01:12 -0800473 gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
474 p1 = gbranch(optoas(OLT, types[TUINT32]), T);
Ken Thompsona6182da2008-11-23 17:26:49 -0800475 gins(ACALL, N, throwindex);
476 patch(p1, pc);
477 }
478
479 if(w != 1) {
480 nodconst(&n1, t, w); // w
481 gins(optoas(OMUL, t), &n1, &n2);
482 }
483
484 if(isptrdarray(nl->type)) {
485 n1 = n3;
486 n1.op = OINDREG;
487 n1.type = types[tptr];
488 n1.xoffset = offsetof(Array, array);
489 gmove(&n1, &n3);
490 }
491 gins(optoas(OADD, types[tptr]), &n2, &n3);
492 gmove(&n3, res);
493
Ken Thompsonf7753f12008-06-07 15:21:02 -0700494 regfree(&n2);
Ken Thompsona6182da2008-11-23 17:26:49 -0800495 regfree(&n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700496 break;
497
Ken Thompsone1a06cc2008-06-15 20:24:30 -0700498 case OIND:
499 cgen(nl, res);
500 break;
Russ Cox74e2e082008-10-06 16:44:17 -0700501
Rob Pike0cafb9e2008-06-04 14:37:38 -0700502 case ODOT:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700503 t = nl->type;
504 agen(nl, res);
505 if(n->xoffset != 0) {
506 nodconst(&n1, types[TINT64], n->xoffset);
507 gins(optoas(OADD, types[tptr]), &n1, res);
508 }
509 break;
510
511 case ODOTPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700512 t = nl->type;
513 if(!isptr[t->etype])
514 fatal("agen: not ptr %N", n);
515 cgen(nl, res);
516 if(n->xoffset != 0) {
517 nodconst(&n1, types[TINT64], n->xoffset);
518 gins(optoas(OADD, types[tptr]), &n1, res);
519 }
520 break;
521 }
Ken Thompson610644a2008-06-08 17:21:46 -0700522
523ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700524 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700525}
526
527vlong
528fieldoffset(Type *t, Node *n)
529{
530 if(t->etype != TSTRUCT)
531 fatal("fieldoffset: not struct %lT", t);
532 if(n->op != ONAME)
533 fatal("fieldoffset: not field name %N", n);
534 return 0;
535}
536
537void
538igen(Node *n, Node *a, Node *res)
539{
540 regalloc(a, types[tptr], res);
541 agen(n, a);
542 a->op = OINDREG;
543 a->type = n->type;
544}
545
546void
547bgen(Node *n, int true, Prog *to)
548{
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700549 int et, a;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700550 Node *nl, *nr, *r;
Ken Thompson610644a2008-06-08 17:21:46 -0700551 Node n1, n2, tmp;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700552 Prog *p1, *p2;
553
Ken Thompson54abac62008-06-21 15:11:29 -0700554 if(debug['g']) {
555 dump("\nbgen", n);
556 }
Ken Thompsond3237f92008-06-28 17:27:39 -0700557
Rob Pike0cafb9e2008-06-04 14:37:38 -0700558 if(n == N)
559 n = booltrue;
560
Ken Thompson610644a2008-06-08 17:21:46 -0700561 nl = n->left;
562 nr = n->right;
563
Rob Pike0cafb9e2008-06-04 14:37:38 -0700564 if(n->type == T) {
565 convlit(n, types[TBOOL]);
566 if(n->type == T)
567 goto ret;
568 }
569
570 et = n->type->etype;
571 if(et != TBOOL) {
572 yyerror("cgen: bad type %T for %O", n->type, n->op);
573 patch(gins(AEND, N, N), to);
574 goto ret;
575 }
576 nl = N;
577 nr = N;
578
579 switch(n->op) {
580 default:
581 regalloc(&n1, n->type, N);
582 cgen(n, &n1);
583 nodconst(&n2, n->type, 0);
584 gins(optoas(OCMP, n->type), &n1, &n2);
585 a = AJNE;
586 if(!true)
587 a = AJEQ;
588 patch(gbranch(a, n->type), to);
589 regfree(&n1);
590 goto ret;
591
592 case OLITERAL:
Ken Thompson9c2ade32008-08-08 17:13:31 -0700593// need to ask if it is bool?
594 if(!true == !n->val.u.bval)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700595 patch(gbranch(AJMP, T), to);
596 goto ret;
597
598 case ONAME:
599 nodconst(&n1, n->type, 0);
600 gins(optoas(OCMP, n->type), n, &n1);
601 a = AJNE;
602 if(!true)
603 a = AJEQ;
604 patch(gbranch(a, n->type), to);
605 goto ret;
606
607 case OANDAND:
608 if(!true)
609 goto caseor;
610
611 caseand:
612 p1 = gbranch(AJMP, T);
613 p2 = gbranch(AJMP, T);
614 patch(p1, pc);
615 bgen(n->left, !true, p2);
616 bgen(n->right, !true, p2);
617 p1 = gbranch(AJMP, T);
618 patch(p1, to);
619 patch(p2, pc);
620 goto ret;
621
622 case OOROR:
623 if(!true)
624 goto caseand;
625
626 caseor:
627 bgen(n->left, true, to);
628 bgen(n->right, true, to);
629 goto ret;
630
631 case OEQ:
632 case ONE:
633 case OLT:
634 case OGT:
635 case OLE:
636 case OGE:
637 nr = n->right;
638 if(nr == N || nr->type == T)
639 goto ret;
640
641 case ONOT: // unary
642 nl = n->left;
643 if(nl == N || nl->type == T)
644 goto ret;
645 }
646
647 switch(n->op) {
648
649 case ONOT:
650 bgen(nl, !true, to);
651 goto ret;
652
653 case OEQ:
654 case ONE:
655 case OLT:
656 case OGT:
657 case OLE:
658 case OGE:
659 a = n->op;
660 if(!true)
661 a = brcom(a);
662
663 // make simplest on right
664 if(nl->ullman < nr->ullman) {
665 a = brrev(a);
666 r = nl;
667 nl = nr;
668 nr = r;
669 }
Ken Thompson610644a2008-06-08 17:21:46 -0700670
Rob Pike0cafb9e2008-06-04 14:37:38 -0700671 a = optoas(a, nr->type);
672
Ken Thompson610644a2008-06-08 17:21:46 -0700673 if(nr->ullman >= UINF) {
674 regalloc(&n1, nr->type, N);
675 cgen(nr, &n1);
676
677 tempname(&tmp, nr->type);
678 gmove(&n1, &tmp);
679 regfree(&n1);
Russ Cox74e2e082008-10-06 16:44:17 -0700680
Ken Thompson610644a2008-06-08 17:21:46 -0700681 regalloc(&n1, nl->type, N);
682 cgen(nl, &n1);
683
684 regalloc(&n2, nr->type, &n2);
685 cgen(&tmp, &n2);
686
687 gins(optoas(OCMP, nr->type), &n1, &n2);
688 patch(gbranch(a, nr->type), to);
689
690 regfree(&n1);
691 regfree(&n2);
692 break;
693 }
694
695
Rob Pike0cafb9e2008-06-04 14:37:38 -0700696 regalloc(&n1, nl->type, N);
697 cgen(nl, &n1);
698
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700699 regalloc(&n2, nr->type, N);
700 cgen(nr, &n2);
701
702 gins(optoas(OCMP, nr->type), &n1, &n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700703 patch(gbranch(a, nr->type), to);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700704
Rob Pike0cafb9e2008-06-04 14:37:38 -0700705 regfree(&n1);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700706 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700707 break;
708 }
709 goto ret;
710
711ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700712 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700713}
714
Ken Thompson30fd44c2008-08-21 20:49:04 -0700715int32
716stkof(Node *n)
717{
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700718 Type *t;
719 Iter flist;
720
Ken Thompson30fd44c2008-08-21 20:49:04 -0700721 switch(n->op) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700722 case OINDREG:
723 return n->xoffset;
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700724
725 case OCALLMETH:
726 case OCALLINTER:
727 case OCALL:
728 t = n->left->type;
729 if(isptr[t->etype])
730 t = t->type;
731
732 t = structfirst(&flist, getoutarg(t));
733 if(t != T)
734 return t->width;
735 break;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700736 }
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700737
Ken Thompson30fd44c2008-08-21 20:49:04 -0700738 // botch - probably failing to recognize address
739 // arithmetic on the above. eg INDEX and DOT
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700740 return -1000;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700741}
742
Rob Pike0cafb9e2008-06-04 14:37:38 -0700743void
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700744sgen(Node *n, Node *ns, int32 w)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700745{
746 Node nodl, nodr;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700747 int32 c, q, odst, osrc;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700748
Ken Thompson54abac62008-06-21 15:11:29 -0700749 if(debug['g']) {
750 dump("\nsgen-res", ns);
751 dump("sgen-r", n);
752 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700753 if(w == 0)
754 return;
755 if(n->ullman >= UINF && ns->ullman >= UINF) {
756 fatal("sgen UINF");
757 }
758
Russ Cox74e2e082008-10-06 16:44:17 -0700759 if(w < 0)
760 fatal("sgen copy %d", w);
761
Ken Thompson30fd44c2008-08-21 20:49:04 -0700762 // offset on the stack
Ken Thompson30fd44c2008-08-21 20:49:04 -0700763 osrc = stkof(n);
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700764 odst = stkof(ns);
765//print("\nnsrc=%N\n", n);
766//print("ndst=%N\n", ns);
767//print("osrc=%d odst=%d w=%d\n", osrc, odst, w);
Ken Thompson30fd44c2008-08-21 20:49:04 -0700768
Rob Pike0cafb9e2008-06-04 14:37:38 -0700769 nodreg(&nodl, types[tptr], D_DI);
770 nodreg(&nodr, types[tptr], D_SI);
771
772 if(n->ullman >= ns->ullman) {
773 agen(n, &nodr);
774 agen(ns, &nodl);
775 } else {
776 agen(ns, &nodl);
777 agen(n, &nodr);
778 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700779
Ken Thompson30fd44c2008-08-21 20:49:04 -0700780 c = w % 8; // bytes
781 q = w / 8; // quads
782
783 // if we are copying forward on the stack and
784 // the src and dst overlap, then reverse direction
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700785 if(osrc < odst && odst < osrc+w) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700786 // reverse direction
787 gins(ASTD, N, N); // set direction flag
788 if(c > 0) {
789 gconreg(AADDQ, w-1, D_SI);
790 gconreg(AADDQ, w-1, D_DI);
791
792 gconreg(AMOVQ, c, D_CX);
793 gins(AREP, N, N); // repeat
794 gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
795 }
796
797 if(q > 0) {
798 if(c > 0) {
799 gconreg(AADDQ, -7, D_SI);
800 gconreg(AADDQ, -7, D_DI);
801 } else {
802 gconreg(AADDQ, w-8, D_SI);
803 gconreg(AADDQ, w-8, D_DI);
804 }
805 gconreg(AMOVQ, q, D_CX);
806 gins(AREP, N, N); // repeat
807 gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
808 }
809 // for future optimization
810 // we leave with the flag clear
811 gins(ACLD, N, N);
812 } else {
813 // normal direction
814 gins(ACLD, N, N); // clear direction flag
815 if(q > 0) {
816 gconreg(AMOVQ, q, D_CX);
817 gins(AREP, N, N); // repeat
818 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
819 }
820
821 if(c > 0) {
822 gconreg(AMOVQ, c, D_CX);
823 gins(AREP, N, N); // repeat
824 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
825 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700826 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700827}