github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/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.Local = 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.Local = 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.Local = 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 { 113 p.From.Offset = -p.From.Offset 114 p.As = AADDC 115 } 116 117 case ASUB: 118 if p.From.Type == obj.TYPE_CONST { 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 fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime()) 246 } 247 ctxt.Bso.Flush() 248 249 var q *obj.Prog 250 var q1 *obj.Prog 251 for p := cursym.Text; p != nil; p = p.Link { 252 switch p.As { 253 /* too hard, just leave alone */ 254 case obj.ATEXT: 255 q = p 256 257 p.Mark |= LABEL | LEAF | SYNC 258 if p.Link != nil { 259 p.Link.Mark |= LABEL 260 } 261 262 case ANOR: 263 q = p 264 if p.To.Type == obj.TYPE_REG { 265 if p.To.Reg == REGZERO { 266 p.Mark |= LABEL | SYNC 267 } 268 } 269 270 case ASYNC, 271 AWORD: 272 q = p 273 p.Mark |= LABEL | SYNC 274 continue 275 276 case AMOVW, AMOVWZ, AMOVD: 277 q = p 278 if p.From.Reg >= REG_RESERVED || p.To.Reg >= REG_RESERVED { 279 p.Mark |= LABEL | SYNC 280 } 281 continue 282 283 case AFABS, 284 AFADD, 285 AFDIV, 286 AFMADD, 287 AFMOVD, 288 AFMOVS, 289 AFMSUB, 290 AFMUL, 291 AFNABS, 292 AFNEG, 293 AFNMADD, 294 AFNMSUB, 295 ALEDBR, 296 ALDEBR, 297 AFSUB: 298 q = p 299 300 p.Mark |= FLOAT 301 continue 302 303 case ABL, 304 ABCL, 305 obj.ADUFFZERO, 306 obj.ADUFFCOPY: 307 cursym.Text.Mark &^= LEAF 308 fallthrough 309 310 case ABC, 311 ABEQ, 312 ABGE, 313 ABGT, 314 ABLE, 315 ABLT, 316 ABNE, 317 ABR, 318 ABVC, 319 ABVS, 320 ACMPBEQ, 321 ACMPBGE, 322 ACMPBGT, 323 ACMPBLE, 324 ACMPBLT, 325 ACMPBNE, 326 ACMPUBEQ, 327 ACMPUBGE, 328 ACMPUBGT, 329 ACMPUBLE, 330 ACMPUBLT, 331 ACMPUBNE: 332 p.Mark |= BRANCH 333 q = p 334 q1 = p.Pcond 335 if q1 != nil { 336 for q1.As == obj.ANOP { 337 q1 = q1.Link 338 p.Pcond = q1 339 } 340 341 if q1.Mark&LEAF == 0 { 342 q1.Mark |= LABEL 343 } 344 } else { 345 p.Mark |= LABEL 346 } 347 q1 = p.Link 348 if q1 != nil { 349 q1.Mark |= LABEL 350 } 351 continue 352 353 case AFCMPO, AFCMPU: 354 q = p 355 p.Mark |= FCMP | FLOAT 356 continue 357 358 case obj.ARET: 359 q = p 360 if p.Link != nil { 361 p.Link.Mark |= LABEL 362 } 363 continue 364 365 case obj.ANOP: 366 q1 = p.Link 367 q.Link = q1 /* q is non-nop */ 368 q1.Mark |= p.Mark 369 continue 370 371 default: 372 q = p 373 continue 374 } 375 } 376 377 autosize := int32(0) 378 var p1 *obj.Prog 379 var p2 *obj.Prog 380 var pLast *obj.Prog 381 var pPre *obj.Prog 382 var pPreempt *obj.Prog 383 wasSplit := false 384 for p := cursym.Text; p != nil; p = p.Link { 385 pLast = p 386 switch p.As { 387 case obj.ATEXT: 388 autosize = int32(textstksiz) 389 390 if p.Mark&LEAF != 0 && autosize == 0 && p.From3.Offset&obj.NOFRAME == 0 { 391 // A leaf function with no locals has no frame. 392 p.From3.Offset |= obj.NOFRAME 393 } 394 395 if p.From3.Offset&obj.NOFRAME == 0 { 396 // If there is a stack frame at all, it includes 397 // space to save the LR. 398 autosize += int32(ctxt.FixedFrameSize()) 399 } 400 401 p.To.Offset = int64(autosize) 402 403 q = p 404 405 if p.From3.Offset&obj.NOSPLIT == 0 { 406 p, pPreempt = stacksplitPre(ctxt, p, autosize) // emit pre part of split check 407 pPre = p 408 wasSplit = true //need post part of split 409 } 410 411 if autosize != 0 { 412 q = obj.Appendp(ctxt, p) 413 q.As = AMOVD 414 q.From.Type = obj.TYPE_ADDR 415 q.From.Offset = int64(-autosize) 416 q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided 417 q.To.Type = obj.TYPE_REG 418 q.To.Reg = REGSP 419 q.Spadj = autosize 420 } else if cursym.Text.Mark&LEAF == 0 { 421 // A very few functions that do not return to their caller 422 // (e.g. gogo) are not identified as leaves but still have 423 // no frame. 424 cursym.Text.Mark |= LEAF 425 } 426 427 if cursym.Text.Mark&LEAF != 0 { 428 cursym.Leaf = true 429 break 430 } 431 432 q = obj.Appendp(ctxt, q) 433 q.As = AMOVD 434 q.From.Type = obj.TYPE_REG 435 q.From.Reg = REG_LR 436 q.To.Type = obj.TYPE_MEM 437 q.To.Reg = REGSP 438 q.To.Offset = 0 439 440 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 441 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 442 // 443 // MOVD g_panic(g), R3 444 // CMP R0, R3 445 // BEQ end 446 // MOVD panic_argp(R3), R4 447 // ADD $(autosize+8), R1, R5 448 // CMP R4, R5 449 // BNE end 450 // ADD $8, R1, R6 451 // MOVD R6, panic_argp(R3) 452 // end: 453 // NOP 454 // 455 // The NOP is needed to give the jumps somewhere to land. 456 // It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes. 457 458 q = obj.Appendp(ctxt, q) 459 460 q.As = AMOVD 461 q.From.Type = obj.TYPE_MEM 462 q.From.Reg = REGG 463 q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic 464 q.To.Type = obj.TYPE_REG 465 q.To.Reg = REG_R3 466 467 q = obj.Appendp(ctxt, q) 468 q.As = ACMP 469 q.From.Type = obj.TYPE_REG 470 q.From.Reg = REG_R0 471 q.To.Type = obj.TYPE_REG 472 q.To.Reg = REG_R3 473 474 q = obj.Appendp(ctxt, q) 475 q.As = ABEQ 476 q.To.Type = obj.TYPE_BRANCH 477 p1 = q 478 479 q = obj.Appendp(ctxt, q) 480 q.As = AMOVD 481 q.From.Type = obj.TYPE_MEM 482 q.From.Reg = REG_R3 483 q.From.Offset = 0 // Panic.argp 484 q.To.Type = obj.TYPE_REG 485 q.To.Reg = REG_R4 486 487 q = obj.Appendp(ctxt, q) 488 q.As = AADD 489 q.From.Type = obj.TYPE_CONST 490 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize() 491 q.Reg = REGSP 492 q.To.Type = obj.TYPE_REG 493 q.To.Reg = REG_R5 494 495 q = obj.Appendp(ctxt, q) 496 q.As = ACMP 497 q.From.Type = obj.TYPE_REG 498 q.From.Reg = REG_R4 499 q.To.Type = obj.TYPE_REG 500 q.To.Reg = REG_R5 501 502 q = obj.Appendp(ctxt, q) 503 q.As = ABNE 504 q.To.Type = obj.TYPE_BRANCH 505 p2 = q 506 507 q = obj.Appendp(ctxt, q) 508 q.As = AADD 509 q.From.Type = obj.TYPE_CONST 510 q.From.Offset = ctxt.FixedFrameSize() 511 q.Reg = REGSP 512 q.To.Type = obj.TYPE_REG 513 q.To.Reg = REG_R6 514 515 q = obj.Appendp(ctxt, q) 516 q.As = AMOVD 517 q.From.Type = obj.TYPE_REG 518 q.From.Reg = REG_R6 519 q.To.Type = obj.TYPE_MEM 520 q.To.Reg = REG_R3 521 q.To.Offset = 0 // Panic.argp 522 523 q = obj.Appendp(ctxt, q) 524 525 q.As = obj.ANOP 526 p1.Pcond = q 527 p2.Pcond = q 528 } 529 530 case obj.ARET: 531 if p.From.Type == obj.TYPE_CONST { 532 ctxt.Diag("using BECOME (%v) is not supported!", p) 533 break 534 } 535 536 retTarget := p.To.Sym 537 538 if cursym.Text.Mark&LEAF != 0 { 539 if autosize == 0 { 540 p.As = ABR 541 p.From = obj.Addr{} 542 if retTarget == nil { 543 p.To.Type = obj.TYPE_REG 544 p.To.Reg = REG_LR 545 } else { 546 p.To.Type = obj.TYPE_BRANCH 547 p.To.Sym = retTarget 548 } 549 p.Mark |= BRANCH 550 break 551 } 552 553 p.As = AADD 554 p.From.Type = obj.TYPE_CONST 555 p.From.Offset = int64(autosize) 556 p.To.Type = obj.TYPE_REG 557 p.To.Reg = REGSP 558 p.Spadj = -autosize 559 560 q = obj.Appendp(ctxt, p) 561 q.As = ABR 562 q.From = obj.Addr{} 563 q.To.Type = obj.TYPE_REG 564 q.To.Reg = REG_LR 565 q.Mark |= BRANCH 566 q.Spadj = autosize 567 break 568 } 569 570 p.As = AMOVD 571 p.From.Type = obj.TYPE_MEM 572 p.From.Reg = REGSP 573 p.From.Offset = 0 574 p.To.Type = obj.TYPE_REG 575 p.To.Reg = REG_LR 576 577 q = p 578 579 if autosize != 0 { 580 q = obj.Appendp(ctxt, q) 581 q.As = AADD 582 q.From.Type = obj.TYPE_CONST 583 q.From.Offset = int64(autosize) 584 q.To.Type = obj.TYPE_REG 585 q.To.Reg = REGSP 586 q.Spadj = -autosize 587 } 588 589 q = obj.Appendp(ctxt, q) 590 q.As = ABR 591 q.From = obj.Addr{} 592 if retTarget == nil { 593 q.To.Type = obj.TYPE_REG 594 q.To.Reg = REG_LR 595 } else { 596 q.To.Type = obj.TYPE_BRANCH 597 q.To.Sym = retTarget 598 } 599 q.Mark |= BRANCH 600 q.Spadj = autosize 601 602 case AADD: 603 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 604 p.Spadj = int32(-p.From.Offset) 605 } 606 } 607 } 608 if wasSplit { 609 pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt) // emit post part of split check 610 } 611 } 612 613 /* 614 // instruction scheduling 615 if(debug['Q'] == 0) 616 return; 617 618 curtext = nil; 619 q = nil; // p - 1 620 q1 = firstp; // top of block 621 o = 0; // count of instructions 622 for(p = firstp; p != nil; p = p1) { 623 p1 = p->link; 624 o++; 625 if(p->mark & NOSCHED){ 626 if(q1 != p){ 627 sched(q1, q); 628 } 629 for(; p != nil; p = p->link){ 630 if(!(p->mark & NOSCHED)) 631 break; 632 q = p; 633 } 634 p1 = p; 635 q1 = p; 636 o = 0; 637 continue; 638 } 639 if(p->mark & (LABEL|SYNC)) { 640 if(q1 != p) 641 sched(q1, q); 642 q1 = p; 643 o = 1; 644 } 645 if(p->mark & (BRANCH|SYNC)) { 646 sched(q1, p); 647 q1 = p1; 648 o = 0; 649 } 650 if(o >= NSCHED) { 651 sched(q1, p); 652 q1 = p1; 653 o = 0; 654 } 655 q = p; 656 } 657 */ 658 func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) { 659 var q *obj.Prog 660 661 // MOVD g_stackguard(g), R3 662 p = obj.Appendp(ctxt, p) 663 664 p.As = AMOVD 665 p.From.Type = obj.TYPE_MEM 666 p.From.Reg = REGG 667 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 668 if ctxt.Cursym.Cfunc { 669 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 670 } 671 p.To.Type = obj.TYPE_REG 672 p.To.Reg = REG_R3 673 674 q = nil 675 if framesize <= obj.StackSmall { 676 // small stack: SP < stackguard 677 // CMP stackguard, SP 678 679 //p.To.Type = obj.TYPE_REG 680 //p.To.Reg = REGSP 681 682 // q1: BLT done 683 684 p = obj.Appendp(ctxt, p) 685 //q1 = p 686 p.From.Type = obj.TYPE_REG 687 p.From.Reg = REG_R3 688 p.Reg = REGSP 689 p.As = ACMPUBGE 690 p.To.Type = obj.TYPE_BRANCH 691 //p = obj.Appendp(ctxt, p) 692 693 //p.As = ACMPU 694 //p.From.Type = obj.TYPE_REG 695 //p.From.Reg = REG_R3 696 //p.To.Type = obj.TYPE_REG 697 //p.To.Reg = REGSP 698 699 //p = obj.Appendp(ctxt, p) 700 //p.As = ABGE 701 //p.To.Type = obj.TYPE_BRANCH 702 703 } else if framesize <= obj.StackBig { 704 // large stack: SP-framesize < stackguard-StackSmall 705 // ADD $-framesize, SP, R4 706 // CMP stackguard, R4 707 p = obj.Appendp(ctxt, p) 708 709 p.As = AADD 710 p.From.Type = obj.TYPE_CONST 711 p.From.Offset = int64(-framesize) 712 p.Reg = REGSP 713 p.To.Type = obj.TYPE_REG 714 p.To.Reg = REG_R4 715 716 p = obj.Appendp(ctxt, p) 717 p.From.Type = obj.TYPE_REG 718 p.From.Reg = REG_R3 719 p.Reg = REG_R4 720 p.As = ACMPUBGE 721 p.To.Type = obj.TYPE_BRANCH 722 723 } else { 724 // Such a large stack we need to protect against wraparound. 725 // If SP is close to zero: 726 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 727 // The +StackGuard on both sides is required to keep the left side positive: 728 // SP is allowed to be slightly below stackguard. See stack.h. 729 // 730 // Preemption sets stackguard to StackPreempt, a very large value. 731 // That breaks the math above, so we have to check for that explicitly. 732 // // stackguard is R3 733 // CMP R3, $StackPreempt 734 // BEQ label-of-call-to-morestack 735 // ADD $StackGuard, SP, R4 736 // SUB R3, R4 737 // MOVD $(framesize+(StackGuard-StackSmall)), TEMP 738 // CMPUBGE TEMP, R4 739 p = obj.Appendp(ctxt, p) 740 741 p.As = ACMP 742 p.From.Type = obj.TYPE_REG 743 p.From.Reg = REG_R3 744 p.To.Type = obj.TYPE_CONST 745 p.To.Offset = obj.StackPreempt 746 747 p = obj.Appendp(ctxt, p) 748 q = p 749 p.As = ABEQ 750 p.To.Type = obj.TYPE_BRANCH 751 752 p = obj.Appendp(ctxt, p) 753 p.As = AADD 754 p.From.Type = obj.TYPE_CONST 755 p.From.Offset = obj.StackGuard 756 p.Reg = REGSP 757 p.To.Type = obj.TYPE_REG 758 p.To.Reg = REG_R4 759 760 p = obj.Appendp(ctxt, p) 761 p.As = ASUB 762 p.From.Type = obj.TYPE_REG 763 p.From.Reg = REG_R3 764 p.To.Type = obj.TYPE_REG 765 p.To.Reg = REG_R4 766 767 p = obj.Appendp(ctxt, p) 768 p.As = AMOVD 769 p.From.Type = obj.TYPE_CONST 770 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 771 p.To.Type = obj.TYPE_REG 772 p.To.Reg = REGTMP 773 774 p = obj.Appendp(ctxt, p) 775 p.From.Type = obj.TYPE_REG 776 p.From.Reg = REGTMP 777 p.Reg = REG_R4 778 p.As = ACMPUBGE 779 p.To.Type = obj.TYPE_BRANCH 780 } 781 782 return p, q 783 } 784 785 func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog) *obj.Prog { 786 787 // MOVD LR, R5 788 p = obj.Appendp(ctxt, p) 789 pPre.Pcond = p 790 p.As = AMOVD 791 p.From.Type = obj.TYPE_REG 792 p.From.Reg = REG_LR 793 p.To.Type = obj.TYPE_REG 794 p.To.Reg = REG_R5 795 if pPreempt != nil { 796 pPreempt.Pcond = p 797 } 798 799 // BL runtime.morestack(SB) 800 p = obj.Appendp(ctxt, p) 801 802 p.As = ABL 803 p.To.Type = obj.TYPE_BRANCH 804 if ctxt.Cursym.Cfunc { 805 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 806 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 807 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 808 } else { 809 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0) 810 } 811 812 // BR start 813 p = obj.Appendp(ctxt, p) 814 815 p.As = ABR 816 p.To.Type = obj.TYPE_BRANCH 817 p.Pcond = ctxt.Cursym.Text.Link 818 return p 819 } 820 821 var pc_cnt int64 822 823 func follow(ctxt *obj.Link, s *obj.LSym) { 824 ctxt.Cursym = s 825 826 pc_cnt = 0 827 firstp := ctxt.NewProg() 828 lastp := firstp 829 xfol(ctxt, s.Text, &lastp) 830 lastp.Link = nil 831 s.Text = firstp.Link 832 } 833 834 func relinv(a obj.As) obj.As { 835 switch a { 836 case ABEQ: 837 return ABNE 838 case ABNE: 839 return ABEQ 840 841 case ABGE: 842 return ABLT 843 case ABLT: 844 return ABGE 845 846 case ABGT: 847 return ABLE 848 case ABLE: 849 return ABGT 850 851 case ABVC: 852 return ABVS 853 case ABVS: 854 return ABVC 855 } 856 857 return 0 858 } 859 860 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 861 var q *obj.Prog 862 var r *obj.Prog 863 var b obj.As 864 865 for p != nil { 866 a := p.As 867 if a == ABR { 868 q = p.Pcond 869 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 870 p.Mark |= FOLL 871 (*last).Link = p 872 *last = p 873 (*last).Pc = pc_cnt 874 pc_cnt += 1 875 p = p.Link 876 xfol(ctxt, p, last) 877 p = q 878 if p != nil && p.Mark&FOLL == 0 { 879 continue 880 } 881 return 882 } 883 884 if q != nil { 885 p.Mark |= FOLL 886 p = q 887 if p.Mark&FOLL == 0 { 888 continue 889 } 890 } 891 } 892 893 if p.Mark&FOLL != 0 { 894 q = p 895 for i := 0; i < 4; i, q = i+1, q.Link { 896 if q == *last || (q.Mark&NOSCHED != 0) { 897 break 898 } 899 b = 0 /* set */ 900 a = q.As 901 if a == obj.ANOP { 902 i-- 903 continue 904 } 905 if a != ABR && a != obj.ARET { 906 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 907 continue 908 } 909 b = relinv(a) 910 if b == 0 { 911 continue 912 } 913 } 914 915 for { 916 r = ctxt.NewProg() 917 *r = *p 918 if r.Mark&FOLL == 0 { 919 fmt.Printf("can't happen 1\n") 920 } 921 r.Mark |= FOLL 922 if p != q { 923 p = p.Link 924 (*last).Link = r 925 *last = r 926 (*last).Pc = pc_cnt 927 pc_cnt += 1 928 continue 929 } 930 931 (*last).Link = r 932 *last = r 933 (*last).Pc = pc_cnt 934 pc_cnt += 1 935 if a == ABR || a == obj.ARET { 936 return 937 } 938 r.As = b 939 r.Pcond = p.Link 940 r.Link = p.Pcond 941 if r.Link.Mark&FOLL == 0 { 942 xfol(ctxt, r.Link, last) 943 } 944 if r.Pcond.Mark&FOLL == 0 { 945 fmt.Printf("can't happen 2\n") 946 } 947 return 948 } 949 } 950 951 a = ABR 952 q = ctxt.NewProg() 953 q.As = a 954 q.Lineno = p.Lineno 955 q.To.Type = obj.TYPE_BRANCH 956 q.To.Offset = p.Pc 957 q.Pcond = p 958 p = q 959 } 960 961 p.Mark |= FOLL 962 (*last).Link = p 963 *last = p 964 (*last).Pc = pc_cnt 965 pc_cnt += 1 966 967 if a == ABR || a == obj.ARET { 968 if p.Mark&NOSCHED != 0 { 969 p = p.Link 970 continue 971 } 972 973 return 974 } 975 976 if p.Pcond != nil { 977 if a != ABL && p.Link != nil { 978 xfol(ctxt, p.Link, last) 979 p = p.Pcond 980 if p == nil || (p.Mark&FOLL != 0) { 981 return 982 } 983 continue 984 } 985 } 986 987 p = p.Link 988 } 989 } 990 991 var unaryDst = map[obj.As]bool{ 992 ASTCK: true, 993 ASTCKC: true, 994 ASTCKE: true, 995 ASTCKF: true, 996 ANEG: true, 997 AVONE: true, 998 AVZERO: true, 999 } 1000 1001 var Links390x = obj.LinkArch{ 1002 Arch: sys.ArchS390X, 1003 Preprocess: preprocess, 1004 Assemble: spanz, 1005 Follow: follow, 1006 Progedit: progedit, 1007 UnaryDst: unaryDst, 1008 }