github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/src/cmd/5g/ggen.c (about) 1 // 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 <u.h> 8 #include <libc.h> 9 #include "gg.h" 10 #include "opt.h" 11 12 static Prog* appendpp(Prog*, int, int, int, int32, int, int, int32); 13 static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0); 14 15 void 16 defframe(Prog *ptxt) 17 { 18 uint32 frame, r0; 19 Prog *p; 20 vlong hi, lo; 21 NodeList *l; 22 Node *n; 23 24 // fill in argument size 25 ptxt->to.type = D_CONST2; 26 ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); 27 28 // fill in final stack size 29 frame = rnd(stksize+maxarg, widthptr); 30 ptxt->to.offset = frame; 31 32 // insert code to contain ambiguously live variables 33 // so that garbage collector only sees initialized values 34 // when it looks for pointers. 35 p = ptxt; 36 lo = hi = 0; 37 r0 = 0; 38 for(l=curfn->dcl; l != nil; l = l->next) { 39 n = l->n; 40 if(!n->needzero) 41 continue; 42 if(n->class != PAUTO) 43 fatal("needzero class %d", n->class); 44 if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0) 45 fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset); 46 if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthptr) { 47 // merge with range we already have 48 lo = rnd(n->xoffset, widthptr); 49 continue; 50 } 51 // zero old range 52 p = zerorange(p, frame, lo, hi, &r0); 53 54 // set new range 55 hi = n->xoffset + n->type->width; 56 lo = n->xoffset; 57 } 58 // zero final range 59 zerorange(p, frame, lo, hi, &r0); 60 } 61 62 static Prog* 63 zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0) 64 { 65 vlong cnt, i; 66 Prog *p1; 67 Node *f; 68 69 cnt = hi - lo; 70 if(cnt == 0) 71 return p; 72 if(*r0 == 0) { 73 p = appendpp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0); 74 *r0 = 1; 75 } 76 if(cnt < 4*widthptr) { 77 for(i = 0; i < cnt; i += widthptr) 78 p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame+lo+i); 79 } else if(!nacl && (cnt <= 128*widthptr)) { 80 p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0); 81 p->reg = REGSP; 82 p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 0); 83 f = sysfunc("duffzero"); 84 naddr(f, &p->to, 1); 85 afunclit(&p->to, f); 86 p->to.offset = 4*(128-cnt/widthptr); 87 } else { 88 p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0); 89 p->reg = REGSP; 90 p = appendpp(p, AADD, D_CONST, NREG, cnt, D_REG, 2, 0); 91 p->reg = 1; 92 p1 = p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4); 93 p->scond |= C_PBIT; 94 p = appendpp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0); 95 p->reg = 2; 96 p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0); 97 patch(p, p1); 98 } 99 return p; 100 } 101 102 static Prog* 103 appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset) 104 { 105 Prog *q; 106 107 q = mal(sizeof(*q)); 108 clearp(q); 109 q->as = as; 110 q->lineno = p->lineno; 111 q->from.type = ftype; 112 q->from.reg = freg; 113 q->from.offset = foffset; 114 q->to.type = ttype; 115 q->to.reg = treg; 116 q->to.offset = toffset; 117 q->link = p->link; 118 p->link = q; 119 return q; 120 } 121 122 // Sweep the prog list to mark any used nodes. 123 void 124 markautoused(Prog* p) 125 { 126 for (; p; p = p->link) { 127 if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL) 128 continue; 129 130 if (p->from.node) 131 p->from.node->used = 1; 132 133 if (p->to.node) 134 p->to.node->used = 1; 135 } 136 } 137 138 // Fixup instructions after allocauto (formerly compactframe) has moved all autos around. 139 void 140 fixautoused(Prog* p) 141 { 142 Prog **lp; 143 144 for (lp=&p; (p=*lp) != P; ) { 145 if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) { 146 *lp = p->link; 147 continue; 148 } 149 if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) { 150 // Cannot remove VARDEF instruction, because - unlike TYPE handled above - 151 // VARDEFs are interspersed with other code, and a jump might be using the 152 // VARDEF as a target. Replace with a no-op instead. A later pass will remove 153 // the no-ops. 154 p->to.type = D_NONE; 155 p->to.node = N; 156 p->as = ANOP; 157 continue; 158 } 159 160 if (p->from.name == D_AUTO && p->from.node) 161 p->from.offset += p->from.node->stkdelta; 162 163 if (p->to.name == D_AUTO && p->to.node) 164 p->to.offset += p->to.node->stkdelta; 165 166 lp = &p->link; 167 } 168 } 169 170 /* 171 * generate: 172 * call f 173 * proc=-1 normal call but no return 174 * proc=0 normal call 175 * proc=1 goroutine run in new proc 176 * proc=2 defer call save away stack 177 * proc=3 normal call to C pointer (not Go func value) 178 */ 179 void 180 ginscall(Node *f, int proc) 181 { 182 Prog *p; 183 Node n1, r, r1, con; 184 185 if(f->type != T) 186 setmaxarg(f->type); 187 188 switch(proc) { 189 default: 190 fatal("ginscall: bad proc %d", proc); 191 break; 192 193 case 0: // normal call 194 case -1: // normal call but no return 195 if(f->op == ONAME && f->class == PFUNC) { 196 if(f == deferreturn) { 197 // Deferred calls will appear to be returning to 198 // the BL deferreturn(SB) that we are about to emit. 199 // However, the stack trace code will show the line 200 // of the instruction before that return PC. 201 // To avoid that instruction being an unrelated instruction, 202 // insert a NOP so that we will have the right line number. 203 // ARM NOP 0x00000000 is really AND.EQ R0, R0, R0. 204 // Use the latter form because the NOP pseudo-instruction 205 // would be removed by the linker. 206 nodreg(&r, types[TINT], 0); 207 p = gins(AAND, &r, &r); 208 p->scond = C_SCOND_EQ; 209 } 210 p = gins(ABL, N, f); 211 afunclit(&p->to, f); 212 if(proc == -1 || noreturn(p)) 213 gins(AUNDEF, N, N); 214 break; 215 } 216 nodreg(&r, types[tptr], 7); 217 nodreg(&r1, types[tptr], 1); 218 gmove(f, &r); 219 r.op = OINDREG; 220 gmove(&r, &r1); 221 r.op = OREGISTER; 222 r1.op = OINDREG; 223 gins(ABL, &r, &r1); 224 break; 225 226 case 3: // normal call of c function pointer 227 gins(ABL, N, f); 228 break; 229 230 case 1: // call in new proc (go) 231 case 2: // deferred call (defer) 232 regalloc(&r, types[tptr], N); 233 p = gins(AMOVW, N, &r); 234 p->from.type = D_OREG; 235 p->from.reg = REGSP; 236 237 p = gins(AMOVW, &r, N); 238 p->to.type = D_OREG; 239 p->to.reg = REGSP; 240 p->to.offset = -12; 241 p->scond |= C_WBIT; 242 243 memset(&n1, 0, sizeof n1); 244 n1.op = OADDR; 245 n1.left = f; 246 gins(AMOVW, &n1, &r); 247 248 p = gins(AMOVW, &r, N); 249 p->to.type = D_OREG; 250 p->to.reg = REGSP; 251 p->to.offset = 8; 252 253 nodconst(&con, types[TINT32], argsize(f->type)); 254 gins(AMOVW, &con, &r); 255 p = gins(AMOVW, &r, N); 256 p->to.type = D_OREG; 257 p->to.reg = REGSP; 258 p->to.offset = 4; 259 regfree(&r); 260 261 if(proc == 1) 262 ginscall(newproc, 0); 263 else 264 ginscall(deferproc, 0); 265 266 nodreg(&r, types[tptr], 1); 267 p = gins(AMOVW, N, N); 268 p->from.type = D_CONST; 269 p->from.reg = REGSP; 270 p->from.offset = 12; 271 p->to.reg = REGSP; 272 p->to.type = D_REG; 273 274 if(proc == 2) { 275 nodconst(&con, types[TINT32], 0); 276 p = gins(ACMP, &con, N); 277 p->reg = 0; 278 p = gbranch(ABEQ, T, +1); 279 cgen_ret(N); 280 patch(p, pc); 281 } 282 break; 283 } 284 } 285 286 /* 287 * n is call to interface method. 288 * generate res = n. 289 */ 290 void 291 cgen_callinter(Node *n, Node *res, int proc) 292 { 293 int r; 294 Node *i, *f; 295 Node tmpi, nodo, nodr, nodsp; 296 Prog *p; 297 298 i = n->left; 299 if(i->op != ODOTINTER) 300 fatal("cgen_callinter: not ODOTINTER %O", i->op); 301 302 f = i->right; // field 303 if(f->op != ONAME) 304 fatal("cgen_callinter: not ONAME %O", f->op); 305 306 i = i->left; // interface 307 308 // Release res register during genlist and cgen, 309 // which might have their own function calls. 310 r = -1; 311 if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { 312 r = res->val.u.reg; 313 reg[r]--; 314 } 315 316 if(!i->addable) { 317 tempname(&tmpi, i->type); 318 cgen(i, &tmpi); 319 i = &tmpi; 320 } 321 322 genlist(n->list); // args 323 if(r >= 0) 324 reg[r]++; 325 326 regalloc(&nodr, types[tptr], res); 327 regalloc(&nodo, types[tptr], &nodr); 328 nodo.op = OINDREG; 329 330 agen(i, &nodr); // REG = &inter 331 332 nodindreg(&nodsp, types[tptr], REGSP); 333 nodsp.xoffset = 4; 334 nodo.xoffset += widthptr; 335 cgen(&nodo, &nodsp); // 4(SP) = 4(REG) -- i.data 336 337 nodo.xoffset -= widthptr; 338 cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab 339 cgen_checknil(&nodr); // in case offset is huge 340 341 nodo.xoffset = n->left->xoffset + 3*widthptr + 8; 342 343 if(proc == 0) { 344 // plain call: use direct c function pointer - more efficient 345 cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f] 346 nodr.op = OINDREG; 347 proc = 3; 348 } else { 349 // go/defer. generate go func value. 350 p = gins(AMOVW, &nodo, &nodr); 351 p->from.type = D_CONST; // REG = &(20+offset(REG)) -- i.tab->fun[f] 352 } 353 354 nodr.type = n->left->type; 355 ginscall(&nodr, proc); 356 357 regfree(&nodr); 358 regfree(&nodo); 359 } 360 361 /* 362 * generate function call; 363 * proc=0 normal call 364 * proc=1 goroutine run in new proc 365 * proc=2 defer call save away stack 366 */ 367 void 368 cgen_call(Node *n, int proc) 369 { 370 Type *t; 371 Node nod, afun; 372 373 if(n == N) 374 return; 375 376 if(n->left->ullman >= UINF) { 377 // if name involves a fn call 378 // precompute the address of the fn 379 tempname(&afun, types[tptr]); 380 cgen(n->left, &afun); 381 } 382 383 genlist(n->list); // assign the args 384 t = n->left->type; 385 386 // call tempname pointer 387 if(n->left->ullman >= UINF) { 388 regalloc(&nod, types[tptr], N); 389 cgen_as(&nod, &afun); 390 nod.type = t; 391 ginscall(&nod, proc); 392 regfree(&nod); 393 goto ret; 394 } 395 396 // call pointer 397 if(n->left->op != ONAME || n->left->class != PFUNC) { 398 regalloc(&nod, types[tptr], N); 399 cgen_as(&nod, n->left); 400 nod.type = t; 401 ginscall(&nod, proc); 402 regfree(&nod); 403 goto ret; 404 } 405 406 // call direct 407 n->left->method = 1; 408 ginscall(n->left, proc); 409 410 411 ret: 412 ; 413 } 414 415 /* 416 * call to n has already been generated. 417 * generate: 418 * res = return value from call. 419 */ 420 void 421 cgen_callret(Node *n, Node *res) 422 { 423 Node nod; 424 Type *fp, *t; 425 Iter flist; 426 427 t = n->left->type; 428 if(t->etype == TPTR32 || t->etype == TPTR64) 429 t = t->type; 430 431 fp = structfirst(&flist, getoutarg(t)); 432 if(fp == T) 433 fatal("cgen_callret: nil"); 434 435 memset(&nod, 0, sizeof(nod)); 436 nod.op = OINDREG; 437 nod.val.u.reg = REGSP; 438 nod.addable = 1; 439 440 nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP) 441 nod.type = fp->type; 442 cgen_as(res, &nod); 443 } 444 445 /* 446 * call to n has already been generated. 447 * generate: 448 * res = &return value from call. 449 */ 450 void 451 cgen_aret(Node *n, Node *res) 452 { 453 Node nod1, nod2; 454 Type *fp, *t; 455 Iter flist; 456 457 t = n->left->type; 458 if(isptr[t->etype]) 459 t = t->type; 460 461 fp = structfirst(&flist, getoutarg(t)); 462 if(fp == T) 463 fatal("cgen_aret: nil"); 464 465 memset(&nod1, 0, sizeof(nod1)); 466 nod1.op = OINDREG; 467 nod1.val.u.reg = REGSP; 468 nod1.addable = 1; 469 470 nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP) 471 nod1.type = fp->type; 472 473 if(res->op != OREGISTER) { 474 regalloc(&nod2, types[tptr], res); 475 agen(&nod1, &nod2); 476 gins(AMOVW, &nod2, res); 477 regfree(&nod2); 478 } else 479 agen(&nod1, res); 480 } 481 482 /* 483 * generate return. 484 * n->left is assignments to return values. 485 */ 486 void 487 cgen_ret(Node *n) 488 { 489 Prog *p; 490 491 if(n != N) 492 genlist(n->list); // copy out args 493 if(hasdefer) 494 ginscall(deferreturn, 0); 495 genlist(curfn->exit); 496 p = gins(ARET, N, N); 497 if(n != N && n->op == ORETJMP) { 498 p->to.name = D_EXTERN; 499 p->to.type = D_CONST; 500 p->to.sym = linksym(n->left->sym); 501 } 502 } 503 504 /* 505 * generate += *= etc. 506 */ 507 void 508 cgen_asop(Node *n) 509 { 510 Node n1, n2, n3, n4; 511 Node *nl, *nr; 512 Prog *p1; 513 Addr addr; 514 int a, w; 515 516 nl = n->left; 517 nr = n->right; 518 519 if(nr->ullman >= UINF && nl->ullman >= UINF) { 520 tempname(&n1, nr->type); 521 cgen(nr, &n1); 522 n2 = *n; 523 n2.right = &n1; 524 cgen_asop(&n2); 525 goto ret; 526 } 527 528 if(!isint[nl->type->etype]) 529 goto hard; 530 if(!isint[nr->type->etype]) 531 goto hard; 532 if(is64(nl->type) || is64(nr->type)) 533 goto hard64; 534 535 switch(n->etype) { 536 case OADD: 537 case OSUB: 538 case OXOR: 539 case OAND: 540 case OOR: 541 a = optoas(n->etype, nl->type); 542 if(nl->addable) { 543 if(smallintconst(nr)) 544 n3 = *nr; 545 else { 546 regalloc(&n3, nr->type, N); 547 cgen(nr, &n3); 548 } 549 regalloc(&n2, nl->type, N); 550 cgen(nl, &n2); 551 gins(a, &n3, &n2); 552 cgen(&n2, nl); 553 regfree(&n2); 554 if(n3.op != OLITERAL) 555 regfree(&n3); 556 goto ret; 557 } 558 if(nr->ullman < UINF) 559 if(sudoaddable(a, nl, &addr, &w)) { 560 w = optoas(OAS, nl->type); 561 regalloc(&n2, nl->type, N); 562 p1 = gins(w, N, &n2); 563 p1->from = addr; 564 regalloc(&n3, nr->type, N); 565 cgen(nr, &n3); 566 gins(a, &n3, &n2); 567 p1 = gins(w, &n2, N); 568 p1->to = addr; 569 regfree(&n2); 570 regfree(&n3); 571 sudoclean(); 572 goto ret; 573 } 574 } 575 576 hard: 577 n2.op = 0; 578 n1.op = 0; 579 if(nr->op == OLITERAL) { 580 // don't allocate a register for literals. 581 } else if(nr->ullman >= nl->ullman || nl->addable) { 582 regalloc(&n2, nr->type, N); 583 cgen(nr, &n2); 584 nr = &n2; 585 } else { 586 tempname(&n2, nr->type); 587 cgen(nr, &n2); 588 nr = &n2; 589 } 590 if(!nl->addable) { 591 igen(nl, &n1, N); 592 nl = &n1; 593 } 594 595 n3 = *n; 596 n3.left = nl; 597 n3.right = nr; 598 n3.op = n->etype; 599 600 regalloc(&n4, nl->type, N); 601 cgen(&n3, &n4); 602 gmove(&n4, nl); 603 604 if(n1.op) 605 regfree(&n1); 606 if(n2.op == OREGISTER) 607 regfree(&n2); 608 regfree(&n4); 609 goto ret; 610 611 hard64: 612 if(nr->ullman > nl->ullman) { 613 tempname(&n2, nr->type); 614 cgen(nr, &n2); 615 igen(nl, &n1, N); 616 } else { 617 igen(nl, &n1, N); 618 tempname(&n2, nr->type); 619 cgen(nr, &n2); 620 } 621 622 n3 = *n; 623 n3.left = &n1; 624 n3.right = &n2; 625 n3.op = n->etype; 626 627 cgen(&n3, &n1); 628 629 ret: 630 ; 631 } 632 633 int 634 samereg(Node *a, Node *b) 635 { 636 if(a->op != OREGISTER) 637 return 0; 638 if(b->op != OREGISTER) 639 return 0; 640 if(a->val.u.reg != b->val.u.reg) 641 return 0; 642 return 1; 643 } 644 645 /* 646 * generate high multiply 647 * res = (nl * nr) >> wordsize 648 */ 649 void 650 cgen_hmul(Node *nl, Node *nr, Node *res) 651 { 652 int w; 653 Node n1, n2, *tmp; 654 Type *t; 655 Prog *p; 656 657 if(nl->ullman < nr->ullman) { 658 tmp = nl; 659 nl = nr; 660 nr = tmp; 661 } 662 t = nl->type; 663 w = t->width * 8; 664 regalloc(&n1, t, res); 665 cgen(nl, &n1); 666 regalloc(&n2, t, N); 667 cgen(nr, &n2); 668 switch(simtype[t->etype]) { 669 case TINT8: 670 case TINT16: 671 gins(optoas(OMUL, t), &n2, &n1); 672 gshift(AMOVW, &n1, SHIFT_AR, w, &n1); 673 break; 674 case TUINT8: 675 case TUINT16: 676 gins(optoas(OMUL, t), &n2, &n1); 677 gshift(AMOVW, &n1, SHIFT_LR, w, &n1); 678 break; 679 case TINT32: 680 case TUINT32: 681 // perform a long multiplication. 682 if(issigned[t->etype]) 683 p = gins(AMULL, &n2, N); 684 else 685 p = gins(AMULLU, &n2, N); 686 // n2 * n1 -> (n1 n2) 687 p->reg = n1.val.u.reg; 688 p->to.type = D_REGREG; 689 p->to.reg = n1.val.u.reg; 690 p->to.offset = n2.val.u.reg; 691 break; 692 default: 693 fatal("cgen_hmul %T", t); 694 break; 695 } 696 cgen(&n1, res); 697 regfree(&n1); 698 regfree(&n2); 699 } 700 701 /* 702 * generate shift according to op, one of: 703 * res = nl << nr 704 * res = nl >> nr 705 */ 706 void 707 cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) 708 { 709 Node n1, n2, n3, nt, t, lo, hi; 710 int w, v; 711 Prog *p1, *p2, *p3; 712 Type *tr; 713 uvlong sc; 714 715 USED(bounded); 716 if(nl->type->width > 4) 717 fatal("cgen_shift %T", nl->type); 718 719 w = nl->type->width * 8; 720 721 if(op == OLROT) { 722 v = mpgetfix(nr->val.u.xval); 723 regalloc(&n1, nl->type, res); 724 if(w == 32) { 725 cgen(nl, &n1); 726 gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1); 727 } else { 728 regalloc(&n2, nl->type, N); 729 cgen(nl, &n2); 730 gshift(AMOVW, &n2, SHIFT_LL, v, &n1); 731 gshift(AORR, &n2, SHIFT_LR, w-v, &n1); 732 regfree(&n2); 733 // Ensure sign/zero-extended result. 734 gins(optoas(OAS, nl->type), &n1, &n1); 735 } 736 gmove(&n1, res); 737 regfree(&n1); 738 return; 739 } 740 741 if(nr->op == OLITERAL) { 742 regalloc(&n1, nl->type, res); 743 cgen(nl, &n1); 744 sc = mpgetfix(nr->val.u.xval); 745 if(sc == 0) { 746 // nothing to do 747 } else if(sc >= nl->type->width*8) { 748 if(op == ORSH && issigned[nl->type->etype]) 749 gshift(AMOVW, &n1, SHIFT_AR, w, &n1); 750 else 751 gins(AEOR, &n1, &n1); 752 } else { 753 if(op == ORSH && issigned[nl->type->etype]) 754 gshift(AMOVW, &n1, SHIFT_AR, sc, &n1); 755 else if(op == ORSH) 756 gshift(AMOVW, &n1, SHIFT_LR, sc, &n1); 757 else // OLSH 758 gshift(AMOVW, &n1, SHIFT_LL, sc, &n1); 759 } 760 if(w < 32 && op == OLSH) 761 gins(optoas(OAS, nl->type), &n1, &n1); 762 gmove(&n1, res); 763 regfree(&n1); 764 return; 765 } 766 767 tr = nr->type; 768 if(tr->width > 4) { 769 tempname(&nt, nr->type); 770 if(nl->ullman >= nr->ullman) { 771 regalloc(&n2, nl->type, res); 772 cgen(nl, &n2); 773 cgen(nr, &nt); 774 n1 = nt; 775 } else { 776 cgen(nr, &nt); 777 regalloc(&n2, nl->type, res); 778 cgen(nl, &n2); 779 } 780 split64(&nt, &lo, &hi); 781 regalloc(&n1, types[TUINT32], N); 782 regalloc(&n3, types[TUINT32], N); 783 gmove(&lo, &n1); 784 gmove(&hi, &n3); 785 splitclean(); 786 gins(ATST, &n3, N); 787 nodconst(&t, types[TUINT32], w); 788 p1 = gins(AMOVW, &t, &n1); 789 p1->scond = C_SCOND_NE; 790 tr = types[TUINT32]; 791 regfree(&n3); 792 } else { 793 if(nl->ullman >= nr->ullman) { 794 regalloc(&n2, nl->type, res); 795 cgen(nl, &n2); 796 regalloc(&n1, nr->type, N); 797 cgen(nr, &n1); 798 } else { 799 regalloc(&n1, nr->type, N); 800 cgen(nr, &n1); 801 regalloc(&n2, nl->type, res); 802 cgen(nl, &n2); 803 } 804 } 805 806 // test for shift being 0 807 gins(ATST, &n1, N); 808 p3 = gbranch(ABEQ, T, -1); 809 810 // test and fix up large shifts 811 // TODO: if(!bounded), don't emit some of this. 812 regalloc(&n3, tr, N); 813 nodconst(&t, types[TUINT32], w); 814 gmove(&t, &n3); 815 gcmp(ACMP, &n1, &n3); 816 if(op == ORSH) { 817 if(issigned[nl->type->etype]) { 818 p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2); 819 p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2); 820 } else { 821 p1 = gins(AEOR, &n2, &n2); 822 p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2); 823 } 824 p1->scond = C_SCOND_HS; 825 p2->scond = C_SCOND_LO; 826 } else { 827 p1 = gins(AEOR, &n2, &n2); 828 p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2); 829 p1->scond = C_SCOND_HS; 830 p2->scond = C_SCOND_LO; 831 } 832 regfree(&n3); 833 834 patch(p3, pc); 835 // Left-shift of smaller word must be sign/zero-extended. 836 if(w < 32 && op == OLSH) 837 gins(optoas(OAS, nl->type), &n2, &n2); 838 gmove(&n2, res); 839 840 regfree(&n1); 841 regfree(&n2); 842 } 843 844 void 845 clearfat(Node *nl) 846 { 847 uint32 w, c, q; 848 Node dst, nc, nz, end, r0, r1, *f; 849 Prog *p, *pl; 850 851 /* clear a fat object */ 852 if(debug['g']) 853 dump("\nclearfat", nl); 854 855 w = nl->type->width; 856 // Avoid taking the address for simple enough types. 857 if(componentgen(N, nl)) 858 return; 859 860 c = w % 4; // bytes 861 q = w / 4; // quads 862 863 r0.op = OREGISTER; 864 r0.val.u.reg = REGALLOC_R0; 865 r1.op = OREGISTER; 866 r1.val.u.reg = REGALLOC_R0 + 1; 867 regalloc(&dst, types[tptr], &r1); 868 agen(nl, &dst); 869 nodconst(&nc, types[TUINT32], 0); 870 regalloc(&nz, types[TUINT32], &r0); 871 cgen(&nc, &nz); 872 873 if(q > 128) { 874 regalloc(&end, types[tptr], N); 875 p = gins(AMOVW, &dst, &end); 876 p->from.type = D_CONST; 877 p->from.offset = q*4; 878 879 p = gins(AMOVW, &nz, &dst); 880 p->to.type = D_OREG; 881 p->to.offset = 4; 882 p->scond |= C_PBIT; 883 pl = p; 884 885 p = gins(ACMP, &dst, N); 886 raddr(&end, p); 887 patch(gbranch(ABNE, T, 0), pl); 888 889 regfree(&end); 890 } else if(q >= 4 && !nacl) { 891 f = sysfunc("duffzero"); 892 p = gins(ADUFFZERO, N, f); 893 afunclit(&p->to, f); 894 // 4 and 128 = magic constants: see ../../runtime/asm_arm.s 895 p->to.offset = 4*(128-q); 896 } else 897 while(q > 0) { 898 p = gins(AMOVW, &nz, &dst); 899 p->to.type = D_OREG; 900 p->to.offset = 4; 901 p->scond |= C_PBIT; 902 //print("1. %P\n", p); 903 q--; 904 } 905 906 while(c > 0) { 907 p = gins(AMOVB, &nz, &dst); 908 p->to.type = D_OREG; 909 p->to.offset = 1; 910 p->scond |= C_PBIT; 911 //print("2. %P\n", p); 912 c--; 913 } 914 regfree(&dst); 915 regfree(&nz); 916 } 917 918 // Called after regopt and peep have run. 919 // Expand CHECKNIL pseudo-op into actual nil pointer check. 920 void 921 expandchecks(Prog *firstp) 922 { 923 int reg; 924 Prog *p, *p1; 925 926 for(p = firstp; p != P; p = p->link) { 927 if(p->as != ACHECKNIL) 928 continue; 929 if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers 930 warnl(p->lineno, "generated nil check"); 931 if(p->from.type != D_REG) 932 fatal("invalid nil check %P", p); 933 reg = p->from.reg; 934 // check is 935 // CMP arg, $0 936 // MOV.EQ arg, 0(arg) 937 p1 = mal(sizeof *p1); 938 clearp(p1); 939 p1->link = p->link; 940 p->link = p1; 941 p1->lineno = p->lineno; 942 p1->pc = 9999; 943 p1->as = AMOVW; 944 p1->from.type = D_REG; 945 p1->from.reg = reg; 946 p1->to.type = D_OREG; 947 p1->to.reg = reg; 948 p1->to.offset = 0; 949 p1->scond = C_SCOND_EQ; 950 p->as = ACMP; 951 p->from.type = D_CONST; 952 p->from.reg = NREG; 953 p->from.offset = 0; 954 p->reg = reg; 955 } 956 }