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