github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/internal/obj/s390x/objz.go (about) 1 // Based on cmd/internal/obj/ppc64/obj9.go. 2 // 3 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 4 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 5 // Portions Copyright © 1997-1999 Vita Nuova Limited 6 // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) 7 // Portions Copyright © 2004,2006 Bruce Ellis 8 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 9 // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others 10 // Portions Copyright © 2009 The Go Authors. All rights reserved. 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining a copy 13 // of this software and associated documentation files (the "Software"), to deal 14 // in the Software without restriction, including without limitation the rights 15 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 // copies of the Software, and to permit persons to whom the Software is 17 // furnished to do so, subject to the following conditions: 18 // 19 // The above copyright notice and this permission notice shall be included in 20 // all copies or substantial portions of the Software. 21 // 22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 // THE SOFTWARE. 29 30 package s390x 31 32 import ( 33 "cmd/internal/obj" 34 "cmd/internal/sys" 35 "fmt" 36 "math" 37 ) 38 39 func progedit(ctxt *obj.Link, p *obj.Prog) { 40 p.From.Class = 0 41 p.To.Class = 0 42 43 // Rewrite BR/BL to symbol as TYPE_BRANCH. 44 switch p.As { 45 case ABR, 46 ABL, 47 obj.ARET, 48 obj.ADUFFZERO, 49 obj.ADUFFCOPY: 50 if p.To.Sym != nil { 51 p.To.Type = obj.TYPE_BRANCH 52 } 53 } 54 55 // Rewrite float constants to values stored in memory unless they are +0. 56 switch p.As { 57 case AFMOVS: 58 if p.From.Type == obj.TYPE_FCONST { 59 f32 := float32(p.From.Val.(float64)) 60 i32 := math.Float32bits(f32) 61 if i32 == 0 { // +0 62 break 63 } 64 literal := fmt.Sprintf("$f32.%08x", i32) 65 s := obj.Linklookup(ctxt, literal, 0) 66 s.Size = 4 67 p.From.Type = obj.TYPE_MEM 68 p.From.Sym = s 69 p.From.Sym.Set(obj.AttrLocal, true) 70 p.From.Name = obj.NAME_EXTERN 71 p.From.Offset = 0 72 } 73 74 case AFMOVD: 75 if p.From.Type == obj.TYPE_FCONST { 76 i64 := math.Float64bits(p.From.Val.(float64)) 77 if i64 == 0 { // +0 78 break 79 } 80 literal := fmt.Sprintf("$f64.%016x", i64) 81 s := obj.Linklookup(ctxt, literal, 0) 82 s.Size = 8 83 p.From.Type = obj.TYPE_MEM 84 p.From.Sym = s 85 p.From.Sym.Set(obj.AttrLocal, true) 86 p.From.Name = obj.NAME_EXTERN 87 p.From.Offset = 0 88 } 89 90 // put constants not loadable by LOAD IMMEDIATE into memory 91 case AMOVD: 92 if p.From.Type == obj.TYPE_CONST { 93 val := p.From.Offset 94 if int64(int32(val)) != val && 95 int64(uint32(val)) != val && 96 int64(uint64(val)&(0xffffffff<<32)) != val { 97 literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset)) 98 s := obj.Linklookup(ctxt, literal, 0) 99 s.Size = 8 100 p.From.Type = obj.TYPE_MEM 101 p.From.Sym = s 102 p.From.Sym.Set(obj.AttrLocal, true) 103 p.From.Name = obj.NAME_EXTERN 104 p.From.Offset = 0 105 } 106 } 107 } 108 109 // Rewrite SUB constants into ADD. 110 switch p.As { 111 case ASUBC: 112 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) { 113 p.From.Offset = -p.From.Offset 114 p.As = AADDC 115 } 116 117 case ASUB: 118 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) { 119 p.From.Offset = -p.From.Offset 120 p.As = AADD 121 } 122 } 123 124 if ctxt.Flag_dynlink { 125 rewriteToUseGot(ctxt, p) 126 } 127 } 128 129 // Rewrite p, if necessary, to access global data via the global offset table. 130 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) { 131 // At the moment EXRL instructions are not emitted by the compiler and only reference local symbols in 132 // assembly code. 133 if p.As == AEXRL { 134 return 135 } 136 137 // We only care about global data: NAME_EXTERN means a global 138 // symbol in the Go sense, and p.Sym.Local is true for a few 139 // internally defined symbols. 140 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 141 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 142 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx 143 if p.To.Type != obj.TYPE_REG || p.As != AMOVD { 144 ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p) 145 } 146 p.From.Type = obj.TYPE_MEM 147 p.From.Name = obj.NAME_GOTREF 148 q := p 149 if p.From.Offset != 0 { 150 q = obj.Appendp(ctxt, p) 151 q.As = AADD 152 q.From.Type = obj.TYPE_CONST 153 q.From.Offset = p.From.Offset 154 q.To = p.To 155 p.From.Offset = 0 156 } 157 } 158 if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { 159 ctxt.Diag("don't know how to handle %v with -dynlink", p) 160 } 161 var source *obj.Addr 162 // MOVD sym, Ry becomes MOVD sym@GOT, REGTMP; MOVD (REGTMP), Ry 163 // MOVD Ry, sym becomes MOVD sym@GOT, REGTMP; MOVD Ry, (REGTMP) 164 // An addition may be inserted between the two MOVs if there is an offset. 165 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 166 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 167 ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 168 } 169 source = &p.From 170 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 171 source = &p.To 172 } else { 173 return 174 } 175 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 176 return 177 } 178 if source.Sym.Type == obj.STLSBSS { 179 return 180 } 181 if source.Type != obj.TYPE_MEM { 182 ctxt.Diag("don't know how to handle %v with -dynlink", p) 183 } 184 p1 := obj.Appendp(ctxt, p) 185 p2 := obj.Appendp(ctxt, p1) 186 187 p1.As = AMOVD 188 p1.From.Type = obj.TYPE_MEM 189 p1.From.Sym = source.Sym 190 p1.From.Name = obj.NAME_GOTREF 191 p1.To.Type = obj.TYPE_REG 192 p1.To.Reg = REGTMP 193 194 p2.As = p.As 195 p2.From = p.From 196 p2.To = p.To 197 if p.From.Name == obj.NAME_EXTERN { 198 p2.From.Reg = REGTMP 199 p2.From.Name = obj.NAME_NONE 200 p2.From.Sym = nil 201 } else if p.To.Name == obj.NAME_EXTERN { 202 p2.To.Reg = REGTMP 203 p2.To.Name = obj.NAME_NONE 204 p2.To.Sym = nil 205 } else { 206 return 207 } 208 obj.Nopout(p) 209 } 210 211 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 212 // TODO(minux): add morestack short-cuts with small fixed frame-size. 213 ctxt.Cursym = cursym 214 215 if cursym.Text == nil || cursym.Text.Link == nil { 216 return 217 } 218 219 p := cursym.Text 220 textstksiz := p.To.Offset 221 if textstksiz == -8 { 222 // Compatibility hack. 223 p.From3.Offset |= obj.NOFRAME 224 textstksiz = 0 225 } 226 if textstksiz%8 != 0 { 227 ctxt.Diag("frame size %d not a multiple of 8", textstksiz) 228 } 229 if p.From3.Offset&obj.NOFRAME != 0 { 230 if textstksiz != 0 { 231 ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz) 232 } 233 } 234 235 cursym.Args = p.To.Val.(int32) 236 cursym.Locals = int32(textstksiz) 237 238 /* 239 * find leaf subroutines 240 * strip NOPs 241 * expand RET 242 * expand BECOME pseudo 243 */ 244 if ctxt.Debugvlog != 0 { 245 ctxt.Logf("%5.2f noops\n", obj.Cputime()) 246 } 247 248 var q *obj.Prog 249 var q1 *obj.Prog 250 for p := cursym.Text; p != nil; p = p.Link { 251 switch p.As { 252 /* too hard, just leave alone */ 253 case obj.ATEXT: 254 q = p 255 256 p.Mark |= LABEL | LEAF | SYNC 257 if p.Link != nil { 258 p.Link.Mark |= LABEL 259 } 260 261 case ASYNC, 262 AWORD: 263 q = p 264 p.Mark |= LABEL | SYNC 265 continue 266 267 case AMOVW, AMOVWZ, AMOVD: 268 q = p 269 if p.From.Reg >= REG_RESERVED || p.To.Reg >= REG_RESERVED { 270 p.Mark |= LABEL | SYNC 271 } 272 continue 273 274 case AFABS, 275 AFADD, 276 AFDIV, 277 AFMADD, 278 AFMOVD, 279 AFMOVS, 280 AFMSUB, 281 AFMUL, 282 AFNABS, 283 AFNEG, 284 AFNMADD, 285 AFNMSUB, 286 ALEDBR, 287 ALDEBR, 288 AFSUB: 289 q = p 290 291 p.Mark |= FLOAT 292 continue 293 294 case ABL, 295 ABCL, 296 obj.ADUFFZERO, 297 obj.ADUFFCOPY: 298 cursym.Text.Mark &^= LEAF 299 fallthrough 300 301 case ABC, 302 ABEQ, 303 ABGE, 304 ABGT, 305 ABLE, 306 ABLT, 307 ABLEU, 308 ABLTU, 309 ABNE, 310 ABR, 311 ABVC, 312 ABVS, 313 ACMPBEQ, 314 ACMPBGE, 315 ACMPBGT, 316 ACMPBLE, 317 ACMPBLT, 318 ACMPBNE, 319 ACMPUBEQ, 320 ACMPUBGE, 321 ACMPUBGT, 322 ACMPUBLE, 323 ACMPUBLT, 324 ACMPUBNE: 325 p.Mark |= BRANCH 326 q = p 327 q1 = p.Pcond 328 if q1 != nil { 329 for q1.As == obj.ANOP { 330 q1 = q1.Link 331 p.Pcond = q1 332 } 333 334 if q1.Mark&LEAF == 0 { 335 q1.Mark |= LABEL 336 } 337 } else { 338 p.Mark |= LABEL 339 } 340 q1 = p.Link 341 if q1 != nil { 342 q1.Mark |= LABEL 343 } 344 continue 345 346 case AFCMPO, AFCMPU: 347 q = p 348 p.Mark |= FCMP | FLOAT 349 continue 350 351 case obj.ARET: 352 q = p 353 if p.Link != nil { 354 p.Link.Mark |= LABEL 355 } 356 continue 357 358 case obj.ANOP: 359 q1 = p.Link 360 q.Link = q1 /* q is non-nop */ 361 q1.Mark |= p.Mark 362 continue 363 364 default: 365 q = p 366 continue 367 } 368 } 369 370 autosize := int32(0) 371 var p1 *obj.Prog 372 var p2 *obj.Prog 373 var pLast *obj.Prog 374 var pPre *obj.Prog 375 var pPreempt *obj.Prog 376 wasSplit := false 377 for p := cursym.Text; p != nil; p = p.Link { 378 pLast = p 379 switch p.As { 380 case obj.ATEXT: 381 autosize = int32(textstksiz) 382 383 if p.Mark&LEAF != 0 && autosize == 0 { 384 // A leaf function with no locals has no frame. 385 p.From3.Offset |= obj.NOFRAME 386 } 387 388 if p.From3.Offset&obj.NOFRAME == 0 { 389 // If there is a stack frame at all, it includes 390 // space to save the LR. 391 autosize += int32(ctxt.FixedFrameSize()) 392 } 393 394 if p.Mark&LEAF != 0 && autosize < obj.StackSmall { 395 // A leaf function with a small stack can be marked 396 // NOSPLIT, avoiding a stack check. 397 p.From3.Offset |= obj.NOSPLIT 398 } 399 400 p.To.Offset = int64(autosize) 401 402 q = p 403 404 if p.From3.Offset&obj.NOSPLIT == 0 { 405 p, pPreempt = stacksplitPre(ctxt, p, autosize) // emit pre part of split check 406 pPre = p 407 wasSplit = true //need post part of split 408 } 409 410 if autosize != 0 { 411 // Make sure to save link register for non-empty frame, even if 412 // it is a leaf function, so that traceback works. 413 // Store link register before decrementing SP, so if a signal comes 414 // during the execution of the function prologue, the traceback 415 // code will not see a half-updated stack frame. 416 q = obj.Appendp(ctxt, p) 417 q.As = AMOVD 418 q.From.Type = obj.TYPE_REG 419 q.From.Reg = REG_LR 420 q.To.Type = obj.TYPE_MEM 421 q.To.Reg = REGSP 422 q.To.Offset = int64(-autosize) 423 424 q = obj.Appendp(ctxt, q) 425 q.As = AMOVD 426 q.From.Type = obj.TYPE_ADDR 427 q.From.Offset = int64(-autosize) 428 q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided 429 q.To.Type = obj.TYPE_REG 430 q.To.Reg = REGSP 431 q.Spadj = autosize 432 } else if cursym.Text.Mark&LEAF == 0 { 433 // A very few functions that do not return to their caller 434 // (e.g. gogo) are not identified as leaves but still have 435 // no frame. 436 cursym.Text.Mark |= LEAF 437 } 438 439 if cursym.Text.Mark&LEAF != 0 { 440 cursym.Set(obj.AttrLeaf, true) 441 break 442 } 443 444 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 445 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 446 // 447 // MOVD g_panic(g), R3 448 // CMP R3, $0 449 // BEQ end 450 // MOVD panic_argp(R3), R4 451 // ADD $(autosize+8), R1, R5 452 // CMP R4, R5 453 // BNE end 454 // ADD $8, R1, R6 455 // MOVD R6, panic_argp(R3) 456 // end: 457 // NOP 458 // 459 // The NOP is needed to give the jumps somewhere to land. 460 // It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes. 461 462 q = obj.Appendp(ctxt, q) 463 464 q.As = AMOVD 465 q.From.Type = obj.TYPE_MEM 466 q.From.Reg = REGG 467 q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic 468 q.To.Type = obj.TYPE_REG 469 q.To.Reg = REG_R3 470 471 q = obj.Appendp(ctxt, q) 472 q.As = ACMP 473 q.From.Type = obj.TYPE_REG 474 q.From.Reg = REG_R3 475 q.To.Type = obj.TYPE_CONST 476 q.To.Offset = 0 477 478 q = obj.Appendp(ctxt, q) 479 q.As = ABEQ 480 q.To.Type = obj.TYPE_BRANCH 481 p1 = q 482 483 q = obj.Appendp(ctxt, q) 484 q.As = AMOVD 485 q.From.Type = obj.TYPE_MEM 486 q.From.Reg = REG_R3 487 q.From.Offset = 0 // Panic.argp 488 q.To.Type = obj.TYPE_REG 489 q.To.Reg = REG_R4 490 491 q = obj.Appendp(ctxt, q) 492 q.As = AADD 493 q.From.Type = obj.TYPE_CONST 494 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize() 495 q.Reg = REGSP 496 q.To.Type = obj.TYPE_REG 497 q.To.Reg = REG_R5 498 499 q = obj.Appendp(ctxt, q) 500 q.As = ACMP 501 q.From.Type = obj.TYPE_REG 502 q.From.Reg = REG_R4 503 q.To.Type = obj.TYPE_REG 504 q.To.Reg = REG_R5 505 506 q = obj.Appendp(ctxt, q) 507 q.As = ABNE 508 q.To.Type = obj.TYPE_BRANCH 509 p2 = q 510 511 q = obj.Appendp(ctxt, q) 512 q.As = AADD 513 q.From.Type = obj.TYPE_CONST 514 q.From.Offset = ctxt.FixedFrameSize() 515 q.Reg = REGSP 516 q.To.Type = obj.TYPE_REG 517 q.To.Reg = REG_R6 518 519 q = obj.Appendp(ctxt, q) 520 q.As = AMOVD 521 q.From.Type = obj.TYPE_REG 522 q.From.Reg = REG_R6 523 q.To.Type = obj.TYPE_MEM 524 q.To.Reg = REG_R3 525 q.To.Offset = 0 // Panic.argp 526 527 q = obj.Appendp(ctxt, q) 528 529 q.As = obj.ANOP 530 p1.Pcond = q 531 p2.Pcond = q 532 } 533 534 case obj.ARET: 535 if p.From.Type == obj.TYPE_CONST { 536 ctxt.Diag("using BECOME (%v) is not supported!", p) 537 break 538 } 539 540 retTarget := p.To.Sym 541 542 if cursym.Text.Mark&LEAF != 0 { 543 if autosize == 0 { 544 p.As = ABR 545 p.From = obj.Addr{} 546 if retTarget == nil { 547 p.To.Type = obj.TYPE_REG 548 p.To.Reg = REG_LR 549 } else { 550 p.To.Type = obj.TYPE_BRANCH 551 p.To.Sym = retTarget 552 } 553 p.Mark |= BRANCH 554 break 555 } 556 557 p.As = AADD 558 p.From.Type = obj.TYPE_CONST 559 p.From.Offset = int64(autosize) 560 p.To.Type = obj.TYPE_REG 561 p.To.Reg = REGSP 562 p.Spadj = -autosize 563 564 q = obj.Appendp(ctxt, p) 565 q.As = ABR 566 q.From = obj.Addr{} 567 q.To.Type = obj.TYPE_REG 568 q.To.Reg = REG_LR 569 q.Mark |= BRANCH 570 q.Spadj = autosize 571 break 572 } 573 574 p.As = AMOVD 575 p.From.Type = obj.TYPE_MEM 576 p.From.Reg = REGSP 577 p.From.Offset = 0 578 p.To.Type = obj.TYPE_REG 579 p.To.Reg = REG_LR 580 581 q = p 582 583 if autosize != 0 { 584 q = obj.Appendp(ctxt, q) 585 q.As = AADD 586 q.From.Type = obj.TYPE_CONST 587 q.From.Offset = int64(autosize) 588 q.To.Type = obj.TYPE_REG 589 q.To.Reg = REGSP 590 q.Spadj = -autosize 591 } 592 593 q = obj.Appendp(ctxt, q) 594 q.As = ABR 595 q.From = obj.Addr{} 596 if retTarget == nil { 597 q.To.Type = obj.TYPE_REG 598 q.To.Reg = REG_LR 599 } else { 600 q.To.Type = obj.TYPE_BRANCH 601 q.To.Sym = retTarget 602 } 603 q.Mark |= BRANCH 604 q.Spadj = autosize 605 606 case AADD: 607 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 608 p.Spadj = int32(-p.From.Offset) 609 } 610 } 611 } 612 if wasSplit { 613 pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt, autosize) // emit post part of split check 614 } 615 } 616 617 /* 618 // instruction scheduling 619 if(debug['Q'] == 0) 620 return; 621 622 curtext = nil; 623 q = nil; // p - 1 624 q1 = firstp; // top of block 625 o = 0; // count of instructions 626 for(p = firstp; p != nil; p = p1) { 627 p1 = p->link; 628 o++; 629 if(p->mark & NOSCHED){ 630 if(q1 != p){ 631 sched(q1, q); 632 } 633 for(; p != nil; p = p->link){ 634 if(!(p->mark & NOSCHED)) 635 break; 636 q = p; 637 } 638 p1 = p; 639 q1 = p; 640 o = 0; 641 continue; 642 } 643 if(p->mark & (LABEL|SYNC)) { 644 if(q1 != p) 645 sched(q1, q); 646 q1 = p; 647 o = 1; 648 } 649 if(p->mark & (BRANCH|SYNC)) { 650 sched(q1, p); 651 q1 = p1; 652 o = 0; 653 } 654 if(o >= NSCHED) { 655 sched(q1, p); 656 q1 = p1; 657 o = 0; 658 } 659 q = p; 660 } 661 */ 662 func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) { 663 var q *obj.Prog 664 665 // MOVD g_stackguard(g), R3 666 p = obj.Appendp(ctxt, p) 667 668 p.As = AMOVD 669 p.From.Type = obj.TYPE_MEM 670 p.From.Reg = REGG 671 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 672 if ctxt.Cursym.CFunc() { 673 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 674 } 675 p.To.Type = obj.TYPE_REG 676 p.To.Reg = REG_R3 677 678 q = nil 679 if framesize <= obj.StackSmall { 680 // small stack: SP < stackguard 681 // CMP stackguard, SP 682 683 //p.To.Type = obj.TYPE_REG 684 //p.To.Reg = REGSP 685 686 // q1: BLT done 687 688 p = obj.Appendp(ctxt, p) 689 //q1 = p 690 p.From.Type = obj.TYPE_REG 691 p.From.Reg = REG_R3 692 p.Reg = REGSP 693 p.As = ACMPUBGE 694 p.To.Type = obj.TYPE_BRANCH 695 //p = obj.Appendp(ctxt, p) 696 697 //p.As = ACMPU 698 //p.From.Type = obj.TYPE_REG 699 //p.From.Reg = REG_R3 700 //p.To.Type = obj.TYPE_REG 701 //p.To.Reg = REGSP 702 703 //p = obj.Appendp(ctxt, p) 704 //p.As = ABGE 705 //p.To.Type = obj.TYPE_BRANCH 706 707 } else if framesize <= obj.StackBig { 708 // large stack: SP-framesize < stackguard-StackSmall 709 // ADD $-framesize, SP, R4 710 // CMP stackguard, R4 711 p = obj.Appendp(ctxt, p) 712 713 p.As = AADD 714 p.From.Type = obj.TYPE_CONST 715 p.From.Offset = int64(-framesize) 716 p.Reg = REGSP 717 p.To.Type = obj.TYPE_REG 718 p.To.Reg = REG_R4 719 720 p = obj.Appendp(ctxt, p) 721 p.From.Type = obj.TYPE_REG 722 p.From.Reg = REG_R3 723 p.Reg = REG_R4 724 p.As = ACMPUBGE 725 p.To.Type = obj.TYPE_BRANCH 726 727 } else { 728 // Such a large stack we need to protect against wraparound. 729 // If SP is close to zero: 730 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 731 // The +StackGuard on both sides is required to keep the left side positive: 732 // SP is allowed to be slightly below stackguard. See stack.h. 733 // 734 // Preemption sets stackguard to StackPreempt, a very large value. 735 // That breaks the math above, so we have to check for that explicitly. 736 // // stackguard is R3 737 // CMP R3, $StackPreempt 738 // BEQ label-of-call-to-morestack 739 // ADD $StackGuard, SP, R4 740 // SUB R3, R4 741 // MOVD $(framesize+(StackGuard-StackSmall)), TEMP 742 // CMPUBGE TEMP, R4 743 p = obj.Appendp(ctxt, p) 744 745 p.As = ACMP 746 p.From.Type = obj.TYPE_REG 747 p.From.Reg = REG_R3 748 p.To.Type = obj.TYPE_CONST 749 p.To.Offset = obj.StackPreempt 750 751 p = obj.Appendp(ctxt, p) 752 q = p 753 p.As = ABEQ 754 p.To.Type = obj.TYPE_BRANCH 755 756 p = obj.Appendp(ctxt, p) 757 p.As = AADD 758 p.From.Type = obj.TYPE_CONST 759 p.From.Offset = obj.StackGuard 760 p.Reg = REGSP 761 p.To.Type = obj.TYPE_REG 762 p.To.Reg = REG_R4 763 764 p = obj.Appendp(ctxt, p) 765 p.As = ASUB 766 p.From.Type = obj.TYPE_REG 767 p.From.Reg = REG_R3 768 p.To.Type = obj.TYPE_REG 769 p.To.Reg = REG_R4 770 771 p = obj.Appendp(ctxt, p) 772 p.As = AMOVD 773 p.From.Type = obj.TYPE_CONST 774 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 775 p.To.Type = obj.TYPE_REG 776 p.To.Reg = REGTMP 777 778 p = obj.Appendp(ctxt, p) 779 p.From.Type = obj.TYPE_REG 780 p.From.Reg = REGTMP 781 p.Reg = REG_R4 782 p.As = ACMPUBGE 783 p.To.Type = obj.TYPE_BRANCH 784 } 785 786 return p, q 787 } 788 789 func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog { 790 // Now we are at the end of the function, but logically 791 // we are still in function prologue. We need to fix the 792 // SP data and PCDATA. 793 spfix := obj.Appendp(ctxt, p) 794 spfix.As = obj.ANOP 795 spfix.Spadj = -framesize 796 797 pcdata := obj.Appendp(ctxt, spfix) 798 pcdata.Lineno = ctxt.Cursym.Text.Lineno 799 pcdata.Mode = ctxt.Cursym.Text.Mode 800 pcdata.As = obj.APCDATA 801 pcdata.From.Type = obj.TYPE_CONST 802 pcdata.From.Offset = obj.PCDATA_StackMapIndex 803 pcdata.To.Type = obj.TYPE_CONST 804 pcdata.To.Offset = -1 // pcdata starts at -1 at function entry 805 806 // MOVD LR, R5 807 p = obj.Appendp(ctxt, pcdata) 808 pPre.Pcond = p 809 p.As = AMOVD 810 p.From.Type = obj.TYPE_REG 811 p.From.Reg = REG_LR 812 p.To.Type = obj.TYPE_REG 813 p.To.Reg = REG_R5 814 if pPreempt != nil { 815 pPreempt.Pcond = p 816 } 817 818 // BL runtime.morestack(SB) 819 p = obj.Appendp(ctxt, p) 820 821 p.As = ABL 822 p.To.Type = obj.TYPE_BRANCH 823 if ctxt.Cursym.CFunc() { 824 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 825 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 826 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 827 } else { 828 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0) 829 } 830 831 // BR start 832 p = obj.Appendp(ctxt, p) 833 834 p.As = ABR 835 p.To.Type = obj.TYPE_BRANCH 836 p.Pcond = ctxt.Cursym.Text.Link 837 return p 838 } 839 840 var pc_cnt int64 841 842 func follow(ctxt *obj.Link, s *obj.LSym) { 843 ctxt.Cursym = s 844 845 pc_cnt = 0 846 firstp := ctxt.NewProg() 847 lastp := firstp 848 xfol(ctxt, s.Text, &lastp) 849 lastp.Link = nil 850 s.Text = firstp.Link 851 } 852 853 func relinv(a obj.As) obj.As { 854 switch a { 855 case ABEQ: 856 return ABNE 857 case ABNE: 858 return ABEQ 859 860 case ABGE: 861 return ABLT 862 case ABLT: 863 return ABGE 864 865 case ABGT: 866 return ABLE 867 case ABLE: 868 return ABGT 869 870 case ABVC: 871 return ABVS 872 case ABVS: 873 return ABVC 874 } 875 876 return 0 877 } 878 879 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 880 var q *obj.Prog 881 var r *obj.Prog 882 var b obj.As 883 884 for p != nil { 885 a := p.As 886 if a == ABR { 887 q = p.Pcond 888 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 889 p.Mark |= FOLL 890 (*last).Link = p 891 *last = p 892 (*last).Pc = pc_cnt 893 pc_cnt += 1 894 p = p.Link 895 xfol(ctxt, p, last) 896 p = q 897 if p != nil && p.Mark&FOLL == 0 { 898 continue 899 } 900 return 901 } 902 903 if q != nil { 904 p.Mark |= FOLL 905 p = q 906 if p.Mark&FOLL == 0 { 907 continue 908 } 909 } 910 } 911 912 if p.Mark&FOLL != 0 { 913 q = p 914 for i := 0; i < 4; i, q = i+1, q.Link { 915 if q == *last || (q.Mark&NOSCHED != 0) { 916 break 917 } 918 b = 0 /* set */ 919 a = q.As 920 if a == obj.ANOP { 921 i-- 922 continue 923 } 924 if a != ABR && a != obj.ARET { 925 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 926 continue 927 } 928 b = relinv(a) 929 if b == 0 { 930 continue 931 } 932 } 933 934 for { 935 r = ctxt.NewProg() 936 *r = *p 937 if r.Mark&FOLL == 0 { 938 fmt.Printf("can't happen 1\n") 939 } 940 r.Mark |= FOLL 941 if p != q { 942 p = p.Link 943 (*last).Link = r 944 *last = r 945 (*last).Pc = pc_cnt 946 pc_cnt += 1 947 continue 948 } 949 950 (*last).Link = r 951 *last = r 952 (*last).Pc = pc_cnt 953 pc_cnt += 1 954 if a == ABR || a == obj.ARET { 955 return 956 } 957 r.As = b 958 r.Pcond = p.Link 959 r.Link = p.Pcond 960 if r.Link.Mark&FOLL == 0 { 961 xfol(ctxt, r.Link, last) 962 } 963 if r.Pcond.Mark&FOLL == 0 { 964 fmt.Printf("can't happen 2\n") 965 } 966 return 967 } 968 } 969 970 a = ABR 971 q = ctxt.NewProg() 972 q.As = a 973 q.Lineno = p.Lineno 974 q.To.Type = obj.TYPE_BRANCH 975 q.To.Offset = p.Pc 976 q.Pcond = p 977 p = q 978 } 979 980 p.Mark |= FOLL 981 (*last).Link = p 982 *last = p 983 (*last).Pc = pc_cnt 984 pc_cnt += 1 985 986 if a == ABR || a == obj.ARET { 987 if p.Mark&NOSCHED != 0 { 988 p = p.Link 989 continue 990 } 991 992 return 993 } 994 995 if p.Pcond != nil { 996 if a != ABL && p.Link != nil { 997 xfol(ctxt, p.Link, last) 998 p = p.Pcond 999 if p == nil || (p.Mark&FOLL != 0) { 1000 return 1001 } 1002 continue 1003 } 1004 } 1005 1006 p = p.Link 1007 } 1008 } 1009 1010 var unaryDst = map[obj.As]bool{ 1011 ASTCK: true, 1012 ASTCKC: true, 1013 ASTCKE: true, 1014 ASTCKF: true, 1015 ANEG: true, 1016 ANEGW: true, 1017 AVONE: true, 1018 AVZERO: true, 1019 } 1020 1021 var Links390x = obj.LinkArch{ 1022 Arch: sys.ArchS390X, 1023 Preprocess: preprocess, 1024 Assemble: spanz, 1025 Follow: follow, 1026 Progedit: progedit, 1027 UnaryDst: unaryDst, 1028 }