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