github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/5l/noop.c (about) 1 // Inferno utils/5l/noop.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/5l/noop.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 // Code transformations. 32 33 #include "l.h" 34 #include "../ld/lib.h" 35 36 // see ../../runtime/proc.c:/StackGuard 37 enum 38 { 39 StackBig = 4096, 40 StackSmall = 128, 41 }; 42 43 static Sym* sym_div; 44 static Sym* sym_divu; 45 static Sym* sym_mod; 46 static Sym* sym_modu; 47 48 static void 49 linkcase(Prog *casep) 50 { 51 Prog *p; 52 53 for(p = casep; p != P; p = p->link){ 54 if(p->as == ABCASE) { 55 for(; p != P && p->as == ABCASE; p = p->link) 56 p->pcrel = casep; 57 break; 58 } 59 } 60 } 61 62 void 63 noops(void) 64 { 65 Prog *p, *q, *q1; 66 int o; 67 Prog *pmorestack; 68 Sym *symmorestack; 69 70 /* 71 * find leaf subroutines 72 * strip NOPs 73 * expand RET 74 * expand BECOME pseudo 75 */ 76 77 if(debug['v']) 78 Bprint(&bso, "%5.2f noops\n", cputime()); 79 Bflush(&bso); 80 81 symmorestack = lookup("runtime.morestack", 0); 82 if(symmorestack->type != STEXT) { 83 diag("runtime·morestack not defined"); 84 errorexit(); 85 } 86 pmorestack = symmorestack->text; 87 pmorestack->reg |= NOSPLIT; 88 89 q = P; 90 for(cursym = textp; cursym != nil; cursym = cursym->next) { 91 for(p = cursym->text; p != P; p = p->link) { 92 switch(p->as) { 93 case ACASE: 94 if(flag_shared) 95 linkcase(p); 96 break; 97 98 case ATEXT: 99 p->mark |= LEAF; 100 break; 101 102 case ARET: 103 break; 104 105 case ADIV: 106 case ADIVU: 107 case AMOD: 108 case AMODU: 109 q = p; 110 if(prog_div == P) 111 initdiv(); 112 cursym->text->mark &= ~LEAF; 113 continue; 114 115 case ANOP: 116 q1 = p->link; 117 q->link = q1; /* q is non-nop */ 118 if(q1 != P) 119 q1->mark |= p->mark; 120 continue; 121 122 case ABL: 123 case ABX: 124 cursym->text->mark &= ~LEAF; 125 126 case ABCASE: 127 case AB: 128 129 case ABEQ: 130 case ABNE: 131 case ABCS: 132 case ABHS: 133 case ABCC: 134 case ABLO: 135 case ABMI: 136 case ABPL: 137 case ABVS: 138 case ABVC: 139 case ABHI: 140 case ABLS: 141 case ABGE: 142 case ABLT: 143 case ABGT: 144 case ABLE: 145 q1 = p->cond; 146 if(q1 != P) { 147 while(q1->as == ANOP) { 148 q1 = q1->link; 149 p->cond = q1; 150 } 151 } 152 break; 153 } 154 q = p; 155 } 156 } 157 158 for(cursym = textp; cursym != nil; cursym = cursym->next) { 159 for(p = cursym->text; p != P; p = p->link) { 160 o = p->as; 161 switch(o) { 162 case ATEXT: 163 autosize = p->to.offset + 4; 164 if(autosize <= 4) 165 if(cursym->text->mark & LEAF) { 166 p->to.offset = -4; 167 autosize = 0; 168 } 169 170 if(!autosize && !(cursym->text->mark & LEAF)) { 171 if(debug['v']) 172 Bprint(&bso, "save suppressed in: %s\n", 173 cursym->name); 174 Bflush(&bso); 175 cursym->text->mark |= LEAF; 176 } 177 if(cursym->text->mark & LEAF) { 178 cursym->leaf = 1; 179 if(!autosize) 180 break; 181 } 182 183 if(p->reg & NOSPLIT) { 184 q1 = prg(); 185 q1->as = AMOVW; 186 q1->scond |= C_WBIT; 187 q1->line = p->line; 188 q1->from.type = D_REG; 189 q1->from.reg = REGLINK; 190 q1->to.type = D_OREG; 191 q1->to.offset = -autosize; 192 q1->to.reg = REGSP; 193 q1->spadj = autosize; 194 q1->link = p->link; 195 p->link = q1; 196 } else if (autosize < StackBig) { 197 // split stack check for small functions 198 // MOVW g_stackguard(g), R1 199 // CMP R1, $-autosize(SP) 200 // MOVW.LO $autosize, R1 201 // MOVW.LO $args, R2 202 // MOVW.LO R14, R3 203 // BL.LO runtime.morestack(SB) // modifies LR 204 // MOVW.W R14,$-autosize(SP) 205 206 // TODO(kaib): add more trampolines 207 // TODO(kaib): put stackguard in register 208 // TODO(kaib): add support for -K and underflow detection 209 210 // MOVW g_stackguard(g), R1 211 p = appendp(p); 212 p->as = AMOVW; 213 p->from.type = D_OREG; 214 p->from.reg = REGG; 215 p->to.type = D_REG; 216 p->to.reg = 1; 217 218 if(autosize < StackSmall) { 219 // CMP R1, SP 220 p = appendp(p); 221 p->as = ACMP; 222 p->from.type = D_REG; 223 p->from.reg = 1; 224 p->reg = REGSP; 225 } else { 226 // MOVW $-autosize(SP), R2 227 // CMP R1, R2 228 p = appendp(p); 229 p->as = AMOVW; 230 p->from.type = D_CONST; 231 p->from.reg = REGSP; 232 p->from.offset = -autosize; 233 p->to.type = D_REG; 234 p->to.reg = 2; 235 236 p = appendp(p); 237 p->as = ACMP; 238 p->from.type = D_REG; 239 p->from.reg = 1; 240 p->reg = 2; 241 } 242 243 // MOVW.LO $autosize, R1 244 p = appendp(p); 245 p->as = AMOVW; 246 p->scond = C_SCOND_LO; 247 p->from.type = D_CONST; 248 p->from.offset = autosize; 249 p->to.type = D_REG; 250 p->to.reg = 1; 251 252 // MOVW.LO $args, R2 253 p = appendp(p); 254 p->as = AMOVW; 255 p->scond = C_SCOND_LO; 256 p->from.type = D_CONST; 257 p->from.offset = (cursym->text->to.offset2 + 3) & ~3; 258 p->to.type = D_REG; 259 p->to.reg = 2; 260 261 // MOVW.LO R14, R3 262 p = appendp(p); 263 p->as = AMOVW; 264 p->scond = C_SCOND_LO; 265 p->from.type = D_REG; 266 p->from.reg = REGLINK; 267 p->to.type = D_REG; 268 p->to.reg = 3; 269 270 // BL.LO runtime.morestack(SB) // modifies LR 271 p = appendp(p); 272 p->as = ABL; 273 p->scond = C_SCOND_LO; 274 p->to.type = D_BRANCH; 275 p->to.sym = symmorestack; 276 p->cond = pmorestack; 277 278 // MOVW.W R14,$-autosize(SP) 279 p = appendp(p); 280 p->as = AMOVW; 281 p->scond |= C_WBIT; 282 p->from.type = D_REG; 283 p->from.reg = REGLINK; 284 p->to.type = D_OREG; 285 p->to.offset = -autosize; 286 p->to.reg = REGSP; 287 p->spadj = autosize; 288 } else { // > StackBig 289 // MOVW $autosize, R1 290 // MOVW $args, R2 291 // MOVW R14, R3 292 // BL runtime.morestack(SB) // modifies LR 293 // MOVW.W R14,$-autosize(SP) 294 295 // MOVW $autosize, R1 296 p = appendp(p); 297 p->as = AMOVW; 298 p->from.type = D_CONST; 299 p->from.offset = autosize; 300 p->to.type = D_REG; 301 p->to.reg = 1; 302 303 // MOVW $args, R2 304 // also need to store the extra 4 bytes. 305 p = appendp(p); 306 p->as = AMOVW; 307 p->from.type = D_CONST; 308 p->from.offset = (cursym->text->to.offset2 + 3) & ~3; 309 p->to.type = D_REG; 310 p->to.reg = 2; 311 312 // MOVW R14, R3 313 p = appendp(p); 314 p->as = AMOVW; 315 p->from.type = D_REG; 316 p->from.reg = REGLINK; 317 p->to.type = D_REG; 318 p->to.reg = 3; 319 320 // BL runtime.morestack(SB) // modifies LR 321 p = appendp(p); 322 p->as = ABL; 323 p->to.type = D_BRANCH; 324 p->to.sym = symmorestack; 325 p->cond = pmorestack; 326 327 // MOVW.W R14,$-autosize(SP) 328 p = appendp(p); 329 p->as = AMOVW; 330 p->scond |= C_WBIT; 331 p->from.type = D_REG; 332 p->from.reg = REGLINK; 333 p->to.type = D_OREG; 334 p->to.offset = -autosize; 335 p->to.reg = REGSP; 336 p->spadj = autosize; 337 } 338 break; 339 340 case ARET: 341 nocache(p); 342 if(cursym->text->mark & LEAF) { 343 if(!autosize) { 344 p->as = AB; 345 p->from = zprg.from; 346 p->to.type = D_OREG; 347 p->to.offset = 0; 348 p->to.reg = REGLINK; 349 break; 350 } 351 } 352 p->as = AMOVW; 353 p->scond |= C_PBIT; 354 p->from.type = D_OREG; 355 p->from.offset = autosize; 356 p->from.reg = REGSP; 357 p->to.type = D_REG; 358 p->to.reg = REGPC; 359 // If there are instructions following 360 // this ARET, they come from a branch 361 // with the same stackframe, so no spadj. 362 break; 363 364 case AADD: 365 if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) 366 p->spadj = -p->from.offset; 367 break; 368 369 case ASUB: 370 if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) 371 p->spadj = p->from.offset; 372 break; 373 374 case ADIV: 375 case ADIVU: 376 case AMOD: 377 case AMODU: 378 if(debug['M']) 379 break; 380 if(p->from.type != D_REG) 381 break; 382 if(p->to.type != D_REG) 383 break; 384 q1 = p; 385 386 /* MOV a,4(SP) */ 387 p = appendp(p); 388 p->as = AMOVW; 389 p->line = q1->line; 390 p->from.type = D_REG; 391 p->from.reg = q1->from.reg; 392 p->to.type = D_OREG; 393 p->to.reg = REGSP; 394 p->to.offset = 4; 395 396 /* MOV b,REGTMP */ 397 p = appendp(p); 398 p->as = AMOVW; 399 p->line = q1->line; 400 p->from.type = D_REG; 401 p->from.reg = q1->reg; 402 if(q1->reg == NREG) 403 p->from.reg = q1->to.reg; 404 p->to.type = D_REG; 405 p->to.reg = REGTMP; 406 p->to.offset = 0; 407 408 /* CALL appropriate */ 409 p = appendp(p); 410 p->as = ABL; 411 p->line = q1->line; 412 p->to.type = D_BRANCH; 413 p->cond = p; 414 switch(o) { 415 case ADIV: 416 p->cond = prog_div; 417 p->to.sym = sym_div; 418 break; 419 case ADIVU: 420 p->cond = prog_divu; 421 p->to.sym = sym_divu; 422 break; 423 case AMOD: 424 p->cond = prog_mod; 425 p->to.sym = sym_mod; 426 break; 427 case AMODU: 428 p->cond = prog_modu; 429 p->to.sym = sym_modu; 430 break; 431 } 432 433 /* MOV REGTMP, b */ 434 p = appendp(p); 435 p->as = AMOVW; 436 p->line = q1->line; 437 p->from.type = D_REG; 438 p->from.reg = REGTMP; 439 p->from.offset = 0; 440 p->to.type = D_REG; 441 p->to.reg = q1->to.reg; 442 443 /* ADD $8,SP */ 444 p = appendp(p); 445 p->as = AADD; 446 p->line = q1->line; 447 p->from.type = D_CONST; 448 p->from.reg = NREG; 449 p->from.offset = 8; 450 p->reg = NREG; 451 p->to.type = D_REG; 452 p->to.reg = REGSP; 453 p->spadj = -8; 454 455 /* SUB $8,SP */ 456 q1->as = ASUB; 457 q1->from.type = D_CONST; 458 q1->from.offset = 8; 459 q1->from.reg = NREG; 460 q1->reg = NREG; 461 q1->to.type = D_REG; 462 q1->to.reg = REGSP; 463 q1->spadj = 8; 464 465 break; 466 case AMOVW: 467 if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) 468 p->spadj = -p->to.offset; 469 if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) 470 p->spadj = -p->from.offset; 471 if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) 472 p->spadj = -p->from.offset; 473 break; 474 } 475 } 476 } 477 } 478 479 static void 480 sigdiv(char *n) 481 { 482 Sym *s; 483 484 s = lookup(n, 0); 485 if(s->type == STEXT) 486 if(s->sig == 0) 487 s->sig = SIGNINTERN; 488 } 489 490 void 491 divsig(void) 492 { 493 sigdiv("_div"); 494 sigdiv("_divu"); 495 sigdiv("_mod"); 496 sigdiv("_modu"); 497 } 498 499 void 500 initdiv(void) 501 { 502 Sym *s2, *s3, *s4, *s5; 503 504 if(prog_div != P) 505 return; 506 sym_div = s2 = lookup("_div", 0); 507 sym_divu = s3 = lookup("_divu", 0); 508 sym_mod = s4 = lookup("_mod", 0); 509 sym_modu = s5 = lookup("_modu", 0); 510 prog_div = s2->text; 511 prog_divu = s3->text; 512 prog_mod = s4->text; 513 prog_modu = s5->text; 514 if(prog_div == P) { 515 diag("undefined: %s", s2->name); 516 prog_div = cursym->text; 517 } 518 if(prog_divu == P) { 519 diag("undefined: %s", s3->name); 520 prog_divu = cursym->text; 521 } 522 if(prog_mod == P) { 523 diag("undefined: %s", s4->name); 524 prog_mod = cursym->text; 525 } 526 if(prog_modu == P) { 527 diag("undefined: %s", s5->name); 528 prog_modu = cursym->text; 529 } 530 } 531 532 void 533 nocache(Prog *p) 534 { 535 p->optab = 0; 536 p->from.class = 0; 537 p->to.class = 0; 538 }