blob: 89a5e42697e95eed760e5e144bdcd185879b3587 [file] [log] [blame]
Russ Coxdc5b4672009-03-31 00:22:59 -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#undef EXTERN
6#define EXTERN
7#include "gg.h"
Ken Thompson0eb2a792009-11-06 16:51:49 -08008#include "opt.h"
Russ Coxdc5b4672009-03-31 00:22:59 -07009
10void
Luuk van Dijke59aa8e2011-06-02 18:48:17 +020011defframe(Prog *ptxt)
Russ Coxdc5b4672009-03-31 00:22:59 -070012{
Russ Coxdc5b4672009-03-31 00:22:59 -070013 // fill in argument size
Russ Coxe7a0f672010-12-13 11:57:41 -050014 ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
Russ Coxdc5b4672009-03-31 00:22:59 -070015
16 // fill in final stack size
Russ Cox6b070212009-04-02 16:48:06 -070017 if(stksize > maxstksize)
18 maxstksize = stksize;
Russ Coxe7a0f672010-12-13 11:57:41 -050019 ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
Russ Cox6b070212009-04-02 16:48:06 -070020 maxstksize = 0;
Russ Coxdc5b4672009-03-31 00:22:59 -070021}
22
Luuk van Dijk2ad42a82011-06-14 17:03:37 +020023// Sweep the prog list to mark any used nodes.
24void
25markautoused(Prog* p)
26{
27 for (; p; p = p->link) {
28 if (p->from.type == D_AUTO && p->from.node)
29 p->from.node->used++;
30
31 if (p->to.type == D_AUTO && p->to.node)
32 p->to.node->used++;
33 }
34}
35
36// Fixup instructions after compactframe has moved all autos around.
37void
38fixautoused(Prog* p)
39{
40 for (; p; p = p->link) {
41 if (p->from.type == D_AUTO && p->from.node)
42 p->from.offset += p->from.node->stkdelta;
43
44 if (p->to.type == D_AUTO && p->to.node)
45 p->to.offset += p->to.node->stkdelta;
46 }
47}
48
Russ Coxdc5b4672009-03-31 00:22:59 -070049void
50clearfat(Node *nl)
51{
Russ Cox5ecd0102009-05-26 16:23:54 -070052 uint32 w, c, q;
53 Node n1;
54
55 /* clear a fat object */
56 if(debug['g'])
57 dump("\nclearfat", nl);
58
59 w = nl->type->width;
60 c = w % 4; // bytes
61 q = w / 4; // quads
62
63 gconreg(AMOVL, 0, D_AX);
64 nodreg(&n1, types[tptr], D_DI);
65 agen(nl, &n1);
66
67 if(q >= 4) {
68 gconreg(AMOVL, q, D_CX);
69 gins(AREP, N, N); // repeat
70 gins(ASTOSL, N, N); // STOL AL,*(DI)+
71 } else
72 while(q > 0) {
73 gins(ASTOSL, N, N); // STOL AL,*(DI)+
74 q--;
75 }
76
77 if(c >= 4) {
78 gconreg(AMOVL, c, D_CX);
79 gins(AREP, N, N); // repeat
80 gins(ASTOSB, N, N); // STOB AL,*(DI)+
81 } else
82 while(c > 0) {
83 gins(ASTOSB, N, N); // STOB AL,*(DI)+
84 c--;
85 }
Russ Coxdc5b4672009-03-31 00:22:59 -070086}
87
88/*
89 * generate:
90 * call f
91 * proc=0 normal call
92 * proc=1 goroutine run in new proc
93 * proc=2 defer call save away stack
94 */
95void
96ginscall(Node *f, int proc)
97{
98 Prog *p;
99 Node reg, con;
100
101 switch(proc) {
102 default:
103 fatal("ginscall: bad proc %d", proc);
104 break;
105
106 case 0: // normal call
107 p = gins(ACALL, N, f);
108 afunclit(&p->to);
109 break;
110
111 case 1: // call in new proc (go)
Russ Cox9b1507b2010-03-31 11:46:01 -0700112 case 2: // deferred call (defer)
113 nodreg(&reg, types[TINT32], D_CX);
Russ Coxdc5b4672009-03-31 00:22:59 -0700114 gins(APUSHL, f, N);
115 nodconst(&con, types[TINT32], argsize(f->type));
116 gins(APUSHL, &con, N);
117 if(proc == 1)
118 ginscall(newproc, 0);
119 else
120 ginscall(deferproc, 0);
121 gins(APOPL, N, &reg);
122 gins(APOPL, N, &reg);
Russ Cox9b1507b2010-03-31 11:46:01 -0700123 if(proc == 2) {
124 nodreg(&reg, types[TINT64], D_AX);
125 gins(ATESTL, &reg, &reg);
Luuk van Dijke59aa8e2011-06-02 18:48:17 +0200126 patch(gbranch(AJNE, T), retpc);
Russ Cox9b1507b2010-03-31 11:46:01 -0700127 }
Russ Coxdc5b4672009-03-31 00:22:59 -0700128 break;
129 }
130}
131
132/*
133 * n is call to interface method.
134 * generate res = n.
135 */
136void
137cgen_callinter(Node *n, Node *res, int proc)
138{
Russ Coxa8e4ed62009-05-26 21:07:26 -0700139 Node *i, *f;
140 Node tmpi, nodo, nodr, nodsp;
141
142 i = n->left;
143 if(i->op != ODOTINTER)
144 fatal("cgen_callinter: not ODOTINTER %O", i->op);
145
146 f = i->right; // field
147 if(f->op != ONAME)
148 fatal("cgen_callinter: not ONAME %O", f->op);
149
150 i = i->left; // interface
151
152 if(!i->addable) {
Russ Cox69c0edd2009-12-02 18:31:29 -0800153 tempname(&tmpi, i->type);
Russ Coxa8e4ed62009-05-26 21:07:26 -0700154 cgen(i, &tmpi);
155 i = &tmpi;
156 }
157
Russ Coxe52e9ca2009-07-17 01:00:44 -0700158 genlist(n->list); // assign the args
Russ Coxa8e4ed62009-05-26 21:07:26 -0700159
160 // Can regalloc now; i is known to be addable,
161 // so the agen will be easy.
162 regalloc(&nodr, types[tptr], res);
163 regalloc(&nodo, types[tptr], &nodr);
164 nodo.op = OINDREG;
165
166 agen(i, &nodr); // REG = &inter
167
168 nodindreg(&nodsp, types[tptr], D_SP);
169 nodo.xoffset += widthptr;
170 cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.s
171
172 nodo.xoffset -= widthptr;
173 cgen(&nodo, &nodr); // REG = 0(REG) -- i.m
174
Russ Cox4589c342010-02-18 18:31:13 -0800175 if(n->left->xoffset == BADWIDTH)
176 fatal("cgen_callinter: badwidth");
Russ Cox9a9ffb22009-06-04 15:24:01 -0700177 nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
Russ Coxa8e4ed62009-05-26 21:07:26 -0700178 cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.m->fun[f]
179
180 // BOTCH nodr.type = fntype;
181 nodr.type = n->left->type;
182 ginscall(&nodr, proc);
183
184 regfree(&nodr);
185 regfree(&nodo);
186
187 setmaxarg(n->left->type);
Russ Coxdc5b4672009-03-31 00:22:59 -0700188}
189
190/*
191 * generate function call;
192 * proc=0 normal call
193 * proc=1 goroutine run in new proc
194 * proc=2 defer call save away stack
195 */
196void
197cgen_call(Node *n, int proc)
198{
Russ Cox6b070212009-04-02 16:48:06 -0700199 Type *t;
200 Node nod, afun;
201
202 if(n == N)
203 return;
204
205 if(n->left->ullman >= UINF) {
206 // if name involves a fn call
207 // precompute the address of the fn
Russ Cox69c0edd2009-12-02 18:31:29 -0800208 tempname(&afun, types[tptr]);
Russ Cox6b070212009-04-02 16:48:06 -0700209 cgen(n->left, &afun);
210 }
211
Russ Coxe52e9ca2009-07-17 01:00:44 -0700212 genlist(n->list); // assign the args
Russ Cox6b070212009-04-02 16:48:06 -0700213 t = n->left->type;
214
215 setmaxarg(t);
216
217 // call tempname pointer
218 if(n->left->ullman >= UINF) {
219 regalloc(&nod, types[tptr], N);
220 cgen_as(&nod, &afun);
Russ Cox6b070212009-04-02 16:48:06 -0700221 nod.type = t;
222 ginscall(&nod, proc);
223 regfree(&nod);
224 return;
225 }
226
227 // call pointer
228 if(n->left->op != ONAME || n->left->class != PFUNC) {
229 regalloc(&nod, types[tptr], N);
230 cgen_as(&nod, n->left);
231 nod.type = t;
232 ginscall(&nod, proc);
233 regfree(&nod);
234 return;
235 }
236
237 // call direct
238 n->left->method = 1;
239 ginscall(n->left, proc);
240}
241
242/*
243 * call to n has already been generated.
244 * generate:
245 * res = return value from call.
246 */
247void
248cgen_callret(Node *n, Node *res)
249{
250 Node nod;
251 Type *fp, *t;
252 Iter flist;
253
254 t = n->left->type;
255 if(t->etype == TPTR32 || t->etype == TPTR64)
256 t = t->type;
257
258 fp = structfirst(&flist, getoutarg(t));
259 if(fp == T)
260 fatal("cgen_callret: nil");
261
262 memset(&nod, 0, sizeof(nod));
263 nod.op = OINDREG;
264 nod.val.u.reg = D_SP;
265 nod.addable = 1;
266
267 nod.xoffset = fp->width;
268 nod.type = fp->type;
269 cgen_as(res, &nod);
270}
271
272/*
273 * call to n has already been generated.
274 * generate:
275 * res = &return value from call.
276 */
277void
278cgen_aret(Node *n, Node *res)
279{
280 Node nod1, nod2;
281 Type *fp, *t;
282 Iter flist;
283
284 t = n->left->type;
285 if(isptr[t->etype])
286 t = t->type;
287
288 fp = structfirst(&flist, getoutarg(t));
289 if(fp == T)
290 fatal("cgen_aret: nil");
291
292 memset(&nod1, 0, sizeof(nod1));
293 nod1.op = OINDREG;
294 nod1.val.u.reg = D_SP;
295 nod1.addable = 1;
296
297 nod1.xoffset = fp->width;
298 nod1.type = fp->type;
299
300 if(res->op != OREGISTER) {
301 regalloc(&nod2, types[tptr], res);
302 gins(ALEAL, &nod1, &nod2);
303 gins(AMOVL, &nod2, res);
304 regfree(&nod2);
305 } else
306 gins(ALEAL, &nod1, res);
Russ Coxdc5b4672009-03-31 00:22:59 -0700307}
308
309/*
310 * generate return.
311 * n->left is assignments to return values.
312 */
313void
314cgen_ret(Node *n)
315{
Russ Coxe52e9ca2009-07-17 01:00:44 -0700316 genlist(n->list); // copy out args
Luuk van Dijke59aa8e2011-06-02 18:48:17 +0200317 if(retpc)
318 gjmp(retpc);
Russ Cox97d0e8f2010-03-26 18:01:02 -0700319 else
320 gins(ARET, N, N);
Russ Coxdc5b4672009-03-31 00:22:59 -0700321}
322
323/*
324 * generate += *= etc.
325 */
326void
327cgen_asop(Node *n)
328{
Russ Cox5ecd0102009-05-26 16:23:54 -0700329 Node n1, n2, n3, n4;
330 Node *nl, *nr;
331 Prog *p1;
332 Addr addr;
333 int a;
334
335 nl = n->left;
336 nr = n->right;
337
338 if(nr->ullman >= UINF && nl->ullman >= UINF) {
Russ Cox69c0edd2009-12-02 18:31:29 -0800339 tempname(&n1, nr->type);
Russ Cox5ecd0102009-05-26 16:23:54 -0700340 cgen(nr, &n1);
341 n2 = *n;
342 n2.right = &n1;
343 cgen_asop(&n2);
344 goto ret;
345 }
346
347 if(!isint[nl->type->etype])
348 goto hard;
349 if(!isint[nr->type->etype])
350 goto hard;
Russ Coxa8e4ed62009-05-26 21:07:26 -0700351 if(is64(nl->type) || is64(nr->type))
352 goto hard;
Russ Cox5ecd0102009-05-26 16:23:54 -0700353
354 switch(n->etype) {
355 case OADD:
356 if(smallintconst(nr))
357 if(mpgetfix(nr->val.u.xval) == 1) {
358 a = optoas(OINC, nl->type);
359 if(nl->addable) {
360 gins(a, N, nl);
361 goto ret;
362 }
363 if(sudoaddable(a, nl, &addr)) {
364 p1 = gins(a, N, N);
365 p1->to = addr;
366 sudoclean();
367 goto ret;
368 }
369 }
370 break;
371
372 case OSUB:
373 if(smallintconst(nr))
374 if(mpgetfix(nr->val.u.xval) == 1) {
375 a = optoas(ODEC, nl->type);
376 if(nl->addable) {
377 gins(a, N, nl);
378 goto ret;
379 }
380 if(sudoaddable(a, nl, &addr)) {
381 p1 = gins(a, N, N);
382 p1->to = addr;
383 sudoclean();
384 goto ret;
385 }
386 }
387 break;
388 }
389
390 switch(n->etype) {
391 case OADD:
392 case OSUB:
393 case OXOR:
394 case OAND:
395 case OOR:
396 a = optoas(n->etype, nl->type);
397 if(nl->addable) {
398 if(smallintconst(nr)) {
399 gins(a, nr, nl);
400 goto ret;
401 }
402 regalloc(&n2, nr->type, N);
403 cgen(nr, &n2);
404 gins(a, &n2, nl);
405 regfree(&n2);
406 goto ret;
407 }
408 if(nr->ullman < UINF)
409 if(sudoaddable(a, nl, &addr)) {
410 if(smallintconst(nr)) {
411 p1 = gins(a, nr, N);
412 p1->to = addr;
413 sudoclean();
414 goto ret;
415 }
416 regalloc(&n2, nr->type, N);
417 cgen(nr, &n2);
418 p1 = gins(a, &n2, N);
419 p1->to = addr;
420 regfree(&n2);
421 sudoclean();
422 goto ret;
423 }
424 }
425
426hard:
Russ Coxac499ed2010-03-05 15:35:09 -0800427 n2.op = 0;
428 n1.op = 0;
429 if(nr->ullman >= nl->ullman || nl->addable) {
430 mgen(nr, &n2, N);
431 nr = &n2;
432 nr = &n2;
433 } else {
434 tempname(&n2, nr->type);
435 cgen(nr, &n2);
436 nr = &n2;
437 }
438 if(!nl->addable) {
439 igen(nl, &n1, N);
440 nl = &n1;
441 }
Russ Cox5ecd0102009-05-26 16:23:54 -0700442
443 n3 = *n;
Russ Coxac499ed2010-03-05 15:35:09 -0800444 n3.left = nl;
445 n3.right = nr;
Russ Cox5ecd0102009-05-26 16:23:54 -0700446 n3.op = n->etype;
447
Russ Coxac499ed2010-03-05 15:35:09 -0800448 mgen(&n3, &n4, N);
449 gmove(&n4, nl);
Russ Cox5ecd0102009-05-26 16:23:54 -0700450
Russ Coxac499ed2010-03-05 15:35:09 -0800451 if(n1.op)
452 regfree(&n1);
453 mfree(&n2);
454 mfree(&n4);
Russ Cox5ecd0102009-05-26 16:23:54 -0700455
456ret:
457 ;
Russ Coxdc5b4672009-03-31 00:22:59 -0700458}
459
Russ Cox76a763e2009-08-07 12:57:44 -0700460int
461samereg(Node *a, Node *b)
462{
463 if(a->op != OREGISTER)
464 return 0;
465 if(b->op != OREGISTER)
466 return 0;
467 if(a->val.u.reg != b->val.u.reg)
468 return 0;
469 return 1;
470}
471
Russ Cox6b070212009-04-02 16:48:06 -0700472/*
Russ Coxa8e4ed62009-05-26 21:07:26 -0700473 * generate division.
474 * caller must set:
475 * ax = allocated AX register
476 * dx = allocated DX register
477 * generates one of:
478 * res = nl / nr
479 * res = nl % nr
480 * according to op.
481 */
482void
Russ Cox9a9ffb22009-06-04 15:24:01 -0700483dodiv(int op, Type *t, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
Russ Coxa8e4ed62009-05-26 21:07:26 -0700484{
Russ Coxdd5f3232009-08-12 13:18:27 -0700485 Node n1, t1, t2, nz;
Russ Coxa8e4ed62009-05-26 21:07:26 -0700486
Russ Cox69c0edd2009-12-02 18:31:29 -0800487 tempname(&t1, nl->type);
488 tempname(&t2, nr->type);
Russ Coxdd5f3232009-08-12 13:18:27 -0700489 cgen(nl, &t1);
490 cgen(nr, &t2);
Russ Coxa8e4ed62009-05-26 21:07:26 -0700491
Russ Coxdd5f3232009-08-12 13:18:27 -0700492 if(!samereg(ax, res) && !samereg(dx, res))
493 regalloc(&n1, t, res);
494 else
495 regalloc(&n1, t, N);
496 gmove(&t2, &n1);
497 gmove(&t1, ax);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700498 if(!issigned[t->etype]) {
Russ Coxdd5f3232009-08-12 13:18:27 -0700499 nodconst(&nz, t, 0);
500 gmove(&nz, dx);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700501 } else
502 gins(optoas(OEXTEND, t), N, N);
Russ Coxdd5f3232009-08-12 13:18:27 -0700503 gins(optoas(op, t), &n1, N);
504 regfree(&n1);
Russ Coxa8e4ed62009-05-26 21:07:26 -0700505
506 if(op == ODIV)
507 gmove(ax, res);
508 else
509 gmove(dx, res);
510}
511
Russ Coxdd5f3232009-08-12 13:18:27 -0700512static void
513savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
514{
515 int r;
516
517 r = reg[dr];
518 nodreg(x, types[TINT32], dr);
519
520 // save current ax and dx if they are live
521 // and not the destination
522 memset(oldx, 0, sizeof *oldx);
523 if(r > 0 && !samereg(x, res)) {
Russ Cox69c0edd2009-12-02 18:31:29 -0800524 tempname(oldx, types[TINT32]);
Russ Coxdd5f3232009-08-12 13:18:27 -0700525 gmove(x, oldx);
526 }
527
528 regalloc(x, t, x);
529}
530
531static void
532restx(Node *x, Node *oldx)
533{
534 regfree(x);
535
536 if(oldx->op != 0) {
537 x->type = types[TINT32];
538 gmove(oldx, x);
Russ Coxdd5f3232009-08-12 13:18:27 -0700539 }
540}
541
Russ Coxa8e4ed62009-05-26 21:07:26 -0700542/*
Russ Cox6b070212009-04-02 16:48:06 -0700543 * generate division according to op, one of:
544 * res = nl / nr
545 * res = nl % nr
546 */
547void
548cgen_div(int op, Node *nl, Node *nr, Node *res)
549{
Russ Coxdd5f3232009-08-12 13:18:27 -0700550 Node ax, dx, oldax, olddx;
Russ Cox9a9ffb22009-06-04 15:24:01 -0700551 Type *t;
Russ Coxa8e4ed62009-05-26 21:07:26 -0700552
Russ Coxa8e4ed62009-05-26 21:07:26 -0700553 if(is64(nl->type))
554 fatal("cgen_div %T", nl->type);
555
Russ Cox9a9ffb22009-06-04 15:24:01 -0700556 t = nl->type;
557 if(t->width == 1)
558 t = types[t->etype+2]; // int8 -> int16, uint8 -> uint16
559
Russ Coxdd5f3232009-08-12 13:18:27 -0700560 savex(D_AX, &ax, &oldax, res, t);
561 savex(D_DX, &dx, &olddx, res, t);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700562 dodiv(op, t, nl, nr, res, &ax, &dx);
Russ Coxdd5f3232009-08-12 13:18:27 -0700563 restx(&dx, &olddx);
564 restx(&ax, &oldax);
Russ Cox6b070212009-04-02 16:48:06 -0700565}
566
567/*
568 * generate shift according to op, one of:
569 * res = nl << nr
570 * res = nl >> nr
571 */
572void
573cgen_shift(int op, Node *nl, Node *nr, Node *res)
574{
Russ Cox76a763e2009-08-07 12:57:44 -0700575 Node n1, n2, cx, oldcx;
Russ Cox9a9ffb22009-06-04 15:24:01 -0700576 int a, w;
577 Prog *p1;
578 uvlong sc;
579
580 if(nl->type->width > 4)
Kai Backman58ee1f52009-10-27 22:38:45 -0700581 fatal("cgen_shift %T", nl->type);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700582
Russ Cox9a9ffb22009-06-04 15:24:01 -0700583 w = nl->type->width * 8;
584
585 a = optoas(op, nl->type);
586
587 if(nr->op == OLITERAL) {
Russ Cox7c9ed792010-06-30 20:45:50 -0700588 tempname(&n2, nl->type);
589 cgen(nl, &n2);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700590 regalloc(&n1, nl->type, res);
Russ Cox7c9ed792010-06-30 20:45:50 -0700591 gmove(&n2, &n1);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700592 sc = mpgetfix(nr->val.u.xval);
593 if(sc >= nl->type->width*8) {
594 // large shift gets 2 shifts by width
595 gins(a, ncon(w-1), &n1);
596 gins(a, ncon(w-1), &n1);
597 } else
598 gins(a, nr, &n1);
599 gmove(&n1, res);
600 regfree(&n1);
601 return;
602 }
603
Russ Cox76a763e2009-08-07 12:57:44 -0700604 memset(&oldcx, 0, sizeof oldcx);
605 nodreg(&cx, types[TUINT32], D_CX);
Russ Coxb71c4842009-09-30 08:56:01 -0700606 if(reg[D_CX] > 1 && !samereg(&cx, res)) {
Russ Cox69c0edd2009-12-02 18:31:29 -0800607 tempname(&oldcx, types[TUINT32]);
Russ Cox76a763e2009-08-07 12:57:44 -0700608 gmove(&cx, &oldcx);
609 }
610
Russ Cox9a9ffb22009-06-04 15:24:01 -0700611 nodreg(&n1, types[TUINT32], D_CX);
612 regalloc(&n1, nr->type, &n1); // to hold the shift type in CX
613
Russ Cox76a763e2009-08-07 12:57:44 -0700614 if(samereg(&cx, res))
615 regalloc(&n2, nl->type, N);
616 else
617 regalloc(&n2, nl->type, res);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700618 if(nl->ullman >= nr->ullman) {
619 cgen(nl, &n2);
620 cgen(nr, &n1);
621 } else {
622 cgen(nr, &n1);
623 cgen(nl, &n2);
624 }
625
626 // test and fix up large shifts
Russ Coxb71c4842009-09-30 08:56:01 -0700627 gins(optoas(OCMP, nr->type), &n1, ncon(w));
Russ Cox9a9ffb22009-06-04 15:24:01 -0700628 p1 = gbranch(optoas(OLT, types[TUINT32]), T);
629 if(op == ORSH && issigned[nl->type->etype]) {
630 gins(a, ncon(w-1), &n2);
631 } else {
632 gmove(ncon(0), &n2);
633 }
634 patch(p1, pc);
635 gins(a, &n1, &n2);
Russ Coxdd5f3232009-08-12 13:18:27 -0700636
Russ Cox69c0edd2009-12-02 18:31:29 -0800637 if(oldcx.op != 0)
Russ Cox76a763e2009-08-07 12:57:44 -0700638 gmove(&oldcx, &cx);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700639
640 gmove(&n2, res);
641
642 regfree(&n1);
643 regfree(&n2);
Russ Cox6b070212009-04-02 16:48:06 -0700644}
645
646/*
647 * generate byte multiply:
648 * res = nl * nr
649 * no byte multiply instruction so have to do
650 * 16-bit multiply and take bottom half.
651 */
652void
653cgen_bmul(int op, Node *nl, Node *nr, Node *res)
654{
Russ Cox3c06bd62009-06-06 19:28:16 -0700655 Node n1b, n2b, n1w, n2w;
656 Type *t;
657 int a;
658
659 if(nl->ullman >= nr->ullman) {
660 regalloc(&n1b, nl->type, res);
661 cgen(nl, &n1b);
662 regalloc(&n2b, nr->type, N);
663 cgen(nr, &n2b);
664 } else {
665 regalloc(&n2b, nr->type, N);
666 cgen(nr, &n2b);
667 regalloc(&n1b, nl->type, res);
668 cgen(nl, &n1b);
669 }
670
671 // copy from byte to short registers
672 t = types[TUINT16];
673 if(issigned[nl->type->etype])
674 t = types[TINT16];
675
676 regalloc(&n2w, t, &n2b);
677 cgen(&n2b, &n2w);
678
679 regalloc(&n1w, t, &n1b);
680 cgen(&n1b, &n1w);
681
682 a = optoas(op, t);
683 gins(a, &n2w, &n1w);
684 cgen(&n1w, &n1b);
685 cgen(&n1b, res);
686
687 regfree(&n1w);
688 regfree(&n2w);
689 regfree(&n1b);
690 regfree(&n2b);
Russ Cox6b070212009-04-02 16:48:06 -0700691}
692
Russ Cox652f5562009-11-20 09:11:46 -0800693static int
694regcmp(const void *va, const void *vb)
695{
696 Node *ra, *rb;
Russ Cox9a9ffb22009-06-04 15:24:01 -0700697
Russ Cox652f5562009-11-20 09:11:46 -0800698 ra = (Node*)va;
699 rb = (Node*)vb;
700 return ra->local - rb->local;
701}
702
703static Prog* throwpc;
704
Russ Cox9bac9d22010-08-03 00:26:02 -0700705// We're only going to bother inlining if we can
706// convert all the arguments to 32 bits safely. Can we?
707static int
708fix64(NodeList *nn, int n)
709{
710 NodeList *l;
711 Node *r;
712 int i;
713
714 l = nn;
715 for(i=0; i<n; i++) {
716 r = l->n->right;
717 if(is64(r->type) && !smallintconst(r)) {
718 if(r->op == OCONV)
719 r = r->left;
720 if(is64(r->type))
721 return 0;
722 }
723 l = l->next;
724 }
725 return 1;
726}
727
Russ Cox652f5562009-11-20 09:11:46 -0800728void
729getargs(NodeList *nn, Node *reg, int n)
730{
731 NodeList *l;
Russ Cox9bac9d22010-08-03 00:26:02 -0700732 Node *r;
Russ Cox652f5562009-11-20 09:11:46 -0800733 int i;
734
735 throwpc = nil;
736
737 l = nn;
738 for(i=0; i<n; i++) {
Russ Cox9bac9d22010-08-03 00:26:02 -0700739 r = l->n->right;
740 if(is64(r->type)) {
741 if(r->op == OCONV)
742 r = r->left;
743 else if(smallintconst(r))
744 r->type = types[TUINT32];
745 if(is64(r->type))
746 fatal("getargs");
747 }
748 if(!smallintconst(r) && !isslice(r->type)) {
Russ Cox652f5562009-11-20 09:11:46 -0800749 if(i < 3) // AX CX DX
Russ Cox9bac9d22010-08-03 00:26:02 -0700750 nodreg(reg+i, r->type, D_AX+i);
Russ Cox652f5562009-11-20 09:11:46 -0800751 else
752 reg[i].op = OXXX;
Russ Cox9bac9d22010-08-03 00:26:02 -0700753 regalloc(reg+i, r->type, reg+i);
754 cgen(r, reg+i);
Russ Cox652f5562009-11-20 09:11:46 -0800755 } else
Russ Cox9bac9d22010-08-03 00:26:02 -0700756 reg[i] = *r;
Russ Cox652f5562009-11-20 09:11:46 -0800757 if(reg[i].local != 0)
758 yyerror("local used");
759 reg[i].local = l->n->left->xoffset;
760 l = l->next;
761 }
762 qsort((void*)reg, n, sizeof(*reg), regcmp);
763 for(i=0; i<n; i++)
764 reg[i].local = 0;
765}
766
767void
768cmpandthrow(Node *nl, Node *nr)
769{
Russ Cox14e0df32010-08-11 21:58:29 -0700770 vlong cl;
Russ Cox652f5562009-11-20 09:11:46 -0800771 Prog *p1;
772 int op;
Russ Cox1d77ff52010-08-11 22:27:47 -0700773 Node *c, n1;
774 Type *t;
Russ Cox652f5562009-11-20 09:11:46 -0800775
776 op = OLE;
777 if(smallintconst(nl)) {
778 cl = mpgetfix(nl->val.u.xval);
779 if(cl == 0)
780 return;
Russ Cox14e0df32010-08-11 21:58:29 -0700781 if(smallintconst(nr))
Russ Cox652f5562009-11-20 09:11:46 -0800782 return;
Russ Cox652f5562009-11-20 09:11:46 -0800783 // put the constant on the right
784 op = brrev(op);
785 c = nl;
786 nl = nr;
787 nr = c;
788 }
Russ Cox1d77ff52010-08-11 22:27:47 -0700789
790 // Arguments are known not to be 64-bit,
791 // but they might be smaller than 32 bits.
792 // Check if we need to use a temporary.
793 // At least one of the arguments is 32 bits
794 // (the len or cap) so one temporary suffices.
795 n1.op = OXXX;
796 t = types[TUINT32];
797 if(nl->type->width != t->width) {
798 regalloc(&n1, t, nl);
799 gmove(nl, &n1);
800 nl = &n1;
801 } else if(nr->type->width != t->width) {
802 regalloc(&n1, t, nr);
803 gmove(nr, &n1);
804 nr = &n1;
805 }
806 gins(optoas(OCMP, t), nl, nr);
807 if(n1.op != OXXX)
808 regfree(&n1);
Russ Cox652f5562009-11-20 09:11:46 -0800809 if(throwpc == nil) {
Russ Cox1d77ff52010-08-11 22:27:47 -0700810 p1 = gbranch(optoas(op, t), T);
Russ Cox652f5562009-11-20 09:11:46 -0800811 throwpc = pc;
Russ Coxf75d0d22010-04-01 22:31:27 -0700812 ginscall(panicslice, 0);
Russ Cox652f5562009-11-20 09:11:46 -0800813 patch(p1, pc);
814 } else {
815 op = brcom(op);
Russ Cox1d77ff52010-08-11 22:27:47 -0700816 p1 = gbranch(optoas(op, t), T);
Russ Cox652f5562009-11-20 09:11:46 -0800817 patch(p1, throwpc);
818 }
819}
820
821int
822sleasy(Node *n)
823{
824 if(n->op != ONAME)
825 return 0;
826 if(!n->addable)
827 return 0;
828 return 1;
829}
830
831// generate inline code for
832// slicearray
833// sliceslice
834// arraytoslice
835int
836cgen_inline(Node *n, Node *res)
837{
838 Node nodes[5];
Russ Cox4f89dcd2010-03-08 14:19:28 -0800839 Node n1, n2, nres, ntemp;
Russ Cox652f5562009-11-20 09:11:46 -0800840 vlong v;
Luuk van Dijkd6b29252011-05-11 16:35:11 +0200841 int i, narg, nochk;
Russ Cox652f5562009-11-20 09:11:46 -0800842
843 if(n->op != OCALLFUNC)
844 goto no;
845 if(!n->left->addable)
846 goto no;
Russ Coxb2a919f2010-07-15 15:25:32 -0700847 if(n->left->sym == S)
848 goto no;
Russ Cox758f2bc2010-01-22 17:06:20 -0800849 if(n->left->sym->pkg != runtimepkg)
Russ Cox652f5562009-11-20 09:11:46 -0800850 goto no;
851 if(strcmp(n->left->sym->name, "slicearray") == 0)
852 goto slicearray;
853 if(strcmp(n->left->sym->name, "sliceslice") == 0) {
854 narg = 4;
855 goto sliceslice;
856 }
857 if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
858 narg = 3;
859 goto sliceslice;
860 }
861 goto no;
862
863slicearray:
864 if(!sleasy(res))
865 goto no;
Russ Cox9bac9d22010-08-03 00:26:02 -0700866 if(!fix64(n->list, 5))
867 goto no;
Russ Cox652f5562009-11-20 09:11:46 -0800868 getargs(n->list, nodes, 5);
869
870 // if(hb[3] > nel[1]) goto throw
871 cmpandthrow(&nodes[3], &nodes[1]);
872
873 // if(lb[2] > hb[3]) goto throw
874 cmpandthrow(&nodes[2], &nodes[3]);
875
876 // len = hb[3] - lb[2] (destroys hb)
877 n2 = *res;
878 n2.xoffset += Array_nel;
Luuk van Dijkd6b29252011-05-11 16:35:11 +0200879 n2.type = types[TUINT32];
Russ Cox652f5562009-11-20 09:11:46 -0800880
881 if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
882 v = mpgetfix(nodes[3].val.u.xval) -
883 mpgetfix(nodes[2].val.u.xval);
884 nodconst(&n1, types[TUINT32], v);
885 gins(optoas(OAS, types[TUINT32]), &n1, &n2);
886 } else {
887 regalloc(&n1, types[TUINT32], &nodes[3]);
888 gmove(&nodes[3], &n1);
889 if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
890 gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
891 gins(optoas(OAS, types[TUINT32]), &n1, &n2);
892 regfree(&n1);
893 }
894
895 // cap = nel[1] - lb[2] (destroys nel)
896 n2 = *res;
897 n2.xoffset += Array_cap;
Luuk van Dijkd6b29252011-05-11 16:35:11 +0200898 n2.type = types[TUINT32];
Russ Cox652f5562009-11-20 09:11:46 -0800899
900 if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
901 v = mpgetfix(nodes[1].val.u.xval) -
902 mpgetfix(nodes[2].val.u.xval);
903 nodconst(&n1, types[TUINT32], v);
904 gins(optoas(OAS, types[TUINT32]), &n1, &n2);
905 } else {
906 regalloc(&n1, types[TUINT32], &nodes[1]);
907 gmove(&nodes[1], &n1);
908 if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
909 gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
910 gins(optoas(OAS, types[TUINT32]), &n1, &n2);
911 regfree(&n1);
912 }
913
914 // if slice could be too big, dereference to
915 // catch nil array pointer.
916 if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
917 n2 = nodes[0];
918 n2.xoffset = 0;
919 n2.op = OINDREG;
920 n2.type = types[TUINT8];
921 gins(ATESTB, nodintconst(0), &n2);
922 }
923
924 // ary = old[0] + (lb[2] * width[4]) (destroys old)
925 n2 = *res;
926 n2.xoffset += Array_array;
Luuk van Dijkd6b29252011-05-11 16:35:11 +0200927 n2.type = types[tptr];
Russ Cox652f5562009-11-20 09:11:46 -0800928
929 if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
930 v = mpgetfix(nodes[2].val.u.xval) *
931 mpgetfix(nodes[4].val.u.xval);
932 if(v != 0) {
933 nodconst(&n1, types[tptr], v);
934 gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
935 }
936 } else {
937 regalloc(&n1, types[tptr], &nodes[2]);
938 gmove(&nodes[2], &n1);
939 if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1)
940 gins(optoas(OMUL, types[tptr]), &nodes[4], &n1);
941 gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
942 regfree(&n1);
943 }
944 gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
945
946 for(i=0; i<5; i++) {
947 if(nodes[i].op == OREGISTER)
948 regfree(&nodes[i]);
949 }
950 return 1;
951
952sliceslice:
Russ Cox9bac9d22010-08-03 00:26:02 -0700953 if(!fix64(n->list, narg))
954 goto no;
Luuk van Dijkd6b29252011-05-11 16:35:11 +0200955 nochk = n->etype; // skip bounds checking
Russ Cox4f89dcd2010-03-08 14:19:28 -0800956 ntemp.op = OXXX;
957 if(!sleasy(n->list->n->right)) {
958 Node *n0;
959
960 n0 = n->list->n->right;
961 tempname(&ntemp, res->type);
962 cgen(n0, &ntemp);
963 n->list->n->right = &ntemp;
964 getargs(n->list, nodes, narg);
965 n->list->n->right = n0;
966 } else
967 getargs(n->list, nodes, narg);
Russ Cox652f5562009-11-20 09:11:46 -0800968
969 nres = *res; // result
Russ Cox4f89dcd2010-03-08 14:19:28 -0800970 if(!sleasy(res)) {
971 if(ntemp.op == OXXX)
972 tempname(&ntemp, res->type);
973 nres = ntemp;
Russ Cox652f5562009-11-20 09:11:46 -0800974 }
Russ Cox4f89dcd2010-03-08 14:19:28 -0800975
Russ Cox652f5562009-11-20 09:11:46 -0800976 if(narg == 3) { // old[lb:]
977 // move width to where it would be for old[lb:hb]
978 nodes[3] = nodes[2];
979 nodes[2].op = OXXX;
980
981 // if(lb[1] > old.nel[0]) goto throw;
Russ Cox4f89dcd2010-03-08 14:19:28 -0800982 n2 = nodes[0];
Russ Cox652f5562009-11-20 09:11:46 -0800983 n2.xoffset += Array_nel;
Russ Cox1d77ff52010-08-11 22:27:47 -0700984 n2.type = types[TUINT32];
Luuk van Dijkd6b29252011-05-11 16:35:11 +0200985 if(!nochk)
986 cmpandthrow(&nodes[1], &n2);
Russ Cox652f5562009-11-20 09:11:46 -0800987
988 // ret.nel = old.nel[0]-lb[1];
Russ Cox4f89dcd2010-03-08 14:19:28 -0800989 n2 = nodes[0];
Russ Cox652f5562009-11-20 09:11:46 -0800990 n2.xoffset += Array_nel;
Luuk van Dijkd6b29252011-05-11 16:35:11 +0200991 n2.type = types[TUINT32];
Russ Cox652f5562009-11-20 09:11:46 -0800992
993 regalloc(&n1, types[TUINT32], N);
994 gins(optoas(OAS, types[TUINT32]), &n2, &n1);
995 if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
996 gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
997
998 n2 = nres;
999 n2.xoffset += Array_nel;
Luuk van Dijkd6b29252011-05-11 16:35:11 +02001000 n2.type = types[TUINT32];
Russ Cox652f5562009-11-20 09:11:46 -08001001 gins(optoas(OAS, types[TUINT32]), &n1, &n2);
1002 regfree(&n1);
1003 } else { // old[lb:hb]
Russ Cox4f89dcd2010-03-08 14:19:28 -08001004 n2 = nodes[0];
Russ Cox652f5562009-11-20 09:11:46 -08001005 n2.xoffset += Array_cap;
Russ Cox1d77ff52010-08-11 22:27:47 -07001006 n2.type = types[TUINT32];
Luuk van Dijkd6b29252011-05-11 16:35:11 +02001007 if (!nochk) {
1008 // if(hb[2] > old.cap[0]) goto throw;
1009 cmpandthrow(&nodes[2], &n2);
1010 // if(lb[1] > hb[2]) goto throw;
1011 cmpandthrow(&nodes[1], &nodes[2]);
1012 }
Russ Cox652f5562009-11-20 09:11:46 -08001013
1014 // ret.len = hb[2]-lb[1]; (destroys hb[2])
1015 n2 = nres;
1016 n2.xoffset += Array_nel;
Luuk van Dijkd6b29252011-05-11 16:35:11 +02001017 n2.type = types[TUINT32];
1018
Russ Cox652f5562009-11-20 09:11:46 -08001019 if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
1020 v = mpgetfix(nodes[2].val.u.xval) -
1021 mpgetfix(nodes[1].val.u.xval);
1022 nodconst(&n1, types[TUINT32], v);
1023 gins(optoas(OAS, types[TUINT32]), &n1, &n2);
1024 } else {
1025 regalloc(&n1, types[TUINT32], &nodes[2]);
1026 gmove(&nodes[2], &n1);
1027 if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
1028 gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
1029 gins(optoas(OAS, types[TUINT32]), &n1, &n2);
1030 regfree(&n1);
1031 }
1032 }
1033
1034 // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
Russ Cox4f89dcd2010-03-08 14:19:28 -08001035 n2 = nodes[0];
Russ Cox652f5562009-11-20 09:11:46 -08001036 n2.xoffset += Array_cap;
Luuk van Dijkd6b29252011-05-11 16:35:11 +02001037 n2.type = types[TUINT32];
Russ Cox652f5562009-11-20 09:11:46 -08001038
1039 regalloc(&n1, types[TUINT32], &nodes[2]);
1040 gins(optoas(OAS, types[TUINT32]), &n2, &n1);
1041 if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
1042 gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
1043
1044 n2 = nres;
1045 n2.xoffset += Array_cap;
Luuk van Dijkd6b29252011-05-11 16:35:11 +02001046 n2.type = types[TUINT32];
Russ Cox652f5562009-11-20 09:11:46 -08001047 gins(optoas(OAS, types[TUINT32]), &n1, &n2);
1048 regfree(&n1);
1049
1050 // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
Russ Cox4f89dcd2010-03-08 14:19:28 -08001051 n2 = nodes[0];
Russ Cox652f5562009-11-20 09:11:46 -08001052 n2.xoffset += Array_array;
Luuk van Dijkd6b29252011-05-11 16:35:11 +02001053 n2.type = types[tptr];
Russ Cox652f5562009-11-20 09:11:46 -08001054
1055 regalloc(&n1, types[tptr], &nodes[1]);
1056 if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
1057 gins(optoas(OAS, types[tptr]), &n2, &n1);
1058 v = mpgetfix(nodes[1].val.u.xval) *
1059 mpgetfix(nodes[3].val.u.xval);
1060 if(v != 0) {
1061 nodconst(&n2, types[tptr], v);
1062 gins(optoas(OADD, types[tptr]), &n2, &n1);
1063 }
1064 } else {
1065 gmove(&nodes[1], &n1);
1066 if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
1067 gins(optoas(OMUL, types[tptr]), &nodes[3], &n1);
1068 gins(optoas(OADD, types[tptr]), &n2, &n1);
1069 }
1070
1071 n2 = nres;
1072 n2.xoffset += Array_array;
Luuk van Dijkd6b29252011-05-11 16:35:11 +02001073 n2.type = types[tptr];
Russ Cox652f5562009-11-20 09:11:46 -08001074 gins(optoas(OAS, types[tptr]), &n1, &n2);
1075 regfree(&n1);
1076
1077 for(i=0; i<4; i++) {
1078 if(nodes[i].op == OREGISTER)
1079 regfree(&nodes[i]);
1080 }
1081
1082 if(!sleasy(res)) {
1083 cgen(&nres, res);
1084 }
Russ Cox652f5562009-11-20 09:11:46 -08001085 return 1;
1086
1087no:
1088 return 0;
1089}