blob: e19fdd11b18fdd9ebe577da76badd434c52c771a [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;
Ken Thompson719b0882008-12-13 16:41:47 -080012 int a, f;
Rob Pike0cafb9e2008-06-04 14:37:38 -070013 Prog *p1, *p2, *p3;
Ken Thompson937ac132008-12-13 13:16:14 -080014 Addr addr;
Rob Pike0cafb9e2008-06-04 14:37:38 -070015
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
Rob Pike0cafb9e2008-06-04 14:37:38 -070023 if(res == N || res->type == T)
24 fatal("cgen: res nil");
25
Ken Thompson6b8bd352008-06-06 16:49:35 -070026 if(n->ullman >= UINF) {
27 if(n->op == OINDREG)
28 fatal("cgen: this is going to misscompile");
Ken Thompson78c8dec2008-06-24 10:30:33 -070029 if(res->ullman >= UINF) {
Ken Thompsonca029d32008-06-27 17:53:23 -070030 tempname(&n1, n->type);
31 cgen(n, &n1);
32 cgen(&n1, res);
33 goto ret;
Ken Thompson78c8dec2008-06-24 10:30:33 -070034 }
Ken Thompson6b8bd352008-06-06 16:49:35 -070035 }
36
Rob Pike0cafb9e2008-06-04 14:37:38 -070037 if(isfat(n->type)) {
38 sgen(n, res, n->type->width);
39 goto ret;
40 }
41
42 if(!res->addable) {
Ken Thompson6b8bd352008-06-06 16:49:35 -070043 if(n->ullman > res->ullman) {
Ken Thompsona93099c2008-06-06 17:01:33 -070044 regalloc(&n1, n->type, res);
Ken Thompson6b8bd352008-06-06 16:49:35 -070045 cgen(n, &n1);
46 cgen(&n1, res);
47 regfree(&n1);
Ken Thompsonca029d32008-06-27 17:53:23 -070048 goto ret;
Ken Thompson6b8bd352008-06-06 16:49:35 -070049 }
50
Ken Thompson719b0882008-12-13 16:41:47 -080051 if(res->ullman >= UINF)
52 goto gen;
53
54 f = 1; // gen thru register
55 switch(n->op) {
56 case OLITERAL:
Ken Thompson23fc0ac2008-12-14 17:06:06 -080057 if(smallintconst(n))
Ken Thompson719b0882008-12-13 16:41:47 -080058 f = 0;
59 break;
60 case OREGISTER:
61 f = 0;
62 break;
63 }
64
Ken Thompson23fc0ac2008-12-14 17:06:06 -080065 if(sudoaddable(res, n->type, &addr)) {
Ken Thompson719b0882008-12-13 16:41:47 -080066 a = optoas(OAS, res->type);
67 if(f) {
68 regalloc(&n2, res->type, N);
69 cgen(n, &n2);
70 p1 = gins(a, &n2, N);
71 regfree(&n2);
72 } else
73 p1 = gins(a, n, N);
74 p1->to = addr;
Ken Thompson23fc0ac2008-12-14 17:06:06 -080075 sudoclean();
Ken Thompson719b0882008-12-13 16:41:47 -080076 goto ret;
77 }
78
79 gen:
Rob Pike0cafb9e2008-06-04 14:37:38 -070080 igen(res, &n1, N);
81 cgen(n, &n1);
82 regfree(&n1);
83 goto ret;
84 }
85
86 if(n->addable) {
87 gmove(n, res);
88 goto ret;
89 }
90
91 nl = n->left;
92 nr = n->right;
93 if(nl != N && nl->ullman >= UINF)
94 if(nr != N && nr->ullman >= UINF) {
Ken Thompson390d5fe2008-06-27 16:59:14 -070095 tempname(&n1, nr->type);
96 cgen(nr, &n1);
97 n2 = *n;
98 n2.right = &n1;
99 cgen(&n2, res);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700100 goto ret;
101 }
102
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800103 if(sudoaddable(n, res->type, &addr)) {
Ken Thompson937ac132008-12-13 13:16:14 -0800104 a = optoas(OAS, n->type);
105 if(res->op == OREGISTER) {
106 p1 = gins(a, N, res);
107 p1->from = addr;
108 } else {
Ken Thompson719b0882008-12-13 16:41:47 -0800109 regalloc(&n2, n->type, &n1);
110 p1 = gins(a, N, &n2);
Ken Thompson937ac132008-12-13 13:16:14 -0800111 p1->from = addr;
Ken Thompson719b0882008-12-13 16:41:47 -0800112 gins(a, &n2, res);
113 regfree(&n2);
Ken Thompson937ac132008-12-13 13:16:14 -0800114 }
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800115 sudoclean();
Ken Thompson719b0882008-12-13 16:41:47 -0800116 goto ret;
Ken Thompson937ac132008-12-13 13:16:14 -0800117 }
118
Rob Pike0cafb9e2008-06-04 14:37:38 -0700119 switch(n->op) {
120 default:
121 dump("cgen", n);
122 fatal("cgen: unknown op %N", n);
123 break;
124
125 // these call bgen to get a bool value
126 case OOROR:
127 case OANDAND:
128 case OEQ:
129 case ONE:
130 case OLT:
131 case OLE:
132 case OGE:
133 case OGT:
134 case ONOT:
135 p1 = gbranch(AJMP, T);
136 p2 = pc;
137 gmove(booltrue, res);
138 p3 = gbranch(AJMP, T);
139 patch(p1, pc);
140 bgen(n, 1, p2);
141 gmove(boolfalse, res);
142 patch(p3, pc);
143 goto ret;
144
145 case OPLUS:
146 cgen(nl, res);
147 goto ret;
148
149 // unary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700150 case OCOM:
Ken Thompsonb89c5382008-08-10 14:35:02 -0700151 a = optoas(OXOR, nl->type);
152 regalloc(&n1, nl->type, N);
153 cgen(nl, &n1);
154 nodconst(&n2, nl->type, -1);
155 gins(a, &n2, &n1);
156 gmove(&n1, res);
157 regfree(&n1);
158 goto ret;
159
160 case OMINUS:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700161 a = optoas(n->op, nl->type);
162 goto uop;
163
164 // symmetric binary
165 case OAND:
166 case OOR:
167 case OXOR:
168 case OADD:
169 case OMUL:
170 a = optoas(n->op, nl->type);
Ken Thompsondc78c642008-11-07 14:20:32 -0800171 if(a != AIMULB)
172 goto sbop;
173 cgen_bmul(n->op, nl, nr, res);
174 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700175
176 // asymmetric binary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700177 case OSUB:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700178 a = optoas(n->op, nl->type);
179 goto abop;
180
181 case OCONV:
182 if(eqtype(n->type, nl->type, 0)) {
183 cgen(nl, res);
184 break;
185 }
186 regalloc(&n1, nl->type, res);
187 cgen(nl, &n1);
Ken Thompson40265002008-12-18 20:06:28 -0800188 if(isptrsarray(n->type) && isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700189 // convert dynamic array to static array
190 n2 = n1;
191 n2.op = OINDREG;
192 n2.xoffset = offsetof(Array,array);
193 n2.type = types[tptr];
194 gins(AMOVQ, &n2, &n1);
195 }
Ken Thompson40265002008-12-18 20:06:28 -0800196 if(isptrdarray(n->type) && isptrsarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700197 // conver static array to dynamic array
198 // it is assumed that the dope is just before the array
Ken Thompson40265002008-12-18 20:06:28 -0800199 nodconst(&n2, types[tptr], sizeof(Array));
Ken Thompson66a603c2008-08-27 17:28:30 -0700200 gins(ASUBQ, &n2, &n1);
201 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700202 gmove(&n1, res);
203 regfree(&n1);
204 break;
205
Rob Pike0cafb9e2008-06-04 14:37:38 -0700206 case ODOT:
207 case ODOTPTR:
Ken Thompson719b0882008-12-13 16:41:47 -0800208 case OINDEXPTR:
209 case OINDEX:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700210 case OIND:
211 igen(n, &n1, res);
212 gmove(&n1, res);
213 regfree(&n1);
214 break;
215
216 case OLEN:
217 if(isptrto(nl->type, TSTRING)) {
218 regalloc(&n1, types[tptr], res);
Ken Thompsonb6eca352008-06-08 17:46:28 -0700219 cgen(nl, &n1);
Ken Thompson193eac72008-09-04 17:15:15 -0700220
221 nodconst(&n2, types[tptr], 0);
222 gins(optoas(OCMP, types[tptr]), &n1, &n2);
223 p1 = gbranch(optoas(OEQ, types[tptr]), T);
224
Ken Thompsone081f252008-11-22 17:58:53 -0800225 n2 = n1;
226 n2.op = OINDREG;
227 n2.type = types[TINT32];
228 gmove(&n2, &n1);
Ken Thompson193eac72008-09-04 17:15:15 -0700229
230 patch(p1, pc);
231
Ken Thompsone081f252008-11-22 17:58:53 -0800232 gmove(&n1, res);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700233 regfree(&n1);
234 break;
235 }
Ken Thompson87dae022008-06-24 14:11:20 -0700236 if(isptrto(nl->type, TMAP)) {
237 regalloc(&n1, types[tptr], res);
238 cgen(nl, &n1);
239 n1.op = OINDREG;
240 n1.type = types[TINT32];
241 gmove(&n1, res);
242 regfree(&n1);
243 break;
244 }
Ken Thompsonc6130e92008-08-28 15:17:37 -0700245 if(isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700246 regalloc(&n1, types[tptr], res);
247 cgen(nl, &n1);
248 n1.op = OINDREG;
249 n1.type = types[TUINT32];
250 n1.xoffset = offsetof(Array,nel);
251 gmove(&n1, res);
252 regfree(&n1);
253 break;
254 }
Ken Thompson40265002008-12-18 20:06:28 -0800255 if(isdarray(nl->type)) {
256 regalloc(&n1, types[tptr], res);
257 agen(nl, &n1);
258 n1.op = OINDREG;
259 n1.type = types[TUINT32];
260 n1.xoffset = offsetof(Array,nel);
261 gmove(&n1, res);
262 regfree(&n1);
263 break;
264 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700265 fatal("cgen: OLEN: unknown type %lT", nl->type);
266 break;
267
Ken Thompson66a603c2008-08-27 17:28:30 -0700268 case OCAP:
Ken Thompsonc6130e92008-08-28 15:17:37 -0700269 if(isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700270 regalloc(&n1, types[tptr], res);
271 cgen(nl, &n1);
272 n1.op = OINDREG;
273 n1.type = types[TUINT32];
274 n1.xoffset = offsetof(Array,cap);
275 gmove(&n1, res);
276 regfree(&n1);
277 break;
278 }
Ken Thompson40265002008-12-18 20:06:28 -0800279 if(isdarray(nl->type)) {
280 regalloc(&n1, types[tptr], res);
281 agen(nl, &n1);
282 n1.op = OINDREG;
283 n1.type = types[TUINT32];
284 n1.xoffset = offsetof(Array,cap);
285 gmove(&n1, res);
286 regfree(&n1);
287 break;
288 }
Ken Thompson66a603c2008-08-27 17:28:30 -0700289 fatal("cgen: OCAP: unknown type %lT", nl->type);
290 break;
291
Rob Pike0cafb9e2008-06-04 14:37:38 -0700292 case OADDR:
293 agen(nl, res);
294 break;
295
296 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700297 cgen_callmeth(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700298 cgen_callret(n, res);
299 break;
300
301 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700302 cgen_callinter(n, res, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700303 cgen_callret(n, res);
304 break;
305
306 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700307 cgen_call(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700308 cgen_callret(n, res);
309 break;
Ken Thompsond83b9942008-06-06 20:43:29 -0700310
311 case OMOD:
312 case ODIV:
Ken Thompson6a659eb2008-06-09 13:16:50 -0700313 if(isfloat[n->type->etype]) {
314 a = optoas(n->op, nl->type);
315 goto abop;
316 }
Ken Thompsond83b9942008-06-06 20:43:29 -0700317 cgen_div(n->op, nl, nr, res);
318 break;
Ken Thompson610644a2008-06-08 17:21:46 -0700319
Ken Thompsonf7753f12008-06-07 15:21:02 -0700320 case OLSH:
321 case ORSH:
322 cgen_shift(n->op, nl, nr, res);
323 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700324 }
325 goto ret;
326
327sbop: // symmetric binary
328 if(nl->ullman < nr->ullman) {
329 r = nl;
330 nl = nr;
331 nr = r;
332 }
333
334abop: // asymmetric binary
Ken Thompsonf7753f12008-06-07 15:21:02 -0700335 if(nl->ullman >= nr->ullman) {
Rob Pike0cafb9e2008-06-04 14:37:38 -0700336 regalloc(&n1, nl->type, res);
337 cgen(nl, &n1);
Ken Thompson937ac132008-12-13 13:16:14 -0800338
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800339 if(sudoaddable(nr, nl->type, &addr)) {
Ken Thompson719b0882008-12-13 16:41:47 -0800340 p1 = gins(a, N, &n1);
341 p1->from = addr;
342 gmove(&n1, res);
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800343 sudoclean();
Ken Thompson719b0882008-12-13 16:41:47 -0800344 regfree(&n1);
345 goto ret;
346 }
Ken Thompson937ac132008-12-13 13:16:14 -0800347
Ken Thompsonf7753f12008-06-07 15:21:02 -0700348 regalloc(&n2, nr->type, N);
349 cgen(nr, &n2);
350 } else {
351 regalloc(&n2, nr->type, N);
352 cgen(nr, &n2);
353 regalloc(&n1, nl->type, res);
354 cgen(nl, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700355 }
Ken Thompsonf7753f12008-06-07 15:21:02 -0700356 gins(a, &n2, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700357 gmove(&n1, res);
358 regfree(&n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700359 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700360 goto ret;
361
362uop: // unary
363 regalloc(&n1, nl->type, res);
364 cgen(nl, &n1);
365 gins(a, N, &n1);
366 gmove(&n1, res);
367 regfree(&n1);
368 goto ret;
369
370ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700371 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700372}
373
374void
375agen(Node *n, Node *res)
376{
377 Node *nl, *nr;
378 Node n1, n2, n3, tmp;
Ken Thompson66a603c2008-08-27 17:28:30 -0700379 Prog *p1;
Russ Cox9aad9fe2008-08-03 17:25:15 -0700380 uint32 w;
Ken Thompson904d4042008-09-12 16:48:35 -0700381 uint64 v;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700382 Type *t;
Ken Thompson54abac62008-06-21 15:11:29 -0700383
384 if(debug['g']) {
385 dump("\nagen-res", res);
386 dump("agen-r", n);
387 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700388 if(n == N || n->type == T)
389 return;
390
391 if(!isptr[res->type->etype])
392 fatal("agen: not tptr: %T", res->type);
393
394 if(n->addable) {
395 regalloc(&n1, types[tptr], res);
396 gins(ALEAQ, n, &n1);
397 gmove(&n1, res);
398 regfree(&n1);
Ken Thompson610644a2008-06-08 17:21:46 -0700399 goto ret;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700400 }
401
Ken Thompson610644a2008-06-08 17:21:46 -0700402 nl = n->left;
403 nr = n->right;
404
Rob Pike0cafb9e2008-06-04 14:37:38 -0700405 switch(n->op) {
406 default:
407 fatal("agen: unknown op %N", n);
408 break;
409
Ken Thompson54abac62008-06-21 15:11:29 -0700410 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700411 cgen_callmeth(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700412 cgen_aret(n, res);
413 break;
414
415 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700416 cgen_callinter(n, res, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700417 cgen_aret(n, res);
418 break;
419
420 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700421 cgen_call(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700422 cgen_aret(n, res);
423 break;
424
Rob Pike0cafb9e2008-06-04 14:37:38 -0700425 case OINDEXPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700426 w = n->type->width;
427 if(nr->addable)
428 goto iprad;
429 if(nl->addable) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800430 if(whatis(nr) != Wlitint) {
431 regalloc(&n1, nr->type, N);
432 cgen(nr, &n1);
433 }
434 regalloc(&n3, types[tptr], res);
435 cgen(nl, &n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700436 goto index;
437 }
438 cgen(nr, res);
439 tempname(&tmp, nr->type);
440 gmove(res, &tmp);
441
442 iprad:
Ken Thompsona6182da2008-11-23 17:26:49 -0800443 regalloc(&n3, types[tptr], res);
444 cgen(nl, &n3);
445 if(whatis(nr) != Wlitint) {
446 regalloc(&n1, nr->type, N);
447 cgen(nr, &n1);
448 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700449 goto index;
450
Rob Pike0cafb9e2008-06-04 14:37:38 -0700451 case OINDEX:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700452 w = n->type->width;
453 if(nr->addable)
454 goto irad;
455 if(nl->addable) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800456 if(whatis(nr) != Wlitint) {
457 regalloc(&n1, nr->type, N);
458 cgen(nr, &n1);
459 }
460 regalloc(&n3, types[tptr], res);
461 agen(nl, &n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700462 goto index;
463 }
464 cgen(nr, res);
465 tempname(&tmp, nr->type);
466 gmove(res, &tmp);
467
468 irad:
Ken Thompsona6182da2008-11-23 17:26:49 -0800469 regalloc(&n3, types[tptr], res);
470 agen(nl, &n3);
471 if(whatis(nr) != Wlitint) {
472 regalloc(&n1, nr->type, N);
473 cgen(nr, &n1);
474 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700475 goto index;
476
477 index:
Ken Thompsona6182da2008-11-23 17:26:49 -0800478 // &a is in &n3 (allocated in res)
479 // i is in &n1 (if not constant)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700480 // w is width
Ken Thompson66a603c2008-08-27 17:28:30 -0700481
Ken Thompson85457002008-09-26 17:41:23 -0700482 if(w == 0)
483 fatal("index is zero width");
484
Ken Thompson8e3fe102008-11-24 14:01:12 -0800485 // constant index
Ken Thompson904d4042008-09-12 16:48:35 -0700486 if(whatis(nr) == Wlitint) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800487 v = mpgetfix(nr->val.u.xval);
Ken Thompsona6182da2008-11-23 17:26:49 -0800488 if(isptrdarray(nl->type)) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800489
490 if(!debug['B']) {
491 n1 = n3;
492 n1.op = OINDREG;
493 n1.type = types[tptr];
494 n1.xoffset = offsetof(Array, nel);
495 nodconst(&n2, types[TUINT64], v);
496 gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
497 p1 = gbranch(optoas(OGT, types[TUINT32]), T);
498 gins(ACALL, N, throwindex);
499 patch(p1, pc);
500 }
501
Ken Thompsona6182da2008-11-23 17:26:49 -0800502 n1 = n3;
503 n1.op = OINDREG;
504 n1.type = types[tptr];
505 n1.xoffset = offsetof(Array, array);
506 gmove(&n1, &n3);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800507 } else
508 if(!debug['B']) {
509 if(v < 0)
510 yyerror("out of bounds on array");
511 else
Ken Thompson40265002008-12-18 20:06:28 -0800512 if(isptrsarray(nl->type)) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800513 if(v >= nl->type->type->bound)
514 yyerror("out of bounds on array");
515 } else
516 if(v >= nl->type->bound)
517 yyerror("out of bounds on array");
Ken Thompsona6182da2008-11-23 17:26:49 -0800518 }
Ken Thompson8e3fe102008-11-24 14:01:12 -0800519
Ken Thompson904d4042008-09-12 16:48:35 -0700520 nodconst(&n2, types[tptr], v*w);
Ken Thompsona6182da2008-11-23 17:26:49 -0800521 gins(optoas(OADD, types[tptr]), &n2, &n3);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800522
Ken Thompsona6182da2008-11-23 17:26:49 -0800523 gmove(&n3, res);
524 regfree(&n3);
Ken Thompson904d4042008-09-12 16:48:35 -0700525 break;
526 }
527
Ken Thompsona6182da2008-11-23 17:26:49 -0800528 // type of the index
Ken Thompson66a603c2008-08-27 17:28:30 -0700529 t = types[TUINT64];
Ken Thompsonf7753f12008-06-07 15:21:02 -0700530 if(issigned[n1.type->etype])
Ken Thompson66a603c2008-08-27 17:28:30 -0700531 t = types[TINT64];
532
533 regalloc(&n2, t, &n1); // i
Ken Thompsonf7753f12008-06-07 15:21:02 -0700534 gmove(&n1, &n2);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700535 regfree(&n1);
Ken Thompson66a603c2008-08-27 17:28:30 -0700536
Ken Thompsona6182da2008-11-23 17:26:49 -0800537 if(!debug['B']) {
538 // check bounds
539 if(isptrdarray(nl->type)) {
540 n1 = n3;
541 n1.op = OINDREG;
542 n1.type = types[tptr];
543 n1.xoffset = offsetof(Array, nel);
544 } else {
545 nodconst(&n1, types[TUINT64], nl->type->bound);
Ken Thompson40265002008-12-18 20:06:28 -0800546 if(isptrsarray(nl->type))
Ken Thompsona6182da2008-11-23 17:26:49 -0800547 nodconst(&n1, types[TUINT64], nl->type->type->bound);
548 }
Ken Thompson8e3fe102008-11-24 14:01:12 -0800549 gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
550 p1 = gbranch(optoas(OLT, types[TUINT32]), T);
Ken Thompsona6182da2008-11-23 17:26:49 -0800551 gins(ACALL, N, throwindex);
552 patch(p1, pc);
553 }
554
Ken Thompsona6182da2008-11-23 17:26:49 -0800555 if(isptrdarray(nl->type)) {
556 n1 = n3;
557 n1.op = OINDREG;
558 n1.type = types[tptr];
559 n1.xoffset = offsetof(Array, array);
560 gmove(&n1, &n3);
561 }
Ken Thompsona6182da2008-11-23 17:26:49 -0800562
Ken Thompsonc8a66a92008-12-02 19:54:51 -0800563 if(w == 1 || w == 2 || w == 4 || w == 8) {
564 p1 = gins(ALEAQ, &n2, &n3);
565 p1->from.scale = w;
566 p1->from.index = p1->from.type;
567 p1->from.type = p1->to.type + D_INDIR;
568 } else {
569 nodconst(&n1, t, w);
570 gins(optoas(OMUL, t), &n1, &n2);
571 gins(optoas(OADD, types[tptr]), &n2, &n3);
572 gmove(&n3, res);
573 }
574
575 gmove(&n3, res);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700576 regfree(&n2);
Ken Thompsona6182da2008-11-23 17:26:49 -0800577 regfree(&n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700578 break;
579
Ken Thompsone1a06cc2008-06-15 20:24:30 -0700580 case OIND:
581 cgen(nl, res);
582 break;
Russ Cox74e2e082008-10-06 16:44:17 -0700583
Rob Pike0cafb9e2008-06-04 14:37:38 -0700584 case ODOT:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700585 t = nl->type;
586 agen(nl, res);
587 if(n->xoffset != 0) {
588 nodconst(&n1, types[TINT64], n->xoffset);
589 gins(optoas(OADD, types[tptr]), &n1, res);
590 }
591 break;
592
593 case ODOTPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700594 t = nl->type;
595 if(!isptr[t->etype])
596 fatal("agen: not ptr %N", n);
597 cgen(nl, res);
598 if(n->xoffset != 0) {
599 nodconst(&n1, types[TINT64], n->xoffset);
600 gins(optoas(OADD, types[tptr]), &n1, res);
601 }
602 break;
603 }
Ken Thompson610644a2008-06-08 17:21:46 -0700604
605ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700606 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700607}
608
609vlong
610fieldoffset(Type *t, Node *n)
611{
612 if(t->etype != TSTRUCT)
613 fatal("fieldoffset: not struct %lT", t);
614 if(n->op != ONAME)
615 fatal("fieldoffset: not field name %N", n);
616 return 0;
617}
618
619void
620igen(Node *n, Node *a, Node *res)
621{
622 regalloc(a, types[tptr], res);
623 agen(n, a);
624 a->op = OINDREG;
625 a->type = n->type;
626}
627
628void
629bgen(Node *n, int true, Prog *to)
630{
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700631 int et, a;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700632 Node *nl, *nr, *r;
Ken Thompson610644a2008-06-08 17:21:46 -0700633 Node n1, n2, tmp;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700634 Prog *p1, *p2;
635
Ken Thompson54abac62008-06-21 15:11:29 -0700636 if(debug['g']) {
637 dump("\nbgen", n);
638 }
Ken Thompsond3237f92008-06-28 17:27:39 -0700639
Rob Pike0cafb9e2008-06-04 14:37:38 -0700640 if(n == N)
641 n = booltrue;
642
Ken Thompson610644a2008-06-08 17:21:46 -0700643 nl = n->left;
644 nr = n->right;
645
Rob Pike0cafb9e2008-06-04 14:37:38 -0700646 if(n->type == T) {
647 convlit(n, types[TBOOL]);
648 if(n->type == T)
649 goto ret;
650 }
651
652 et = n->type->etype;
653 if(et != TBOOL) {
654 yyerror("cgen: bad type %T for %O", n->type, n->op);
655 patch(gins(AEND, N, N), to);
656 goto ret;
657 }
658 nl = N;
659 nr = N;
660
661 switch(n->op) {
662 default:
663 regalloc(&n1, n->type, N);
664 cgen(n, &n1);
665 nodconst(&n2, n->type, 0);
666 gins(optoas(OCMP, n->type), &n1, &n2);
667 a = AJNE;
668 if(!true)
669 a = AJEQ;
670 patch(gbranch(a, n->type), to);
671 regfree(&n1);
672 goto ret;
673
674 case OLITERAL:
Ken Thompson9c2ade32008-08-08 17:13:31 -0700675// need to ask if it is bool?
676 if(!true == !n->val.u.bval)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700677 patch(gbranch(AJMP, T), to);
678 goto ret;
679
680 case ONAME:
681 nodconst(&n1, n->type, 0);
682 gins(optoas(OCMP, n->type), n, &n1);
683 a = AJNE;
684 if(!true)
685 a = AJEQ;
686 patch(gbranch(a, n->type), to);
687 goto ret;
688
689 case OANDAND:
690 if(!true)
691 goto caseor;
692
693 caseand:
694 p1 = gbranch(AJMP, T);
695 p2 = gbranch(AJMP, T);
696 patch(p1, pc);
697 bgen(n->left, !true, p2);
698 bgen(n->right, !true, p2);
699 p1 = gbranch(AJMP, T);
700 patch(p1, to);
701 patch(p2, pc);
702 goto ret;
703
704 case OOROR:
705 if(!true)
706 goto caseand;
707
708 caseor:
709 bgen(n->left, true, to);
710 bgen(n->right, true, to);
711 goto ret;
712
713 case OEQ:
714 case ONE:
715 case OLT:
716 case OGT:
717 case OLE:
718 case OGE:
719 nr = n->right;
720 if(nr == N || nr->type == T)
721 goto ret;
722
723 case ONOT: // unary
724 nl = n->left;
725 if(nl == N || nl->type == T)
726 goto ret;
727 }
728
729 switch(n->op) {
730
731 case ONOT:
732 bgen(nl, !true, to);
733 goto ret;
734
735 case OEQ:
736 case ONE:
737 case OLT:
738 case OGT:
739 case OLE:
740 case OGE:
741 a = n->op;
742 if(!true)
743 a = brcom(a);
744
745 // make simplest on right
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800746 if(nl->op == OLITERAL || nl->ullman < nr->ullman) {
Rob Pike0cafb9e2008-06-04 14:37:38 -0700747 a = brrev(a);
748 r = nl;
749 nl = nr;
750 nr = r;
751 }
Ken Thompson610644a2008-06-08 17:21:46 -0700752
Rob Pike0cafb9e2008-06-04 14:37:38 -0700753 a = optoas(a, nr->type);
754
Ken Thompson610644a2008-06-08 17:21:46 -0700755 if(nr->ullman >= UINF) {
756 regalloc(&n1, nr->type, N);
757 cgen(nr, &n1);
758
759 tempname(&tmp, nr->type);
760 gmove(&n1, &tmp);
761 regfree(&n1);
Russ Cox74e2e082008-10-06 16:44:17 -0700762
Ken Thompson610644a2008-06-08 17:21:46 -0700763 regalloc(&n1, nl->type, N);
764 cgen(nl, &n1);
765
766 regalloc(&n2, nr->type, &n2);
767 cgen(&tmp, &n2);
768
769 gins(optoas(OCMP, nr->type), &n1, &n2);
770 patch(gbranch(a, nr->type), to);
771
772 regfree(&n1);
773 regfree(&n2);
774 break;
775 }
776
Rob Pike0cafb9e2008-06-04 14:37:38 -0700777 regalloc(&n1, nl->type, N);
778 cgen(nl, &n1);
779
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800780 if(smallintconst(nr)) {
781 gins(optoas(OCMP, nr->type), &n1, nr);
782 patch(gbranch(a, nr->type), to);
783 regfree(&n1);
784 break;
785 }
786
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700787 regalloc(&n2, nr->type, N);
788 cgen(nr, &n2);
789
790 gins(optoas(OCMP, nr->type), &n1, &n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700791 patch(gbranch(a, nr->type), to);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700792
Rob Pike0cafb9e2008-06-04 14:37:38 -0700793 regfree(&n1);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700794 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700795 break;
796 }
797 goto ret;
798
799ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700800 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700801}
802
Ken Thompson30fd44c2008-08-21 20:49:04 -0700803int32
804stkof(Node *n)
805{
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700806 Type *t;
807 Iter flist;
808
Ken Thompson30fd44c2008-08-21 20:49:04 -0700809 switch(n->op) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700810 case OINDREG:
811 return n->xoffset;
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700812
813 case OCALLMETH:
814 case OCALLINTER:
815 case OCALL:
816 t = n->left->type;
817 if(isptr[t->etype])
818 t = t->type;
819
820 t = structfirst(&flist, getoutarg(t));
821 if(t != T)
822 return t->width;
823 break;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700824 }
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700825
Ken Thompson30fd44c2008-08-21 20:49:04 -0700826 // botch - probably failing to recognize address
827 // arithmetic on the above. eg INDEX and DOT
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700828 return -1000;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700829}
830
Rob Pike0cafb9e2008-06-04 14:37:38 -0700831void
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700832sgen(Node *n, Node *ns, int32 w)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700833{
834 Node nodl, nodr;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700835 int32 c, q, odst, osrc;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700836
Ken Thompson54abac62008-06-21 15:11:29 -0700837 if(debug['g']) {
Ken Thompson40265002008-12-18 20:06:28 -0800838 print("\nsgen w=%d\n", w);
839 dump("r", n);
840 dump("res", ns);
Ken Thompson54abac62008-06-21 15:11:29 -0700841 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700842 if(w == 0)
843 return;
844 if(n->ullman >= UINF && ns->ullman >= UINF) {
845 fatal("sgen UINF");
846 }
847
Russ Cox74e2e082008-10-06 16:44:17 -0700848 if(w < 0)
849 fatal("sgen copy %d", w);
850
Ken Thompson30fd44c2008-08-21 20:49:04 -0700851 // offset on the stack
Ken Thompson30fd44c2008-08-21 20:49:04 -0700852 osrc = stkof(n);
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700853 odst = stkof(ns);
Ken Thompson30fd44c2008-08-21 20:49:04 -0700854
Rob Pike0cafb9e2008-06-04 14:37:38 -0700855 nodreg(&nodl, types[tptr], D_DI);
856 nodreg(&nodr, types[tptr], D_SI);
857
858 if(n->ullman >= ns->ullman) {
859 agen(n, &nodr);
860 agen(ns, &nodl);
861 } else {
862 agen(ns, &nodl);
863 agen(n, &nodr);
864 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700865
Ken Thompson30fd44c2008-08-21 20:49:04 -0700866 c = w % 8; // bytes
867 q = w / 8; // quads
868
869 // if we are copying forward on the stack and
870 // the src and dst overlap, then reverse direction
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700871 if(osrc < odst && odst < osrc+w) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700872 // reverse direction
873 gins(ASTD, N, N); // set direction flag
874 if(c > 0) {
875 gconreg(AADDQ, w-1, D_SI);
876 gconreg(AADDQ, w-1, D_DI);
877
878 gconreg(AMOVQ, c, D_CX);
879 gins(AREP, N, N); // repeat
880 gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
881 }
882
883 if(q > 0) {
884 if(c > 0) {
885 gconreg(AADDQ, -7, D_SI);
886 gconreg(AADDQ, -7, D_DI);
887 } else {
888 gconreg(AADDQ, w-8, D_SI);
889 gconreg(AADDQ, w-8, D_DI);
890 }
891 gconreg(AMOVQ, q, D_CX);
892 gins(AREP, N, N); // repeat
893 gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
894 }
Ken Thompson30fd44c2008-08-21 20:49:04 -0700895 // we leave with the flag clear
896 gins(ACLD, N, N);
897 } else {
898 // normal direction
Ken Thompson8f53bc02008-12-15 15:07:35 -0800899 if(q >= 4) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700900 gconreg(AMOVQ, q, D_CX);
901 gins(AREP, N, N); // repeat
902 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
Ken Thompson8f53bc02008-12-15 15:07:35 -0800903 } else
904 while(q > 0) {
905 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
906 q--;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700907 }
908
Ken Thompson8f53bc02008-12-15 15:07:35 -0800909 if(c >= 4) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700910 gconreg(AMOVQ, c, D_CX);
911 gins(AREP, N, N); // repeat
912 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
Ken Thompson8f53bc02008-12-15 15:07:35 -0800913
914 } else
915 while(c > 0) {
916 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
917 c--;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700918 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700919 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700920}