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