blob: 749f913ef5ee4548a52d1a4a8a3ae34546cdd731 [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
Russ Cox61f84a22011-08-25 16:25:10 -04007#include <u.h>
8#include <libc.h>
Russ Coxdc5b4672009-03-31 00:22:59 -07009#include "gg.h"
Ken Thompson0eb2a792009-11-06 16:51:49 -080010#include "opt.h"
Russ Coxdc5b4672009-03-31 00:22:59 -070011
12void
Luuk van Dijke59aa8e2011-06-02 18:48:17 +020013defframe(Prog *ptxt)
Russ Coxdc5b4672009-03-31 00:22:59 -070014{
Russ Coxdc5b4672009-03-31 00:22:59 -070015 // fill in argument size
Russ Coxe7a0f672010-12-13 11:57:41 -050016 ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
Russ Coxdc5b4672009-03-31 00:22:59 -070017
18 // fill in final stack size
Russ Cox6b070212009-04-02 16:48:06 -070019 if(stksize > maxstksize)
20 maxstksize = stksize;
Russ Coxe7a0f672010-12-13 11:57:41 -050021 ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
Russ Cox6b070212009-04-02 16:48:06 -070022 maxstksize = 0;
Russ Coxdc5b4672009-03-31 00:22:59 -070023}
24
Luuk van Dijk2ad42a82011-06-14 17:03:37 +020025// Sweep the prog list to mark any used nodes.
26void
27markautoused(Prog* p)
28{
29 for (; p; p = p->link) {
30 if (p->from.type == D_AUTO && p->from.node)
Rémy Oudomphengf2ad3742012-02-21 16:38:01 +110031 p->from.node->used = 1;
Luuk van Dijk2ad42a82011-06-14 17:03:37 +020032
33 if (p->to.type == D_AUTO && p->to.node)
Rémy Oudomphengf2ad3742012-02-21 16:38:01 +110034 p->to.node->used = 1;
Luuk van Dijk2ad42a82011-06-14 17:03:37 +020035 }
36}
37
38// Fixup instructions after compactframe has moved all autos around.
39void
40fixautoused(Prog* p)
41{
42 for (; p; p = p->link) {
43 if (p->from.type == D_AUTO && p->from.node)
44 p->from.offset += p->from.node->stkdelta;
45
46 if (p->to.type == D_AUTO && p->to.node)
47 p->to.offset += p->to.node->stkdelta;
48 }
49}
50
Russ Coxdc5b4672009-03-31 00:22:59 -070051void
52clearfat(Node *nl)
53{
Russ Cox5ecd0102009-05-26 16:23:54 -070054 uint32 w, c, q;
55 Node n1;
56
57 /* clear a fat object */
58 if(debug['g'])
59 dump("\nclearfat", nl);
60
61 w = nl->type->width;
62 c = w % 4; // bytes
63 q = w / 4; // quads
64
65 gconreg(AMOVL, 0, D_AX);
66 nodreg(&n1, types[tptr], D_DI);
67 agen(nl, &n1);
68
69 if(q >= 4) {
70 gconreg(AMOVL, q, D_CX);
71 gins(AREP, N, N); // repeat
72 gins(ASTOSL, N, N); // STOL AL,*(DI)+
73 } else
74 while(q > 0) {
75 gins(ASTOSL, N, N); // STOL AL,*(DI)+
76 q--;
77 }
78
79 if(c >= 4) {
80 gconreg(AMOVL, c, D_CX);
81 gins(AREP, N, N); // repeat
82 gins(ASTOSB, N, N); // STOB AL,*(DI)+
83 } else
84 while(c > 0) {
85 gins(ASTOSB, N, N); // STOB AL,*(DI)+
86 c--;
87 }
Russ Coxdc5b4672009-03-31 00:22:59 -070088}
89
90/*
91 * generate:
92 * call f
93 * proc=0 normal call
94 * proc=1 goroutine run in new proc
95 * proc=2 defer call save away stack
96 */
97void
98ginscall(Node *f, int proc)
99{
100 Prog *p;
101 Node reg, con;
102
103 switch(proc) {
104 default:
105 fatal("ginscall: bad proc %d", proc);
106 break;
107
108 case 0: // normal call
Russ Cox001b75c2012-05-30 18:07:39 -0400109 case -1: // normal call but no return
Russ Coxdc5b4672009-03-31 00:22:59 -0700110 p = gins(ACALL, N, f);
111 afunclit(&p->to);
Luuk van Dijk40af78c2012-06-02 22:50:57 -0400112 if(proc == -1 || noreturn(p))
Russ Cox001b75c2012-05-30 18:07:39 -0400113 gins(AUNDEF, N, N);
Russ Coxdc5b4672009-03-31 00:22:59 -0700114 break;
115
116 case 1: // call in new proc (go)
Russ Cox9b1507b2010-03-31 11:46:01 -0700117 case 2: // deferred call (defer)
118 nodreg(&reg, types[TINT32], D_CX);
Russ Coxdc5b4672009-03-31 00:22:59 -0700119 gins(APUSHL, f, N);
120 nodconst(&con, types[TINT32], argsize(f->type));
121 gins(APUSHL, &con, N);
122 if(proc == 1)
123 ginscall(newproc, 0);
124 else
125 ginscall(deferproc, 0);
126 gins(APOPL, N, &reg);
127 gins(APOPL, N, &reg);
Russ Cox9b1507b2010-03-31 11:46:01 -0700128 if(proc == 2) {
129 nodreg(&reg, types[TINT64], D_AX);
130 gins(ATESTL, &reg, &reg);
Russ Cox001b75c2012-05-30 18:07:39 -0400131 patch(gbranch(AJNE, T, -1), retpc);
Russ Cox9b1507b2010-03-31 11:46:01 -0700132 }
Russ Coxdc5b4672009-03-31 00:22:59 -0700133 break;
134 }
135}
136
137/*
138 * n is call to interface method.
139 * generate res = n.
140 */
141void
142cgen_callinter(Node *n, Node *res, int proc)
143{
Russ Coxa8e4ed62009-05-26 21:07:26 -0700144 Node *i, *f;
145 Node tmpi, nodo, nodr, nodsp;
146
147 i = n->left;
148 if(i->op != ODOTINTER)
149 fatal("cgen_callinter: not ODOTINTER %O", i->op);
150
151 f = i->right; // field
152 if(f->op != ONAME)
153 fatal("cgen_callinter: not ONAME %O", f->op);
154
155 i = i->left; // interface
156
157 if(!i->addable) {
Russ Cox69c0edd2009-12-02 18:31:29 -0800158 tempname(&tmpi, i->type);
Russ Coxa8e4ed62009-05-26 21:07:26 -0700159 cgen(i, &tmpi);
160 i = &tmpi;
161 }
162
Russ Coxe52e9ca2009-07-17 01:00:44 -0700163 genlist(n->list); // assign the args
Russ Coxa8e4ed62009-05-26 21:07:26 -0700164
165 // Can regalloc now; i is known to be addable,
166 // so the agen will be easy.
167 regalloc(&nodr, types[tptr], res);
168 regalloc(&nodo, types[tptr], &nodr);
169 nodo.op = OINDREG;
170
171 agen(i, &nodr); // REG = &inter
172
173 nodindreg(&nodsp, types[tptr], D_SP);
174 nodo.xoffset += widthptr;
Anthony Martin028f74f2011-06-20 14:49:29 -0400175 cgen(&nodo, &nodsp); // 0(SP) = 4(REG) -- i.data
Russ Coxa8e4ed62009-05-26 21:07:26 -0700176
177 nodo.xoffset -= widthptr;
Anthony Martin028f74f2011-06-20 14:49:29 -0400178 cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
Russ Coxa8e4ed62009-05-26 21:07:26 -0700179
Russ Cox4589c342010-02-18 18:31:13 -0800180 if(n->left->xoffset == BADWIDTH)
181 fatal("cgen_callinter: badwidth");
Russ Cox9a9ffb22009-06-04 15:24:01 -0700182 nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
Anthony Martin028f74f2011-06-20 14:49:29 -0400183 cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
Russ Coxa8e4ed62009-05-26 21:07:26 -0700184
185 // BOTCH nodr.type = fntype;
186 nodr.type = n->left->type;
187 ginscall(&nodr, proc);
188
189 regfree(&nodr);
190 regfree(&nodo);
191
192 setmaxarg(n->left->type);
Russ Coxdc5b4672009-03-31 00:22:59 -0700193}
194
195/*
196 * generate function call;
197 * proc=0 normal call
198 * proc=1 goroutine run in new proc
199 * proc=2 defer call save away stack
200 */
201void
202cgen_call(Node *n, int proc)
203{
Russ Cox6b070212009-04-02 16:48:06 -0700204 Type *t;
205 Node nod, afun;
206
207 if(n == N)
208 return;
209
210 if(n->left->ullman >= UINF) {
211 // if name involves a fn call
212 // precompute the address of the fn
Russ Cox69c0edd2009-12-02 18:31:29 -0800213 tempname(&afun, types[tptr]);
Russ Cox6b070212009-04-02 16:48:06 -0700214 cgen(n->left, &afun);
215 }
216
Russ Coxe52e9ca2009-07-17 01:00:44 -0700217 genlist(n->list); // assign the args
Russ Cox6b070212009-04-02 16:48:06 -0700218 t = n->left->type;
219
220 setmaxarg(t);
221
222 // call tempname pointer
223 if(n->left->ullman >= UINF) {
224 regalloc(&nod, types[tptr], N);
225 cgen_as(&nod, &afun);
Russ Cox6b070212009-04-02 16:48:06 -0700226 nod.type = t;
227 ginscall(&nod, proc);
228 regfree(&nod);
229 return;
230 }
231
232 // call pointer
233 if(n->left->op != ONAME || n->left->class != PFUNC) {
234 regalloc(&nod, types[tptr], N);
235 cgen_as(&nod, n->left);
236 nod.type = t;
237 ginscall(&nod, proc);
238 regfree(&nod);
239 return;
240 }
241
242 // call direct
243 n->left->method = 1;
244 ginscall(n->left, proc);
245}
246
247/*
248 * call to n has already been generated.
249 * generate:
250 * res = return value from call.
251 */
252void
253cgen_callret(Node *n, Node *res)
254{
255 Node nod;
256 Type *fp, *t;
257 Iter flist;
258
259 t = n->left->type;
260 if(t->etype == TPTR32 || t->etype == TPTR64)
261 t = t->type;
262
263 fp = structfirst(&flist, getoutarg(t));
264 if(fp == T)
265 fatal("cgen_callret: nil");
266
267 memset(&nod, 0, sizeof(nod));
268 nod.op = OINDREG;
269 nod.val.u.reg = D_SP;
270 nod.addable = 1;
271
272 nod.xoffset = fp->width;
273 nod.type = fp->type;
274 cgen_as(res, &nod);
275}
276
277/*
278 * call to n has already been generated.
279 * generate:
280 * res = &return value from call.
281 */
282void
283cgen_aret(Node *n, Node *res)
284{
285 Node nod1, nod2;
286 Type *fp, *t;
287 Iter flist;
288
289 t = n->left->type;
290 if(isptr[t->etype])
291 t = t->type;
292
293 fp = structfirst(&flist, getoutarg(t));
294 if(fp == T)
295 fatal("cgen_aret: nil");
296
297 memset(&nod1, 0, sizeof(nod1));
298 nod1.op = OINDREG;
299 nod1.val.u.reg = D_SP;
300 nod1.addable = 1;
301
302 nod1.xoffset = fp->width;
303 nod1.type = fp->type;
304
305 if(res->op != OREGISTER) {
306 regalloc(&nod2, types[tptr], res);
307 gins(ALEAL, &nod1, &nod2);
308 gins(AMOVL, &nod2, res);
309 regfree(&nod2);
310 } else
311 gins(ALEAL, &nod1, res);
Russ Coxdc5b4672009-03-31 00:22:59 -0700312}
313
314/*
315 * generate return.
316 * n->left is assignments to return values.
317 */
318void
319cgen_ret(Node *n)
320{
Russ Coxe52e9ca2009-07-17 01:00:44 -0700321 genlist(n->list); // copy out args
Luuk van Dijke59aa8e2011-06-02 18:48:17 +0200322 if(retpc)
323 gjmp(retpc);
Russ Cox97d0e8f2010-03-26 18:01:02 -0700324 else
325 gins(ARET, N, N);
Russ Coxdc5b4672009-03-31 00:22:59 -0700326}
327
328/*
329 * generate += *= etc.
330 */
331void
332cgen_asop(Node *n)
333{
Russ Cox5ecd0102009-05-26 16:23:54 -0700334 Node n1, n2, n3, n4;
335 Node *nl, *nr;
336 Prog *p1;
337 Addr addr;
338 int a;
339
340 nl = n->left;
341 nr = n->right;
342
343 if(nr->ullman >= UINF && nl->ullman >= UINF) {
Russ Cox69c0edd2009-12-02 18:31:29 -0800344 tempname(&n1, nr->type);
Russ Cox5ecd0102009-05-26 16:23:54 -0700345 cgen(nr, &n1);
346 n2 = *n;
347 n2.right = &n1;
348 cgen_asop(&n2);
349 goto ret;
350 }
351
352 if(!isint[nl->type->etype])
353 goto hard;
354 if(!isint[nr->type->etype])
355 goto hard;
Russ Coxa8e4ed62009-05-26 21:07:26 -0700356 if(is64(nl->type) || is64(nr->type))
357 goto hard;
Russ Cox5ecd0102009-05-26 16:23:54 -0700358
359 switch(n->etype) {
360 case OADD:
361 if(smallintconst(nr))
362 if(mpgetfix(nr->val.u.xval) == 1) {
363 a = optoas(OINC, nl->type);
364 if(nl->addable) {
365 gins(a, N, nl);
366 goto ret;
367 }
368 if(sudoaddable(a, nl, &addr)) {
369 p1 = gins(a, N, N);
370 p1->to = addr;
371 sudoclean();
372 goto ret;
373 }
374 }
375 break;
376
377 case OSUB:
378 if(smallintconst(nr))
379 if(mpgetfix(nr->val.u.xval) == 1) {
380 a = optoas(ODEC, nl->type);
381 if(nl->addable) {
382 gins(a, N, nl);
383 goto ret;
384 }
385 if(sudoaddable(a, nl, &addr)) {
386 p1 = gins(a, N, N);
387 p1->to = addr;
388 sudoclean();
389 goto ret;
390 }
391 }
392 break;
393 }
394
395 switch(n->etype) {
396 case OADD:
397 case OSUB:
398 case OXOR:
399 case OAND:
400 case OOR:
401 a = optoas(n->etype, nl->type);
402 if(nl->addable) {
403 if(smallintconst(nr)) {
404 gins(a, nr, nl);
405 goto ret;
406 }
407 regalloc(&n2, nr->type, N);
408 cgen(nr, &n2);
409 gins(a, &n2, nl);
410 regfree(&n2);
411 goto ret;
412 }
413 if(nr->ullman < UINF)
414 if(sudoaddable(a, nl, &addr)) {
415 if(smallintconst(nr)) {
416 p1 = gins(a, nr, N);
417 p1->to = addr;
418 sudoclean();
419 goto ret;
420 }
421 regalloc(&n2, nr->type, N);
422 cgen(nr, &n2);
423 p1 = gins(a, &n2, N);
424 p1->to = addr;
425 regfree(&n2);
426 sudoclean();
427 goto ret;
428 }
429 }
430
431hard:
Russ Coxac499ed2010-03-05 15:35:09 -0800432 n2.op = 0;
433 n1.op = 0;
434 if(nr->ullman >= nl->ullman || nl->addable) {
435 mgen(nr, &n2, N);
436 nr = &n2;
Russ Coxac499ed2010-03-05 15:35:09 -0800437 } else {
438 tempname(&n2, nr->type);
439 cgen(nr, &n2);
440 nr = &n2;
441 }
442 if(!nl->addable) {
443 igen(nl, &n1, N);
444 nl = &n1;
445 }
Russ Cox5ecd0102009-05-26 16:23:54 -0700446
447 n3 = *n;
Russ Coxac499ed2010-03-05 15:35:09 -0800448 n3.left = nl;
449 n3.right = nr;
Russ Cox5ecd0102009-05-26 16:23:54 -0700450 n3.op = n->etype;
451
Russ Coxac499ed2010-03-05 15:35:09 -0800452 mgen(&n3, &n4, N);
453 gmove(&n4, nl);
Russ Cox5ecd0102009-05-26 16:23:54 -0700454
Russ Coxac499ed2010-03-05 15:35:09 -0800455 if(n1.op)
456 regfree(&n1);
457 mfree(&n2);
458 mfree(&n4);
Russ Cox5ecd0102009-05-26 16:23:54 -0700459
460ret:
461 ;
Russ Coxdc5b4672009-03-31 00:22:59 -0700462}
463
Russ Cox76a763e2009-08-07 12:57:44 -0700464int
465samereg(Node *a, Node *b)
466{
467 if(a->op != OREGISTER)
468 return 0;
469 if(b->op != OREGISTER)
470 return 0;
471 if(a->val.u.reg != b->val.u.reg)
472 return 0;
473 return 1;
474}
475
Russ Cox6b070212009-04-02 16:48:06 -0700476/*
Russ Coxa8e4ed62009-05-26 21:07:26 -0700477 * generate division.
478 * caller must set:
479 * ax = allocated AX register
480 * dx = allocated DX register
481 * generates one of:
482 * res = nl / nr
483 * res = nl % nr
484 * according to op.
485 */
486void
Russ Cox08bfb392011-07-28 14:18:22 -0400487dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
Russ Coxa8e4ed62009-05-26 21:07:26 -0700488{
Russ Cox08bfb392011-07-28 14:18:22 -0400489 int check;
Russ Cox4fb3c4f2011-08-30 08:47:28 -0400490 Node n1, t1, t2, t3, t4, n4, nz;
491 Type *t, *t0;
Russ Cox08bfb392011-07-28 14:18:22 -0400492 Prog *p1, *p2, *p3;
Russ Coxa8e4ed62009-05-26 21:07:26 -0700493
Russ Cox08bfb392011-07-28 14:18:22 -0400494 // Have to be careful about handling
495 // most negative int divided by -1 correctly.
496 // The hardware will trap.
497 // Also the byte divide instruction needs AH,
498 // which we otherwise don't have to deal with.
499 // Easiest way to avoid for int8, int16: use int32.
500 // For int32 and int64, use explicit test.
501 // Could use int64 hw for int32.
502 t = nl->type;
Russ Cox4fb3c4f2011-08-30 08:47:28 -0400503 t0 = t;
Russ Cox08bfb392011-07-28 14:18:22 -0400504 check = 0;
505 if(issigned[t->etype]) {
506 check = 1;
507 if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1))
508 check = 0;
509 else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
510 check = 0;
511 }
512 if(t->width < 4) {
513 if(issigned[t->etype])
514 t = types[TINT32];
515 else
516 t = types[TUINT32];
517 check = 0;
518 }
519
520 tempname(&t1, t);
521 tempname(&t2, t);
Russ Cox4fb3c4f2011-08-30 08:47:28 -0400522 if(t0 != t) {
523 tempname(&t3, t0);
524 tempname(&t4, t0);
525 cgen(nl, &t3);
526 cgen(nr, &t4);
527 // Convert.
528 gmove(&t3, &t1);
529 gmove(&t4, &t2);
530 } else {
531 cgen(nl, &t1);
532 cgen(nr, &t2);
533 }
Russ Coxa8e4ed62009-05-26 21:07:26 -0700534
Russ Coxdd5f3232009-08-12 13:18:27 -0700535 if(!samereg(ax, res) && !samereg(dx, res))
536 regalloc(&n1, t, res);
537 else
538 regalloc(&n1, t, N);
539 gmove(&t2, &n1);
540 gmove(&t1, ax);
Russ Cox08bfb392011-07-28 14:18:22 -0400541 p3 = P;
542 if(check) {
543 nodconst(&n4, t, -1);
544 gins(optoas(OCMP, t), &n1, &n4);
Russ Cox001b75c2012-05-30 18:07:39 -0400545 p1 = gbranch(optoas(ONE, t), T, +1);
Russ Cox08bfb392011-07-28 14:18:22 -0400546 nodconst(&n4, t, -1LL<<(t->width*8-1));
547 gins(optoas(OCMP, t), ax, &n4);
Russ Cox001b75c2012-05-30 18:07:39 -0400548 p2 = gbranch(optoas(ONE, t), T, +1);
Russ Cox08bfb392011-07-28 14:18:22 -0400549 if(op == ODIV)
550 gmove(&n4, res);
551 if(op == OMOD) {
552 nodconst(&n4, t, 0);
553 gmove(&n4, res);
554 }
Russ Cox001b75c2012-05-30 18:07:39 -0400555 p3 = gbranch(AJMP, T, 0);
Russ Cox08bfb392011-07-28 14:18:22 -0400556 patch(p1, pc);
557 patch(p2, pc);
558 }
Russ Cox9a9ffb22009-06-04 15:24:01 -0700559 if(!issigned[t->etype]) {
Russ Coxdd5f3232009-08-12 13:18:27 -0700560 nodconst(&nz, t, 0);
561 gmove(&nz, dx);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700562 } else
563 gins(optoas(OEXTEND, t), N, N);
Russ Coxdd5f3232009-08-12 13:18:27 -0700564 gins(optoas(op, t), &n1, N);
565 regfree(&n1);
Russ Coxa8e4ed62009-05-26 21:07:26 -0700566
567 if(op == ODIV)
568 gmove(ax, res);
569 else
570 gmove(dx, res);
Russ Cox08bfb392011-07-28 14:18:22 -0400571 if(check)
572 patch(p3, pc);
Russ Coxa8e4ed62009-05-26 21:07:26 -0700573}
574
Russ Coxdd5f3232009-08-12 13:18:27 -0700575static void
576savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
577{
578 int r;
579
580 r = reg[dr];
581 nodreg(x, types[TINT32], dr);
582
583 // save current ax and dx if they are live
584 // and not the destination
585 memset(oldx, 0, sizeof *oldx);
586 if(r > 0 && !samereg(x, res)) {
Russ Cox69c0edd2009-12-02 18:31:29 -0800587 tempname(oldx, types[TINT32]);
Russ Coxdd5f3232009-08-12 13:18:27 -0700588 gmove(x, oldx);
589 }
590
591 regalloc(x, t, x);
592}
593
594static void
595restx(Node *x, Node *oldx)
596{
597 regfree(x);
598
599 if(oldx->op != 0) {
600 x->type = types[TINT32];
601 gmove(oldx, x);
Russ Coxdd5f3232009-08-12 13:18:27 -0700602 }
603}
604
Russ Coxa8e4ed62009-05-26 21:07:26 -0700605/*
Russ Cox6b070212009-04-02 16:48:06 -0700606 * generate division according to op, one of:
607 * res = nl / nr
608 * res = nl % nr
609 */
610void
611cgen_div(int op, Node *nl, Node *nr, Node *res)
612{
Russ Coxdd5f3232009-08-12 13:18:27 -0700613 Node ax, dx, oldax, olddx;
Russ Cox9a9ffb22009-06-04 15:24:01 -0700614 Type *t;
Russ Coxa8e4ed62009-05-26 21:07:26 -0700615
Russ Coxa8e4ed62009-05-26 21:07:26 -0700616 if(is64(nl->type))
617 fatal("cgen_div %T", nl->type);
618
Russ Cox08bfb392011-07-28 14:18:22 -0400619 if(issigned[nl->type->etype])
620 t = types[TINT32];
621 else
622 t = types[TUINT32];
Russ Coxdd5f3232009-08-12 13:18:27 -0700623 savex(D_AX, &ax, &oldax, res, t);
624 savex(D_DX, &dx, &olddx, res, t);
Russ Cox08bfb392011-07-28 14:18:22 -0400625 dodiv(op, nl, nr, res, &ax, &dx);
Russ Coxdd5f3232009-08-12 13:18:27 -0700626 restx(&dx, &olddx);
627 restx(&ax, &oldax);
Russ Cox6b070212009-04-02 16:48:06 -0700628}
629
630/*
631 * generate shift according to op, one of:
632 * res = nl << nr
633 * res = nl >> nr
634 */
635void
Russ Coxc6ce4482012-05-24 17:20:07 -0400636cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
Russ Cox6b070212009-04-02 16:48:06 -0700637{
Russ Cox28a23672011-07-28 18:22:12 -0400638 Node n1, n2, nt, cx, oldcx, hi, lo;
Russ Cox9a9ffb22009-06-04 15:24:01 -0700639 int a, w;
Russ Cox28a23672011-07-28 18:22:12 -0400640 Prog *p1, *p2;
Russ Cox9a9ffb22009-06-04 15:24:01 -0700641 uvlong sc;
642
643 if(nl->type->width > 4)
Kai Backman58ee1f52009-10-27 22:38:45 -0700644 fatal("cgen_shift %T", nl->type);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700645
Russ Cox9a9ffb22009-06-04 15:24:01 -0700646 w = nl->type->width * 8;
647
648 a = optoas(op, nl->type);
649
650 if(nr->op == OLITERAL) {
Russ Cox7c9ed792010-06-30 20:45:50 -0700651 tempname(&n2, nl->type);
652 cgen(nl, &n2);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700653 regalloc(&n1, nl->type, res);
Russ Cox7c9ed792010-06-30 20:45:50 -0700654 gmove(&n2, &n1);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700655 sc = mpgetfix(nr->val.u.xval);
656 if(sc >= nl->type->width*8) {
Russ Coxc6ce4482012-05-24 17:20:07 -0400657 // large shift gets 2 shifts by width-1
Russ Cox9a9ffb22009-06-04 15:24:01 -0700658 gins(a, ncon(w-1), &n1);
659 gins(a, ncon(w-1), &n1);
660 } else
661 gins(a, nr, &n1);
662 gmove(&n1, res);
663 regfree(&n1);
664 return;
665 }
666
Russ Cox76a763e2009-08-07 12:57:44 -0700667 memset(&oldcx, 0, sizeof oldcx);
668 nodreg(&cx, types[TUINT32], D_CX);
Russ Coxb71c4842009-09-30 08:56:01 -0700669 if(reg[D_CX] > 1 && !samereg(&cx, res)) {
Russ Cox69c0edd2009-12-02 18:31:29 -0800670 tempname(&oldcx, types[TUINT32]);
Russ Cox76a763e2009-08-07 12:57:44 -0700671 gmove(&cx, &oldcx);
672 }
673
Russ Cox28a23672011-07-28 18:22:12 -0400674 if(nr->type->width > 4) {
675 tempname(&nt, nr->type);
676 n1 = nt;
677 } else {
678 nodreg(&n1, types[TUINT32], D_CX);
679 regalloc(&n1, nr->type, &n1); // to hold the shift type in CX
680 }
Russ Cox9a9ffb22009-06-04 15:24:01 -0700681
Russ Cox76a763e2009-08-07 12:57:44 -0700682 if(samereg(&cx, res))
683 regalloc(&n2, nl->type, N);
684 else
685 regalloc(&n2, nl->type, res);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700686 if(nl->ullman >= nr->ullman) {
687 cgen(nl, &n2);
688 cgen(nr, &n1);
689 } else {
690 cgen(nr, &n1);
691 cgen(nl, &n2);
692 }
693
694 // test and fix up large shifts
Russ Coxc6ce4482012-05-24 17:20:07 -0400695 if(bounded) {
696 if(nr->type->width > 4) {
697 // delayed reg alloc
698 nodreg(&n1, types[TUINT32], D_CX);
699 regalloc(&n1, types[TUINT32], &n1); // to hold the shift type in CX
700 split64(&nt, &lo, &hi);
701 gmove(&lo, &n1);
702 }
Russ Cox28a23672011-07-28 18:22:12 -0400703 } else {
Russ Coxc6ce4482012-05-24 17:20:07 -0400704 if(nr->type->width > 4) {
705 // delayed reg alloc
706 nodreg(&n1, types[TUINT32], D_CX);
707 regalloc(&n1, types[TUINT32], &n1); // to hold the shift type in CX
708 split64(&nt, &lo, &hi);
709 gmove(&lo, &n1);
710 gins(optoas(OCMP, types[TUINT32]), &hi, ncon(0));
Russ Cox001b75c2012-05-30 18:07:39 -0400711 p2 = gbranch(optoas(ONE, types[TUINT32]), T, +1);
Russ Coxc6ce4482012-05-24 17:20:07 -0400712 gins(optoas(OCMP, types[TUINT32]), &n1, ncon(w));
Russ Cox001b75c2012-05-30 18:07:39 -0400713 p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
Russ Coxc6ce4482012-05-24 17:20:07 -0400714 patch(p2, pc);
715 } else {
716 gins(optoas(OCMP, nr->type), &n1, ncon(w));
Russ Cox001b75c2012-05-30 18:07:39 -0400717 p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
Russ Coxc6ce4482012-05-24 17:20:07 -0400718 }
719 if(op == ORSH && issigned[nl->type->etype]) {
720 gins(a, ncon(w-1), &n2);
721 } else {
722 gmove(ncon(0), &n2);
723 }
724 patch(p1, pc);
Russ Cox28a23672011-07-28 18:22:12 -0400725 }
Russ Cox9a9ffb22009-06-04 15:24:01 -0700726 gins(a, &n1, &n2);
Russ Coxdd5f3232009-08-12 13:18:27 -0700727
Russ Cox69c0edd2009-12-02 18:31:29 -0800728 if(oldcx.op != 0)
Russ Cox76a763e2009-08-07 12:57:44 -0700729 gmove(&oldcx, &cx);
Russ Cox9a9ffb22009-06-04 15:24:01 -0700730
731 gmove(&n2, res);
732
733 regfree(&n1);
734 regfree(&n2);
Russ Cox6b070212009-04-02 16:48:06 -0700735}
736
737/*
738 * generate byte multiply:
739 * res = nl * nr
740 * no byte multiply instruction so have to do
741 * 16-bit multiply and take bottom half.
742 */
743void
744cgen_bmul(int op, Node *nl, Node *nr, Node *res)
745{
Russ Cox3c06bd62009-06-06 19:28:16 -0700746 Node n1b, n2b, n1w, n2w;
747 Type *t;
748 int a;
749
750 if(nl->ullman >= nr->ullman) {
751 regalloc(&n1b, nl->type, res);
752 cgen(nl, &n1b);
753 regalloc(&n2b, nr->type, N);
754 cgen(nr, &n2b);
755 } else {
756 regalloc(&n2b, nr->type, N);
757 cgen(nr, &n2b);
758 regalloc(&n1b, nl->type, res);
759 cgen(nl, &n1b);
760 }
761
762 // copy from byte to short registers
763 t = types[TUINT16];
764 if(issigned[nl->type->etype])
765 t = types[TINT16];
766
767 regalloc(&n2w, t, &n2b);
768 cgen(&n2b, &n2w);
769
770 regalloc(&n1w, t, &n1b);
771 cgen(&n1b, &n1w);
772
773 a = optoas(op, t);
774 gins(a, &n2w, &n1w);
775 cgen(&n1w, &n1b);
776 cgen(&n1b, res);
777
778 regfree(&n1w);
779 regfree(&n2w);
780 regfree(&n1b);
781 regfree(&n2b);
Russ Cox6b070212009-04-02 16:48:06 -0700782}