github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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 ALEDBR, 285 ALDEBR, 286 AFSUB: 287 q = p 288 289 p.Mark |= FLOAT 290 continue 291 292 case ABL, 293 ABCL, 294 obj.ADUFFZERO, 295 obj.ADUFFCOPY: 296 cursym.Text.Mark &^= LEAF 297 fallthrough 298 299 case ABC, 300 ABEQ, 301 ABGE, 302 ABGT, 303 ABLE, 304 ABLT, 305 ABLEU, 306 ABLTU, 307 ABNE, 308 ABR, 309 ABVC, 310 ABVS, 311 ACMPBEQ, 312 ACMPBGE, 313 ACMPBGT, 314 ACMPBLE, 315 ACMPBLT, 316 ACMPBNE, 317 ACMPUBEQ, 318 ACMPUBGE, 319 ACMPUBGT, 320 ACMPUBLE, 321 ACMPUBLT, 322 ACMPUBNE: 323 p.Mark |= BRANCH 324 q = p 325 q1 = p.Pcond 326 if q1 != nil { 327 for q1.As == obj.ANOP { 328 q1 = q1.Link 329 p.Pcond = q1 330 } 331 332 if q1.Mark&LEAF == 0 { 333 q1.Mark |= LABEL 334 } 335 } else { 336 p.Mark |= LABEL 337 } 338 q1 = p.Link 339 if q1 != nil { 340 q1.Mark |= LABEL 341 } 342 continue 343 344 case AFCMPO, AFCMPU: 345 q = p 346 p.Mark |= FCMP | FLOAT 347 continue 348 349 case obj.ARET: 350 q = p 351 if p.Link != nil { 352 p.Link.Mark |= LABEL 353 } 354 continue 355 356 case obj.ANOP: 357 q1 = p.Link 358 q.Link = q1 /* q is non-nop */ 359 q1.Mark |= p.Mark 360 continue 361 362 default: 363 q = p 364 continue 365 } 366 } 367 368 autosize := int32(0) 369 var p1 *obj.Prog 370 var p2 *obj.Prog 371 var pLast *obj.Prog 372 var pPre *obj.Prog 373 var pPreempt *obj.Prog 374 wasSplit := false 375 for p := cursym.Text; p != nil; p = p.Link { 376 pLast = p 377 switch p.As { 378 case obj.ATEXT: 379 autosize = int32(textstksiz) 380 381 if p.Mark&LEAF != 0 && autosize == 0 { 382 // A leaf function with no locals has no frame. 383 p.From3.Offset |= obj.NOFRAME 384 } 385 386 if p.From3.Offset&obj.NOFRAME == 0 { 387 // If there is a stack frame at all, it includes 388 // space to save the LR. 389 autosize += int32(ctxt.FixedFrameSize()) 390 } 391 392 if p.Mark&LEAF != 0 && autosize < obj.StackSmall { 393 // A leaf function with a small stack can be marked 394 // NOSPLIT, avoiding a stack check. 395 p.From3.Offset |= obj.NOSPLIT 396 } 397 398 p.To.Offset = int64(autosize) 399 400 q = p 401 402 if p.From3.Offset&obj.NOSPLIT == 0 { 403 p, pPreempt = stacksplitPre(ctxt, p, autosize) // emit pre part of split check 404 pPre = p 405 wasSplit = true //need post part of split 406 } 407 408 if autosize != 0 { 409 // Make sure to save link register for non-empty frame, even if 410 // it is a leaf function, so that traceback works. 411 // Store link register before decrementing SP, so if a signal comes 412 // during the execution of the function prologue, the traceback 413 // code will not see a half-updated stack frame. 414 q = obj.Appendp(ctxt, p) 415 q.As = AMOVD 416 q.From.Type = obj.TYPE_REG 417 q.From.Reg = REG_LR 418 q.To.Type = obj.TYPE_MEM 419 q.To.Reg = REGSP 420 q.To.Offset = int64(-autosize) 421 422 q = obj.Appendp(ctxt, q) 423 q.As = AMOVD 424 q.From.Type = obj.TYPE_ADDR 425 q.From.Offset = int64(-autosize) 426 q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided 427 q.To.Type = obj.TYPE_REG 428 q.To.Reg = REGSP 429 q.Spadj = autosize 430 } else if cursym.Text.Mark&LEAF == 0 { 431 // A very few functions that do not return to their caller 432 // (e.g. gogo) are not identified as leaves but still have 433 // no frame. 434 cursym.Text.Mark |= LEAF 435 } 436 437 if cursym.Text.Mark&LEAF != 0 { 438 cursym.Set(obj.AttrLeaf, true) 439 break 440 } 441 442 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 443 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 444 // 445 // MOVD g_panic(g), R3 446 // CMP R3, $0 447 // BEQ end 448 // MOVD panic_argp(R3), R4 449 // ADD $(autosize+8), R1, R5 450 // CMP R4, R5 451 // BNE end 452 // ADD $8, R1, R6 453 // MOVD R6, panic_argp(R3) 454 // end: 455 // NOP 456 // 457 // The NOP is needed to give the jumps somewhere to land. 458 // It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes. 459 460 q = obj.Appendp(ctxt, q) 461 462 q.As = AMOVD 463 q.From.Type = obj.TYPE_MEM 464 q.From.Reg = REGG 465 q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic 466 q.To.Type = obj.TYPE_REG 467 q.To.Reg = REG_R3 468 469 q = obj.Appendp(ctxt, q) 470 q.As = ACMP 471 q.From.Type = obj.TYPE_REG 472 q.From.Reg = REG_R3 473 q.To.Type = obj.TYPE_CONST 474 q.To.Offset = 0 475 476 q = obj.Appendp(ctxt, q) 477 q.As = ABEQ 478 q.To.Type = obj.TYPE_BRANCH 479 p1 = q 480 481 q = obj.Appendp(ctxt, q) 482 q.As = AMOVD 483 q.From.Type = obj.TYPE_MEM 484 q.From.Reg = REG_R3 485 q.From.Offset = 0 // Panic.argp 486 q.To.Type = obj.TYPE_REG 487 q.To.Reg = REG_R4 488 489 q = obj.Appendp(ctxt, q) 490 q.As = AADD 491 q.From.Type = obj.TYPE_CONST 492 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize() 493 q.Reg = REGSP 494 q.To.Type = obj.TYPE_REG 495 q.To.Reg = REG_R5 496 497 q = obj.Appendp(ctxt, q) 498 q.As = ACMP 499 q.From.Type = obj.TYPE_REG 500 q.From.Reg = REG_R4 501 q.To.Type = obj.TYPE_REG 502 q.To.Reg = REG_R5 503 504 q = obj.Appendp(ctxt, q) 505 q.As = ABNE 506 q.To.Type = obj.TYPE_BRANCH 507 p2 = q 508 509 q = obj.Appendp(ctxt, q) 510 q.As = AADD 511 q.From.Type = obj.TYPE_CONST 512 q.From.Offset = ctxt.FixedFrameSize() 513 q.Reg = REGSP 514 q.To.Type = obj.TYPE_REG 515 q.To.Reg = REG_R6 516 517 q = obj.Appendp(ctxt, q) 518 q.As = AMOVD 519 q.From.Type = obj.TYPE_REG 520 q.From.Reg = REG_R6 521 q.To.Type = obj.TYPE_MEM 522 q.To.Reg = REG_R3 523 q.To.Offset = 0 // Panic.argp 524 525 q = obj.Appendp(ctxt, q) 526 527 q.As = obj.ANOP 528 p1.Pcond = q 529 p2.Pcond = q 530 } 531 532 case obj.ARET: 533 if p.From.Type == obj.TYPE_CONST { 534 ctxt.Diag("using BECOME (%v) is not supported!", p) 535 break 536 } 537 538 retTarget := p.To.Sym 539 540 if cursym.Text.Mark&LEAF != 0 { 541 if autosize == 0 { 542 p.As = ABR 543 p.From = obj.Addr{} 544 if retTarget == nil { 545 p.To.Type = obj.TYPE_REG 546 p.To.Reg = REG_LR 547 } else { 548 p.To.Type = obj.TYPE_BRANCH 549 p.To.Sym = retTarget 550 } 551 p.Mark |= BRANCH 552 break 553 } 554 555 p.As = AADD 556 p.From.Type = obj.TYPE_CONST 557 p.From.Offset = int64(autosize) 558 p.To.Type = obj.TYPE_REG 559 p.To.Reg = REGSP 560 p.Spadj = -autosize 561 562 q = obj.Appendp(ctxt, p) 563 q.As = ABR 564 q.From = obj.Addr{} 565 q.To.Type = obj.TYPE_REG 566 q.To.Reg = REG_LR 567 q.Mark |= BRANCH 568 q.Spadj = autosize 569 break 570 } 571 572 p.As = AMOVD 573 p.From.Type = obj.TYPE_MEM 574 p.From.Reg = REGSP 575 p.From.Offset = 0 576 p.To.Type = obj.TYPE_REG 577 p.To.Reg = REG_LR 578 579 q = p 580 581 if autosize != 0 { 582 q = obj.Appendp(ctxt, q) 583 q.As = AADD 584 q.From.Type = obj.TYPE_CONST 585 q.From.Offset = int64(autosize) 586 q.To.Type = obj.TYPE_REG 587 q.To.Reg = REGSP 588 q.Spadj = -autosize 589 } 590 591 q = obj.Appendp(ctxt, q) 592 q.As = ABR 593 q.From = obj.Addr{} 594 if retTarget == nil { 595 q.To.Type = obj.TYPE_REG 596 q.To.Reg = REG_LR 597 } else { 598 q.To.Type = obj.TYPE_BRANCH 599 q.To.Sym = retTarget 600 } 601 q.Mark |= BRANCH 602 q.Spadj = autosize 603 604 case AADD: 605 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 606 p.Spadj = int32(-p.From.Offset) 607 } 608 } 609 } 610 if wasSplit { 611 pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt, autosize) // emit post part of split check 612 } 613 } 614 615 /* 616 // instruction scheduling 617 if(debug['Q'] == 0) 618 return; 619 620 curtext = nil; 621 q = nil; // p - 1 622 q1 = firstp; // top of block 623 o = 0; // count of instructions 624 for(p = firstp; p != nil; p = p1) { 625 p1 = p->link; 626 o++; 627 if(p->mark & NOSCHED){ 628 if(q1 != p){ 629 sched(q1, q); 630 } 631 for(; p != nil; p = p->link){ 632 if(!(p->mark & NOSCHED)) 633 break; 634 q = p; 635 } 636 p1 = p; 637 q1 = p; 638 o = 0; 639 continue; 640 } 641 if(p->mark & (LABEL|SYNC)) { 642 if(q1 != p) 643 sched(q1, q); 644 q1 = p; 645 o = 1; 646 } 647 if(p->mark & (BRANCH|SYNC)) { 648 sched(q1, p); 649 q1 = p1; 650 o = 0; 651 } 652 if(o >= NSCHED) { 653 sched(q1, p); 654 q1 = p1; 655 o = 0; 656 } 657 q = p; 658 } 659 */ 660 func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) { 661 var q *obj.Prog 662 663 // MOVD g_stackguard(g), R3 664 p = obj.Appendp(ctxt, p) 665 666 p.As = AMOVD 667 p.From.Type = obj.TYPE_MEM 668 p.From.Reg = REGG 669 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 670 if ctxt.Cursym.CFunc() { 671 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 672 } 673 p.To.Type = obj.TYPE_REG 674 p.To.Reg = REG_R3 675 676 q = nil 677 if framesize <= obj.StackSmall { 678 // small stack: SP < stackguard 679 // CMP stackguard, SP 680 681 //p.To.Type = obj.TYPE_REG 682 //p.To.Reg = REGSP 683 684 // q1: BLT done 685 686 p = obj.Appendp(ctxt, p) 687 //q1 = p 688 p.From.Type = obj.TYPE_REG 689 p.From.Reg = REG_R3 690 p.Reg = REGSP 691 p.As = ACMPUBGE 692 p.To.Type = obj.TYPE_BRANCH 693 //p = obj.Appendp(ctxt, p) 694 695 //p.As = ACMPU 696 //p.From.Type = obj.TYPE_REG 697 //p.From.Reg = REG_R3 698 //p.To.Type = obj.TYPE_REG 699 //p.To.Reg = REGSP 700 701 //p = obj.Appendp(ctxt, p) 702 //p.As = ABGE 703 //p.To.Type = obj.TYPE_BRANCH 704 705 } else if framesize <= obj.StackBig { 706 // large stack: SP-framesize < stackguard-StackSmall 707 // ADD $-framesize, SP, R4 708 // CMP stackguard, R4 709 p = obj.Appendp(ctxt, p) 710 711 p.As = AADD 712 p.From.Type = obj.TYPE_CONST 713 p.From.Offset = int64(-framesize) 714 p.Reg = REGSP 715 p.To.Type = obj.TYPE_REG 716 p.To.Reg = REG_R4 717 718 p = obj.Appendp(ctxt, p) 719 p.From.Type = obj.TYPE_REG 720 p.From.Reg = REG_R3 721 p.Reg = REG_R4 722 p.As = ACMPUBGE 723 p.To.Type = obj.TYPE_BRANCH 724 725 } else { 726 // Such a large stack we need to protect against wraparound. 727 // If SP is close to zero: 728 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 729 // The +StackGuard on both sides is required to keep the left side positive: 730 // SP is allowed to be slightly below stackguard. See stack.h. 731 // 732 // Preemption sets stackguard to StackPreempt, a very large value. 733 // That breaks the math above, so we have to check for that explicitly. 734 // // stackguard is R3 735 // CMP R3, $StackPreempt 736 // BEQ label-of-call-to-morestack 737 // ADD $StackGuard, SP, R4 738 // SUB R3, R4 739 // MOVD $(framesize+(StackGuard-StackSmall)), TEMP 740 // CMPUBGE TEMP, R4 741 p = obj.Appendp(ctxt, p) 742 743 p.As = ACMP 744 p.From.Type = obj.TYPE_REG 745 p.From.Reg = REG_R3 746 p.To.Type = obj.TYPE_CONST 747 p.To.Offset = obj.StackPreempt 748 749 p = obj.Appendp(ctxt, p) 750 q = p 751 p.As = ABEQ 752 p.To.Type = obj.TYPE_BRANCH 753 754 p = obj.Appendp(ctxt, p) 755 p.As = AADD 756 p.From.Type = obj.TYPE_CONST 757 p.From.Offset = obj.StackGuard 758 p.Reg = REGSP 759 p.To.Type = obj.TYPE_REG 760 p.To.Reg = REG_R4 761 762 p = obj.Appendp(ctxt, p) 763 p.As = ASUB 764 p.From.Type = obj.TYPE_REG 765 p.From.Reg = REG_R3 766 p.To.Type = obj.TYPE_REG 767 p.To.Reg = REG_R4 768 769 p = obj.Appendp(ctxt, p) 770 p.As = AMOVD 771 p.From.Type = obj.TYPE_CONST 772 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 773 p.To.Type = obj.TYPE_REG 774 p.To.Reg = REGTMP 775 776 p = obj.Appendp(ctxt, p) 777 p.From.Type = obj.TYPE_REG 778 p.From.Reg = REGTMP 779 p.Reg = REG_R4 780 p.As = ACMPUBGE 781 p.To.Type = obj.TYPE_BRANCH 782 } 783 784 return p, q 785 } 786 787 func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog { 788 // Now we are at the end of the function, but logically 789 // we are still in function prologue. We need to fix the 790 // SP data and PCDATA. 791 spfix := obj.Appendp(ctxt, p) 792 spfix.As = obj.ANOP 793 spfix.Spadj = -framesize 794 795 pcdata := obj.Appendp(ctxt, spfix) 796 pcdata.Pos = ctxt.Cursym.Text.Pos 797 pcdata.Mode = ctxt.Cursym.Text.Mode 798 pcdata.As = obj.APCDATA 799 pcdata.From.Type = obj.TYPE_CONST 800 pcdata.From.Offset = obj.PCDATA_StackMapIndex 801 pcdata.To.Type = obj.TYPE_CONST 802 pcdata.To.Offset = -1 // pcdata starts at -1 at function entry 803 804 // MOVD LR, R5 805 p = obj.Appendp(ctxt, pcdata) 806 pPre.Pcond = p 807 p.As = AMOVD 808 p.From.Type = obj.TYPE_REG 809 p.From.Reg = REG_LR 810 p.To.Type = obj.TYPE_REG 811 p.To.Reg = REG_R5 812 if pPreempt != nil { 813 pPreempt.Pcond = p 814 } 815 816 // BL runtime.morestack(SB) 817 p = obj.Appendp(ctxt, p) 818 819 p.As = ABL 820 p.To.Type = obj.TYPE_BRANCH 821 if ctxt.Cursym.CFunc() { 822 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 823 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 824 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 825 } else { 826 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0) 827 } 828 829 // BR start 830 p = obj.Appendp(ctxt, p) 831 832 p.As = ABR 833 p.To.Type = obj.TYPE_BRANCH 834 p.Pcond = ctxt.Cursym.Text.Link 835 return p 836 } 837 838 var unaryDst = map[obj.As]bool{ 839 ASTCK: true, 840 ASTCKC: true, 841 ASTCKE: true, 842 ASTCKF: true, 843 ANEG: true, 844 ANEGW: true, 845 AVONE: true, 846 AVZERO: true, 847 } 848 849 var Links390x = obj.LinkArch{ 850 Arch: sys.ArchS390X, 851 Preprocess: preprocess, 852 Assemble: spanz, 853 Progedit: progedit, 854 UnaryDst: unaryDst, 855 }