blob: fa31c5af2f8cd88246ff400b286717506522a104 [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;
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
Rob Pike0cafb9e2008-06-04 14:37:38 -070051 igen(res, &n1, N);
52 cgen(n, &n1);
53 regfree(&n1);
54 goto ret;
55 }
56
57 if(n->addable) {
58 gmove(n, res);
59 goto ret;
60 }
61
62 nl = n->left;
63 nr = n->right;
64 if(nl != N && nl->ullman >= UINF)
65 if(nr != N && nr->ullman >= UINF) {
Ken Thompson390d5fe2008-06-27 16:59:14 -070066 tempname(&n1, nr->type);
67 cgen(nr, &n1);
68 n2 = *n;
69 n2.right = &n1;
70 cgen(&n2, res);
Rob Pike0cafb9e2008-06-04 14:37:38 -070071 goto ret;
72 }
73
Ken Thompson937ac132008-12-13 13:16:14 -080074 if(sudoaddable(n, res->type, &addr)) {
75 a = optoas(OAS, n->type);
76 if(res->op == OREGISTER) {
77 p1 = gins(a, N, res);
78 p1->from = addr;
79 } else {
80 regalloc(&n1, n->type, N);
81 p1 = gins(a, N, &n1);
82 p1->from = addr;
83 gins(a, &n1, res);
84 regfree(&n1);
85 }
86 return;
87 }
88
Rob Pike0cafb9e2008-06-04 14:37:38 -070089 switch(n->op) {
90 default:
91 dump("cgen", n);
92 fatal("cgen: unknown op %N", n);
93 break;
94
95 // these call bgen to get a bool value
96 case OOROR:
97 case OANDAND:
98 case OEQ:
99 case ONE:
100 case OLT:
101 case OLE:
102 case OGE:
103 case OGT:
104 case ONOT:
105 p1 = gbranch(AJMP, T);
106 p2 = pc;
107 gmove(booltrue, res);
108 p3 = gbranch(AJMP, T);
109 patch(p1, pc);
110 bgen(n, 1, p2);
111 gmove(boolfalse, res);
112 patch(p3, pc);
113 goto ret;
114
115 case OPLUS:
116 cgen(nl, res);
117 goto ret;
118
119 // unary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700120 case OCOM:
Ken Thompsonb89c5382008-08-10 14:35:02 -0700121 a = optoas(OXOR, nl->type);
122 regalloc(&n1, nl->type, N);
123 cgen(nl, &n1);
124 nodconst(&n2, nl->type, -1);
125 gins(a, &n2, &n1);
126 gmove(&n1, res);
127 regfree(&n1);
128 goto ret;
129
130 case OMINUS:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700131 a = optoas(n->op, nl->type);
132 goto uop;
133
134 // symmetric binary
135 case OAND:
136 case OOR:
137 case OXOR:
138 case OADD:
139 case OMUL:
140 a = optoas(n->op, nl->type);
Ken Thompsondc78c642008-11-07 14:20:32 -0800141 if(a != AIMULB)
142 goto sbop;
143 cgen_bmul(n->op, nl, nr, res);
144 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700145
146 // asymmetric binary
Rob Pike0cafb9e2008-06-04 14:37:38 -0700147 case OSUB:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700148 a = optoas(n->op, nl->type);
149 goto abop;
150
151 case OCONV:
152 if(eqtype(n->type, nl->type, 0)) {
153 cgen(nl, res);
154 break;
155 }
156 regalloc(&n1, nl->type, res);
157 cgen(nl, &n1);
Ken Thompsonc6130e92008-08-28 15:17:37 -0700158 if(isptrarray(n->type) && isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700159 // convert dynamic array to static array
160 n2 = n1;
161 n2.op = OINDREG;
162 n2.xoffset = offsetof(Array,array);
163 n2.type = types[tptr];
164 gins(AMOVQ, &n2, &n1);
165 }
Ken Thompsonc6130e92008-08-28 15:17:37 -0700166 if(isptrdarray(n->type) && isptrarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700167 // conver static array to dynamic array
168 // it is assumed that the dope is just before the array
169 nodconst(&n2, types[tptr], offsetof(Array,b));
170 gins(ASUBQ, &n2, &n1);
171 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700172 gmove(&n1, res);
173 regfree(&n1);
174 break;
175
Rob Pike0cafb9e2008-06-04 14:37:38 -0700176 case OINDEXPTR:
177 case OINDEX:
178 case ODOT:
179 case ODOTPTR:
180 case OIND:
181 igen(n, &n1, res);
182 gmove(&n1, res);
183 regfree(&n1);
184 break;
185
186 case OLEN:
187 if(isptrto(nl->type, TSTRING)) {
188 regalloc(&n1, types[tptr], res);
Ken Thompsonb6eca352008-06-08 17:46:28 -0700189 cgen(nl, &n1);
Ken Thompson193eac72008-09-04 17:15:15 -0700190
191 nodconst(&n2, types[tptr], 0);
192 gins(optoas(OCMP, types[tptr]), &n1, &n2);
193 p1 = gbranch(optoas(OEQ, types[tptr]), T);
194
Ken Thompsone081f252008-11-22 17:58:53 -0800195 n2 = n1;
196 n2.op = OINDREG;
197 n2.type = types[TINT32];
198 gmove(&n2, &n1);
Ken Thompson193eac72008-09-04 17:15:15 -0700199
200 patch(p1, pc);
201
Ken Thompsone081f252008-11-22 17:58:53 -0800202 gmove(&n1, res);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700203 regfree(&n1);
204 break;
205 }
Ken Thompson87dae022008-06-24 14:11:20 -0700206 if(isptrto(nl->type, TMAP)) {
207 regalloc(&n1, types[tptr], res);
208 cgen(nl, &n1);
209 n1.op = OINDREG;
210 n1.type = types[TINT32];
211 gmove(&n1, res);
212 regfree(&n1);
213 break;
214 }
Ken Thompsonc6130e92008-08-28 15:17:37 -0700215 if(isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700216 regalloc(&n1, types[tptr], res);
217 cgen(nl, &n1);
218 n1.op = OINDREG;
219 n1.type = types[TUINT32];
220 n1.xoffset = offsetof(Array,nel);
221 gmove(&n1, res);
222 regfree(&n1);
223 break;
224 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700225 fatal("cgen: OLEN: unknown type %lT", nl->type);
226 break;
227
Ken Thompson66a603c2008-08-27 17:28:30 -0700228 case OCAP:
Ken Thompsonc6130e92008-08-28 15:17:37 -0700229 if(isptrdarray(nl->type)) {
Ken Thompson66a603c2008-08-27 17:28:30 -0700230 regalloc(&n1, types[tptr], res);
231 cgen(nl, &n1);
232 n1.op = OINDREG;
233 n1.type = types[TUINT32];
234 n1.xoffset = offsetof(Array,cap);
235 gmove(&n1, res);
236 regfree(&n1);
237 break;
238 }
239 fatal("cgen: OCAP: unknown type %lT", nl->type);
240 break;
241
Rob Pike0cafb9e2008-06-04 14:37:38 -0700242 case OADDR:
243 agen(nl, res);
244 break;
245
246 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700247 cgen_callmeth(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700248 cgen_callret(n, res);
249 break;
250
251 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700252 cgen_callinter(n, res, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700253 cgen_callret(n, res);
254 break;
255
256 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700257 cgen_call(n, 0);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700258 cgen_callret(n, res);
259 break;
Ken Thompsond83b9942008-06-06 20:43:29 -0700260
261 case OMOD:
262 case ODIV:
Ken Thompson6a659eb2008-06-09 13:16:50 -0700263 if(isfloat[n->type->etype]) {
264 a = optoas(n->op, nl->type);
265 goto abop;
266 }
Ken Thompsond83b9942008-06-06 20:43:29 -0700267 cgen_div(n->op, nl, nr, res);
268 break;
Ken Thompson610644a2008-06-08 17:21:46 -0700269
Ken Thompsonf7753f12008-06-07 15:21:02 -0700270 case OLSH:
271 case ORSH:
272 cgen_shift(n->op, nl, nr, res);
273 break;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700274 }
275 goto ret;
276
277sbop: // symmetric binary
278 if(nl->ullman < nr->ullman) {
279 r = nl;
280 nl = nr;
281 nr = r;
282 }
283
284abop: // asymmetric binary
Ken Thompsonf7753f12008-06-07 15:21:02 -0700285 if(nl->ullman >= nr->ullman) {
Rob Pike0cafb9e2008-06-04 14:37:38 -0700286 regalloc(&n1, nl->type, res);
287 cgen(nl, &n1);
Ken Thompson937ac132008-12-13 13:16:14 -0800288
289if(sudoaddable(nr, nl->type, &addr)) {
290 p1 = gins(a, N, &n1);
291 p1->from = addr;
292 gmove(&n1, res);
293 regfree(&n1);
294 goto ret;
295}
296
Ken Thompsonf7753f12008-06-07 15:21:02 -0700297 regalloc(&n2, nr->type, N);
298 cgen(nr, &n2);
299 } else {
300 regalloc(&n2, nr->type, N);
301 cgen(nr, &n2);
302 regalloc(&n1, nl->type, res);
303 cgen(nl, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700304 }
Ken Thompsonf7753f12008-06-07 15:21:02 -0700305 gins(a, &n2, &n1);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700306 gmove(&n1, res);
307 regfree(&n1);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700308 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700309 goto ret;
310
311uop: // unary
312 regalloc(&n1, nl->type, res);
313 cgen(nl, &n1);
314 gins(a, N, &n1);
315 gmove(&n1, res);
316 regfree(&n1);
317 goto ret;
318
319ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700320 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700321}
322
323void
324agen(Node *n, Node *res)
325{
326 Node *nl, *nr;
327 Node n1, n2, n3, tmp;
Ken Thompson66a603c2008-08-27 17:28:30 -0700328 Prog *p1;
Russ Cox9aad9fe2008-08-03 17:25:15 -0700329 uint32 w;
Ken Thompson904d4042008-09-12 16:48:35 -0700330 uint64 v;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700331 Type *t;
Ken Thompson54abac62008-06-21 15:11:29 -0700332
333 if(debug['g']) {
334 dump("\nagen-res", res);
335 dump("agen-r", n);
336 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700337 if(n == N || n->type == T)
338 return;
339
340 if(!isptr[res->type->etype])
341 fatal("agen: not tptr: %T", res->type);
342
343 if(n->addable) {
344 regalloc(&n1, types[tptr], res);
345 gins(ALEAQ, n, &n1);
346 gmove(&n1, res);
347 regfree(&n1);
Ken Thompson610644a2008-06-08 17:21:46 -0700348 goto ret;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700349 }
350
Ken Thompson610644a2008-06-08 17:21:46 -0700351 nl = n->left;
352 nr = n->right;
353
Rob Pike0cafb9e2008-06-04 14:37:38 -0700354 switch(n->op) {
355 default:
356 fatal("agen: unknown op %N", n);
357 break;
358
Ken Thompson54abac62008-06-21 15:11:29 -0700359 case OCALLMETH:
Ken Thompson1d31a252008-07-07 17:59:32 -0700360 cgen_callmeth(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700361 cgen_aret(n, res);
362 break;
363
364 case OCALLINTER:
Ken Thompson1d31a252008-07-07 17:59:32 -0700365 cgen_callinter(n, res, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700366 cgen_aret(n, res);
367 break;
368
369 case OCALL:
Ken Thompson1d31a252008-07-07 17:59:32 -0700370 cgen_call(n, 0);
Ken Thompson54abac62008-06-21 15:11:29 -0700371 cgen_aret(n, res);
372 break;
373
Rob Pike0cafb9e2008-06-04 14:37:38 -0700374 case OINDEXPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700375 w = n->type->width;
376 if(nr->addable)
377 goto iprad;
378 if(nl->addable) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800379 if(whatis(nr) != Wlitint) {
380 regalloc(&n1, nr->type, N);
381 cgen(nr, &n1);
382 }
383 regalloc(&n3, types[tptr], res);
384 cgen(nl, &n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700385 goto index;
386 }
387 cgen(nr, res);
388 tempname(&tmp, nr->type);
389 gmove(res, &tmp);
390
391 iprad:
Ken Thompsona6182da2008-11-23 17:26:49 -0800392 regalloc(&n3, types[tptr], res);
393 cgen(nl, &n3);
394 if(whatis(nr) != Wlitint) {
395 regalloc(&n1, nr->type, N);
396 cgen(nr, &n1);
397 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700398 goto index;
399
Rob Pike0cafb9e2008-06-04 14:37:38 -0700400 case OINDEX:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700401 w = n->type->width;
402 if(nr->addable)
403 goto irad;
404 if(nl->addable) {
Ken Thompsona6182da2008-11-23 17:26:49 -0800405 if(whatis(nr) != Wlitint) {
406 regalloc(&n1, nr->type, N);
407 cgen(nr, &n1);
408 }
409 regalloc(&n3, types[tptr], res);
410 agen(nl, &n3);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700411 goto index;
412 }
413 cgen(nr, res);
414 tempname(&tmp, nr->type);
415 gmove(res, &tmp);
416
417 irad:
Ken Thompsona6182da2008-11-23 17:26:49 -0800418 regalloc(&n3, types[tptr], res);
419 agen(nl, &n3);
420 if(whatis(nr) != Wlitint) {
421 regalloc(&n1, nr->type, N);
422 cgen(nr, &n1);
423 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700424 goto index;
425
426 index:
Ken Thompsona6182da2008-11-23 17:26:49 -0800427 // &a is in &n3 (allocated in res)
428 // i is in &n1 (if not constant)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700429 // w is width
Ken Thompson66a603c2008-08-27 17:28:30 -0700430
Ken Thompson85457002008-09-26 17:41:23 -0700431 if(w == 0)
432 fatal("index is zero width");
433
Ken Thompson8e3fe102008-11-24 14:01:12 -0800434 // constant index
Ken Thompson904d4042008-09-12 16:48:35 -0700435 if(whatis(nr) == Wlitint) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800436 v = mpgetfix(nr->val.u.xval);
Ken Thompsona6182da2008-11-23 17:26:49 -0800437 if(isptrdarray(nl->type)) {
Ken Thompson8e3fe102008-11-24 14:01:12 -0800438
439 if(!debug['B']) {
440 n1 = n3;
441 n1.op = OINDREG;
442 n1.type = types[tptr];
443 n1.xoffset = offsetof(Array, nel);
444 nodconst(&n2, types[TUINT64], v);
445 gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
446 p1 = gbranch(optoas(OGT, types[TUINT32]), T);
447 gins(ACALL, N, throwindex);
448 patch(p1, pc);
449 }
450
Ken Thompsona6182da2008-11-23 17:26:49 -0800451 n1 = n3;
452 n1.op = OINDREG;
453 n1.type = types[tptr];
454 n1.xoffset = offsetof(Array, array);
455 gmove(&n1, &n3);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800456 } else
457 if(!debug['B']) {
458 if(v < 0)
459 yyerror("out of bounds on array");
460 else
461 if(isptrarray(nl->type)) {
462 if(v >= nl->type->type->bound)
463 yyerror("out of bounds on array");
464 } else
465 if(v >= nl->type->bound)
466 yyerror("out of bounds on array");
Ken Thompsona6182da2008-11-23 17:26:49 -0800467 }
Ken Thompson8e3fe102008-11-24 14:01:12 -0800468
Ken Thompson904d4042008-09-12 16:48:35 -0700469 nodconst(&n2, types[tptr], v*w);
Ken Thompsona6182da2008-11-23 17:26:49 -0800470 gins(optoas(OADD, types[tptr]), &n2, &n3);
Ken Thompson8e3fe102008-11-24 14:01:12 -0800471
Ken Thompsona6182da2008-11-23 17:26:49 -0800472 gmove(&n3, res);
473 regfree(&n3);
Ken Thompson904d4042008-09-12 16:48:35 -0700474 break;
475 }
476
Ken Thompsona6182da2008-11-23 17:26:49 -0800477 // type of the index
Ken Thompson66a603c2008-08-27 17:28:30 -0700478 t = types[TUINT64];
Ken Thompsonf7753f12008-06-07 15:21:02 -0700479 if(issigned[n1.type->etype])
Ken Thompson66a603c2008-08-27 17:28:30 -0700480 t = types[TINT64];
481
482 regalloc(&n2, t, &n1); // i
Ken Thompsonf7753f12008-06-07 15:21:02 -0700483 gmove(&n1, &n2);
Ken Thompsonf7753f12008-06-07 15:21:02 -0700484 regfree(&n1);
Ken Thompson66a603c2008-08-27 17:28:30 -0700485
Ken Thompsona6182da2008-11-23 17:26:49 -0800486 if(!debug['B']) {
487 // check bounds
488 if(isptrdarray(nl->type)) {
489 n1 = n3;
490 n1.op = OINDREG;
491 n1.type = types[tptr];
492 n1.xoffset = offsetof(Array, nel);
493 } else {
494 nodconst(&n1, types[TUINT64], nl->type->bound);
495 if(isptrarray(nl->type))
496 nodconst(&n1, types[TUINT64], nl->type->type->bound);
497 }
Ken Thompson8e3fe102008-11-24 14:01:12 -0800498 gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
499 p1 = gbranch(optoas(OLT, types[TUINT32]), T);
Ken Thompsona6182da2008-11-23 17:26:49 -0800500 gins(ACALL, N, throwindex);
501 patch(p1, pc);
502 }
503
Ken Thompsona6182da2008-11-23 17:26:49 -0800504 if(isptrdarray(nl->type)) {
505 n1 = n3;
506 n1.op = OINDREG;
507 n1.type = types[tptr];
508 n1.xoffset = offsetof(Array, array);
509 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
Ken Thompsone1a06cc2008-06-15 20:24:30 -0700529 case OIND:
530 cgen(nl, res);
531 break;
Russ Cox74e2e082008-10-06 16:44:17 -0700532
Rob Pike0cafb9e2008-06-04 14:37:38 -0700533 case ODOT:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700534 t = nl->type;
535 agen(nl, res);
536 if(n->xoffset != 0) {
537 nodconst(&n1, types[TINT64], n->xoffset);
538 gins(optoas(OADD, types[tptr]), &n1, res);
539 }
540 break;
541
542 case ODOTPTR:
Rob Pike0cafb9e2008-06-04 14:37:38 -0700543 t = nl->type;
544 if(!isptr[t->etype])
545 fatal("agen: not ptr %N", n);
546 cgen(nl, res);
547 if(n->xoffset != 0) {
548 nodconst(&n1, types[TINT64], n->xoffset);
549 gins(optoas(OADD, types[tptr]), &n1, res);
550 }
551 break;
552 }
Ken Thompson610644a2008-06-08 17:21:46 -0700553
554ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700555 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700556}
557
558vlong
559fieldoffset(Type *t, Node *n)
560{
561 if(t->etype != TSTRUCT)
562 fatal("fieldoffset: not struct %lT", t);
563 if(n->op != ONAME)
564 fatal("fieldoffset: not field name %N", n);
565 return 0;
566}
567
568void
569igen(Node *n, Node *a, Node *res)
570{
571 regalloc(a, types[tptr], res);
572 agen(n, a);
573 a->op = OINDREG;
574 a->type = n->type;
575}
576
577void
578bgen(Node *n, int true, Prog *to)
579{
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700580 int et, a;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700581 Node *nl, *nr, *r;
Ken Thompson610644a2008-06-08 17:21:46 -0700582 Node n1, n2, tmp;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700583 Prog *p1, *p2;
584
Ken Thompson54abac62008-06-21 15:11:29 -0700585 if(debug['g']) {
586 dump("\nbgen", n);
587 }
Ken Thompsond3237f92008-06-28 17:27:39 -0700588
Rob Pike0cafb9e2008-06-04 14:37:38 -0700589 if(n == N)
590 n = booltrue;
591
Ken Thompson610644a2008-06-08 17:21:46 -0700592 nl = n->left;
593 nr = n->right;
594
Rob Pike0cafb9e2008-06-04 14:37:38 -0700595 if(n->type == T) {
596 convlit(n, types[TBOOL]);
597 if(n->type == T)
598 goto ret;
599 }
600
601 et = n->type->etype;
602 if(et != TBOOL) {
603 yyerror("cgen: bad type %T for %O", n->type, n->op);
604 patch(gins(AEND, N, N), to);
605 goto ret;
606 }
607 nl = N;
608 nr = N;
609
610 switch(n->op) {
611 default:
612 regalloc(&n1, n->type, N);
613 cgen(n, &n1);
614 nodconst(&n2, n->type, 0);
615 gins(optoas(OCMP, n->type), &n1, &n2);
616 a = AJNE;
617 if(!true)
618 a = AJEQ;
619 patch(gbranch(a, n->type), to);
620 regfree(&n1);
621 goto ret;
622
623 case OLITERAL:
Ken Thompson9c2ade32008-08-08 17:13:31 -0700624// need to ask if it is bool?
625 if(!true == !n->val.u.bval)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700626 patch(gbranch(AJMP, T), to);
627 goto ret;
628
629 case ONAME:
630 nodconst(&n1, n->type, 0);
631 gins(optoas(OCMP, n->type), n, &n1);
632 a = AJNE;
633 if(!true)
634 a = AJEQ;
635 patch(gbranch(a, n->type), to);
636 goto ret;
637
638 case OANDAND:
639 if(!true)
640 goto caseor;
641
642 caseand:
643 p1 = gbranch(AJMP, T);
644 p2 = gbranch(AJMP, T);
645 patch(p1, pc);
646 bgen(n->left, !true, p2);
647 bgen(n->right, !true, p2);
648 p1 = gbranch(AJMP, T);
649 patch(p1, to);
650 patch(p2, pc);
651 goto ret;
652
653 case OOROR:
654 if(!true)
655 goto caseand;
656
657 caseor:
658 bgen(n->left, true, to);
659 bgen(n->right, true, to);
660 goto ret;
661
662 case OEQ:
663 case ONE:
664 case OLT:
665 case OGT:
666 case OLE:
667 case OGE:
668 nr = n->right;
669 if(nr == N || nr->type == T)
670 goto ret;
671
672 case ONOT: // unary
673 nl = n->left;
674 if(nl == N || nl->type == T)
675 goto ret;
676 }
677
678 switch(n->op) {
679
680 case ONOT:
681 bgen(nl, !true, to);
682 goto ret;
683
684 case OEQ:
685 case ONE:
686 case OLT:
687 case OGT:
688 case OLE:
689 case OGE:
690 a = n->op;
691 if(!true)
692 a = brcom(a);
693
694 // make simplest on right
695 if(nl->ullman < nr->ullman) {
696 a = brrev(a);
697 r = nl;
698 nl = nr;
699 nr = r;
700 }
Ken Thompson610644a2008-06-08 17:21:46 -0700701
Rob Pike0cafb9e2008-06-04 14:37:38 -0700702 a = optoas(a, nr->type);
703
Ken Thompson610644a2008-06-08 17:21:46 -0700704 if(nr->ullman >= UINF) {
705 regalloc(&n1, nr->type, N);
706 cgen(nr, &n1);
707
708 tempname(&tmp, nr->type);
709 gmove(&n1, &tmp);
710 regfree(&n1);
Russ Cox74e2e082008-10-06 16:44:17 -0700711
Ken Thompson610644a2008-06-08 17:21:46 -0700712 regalloc(&n1, nl->type, N);
713 cgen(nl, &n1);
714
715 regalloc(&n2, nr->type, &n2);
716 cgen(&tmp, &n2);
717
718 gins(optoas(OCMP, nr->type), &n1, &n2);
719 patch(gbranch(a, nr->type), to);
720
721 regfree(&n1);
722 regfree(&n2);
723 break;
724 }
725
726
Rob Pike0cafb9e2008-06-04 14:37:38 -0700727 regalloc(&n1, nl->type, N);
728 cgen(nl, &n1);
729
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700730 regalloc(&n2, nr->type, N);
731 cgen(nr, &n2);
732
733 gins(optoas(OCMP, nr->type), &n1, &n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700734 patch(gbranch(a, nr->type), to);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700735
Rob Pike0cafb9e2008-06-04 14:37:38 -0700736 regfree(&n1);
Ken Thompson36bfd2a2008-06-08 16:11:14 -0700737 regfree(&n2);
Rob Pike0cafb9e2008-06-04 14:37:38 -0700738 break;
739 }
740 goto ret;
741
742ret:
Ken Thompsond3237f92008-06-28 17:27:39 -0700743 ;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700744}
745
Ken Thompson30fd44c2008-08-21 20:49:04 -0700746int32
747stkof(Node *n)
748{
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700749 Type *t;
750 Iter flist;
751
Ken Thompson30fd44c2008-08-21 20:49:04 -0700752 switch(n->op) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700753 case OINDREG:
754 return n->xoffset;
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700755
756 case OCALLMETH:
757 case OCALLINTER:
758 case OCALL:
759 t = n->left->type;
760 if(isptr[t->etype])
761 t = t->type;
762
763 t = structfirst(&flist, getoutarg(t));
764 if(t != T)
765 return t->width;
766 break;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700767 }
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700768
Ken Thompson30fd44c2008-08-21 20:49:04 -0700769 // botch - probably failing to recognize address
770 // arithmetic on the above. eg INDEX and DOT
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700771 return -1000;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700772}
773
Rob Pike0cafb9e2008-06-04 14:37:38 -0700774void
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700775sgen(Node *n, Node *ns, int32 w)
Rob Pike0cafb9e2008-06-04 14:37:38 -0700776{
777 Node nodl, nodr;
Ken Thompson30fd44c2008-08-21 20:49:04 -0700778 int32 c, q, odst, osrc;
Rob Pike0cafb9e2008-06-04 14:37:38 -0700779
Ken Thompson54abac62008-06-21 15:11:29 -0700780 if(debug['g']) {
781 dump("\nsgen-res", ns);
782 dump("sgen-r", n);
783 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700784 if(w == 0)
785 return;
786 if(n->ullman >= UINF && ns->ullman >= UINF) {
787 fatal("sgen UINF");
788 }
789
Russ Cox74e2e082008-10-06 16:44:17 -0700790 if(w < 0)
791 fatal("sgen copy %d", w);
792
Ken Thompson30fd44c2008-08-21 20:49:04 -0700793 // offset on the stack
Ken Thompson30fd44c2008-08-21 20:49:04 -0700794 osrc = stkof(n);
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700795 odst = stkof(ns);
796//print("\nnsrc=%N\n", n);
797//print("ndst=%N\n", ns);
798//print("osrc=%d odst=%d w=%d\n", osrc, odst, w);
Ken Thompson30fd44c2008-08-21 20:49:04 -0700799
Rob Pike0cafb9e2008-06-04 14:37:38 -0700800 nodreg(&nodl, types[tptr], D_DI);
801 nodreg(&nodr, types[tptr], D_SI);
802
803 if(n->ullman >= ns->ullman) {
804 agen(n, &nodr);
805 agen(ns, &nodl);
806 } else {
807 agen(ns, &nodl);
808 agen(n, &nodr);
809 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700810
Ken Thompson30fd44c2008-08-21 20:49:04 -0700811 c = w % 8; // bytes
812 q = w / 8; // quads
813
814 // if we are copying forward on the stack and
815 // the src and dst overlap, then reverse direction
Ken Thompsonadaec0c2008-09-22 16:58:30 -0700816 if(osrc < odst && odst < osrc+w) {
Ken Thompson30fd44c2008-08-21 20:49:04 -0700817 // reverse direction
818 gins(ASTD, N, N); // set direction flag
819 if(c > 0) {
820 gconreg(AADDQ, w-1, D_SI);
821 gconreg(AADDQ, w-1, D_DI);
822
823 gconreg(AMOVQ, c, D_CX);
824 gins(AREP, N, N); // repeat
825 gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
826 }
827
828 if(q > 0) {
829 if(c > 0) {
830 gconreg(AADDQ, -7, D_SI);
831 gconreg(AADDQ, -7, D_DI);
832 } else {
833 gconreg(AADDQ, w-8, D_SI);
834 gconreg(AADDQ, w-8, D_DI);
835 }
836 gconreg(AMOVQ, q, D_CX);
837 gins(AREP, N, N); // repeat
838 gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
839 }
840 // for future optimization
841 // we leave with the flag clear
842 gins(ACLD, N, N);
843 } else {
844 // normal direction
845 gins(ACLD, N, N); // clear direction flag
846 if(q > 0) {
847 gconreg(AMOVQ, q, D_CX);
848 gins(AREP, N, N); // repeat
849 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
850 }
851
852 if(c > 0) {
853 gconreg(AMOVQ, c, D_CX);
854 gins(AREP, N, N); // repeat
855 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
856 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700857 }
Rob Pike0cafb9e2008-06-04 14:37:38 -0700858}