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