blob: d12bbef6888c14b863880f0a41c2355009ef50bc [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
Russ Cox2d259c82009-01-05 17:32:23 -08007/*
8 * generate:
9 * res = n;
Russ Cox8fb60762009-01-13 13:46:09 -080010 * simplifies and calls gmove.
Russ Cox2d259c82009-01-05 17:32:23 -080011 */
Rob Pike0cafb9e2008-06-04 14:37:38 -070012void
13cgen(Node *n, Node *res)
14{
Rob Pike0cafb9e2008-06-04 14:37:38 -070015 Node *nl, *nr, *r;
Ken Thompsonf7753f12008-06-07 15:21:02 -070016 Node n1, n2;
Ken Thompson719b0882008-12-13 16:41:47 -080017 int a, f;
Rob Pike0cafb9e2008-06-04 14:37:38 -070018 Prog *p1, *p2, *p3;
Ken Thompson937ac132008-12-13 13:16:14 -080019 Addr addr;
Rob Pike0cafb9e2008-06-04 14:37:38 -070020
21 if(debug['g']) {
Russ Cox4a431982009-01-30 14:39:42 -080022 dump("\ncgen-n", n);
23 dump("cgen-res", res);
Rob Pike0cafb9e2008-06-04 14:37:38 -070024 }
25 if(n == N || n->type == T)
26 return;
Ken Thompson78c8dec2008-06-24 10:30:33 -070027
Rob Pike0cafb9e2008-06-04 14:37:38 -070028 if(res == N || res->type == T)
29 fatal("cgen: res nil");
30
Ken Thompson6b8bd352008-06-06 16:49:35 -070031 if(n->ullman >= UINF) {
32 if(n->op == OINDREG)
33 fatal("cgen: this is going to misscompile");
Ken Thompson78c8dec2008-06-24 10:30:33 -070034 if(res->ullman >= UINF) {
Ken Thompsonca029d32008-06-27 17:53:23 -070035 tempname(&n1, n->type);
36 cgen(n, &n1);
37 cgen(&n1, res);
38 goto ret;
Ken Thompson78c8dec2008-06-24 10:30:33 -070039 }
Ken Thompson6b8bd352008-06-06 16:49:35 -070040 }
41
Rob Pike0cafb9e2008-06-04 14:37:38 -070042 if(isfat(n->type)) {
43 sgen(n, res, n->type->width);
44 goto ret;
45 }
46
47 if(!res->addable) {
Ken Thompson6b8bd352008-06-06 16:49:35 -070048 if(n->ullman > res->ullman) {
Ken Thompsona93099c2008-06-06 17:01:33 -070049 regalloc(&n1, n->type, res);
Ken Thompson6b8bd352008-06-06 16:49:35 -070050 cgen(n, &n1);
Russ Cox391425a2009-01-29 17:38:58 -080051 if(n1.ullman > res->ullman) {
52 dump("n1", &n1);
53 dump("res", res);
54 fatal("loop in cgen");
55 }
Ken Thompson6b8bd352008-06-06 16:49:35 -070056 cgen(&n1, res);
57 regfree(&n1);
Ken Thompsonca029d32008-06-27 17:53:23 -070058 goto ret;
Ken Thompson6b8bd352008-06-06 16:49:35 -070059 }
60
Ken Thompson719b0882008-12-13 16:41:47 -080061 if(res->ullman >= UINF)
62 goto gen;
63
64 f = 1; // gen thru register
65 switch(n->op) {
66 case OLITERAL:
Ken Thompson23fc0ac2008-12-14 17:06:06 -080067 if(smallintconst(n))
Ken Thompson719b0882008-12-13 16:41:47 -080068 f = 0;
69 break;
70 case OREGISTER:
71 f = 0;
72 break;
73 }
74
Ken Thompsona5a87892009-05-03 15:17:03 -070075 a = optoas(OAS, res->type);
76 if(sudoaddable(a, res, &addr)) {
Ken Thompson719b0882008-12-13 16:41:47 -080077 if(f) {
78 regalloc(&n2, res->type, N);
79 cgen(n, &n2);
80 p1 = gins(a, &n2, N);
81 regfree(&n2);
82 } else
83 p1 = gins(a, n, N);
84 p1->to = addr;
Russ Cox4a431982009-01-30 14:39:42 -080085 if(debug['g'])
86 print("%P [ignore previous line]\n", p1);
Ken Thompson23fc0ac2008-12-14 17:06:06 -080087 sudoclean();
Ken Thompson719b0882008-12-13 16:41:47 -080088 goto ret;
89 }
90
91 gen:
Rob Pike0cafb9e2008-06-04 14:37:38 -070092 igen(res, &n1, N);
93 cgen(n, &n1);
94 regfree(&n1);
95 goto ret;
96 }
97
98 if(n->addable) {
99 gmove(n, res);
100 goto ret;
101 }
102
103 nl = n->left;
104 nr = n->right;
105 if(nl != N && nl->ullman >= UINF)
106 if(nr != N && nr->ullman >= UINF) {
Ken Thompsonf9854972009-04-09 19:11:24 -0700107 tempname(&n1, nl->type);
108 cgen(nl, &n1);
Ken Thompson390d5fe2008-06-27 16:59:14 -0700109 n2 = *n;
Ken Thompsonf9854972009-04-09 19:11:24 -0700110 n2.left = &n1;
Ken Thompson390d5fe2008-06-27 16:59:14 -0700111 cgen(&n2, res);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700112 goto ret;
113 }
114
Ken Thompsona5a87892009-05-03 15:17:03 -0700115 a = optoas(OAS, n->type);
116 if(sudoaddable(a, n, &addr)) {
Ken Thompson937ac132008-12-13 13:16:14 -0800117 if(res->op == OREGISTER) {
118 p1 = gins(a, N, res);
119 p1->from = addr;
120 } else {
Russ Cox7b6bdfb2009-01-30 15:11:46 -0800121 regalloc(&n2, n->type, N);
Ken Thompson719b0882008-12-13 16:41:47 -0800122 p1 = gins(a, N, &n2);
Ken Thompson937ac132008-12-13 13:16:14 -0800123 p1->from = addr;
Ken Thompson719b0882008-12-13 16:41:47 -0800124 gins(a, &n2, res);
125 regfree(&n2);
Ken Thompson937ac132008-12-13 13:16:14 -0800126 }
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800127 sudoclean();
Ken Thompson719b0882008-12-13 16:41:47 -0800128 goto ret;
Ken Thompson937ac132008-12-13 13:16:14 -0800129 }
130
Rob Pike0cafb9e2008-06-04 14:37:38 -0700131 switch(n->op) {
132 default:
133 dump("cgen", n);
134 fatal("cgen: unknown op %N", n);
135 break;
136
137 // these call bgen to get a bool value
138 case OOROR:
139 case OANDAND:
140 case OEQ:
141 case ONE:
142 case OLT:
143 case OLE:
144 case OGE:
145 case OGT:
146 case ONOT:
147 p1 = gbranch(AJMP, T);
148 p2 = pc;
Russ Cox8f194bf2009-03-12 19:04:38 -0700149 gmove(nodbool(1), res);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700150 p3 = gbranch(AJMP, T);
151 patch(p1, pc);
152 bgen(n, 1, p2);
Russ Cox8f194bf2009-03-12 19:04:38 -0700153 gmove(nodbool(0), res);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700154 patch(p3, pc);
155 goto ret;
156
157 case OPLUS:
158 cgen(nl, res);
159 goto ret;
160
161 // unary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700162 case OCOM:
Ken Thompsonb89c5382008-08-10 14:35:02 -0700163 a = optoas(OXOR, nl->type);
164 regalloc(&n1, nl->type, N);
165 cgen(nl, &n1);
166 nodconst(&n2, nl->type, -1);
167 gins(a, &n2, &n1);
168 gmove(&n1, res);
169 regfree(&n1);
170 goto ret;
171
172 case OMINUS:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700173 a = optoas(n->op, nl->type);
174 goto uop;
175
176 // symmetric binary
177 case OAND:
178 case OOR:
179 case OXOR:
180 case OADD:
181 case OMUL:
182 a = optoas(n->op, nl->type);
Ken Thompsondc78c642008-11-07 14:20:32 -0800183 if(a != AIMULB)
184 goto sbop;
185 cgen_bmul(n->op, nl, nr, res);
186 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700187
188 // asymmetric binary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700189 case OSUB:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700190 a = optoas(n->op, nl->type);
191 goto abop;
192
193 case OCONV:
194 if(eqtype(n->type, nl->type, 0)) {
195 cgen(nl, res);
196 break;
197 }
198 regalloc(&n1, nl->type, res);
199 cgen(nl, &n1);
200 gmove(&n1, res);
201 regfree(&n1);
202 break;
203
Rob Pike0cafb9e2008-06-04 14:37:38 -0700204 case ODOT:
205 case ODOTPTR:
Ken Thompson719b0882008-12-13 16:41:47 -0800206 case OINDEX:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700207 case OIND:
Russ Cox0970c462009-02-06 13:47:10 -0800208 case ONAME: // PHEAP or PPARAMREF var
Rob Pike0cafb9e2008-06-04 14:37:38 -0700209 igen(n, &n1, res);
210 gmove(&n1, res);
211 regfree(&n1);
212 break;
213
214 case OLEN:
Ken Thompson36570612009-04-09 18:16:21 -0700215 if(istype(nl->type, TMAP)) {
216 // map hsd len in the first 32-bit word.
Russ Coxae167bf2009-01-09 15:21:41 -0800217 // a zero pointer means zero length
Rob Pike0cafb9e2008-06-04 14:37:38 -0700218 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 Thompson36570612009-04-09 18:16:21 -0700236 if(istype(nl->type, TSTRING) || isslice(nl->type)) {
237 // both slice and string have len in the first 32-bit word.
238 // a zero pointer means zero length
Ken Thompson40265002008-12-18 20:06:28 -0800239 regalloc(&n1, types[tptr], res);
240 agen(nl, &n1);
241 n1.op = OINDREG;
242 n1.type = types[TUINT32];
Ken Thompson6fa74e02008-12-19 14:04:25 -0800243 n1.xoffset = Array_nel;
Ken Thompson40265002008-12-18 20:06:28 -0800244 gmove(&n1, res);
245 regfree(&n1);
246 break;
247 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700248 fatal("cgen: OLEN: unknown type %lT", nl->type);
249 break;
250
Ken Thompson66a603c2008-08-27 17:28:30 -0700251 case OCAP:
Russ Coxae167bf2009-01-09 15:21:41 -0800252 if(isslice(nl->type)) {
Ken Thompson40265002008-12-18 20:06:28 -0800253 regalloc(&n1, types[tptr], res);
254 agen(nl, &n1);
255 n1.op = OINDREG;
256 n1.type = types[TUINT32];
Ken Thompson6fa74e02008-12-19 14:04:25 -0800257 n1.xoffset = Array_cap;
Ken Thompson40265002008-12-18 20:06:28 -0800258 gmove(&n1, res);
259 regfree(&n1);
260 break;
261 }
Ken Thompson66a603c2008-08-27 17:28:30 -0700262 fatal("cgen: OCAP: unknown type %lT", nl->type);
263 break;
264
Rob Pike0cafb9e2008-06-04 14:37:38 -0700265 case OADDR:
266 agen(nl, res);
267 break;
268
269 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700270 cgen_callmeth(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700271 cgen_callret(n, res);
272 break;
273
274 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700275 cgen_callinter(n, res, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700276 cgen_callret(n, res);
277 break;
278
279 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700280 cgen_call(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700281 cgen_callret(n, res);
282 break;
Ken Thompsond83b9942008-06-06 20:43:29 -0700283
284 case OMOD:
285 case ODIV:
Ken Thompson6a659eb2008-06-09 13:16:50 -0700286 if(isfloat[n->type->etype]) {
287 a = optoas(n->op, nl->type);
288 goto abop;
289 }
Ken Thompsond83b9942008-06-06 20:43:29 -0700290 cgen_div(n->op, nl, nr, res);
291 break;
Ken Thompson610644a2008-06-08 17:21:46 -0700292
Ken Thompsonf7753f12008-06-07 15:21:02 -0700293 case OLSH:
294 case ORSH:
295 cgen_shift(n->op, nl, nr, res);
296 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700297 }
298 goto ret;
299
300sbop: // symmetric binary
301 if(nl->ullman < nr->ullman) {
302 r = nl;
303 nl = nr;
304 nr = r;
305 }
306
307abop: // asymmetric binary
Ken Thompsonf7753f12008-06-07 15:21:02 -0700308 if(nl->ullman >= nr->ullman) {
Rob Pike0cafb9e2008-06-04 14:37:38 -0700309 regalloc(&n1, nl->type, res);
310 cgen(nl, &n1);
Ken Thompson937ac132008-12-13 13:16:14 -0800311
Ken Thompsona5a87892009-05-03 15:17:03 -0700312 if(sudoaddable(a, nr, &addr)) {
Ken Thompson719b0882008-12-13 16:41:47 -0800313 p1 = gins(a, N, &n1);
314 p1->from = addr;
315 gmove(&n1, res);
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800316 sudoclean();
Ken Thompson719b0882008-12-13 16:41:47 -0800317 regfree(&n1);
318 goto ret;
319 }
Ken Thompsonf7753f12008-06-07 15:21:02 -0700320 regalloc(&n2, nr->type, N);
321 cgen(nr, &n2);
322 } else {
323 regalloc(&n2, nr->type, N);
324 cgen(nr, &n2);
325 regalloc(&n1, nl->type, res);
326 cgen(nl, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700327 }
Ken Thompsonf7753f12008-06-07 15:21:02 -0700328 gins(a, &n2, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700329 gmove(&n1, res);
330 regfree(&n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700331 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700332 goto ret;
333
334uop: // unary
335 regalloc(&n1, nl->type, res);
336 cgen(nl, &n1);
337 gins(a, N, &n1);
338 gmove(&n1, res);
339 regfree(&n1);
340 goto ret;
341
342ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700343 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700344}
345
Russ Cox2d259c82009-01-05 17:32:23 -0800346/*
347 * generate:
348 * res = &n;
349 */
Rob Pike0cafb9e2008-06-04 14:37:38 -0700350void
351agen(Node *n, Node *res)
352{
353 Node *nl, *nr;
354 Node n1, n2, n3, tmp;
Ken Thompson66a603c2008-08-27 17:28:30 -0700355 Prog *p1;
Russ Cox9aad9fe2008-08-03 17:25:15 -0700356 uint32 w;
Ken Thompson904d4042008-09-12 16:48:35 -0700357 uint64 v;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700358 Type *t;
Ken Thompson54abac62008-06-21 15:11:29 -0700359
360 if(debug['g']) {
361 dump("\nagen-res", res);
362 dump("agen-r", n);
363 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700364 if(n == N || n->type == T)
365 return;
366
367 if(!isptr[res->type->etype])
368 fatal("agen: not tptr: %T", res->type);
369
370 if(n->addable) {
371 regalloc(&n1, types[tptr], res);
372 gins(ALEAQ, n, &n1);
373 gmove(&n1, res);
374 regfree(&n1);
Ken Thompson610644a2008-06-08 17:21:46 -0700375 goto ret;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700376 }
377
Ken Thompson610644a2008-06-08 17:21:46 -0700378 nl = n->left;
379 nr = n->right;
380
Rob Pike0cafb9e2008-06-04 14:37:38 -0700381 switch(n->op) {
382 default:
383 fatal("agen: unknown op %N", n);
384 break;
385
Russ Cox1b7881a2009-01-08 15:01:22 -0800386 case OCONV:
387 if(!eqtype(n->type, nl->type, 0))
388 fatal("agen: non-trivial OCONV");
389 agen(nl, res);
390 return;
391
Ken Thompson54abac62008-06-21 15:11:29 -0700392 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700393 cgen_callmeth(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700394 cgen_aret(n, res);
395 break;
396
397 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700398 cgen_callinter(n, res, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700399 cgen_aret(n, res);
400 break;
401
402 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700403 cgen_call(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700404 cgen_aret(n, res);
405 break;
406
Rob Pike0cafb9e2008-06-04 14:37:38 -0700407 case OINDEX:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700408 w = n->type->width;
409 if(nr->addable)
410 goto irad;
411 if(nl->addable) {
Russ Cox8f194bf2009-03-12 19:04:38 -0700412 if(!isconst(nr, CTINT)) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800413 regalloc(&n1, nr->type, N);
414 cgen(nr, &n1);
415 }
416 regalloc(&n3, types[tptr], res);
417 agen(nl, &n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700418 goto index;
419 }
420 cgen(nr, res);
421 tempname(&tmp, nr->type);
422 gmove(res, &tmp);
423
424 irad:
Ken Thompsona6182da2008-11-23 17:26:49 -0800425 regalloc(&n3, types[tptr], res);
426 agen(nl, &n3);
Russ Cox8f194bf2009-03-12 19:04:38 -0700427 if(!isconst(nr, CTINT)) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800428 regalloc(&n1, nr->type, N);
429 cgen(nr, &n1);
430 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700431 goto index;
432
433 index:
Ken Thompsona6182da2008-11-23 17:26:49 -0800434 // &a is in &n3 (allocated in res)
435 // i is in &n1 (if not constant)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700436 // w is width
Ken Thompson66a603c2008-08-27 17:28:30 -0700437
Ken Thompson85457002008-09-26 17:41:23 -0700438 if(w == 0)
439 fatal("index is zero width");
440
Ken Thompson8e3fe102008-11-24 14:01:12 -0800441 // constant index
Russ Cox8f194bf2009-03-12 19:04:38 -0700442 if(isconst(nr, CTINT)) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800443 v = mpgetfix(nr->val.u.xval);
Russ Coxae167bf2009-01-09 15:21:41 -0800444 if(isslice(nl->type)) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800445
446 if(!debug['B']) {
447 n1 = n3;
448 n1.op = OINDREG;
449 n1.type = types[tptr];
Ken Thompson6fa74e02008-12-19 14:04:25 -0800450 n1.xoffset = Array_nel;
Ken Thompson8e3fe102008-11-24 14:01:12 -0800451 nodconst(&n2, types[TUINT64], v);
452 gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
453 p1 = gbranch(optoas(OGT, types[TUINT32]), T);
Russ Cox4a431982009-01-30 14:39:42 -0800454 ginscall(throwindex, 0);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800455 patch(p1, pc);
456 }
457
Ken Thompsona6182da2008-11-23 17:26:49 -0800458 n1 = n3;
459 n1.op = OINDREG;
460 n1.type = types[tptr];
Ken Thompson6fa74e02008-12-19 14:04:25 -0800461 n1.xoffset = Array_array;
Ken Thompsona6182da2008-11-23 17:26:49 -0800462 gmove(&n1, &n3);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800463 } else
464 if(!debug['B']) {
465 if(v < 0)
466 yyerror("out of bounds on array");
467 else
Ken Thompson8e3fe102008-11-24 14:01:12 -0800468 if(v >= nl->type->bound)
469 yyerror("out of bounds on array");
Ken Thompsona6182da2008-11-23 17:26:49 -0800470 }
Ken Thompson8e3fe102008-11-24 14:01:12 -0800471
Ken Thompson904d4042008-09-12 16:48:35 -0700472 nodconst(&n2, types[tptr], v*w);
Ken Thompsona6182da2008-11-23 17:26:49 -0800473 gins(optoas(OADD, types[tptr]), &n2, &n3);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800474
Ken Thompsona6182da2008-11-23 17:26:49 -0800475 gmove(&n3, res);
476 regfree(&n3);
Ken Thompson904d4042008-09-12 16:48:35 -0700477 break;
478 }
479
Ken Thompsona6182da2008-11-23 17:26:49 -0800480 // type of the index
Ken Thompson66a603c2008-08-27 17:28:30 -0700481 t = types[TUINT64];
Ken Thompsonf7753f12008-06-07 15:21:02 -0700482 if(issigned[n1.type->etype])
Ken Thompson66a603c2008-08-27 17:28:30 -0700483 t = types[TINT64];
484
485 regalloc(&n2, t, &n1); // i
Ken Thompsonf7753f12008-06-07 15:21:02 -0700486 gmove(&n1, &n2);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700487 regfree(&n1);
Ken Thompson66a603c2008-08-27 17:28:30 -0700488
Ken Thompsona6182da2008-11-23 17:26:49 -0800489 if(!debug['B']) {
490 // check bounds
Russ Coxae167bf2009-01-09 15:21:41 -0800491 if(isslice(nl->type)) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800492 n1 = n3;
493 n1.op = OINDREG;
494 n1.type = types[tptr];
Ken Thompson6fa74e02008-12-19 14:04:25 -0800495 n1.xoffset = Array_nel;
Russ Coxae167bf2009-01-09 15:21:41 -0800496 } else
Ken Thompsona6182da2008-11-23 17:26:49 -0800497 nodconst(&n1, types[TUINT64], nl->type->bound);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800498 gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
499 p1 = gbranch(optoas(OLT, types[TUINT32]), T);
Russ Cox4a431982009-01-30 14:39:42 -0800500 ginscall(throwindex, 0);
Ken Thompsona6182da2008-11-23 17:26:49 -0800501 patch(p1, pc);
502 }
503
Russ Coxae167bf2009-01-09 15:21:41 -0800504 if(isslice(nl->type)) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800505 n1 = n3;
506 n1.op = OINDREG;
507 n1.type = types[tptr];
Ken Thompson6fa74e02008-12-19 14:04:25 -0800508 n1.xoffset = Array_array;
Ken Thompsona6182da2008-11-23 17:26:49 -0800509 gmove(&n1, &n3);
510 }
Ken Thompsona6182da2008-11-23 17:26:49 -0800511
Ken Thompsonc8a66a92008-12-02 19:54:51 -0800512 if(w == 1 || w == 2 || w == 4 || w == 8) {
513 p1 = gins(ALEAQ, &n2, &n3);
514 p1->from.scale = w;
515 p1->from.index = p1->from.type;
516 p1->from.type = p1->to.type + D_INDIR;
517 } else {
518 nodconst(&n1, t, w);
519 gins(optoas(OMUL, t), &n1, &n2);
520 gins(optoas(OADD, types[tptr]), &n2, &n3);
521 gmove(&n3, res);
522 }
523
524 gmove(&n3, res);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700525 regfree(&n2);
Ken Thompsona6182da2008-11-23 17:26:49 -0800526 regfree(&n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700527 break;
528
Russ Cox391425a2009-01-29 17:38:58 -0800529 case ONAME:
Russ Cox0970c462009-02-06 13:47:10 -0800530 // should only get here with names in this func.
531 if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
532 dump("bad agen", n);
533 fatal("agen: bad ONAME funcdepth %d != %d",
534 n->funcdepth, funcdepth);
535 }
536
537 // should only get here for heap vars or paramref
538 if(!(n->class & PHEAP) && n->class != PPARAMREF) {
539 dump("bad agen", n);
Russ Cox391425a2009-01-29 17:38:58 -0800540 fatal("agen: bad ONAME class %#x", n->class);
Russ Cox0970c462009-02-06 13:47:10 -0800541 }
Russ Cox391425a2009-01-29 17:38:58 -0800542 cgen(n->heapaddr, res);
543 if(n->xoffset != 0) {
544 nodconst(&n1, types[TINT64], n->xoffset);
545 gins(optoas(OADD, types[tptr]), &n1, res);
546 }
547 break;
548
Ken Thompsone1a06cc2008-06-15 20:24:30 -0700549 case OIND:
550 cgen(nl, res);
551 break;
Russ Cox74e2e082008-10-06 16:44:17 -0700552
Rob Pike0cafb9e2008-06-04 14:37:38 -0700553 case ODOT:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700554 t = nl->type;
555 agen(nl, res);
556 if(n->xoffset != 0) {
557 nodconst(&n1, types[TINT64], n->xoffset);
558 gins(optoas(OADD, types[tptr]), &n1, res);
559 }
560 break;
561
562 case ODOTPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700563 t = nl->type;
564 if(!isptr[t->etype])
565 fatal("agen: not ptr %N", n);
566 cgen(nl, res);
567 if(n->xoffset != 0) {
568 nodconst(&n1, types[TINT64], n->xoffset);
569 gins(optoas(OADD, types[tptr]), &n1, res);
570 }
571 break;
572 }
Ken Thompson610644a2008-06-08 17:21:46 -0700573
574ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700575 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700576}
577
Russ Cox2d259c82009-01-05 17:32:23 -0800578/*
579 * generate:
580 * newreg = &n;
581 * res = newreg
582 *
583 * on exit, a has been changed to be *newreg.
584 * caller must regfree(a).
585 */
Rob Pike0cafb9e2008-06-04 14:37:38 -0700586void
587igen(Node *n, Node *a, Node *res)
588{
589 regalloc(a, types[tptr], res);
590 agen(n, a);
591 a->op = OINDREG;
592 a->type = n->type;
593}
594
Russ Cox2d259c82009-01-05 17:32:23 -0800595/*
596 * generate:
597 * if(n == true) goto to;
598 */
Rob Pike0cafb9e2008-06-04 14:37:38 -0700599void
600bgen(Node *n, int true, Prog *to)
601{
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700602 int et, a;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700603 Node *nl, *nr, *r;
Ken Thompson610644a2008-06-08 17:21:46 -0700604 Node n1, n2, tmp;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700605 Prog *p1, *p2;
606
Ken Thompson54abac62008-06-21 15:11:29 -0700607 if(debug['g']) {
608 dump("\nbgen", n);
609 }
Ken Thompsond3237f92008-06-28 17:27:39 -0700610
Rob Pike0cafb9e2008-06-04 14:37:38 -0700611 if(n == N)
Russ Cox8f194bf2009-03-12 19:04:38 -0700612 n = nodbool(1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700613
Ken Thompson610644a2008-06-08 17:21:46 -0700614 nl = n->left;
615 nr = n->right;
616
Rob Pike0cafb9e2008-06-04 14:37:38 -0700617 if(n->type == T) {
618 convlit(n, types[TBOOL]);
619 if(n->type == T)
620 goto ret;
621 }
622
623 et = n->type->etype;
624 if(et != TBOOL) {
625 yyerror("cgen: bad type %T for %O", n->type, n->op);
626 patch(gins(AEND, N, N), to);
627 goto ret;
628 }
629 nl = N;
630 nr = N;
631
632 switch(n->op) {
633 default:
Ken Thompson91ce0ef2009-04-28 13:52:56 -0700634 def:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700635 regalloc(&n1, n->type, N);
636 cgen(n, &n1);
637 nodconst(&n2, n->type, 0);
638 gins(optoas(OCMP, n->type), &n1, &n2);
639 a = AJNE;
640 if(!true)
641 a = AJEQ;
642 patch(gbranch(a, n->type), to);
643 regfree(&n1);
644 goto ret;
645
646 case OLITERAL:
Ken Thompson91ce0ef2009-04-28 13:52:56 -0700647 // need to ask if it is bool?
Ken Thompson9c2ade32008-08-08 17:13:31 -0700648 if(!true == !n->val.u.bval)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700649 patch(gbranch(AJMP, T), to);
650 goto ret;
651
652 case ONAME:
Ken Thompson91ce0ef2009-04-28 13:52:56 -0700653 if(n->addable == 0)
654 goto def;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700655 nodconst(&n1, n->type, 0);
656 gins(optoas(OCMP, n->type), n, &n1);
657 a = AJNE;
658 if(!true)
659 a = AJEQ;
660 patch(gbranch(a, n->type), to);
661 goto ret;
662
663 case OANDAND:
664 if(!true)
665 goto caseor;
666
667 caseand:
668 p1 = gbranch(AJMP, T);
669 p2 = gbranch(AJMP, T);
670 patch(p1, pc);
671 bgen(n->left, !true, p2);
672 bgen(n->right, !true, p2);
673 p1 = gbranch(AJMP, T);
674 patch(p1, to);
675 patch(p2, pc);
676 goto ret;
677
678 case OOROR:
679 if(!true)
680 goto caseand;
681
682 caseor:
683 bgen(n->left, true, to);
684 bgen(n->right, true, to);
685 goto ret;
686
687 case OEQ:
688 case ONE:
689 case OLT:
690 case OGT:
691 case OLE:
692 case OGE:
693 nr = n->right;
694 if(nr == N || nr->type == T)
695 goto ret;
696
697 case ONOT: // unary
698 nl = n->left;
699 if(nl == N || nl->type == T)
700 goto ret;
701 }
702
703 switch(n->op) {
704
705 case ONOT:
706 bgen(nl, !true, to);
707 goto ret;
708
709 case OEQ:
710 case ONE:
711 case OLT:
712 case OGT:
713 case OLE:
714 case OGE:
715 a = n->op;
716 if(!true)
717 a = brcom(a);
718
719 // make simplest on right
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800720 if(nl->op == OLITERAL || nl->ullman < nr->ullman) {
Rob Pike0cafb9e2008-06-04 14:37:38 -0700721 a = brrev(a);
722 r = nl;
723 nl = nr;
724 nr = r;
725 }
Ken Thompson610644a2008-06-08 17:21:46 -0700726
Russ Coxae167bf2009-01-09 15:21:41 -0800727 if(isslice(nl->type)) {
Ken Thompsona91a0a62008-12-19 14:26:52 -0800728 // only valid to cmp darray to literal nil
729 if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
730 yyerror("illegal array comparison");
731 break;
732 }
Ken Thompsondcc064f2008-12-18 21:33:45 -0800733 a = optoas(a, types[tptr]);
734 regalloc(&n1, types[tptr], N);
735 agen(nl, &n1);
736 n2 = n1;
737 n2.op = OINDREG;
Ken Thompson6fa74e02008-12-19 14:04:25 -0800738 n2.xoffset = Array_array;
Ken Thompsondcc064f2008-12-18 21:33:45 -0800739 nodconst(&tmp, types[tptr], 0);
740 gins(optoas(OCMP, types[tptr]), &n2, &tmp);
741 patch(gbranch(a, types[tptr]), to);
742 regfree(&n1);
743 break;
744 }
745
Rob Pike0cafb9e2008-06-04 14:37:38 -0700746 a = optoas(a, nr->type);
747
Ken Thompson610644a2008-06-08 17:21:46 -0700748 if(nr->ullman >= UINF) {
749 regalloc(&n1, nr->type, N);
750 cgen(nr, &n1);
751
752 tempname(&tmp, nr->type);
753 gmove(&n1, &tmp);
754 regfree(&n1);
Russ Cox74e2e082008-10-06 16:44:17 -0700755
Ken Thompson610644a2008-06-08 17:21:46 -0700756 regalloc(&n1, nl->type, N);
757 cgen(nl, &n1);
758
759 regalloc(&n2, nr->type, &n2);
760 cgen(&tmp, &n2);
761
762 gins(optoas(OCMP, nr->type), &n1, &n2);
763 patch(gbranch(a, nr->type), to);
764
765 regfree(&n1);
766 regfree(&n2);
767 break;
768 }
769
Rob Pike0cafb9e2008-06-04 14:37:38 -0700770 regalloc(&n1, nl->type, N);
771 cgen(nl, &n1);
772
Ken Thompson23fc0ac2008-12-14 17:06:06 -0800773 if(smallintconst(nr)) {
774 gins(optoas(OCMP, nr->type), &n1, nr);
775 patch(gbranch(a, nr->type), to);
776 regfree(&n1);
777 break;
778 }
779
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700780 regalloc(&n2, nr->type, N);
781 cgen(nr, &n2);
782
783 gins(optoas(OCMP, nr->type), &n1, &n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700784 patch(gbranch(a, nr->type), to);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700785
Rob Pike0cafb9e2008-06-04 14:37:38 -0700786 regfree(&n1);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700787 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700788 break;
789 }
790 goto ret;
791
792ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700793 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700794}
795
Russ Cox2d259c82009-01-05 17:32:23 -0800796/*
797 * n is on stack, either local variable
798 * or return value from function call.
799 * return n's offset from SP.
800 */
Ken Thompson30fd44c2008-08-21 20:49:04 -0700801int32
802stkof(Node *n)
803{
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700804 Type *t;
805 Iter flist;
806
Ken Thompson30fd44c2008-08-21 20:49:04 -0700807 switch(n->op) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700808 case OINDREG:
809 return n->xoffset;
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700810
811 case OCALLMETH:
812 case OCALLINTER:
813 case OCALL:
814 t = n->left->type;
815 if(isptr[t->etype])
816 t = t->type;
817
818 t = structfirst(&flist, getoutarg(t));
819 if(t != T)
820 return t->width;
821 break;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700822 }
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700823
Ken Thompson30fd44c2008-08-21 20:49:04 -0700824 // botch - probably failing to recognize address
825 // arithmetic on the above. eg INDEX and DOT
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700826 return -1000;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700827}
828
Russ Cox2d259c82009-01-05 17:32:23 -0800829/*
830 * block copy:
831 * memmove(&n, &ns, w);
832 */
Rob Pike0cafb9e2008-06-04 14:37:38 -0700833void
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700834sgen(Node *n, Node *ns, int32 w)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700835{
836 Node nodl, nodr;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700837 int32 c, q, odst, osrc;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700838
Ken Thompson54abac62008-06-21 15:11:29 -0700839 if(debug['g']) {
Ken Thompson40265002008-12-18 20:06:28 -0800840 print("\nsgen w=%d\n", w);
841 dump("r", n);
842 dump("res", ns);
Ken Thompson54abac62008-06-21 15:11:29 -0700843 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700844 if(w == 0)
845 return;
846 if(n->ullman >= UINF && ns->ullman >= UINF) {
847 fatal("sgen UINF");
848 }
849
Russ Cox74e2e082008-10-06 16:44:17 -0700850 if(w < 0)
851 fatal("sgen copy %d", w);
852
Ken Thompson30fd44c2008-08-21 20:49:04 -0700853 // offset on the stack
Ken Thompson30fd44c2008-08-21 20:49:04 -0700854 osrc = stkof(n);
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700855 odst = stkof(ns);
Ken Thompson30fd44c2008-08-21 20:49:04 -0700856
Rob Pike0cafb9e2008-06-04 14:37:38 -0700857 nodreg(&nodl, types[tptr], D_DI);
858 nodreg(&nodr, types[tptr], D_SI);
859
860 if(n->ullman >= ns->ullman) {
861 agen(n, &nodr);
862 agen(ns, &nodl);
863 } else {
864 agen(ns, &nodl);
865 agen(n, &nodr);
866 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700867
Ken Thompson30fd44c2008-08-21 20:49:04 -0700868 c = w % 8; // bytes
869 q = w / 8; // quads
870
871 // if we are copying forward on the stack and
872 // the src and dst overlap, then reverse direction
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700873 if(osrc < odst && odst < osrc+w) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700874 // reverse direction
875 gins(ASTD, N, N); // set direction flag
876 if(c > 0) {
877 gconreg(AADDQ, w-1, D_SI);
878 gconreg(AADDQ, w-1, D_DI);
879
880 gconreg(AMOVQ, c, D_CX);
881 gins(AREP, N, N); // repeat
882 gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
883 }
884
885 if(q > 0) {
886 if(c > 0) {
887 gconreg(AADDQ, -7, D_SI);
888 gconreg(AADDQ, -7, D_DI);
889 } else {
890 gconreg(AADDQ, w-8, D_SI);
891 gconreg(AADDQ, w-8, D_DI);
892 }
893 gconreg(AMOVQ, q, D_CX);
894 gins(AREP, N, N); // repeat
895 gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
896 }
Ken Thompson30fd44c2008-08-21 20:49:04 -0700897 // we leave with the flag clear
898 gins(ACLD, N, N);
899 } else {
900 // normal direction
Ken Thompson8f53bc02008-12-15 15:07:35 -0800901 if(q >= 4) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700902 gconreg(AMOVQ, q, D_CX);
903 gins(AREP, N, N); // repeat
904 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
Ken Thompson8f53bc02008-12-15 15:07:35 -0800905 } else
906 while(q > 0) {
907 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
908 q--;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700909 }
910
Ken Thompson8f53bc02008-12-15 15:07:35 -0800911 if(c >= 4) {
Russ Coxf61639d2009-02-02 13:41:38 -0800912 gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
913 c -= 4;
914 }
Ken Thompson8f53bc02008-12-15 15:07:35 -0800915 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}