github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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/objabi" 35 "cmd/internal/sys" 36 "math" 37 ) 38 39 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { 40 p.From.Class = 0 41 p.To.Class = 0 42 43 c := ctxtz{ctxt: ctxt, newprog: newprog} 44 45 // Rewrite BR/BL to symbol as TYPE_BRANCH. 46 switch p.As { 47 case ABR, ABL, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY: 48 if p.To.Sym != nil { 49 p.To.Type = obj.TYPE_BRANCH 50 } 51 } 52 53 // Rewrite float constants to values stored in memory unless they are +0. 54 switch p.As { 55 case AFMOVS: 56 if p.From.Type == obj.TYPE_FCONST { 57 f32 := float32(p.From.Val.(float64)) 58 if math.Float32bits(f32) == 0 { // +0 59 break 60 } 61 p.From.Type = obj.TYPE_MEM 62 p.From.Sym = ctxt.Float32Sym(f32) 63 p.From.Name = obj.NAME_EXTERN 64 p.From.Offset = 0 65 } 66 67 case AFMOVD: 68 if p.From.Type == obj.TYPE_FCONST { 69 f64 := p.From.Val.(float64) 70 if math.Float64bits(f64) == 0 { // +0 71 break 72 } 73 p.From.Type = obj.TYPE_MEM 74 p.From.Sym = ctxt.Float64Sym(f64) 75 p.From.Name = obj.NAME_EXTERN 76 p.From.Offset = 0 77 } 78 79 // put constants not loadable by LOAD IMMEDIATE into memory 80 case AMOVD: 81 if p.From.Type == obj.TYPE_CONST { 82 val := p.From.Offset 83 if int64(int32(val)) != val && 84 int64(uint32(val)) != val && 85 int64(uint64(val)&(0xffffffff<<32)) != val { 86 p.From.Type = obj.TYPE_MEM 87 p.From.Sym = ctxt.Int64Sym(p.From.Offset) 88 p.From.Name = obj.NAME_EXTERN 89 p.From.Offset = 0 90 } 91 } 92 } 93 94 // Rewrite SUB constants into ADD. 95 switch p.As { 96 case ASUBC: 97 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) { 98 p.From.Offset = -p.From.Offset 99 p.As = AADDC 100 } 101 102 case ASUB: 103 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) { 104 p.From.Offset = -p.From.Offset 105 p.As = AADD 106 } 107 } 108 109 if c.ctxt.Flag_dynlink { 110 c.rewriteToUseGot(p) 111 } 112 } 113 114 // Rewrite p, if necessary, to access global data via the global offset table. 115 func (c *ctxtz) rewriteToUseGot(p *obj.Prog) { 116 // At the moment EXRL instructions are not emitted by the compiler and only reference local symbols in 117 // assembly code. 118 if p.As == AEXRL { 119 return 120 } 121 122 // We only care about global data: NAME_EXTERN means a global 123 // symbol in the Go sense, and p.Sym.Local is true for a few 124 // internally defined symbols. 125 // Rewrites must not clobber flags and therefore cannot use the 126 // ADD instruction. 127 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 128 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 129 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx or REGTMP2; MOVD $<off>(Rx or REGTMP2), Rx 130 if p.To.Type != obj.TYPE_REG || p.As != AMOVD { 131 c.ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p) 132 } 133 p.From.Type = obj.TYPE_MEM 134 p.From.Name = obj.NAME_GOTREF 135 q := p 136 if p.From.Offset != 0 { 137 target := p.To.Reg 138 if target == REG_R0 { 139 // Cannot use R0 as input to address calculation. 140 // REGTMP might be used by the assembler. 141 p.To.Reg = REGTMP2 142 } 143 q = obj.Appendp(q, c.newprog) 144 q.As = AMOVD 145 q.From.Type = obj.TYPE_ADDR 146 q.From.Offset = p.From.Offset 147 q.From.Reg = p.To.Reg 148 q.To.Type = obj.TYPE_REG 149 q.To.Reg = target 150 p.From.Offset = 0 151 } 152 } 153 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN { 154 c.ctxt.Diag("don't know how to handle %v with -dynlink", p) 155 } 156 var source *obj.Addr 157 // MOVD sym, Ry becomes MOVD sym@GOT, REGTMP2; MOVD (REGTMP2), Ry 158 // MOVD Ry, sym becomes MOVD sym@GOT, REGTMP2; MOVD Ry, (REGTMP2) 159 // An addition may be inserted between the two MOVs if there is an offset. 160 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 161 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 162 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 163 } 164 source = &p.From 165 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 166 source = &p.To 167 } else { 168 return 169 } 170 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 171 return 172 } 173 if source.Sym.Type == objabi.STLSBSS { 174 return 175 } 176 if source.Type != obj.TYPE_MEM { 177 c.ctxt.Diag("don't know how to handle %v with -dynlink", p) 178 } 179 p1 := obj.Appendp(p, c.newprog) 180 p2 := obj.Appendp(p1, c.newprog) 181 182 p1.As = AMOVD 183 p1.From.Type = obj.TYPE_MEM 184 p1.From.Sym = source.Sym 185 p1.From.Name = obj.NAME_GOTREF 186 p1.To.Type = obj.TYPE_REG 187 p1.To.Reg = REGTMP2 188 189 p2.As = p.As 190 p2.From = p.From 191 p2.To = p.To 192 if p.From.Name == obj.NAME_EXTERN { 193 p2.From.Reg = REGTMP2 194 p2.From.Name = obj.NAME_NONE 195 p2.From.Sym = nil 196 } else if p.To.Name == obj.NAME_EXTERN { 197 p2.To.Reg = REGTMP2 198 p2.To.Name = obj.NAME_NONE 199 p2.To.Sym = nil 200 } else { 201 return 202 } 203 obj.Nopout(p) 204 } 205 206 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 207 // TODO(minux): add morestack short-cuts with small fixed frame-size. 208 if cursym.Func.Text == nil || cursym.Func.Text.Link == nil { 209 return 210 } 211 212 c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog} 213 214 p := c.cursym.Func.Text 215 textstksiz := p.To.Offset 216 if textstksiz == -8 { 217 // Compatibility hack. 218 p.From.Sym.Set(obj.AttrNoFrame, true) 219 textstksiz = 0 220 } 221 if textstksiz%8 != 0 { 222 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz) 223 } 224 if p.From.Sym.NoFrame() { 225 if textstksiz != 0 { 226 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz) 227 } 228 } 229 230 c.cursym.Func.Args = p.To.Val.(int32) 231 c.cursym.Func.Locals = int32(textstksiz) 232 233 /* 234 * find leaf subroutines 235 * strip NOPs 236 * expand RET 237 */ 238 239 var q *obj.Prog 240 for p := c.cursym.Func.Text; p != nil; p = p.Link { 241 switch p.As { 242 case obj.ATEXT: 243 q = p 244 p.Mark |= LEAF 245 246 case ABL, ABCL: 247 q = p 248 c.cursym.Func.Text.Mark &^= LEAF 249 fallthrough 250 251 case ABC, 252 ABEQ, 253 ABGE, 254 ABGT, 255 ABLE, 256 ABLT, 257 ABLEU, 258 ABLTU, 259 ABNE, 260 ABR, 261 ABVC, 262 ABVS, 263 ACMPBEQ, 264 ACMPBGE, 265 ACMPBGT, 266 ACMPBLE, 267 ACMPBLT, 268 ACMPBNE, 269 ACMPUBEQ, 270 ACMPUBGE, 271 ACMPUBGT, 272 ACMPUBLE, 273 ACMPUBLT, 274 ACMPUBNE: 275 q = p 276 p.Mark |= BRANCH 277 if p.Pcond != nil { 278 q := p.Pcond 279 for q.As == obj.ANOP { 280 q = q.Link 281 p.Pcond = q 282 } 283 } 284 285 case obj.ANOP: 286 q.Link = p.Link /* q is non-nop */ 287 p.Link.Mark |= p.Mark 288 289 default: 290 q = p 291 } 292 } 293 294 autosize := int32(0) 295 var pLast *obj.Prog 296 var pPre *obj.Prog 297 var pPreempt *obj.Prog 298 wasSplit := false 299 for p := c.cursym.Func.Text; p != nil; p = p.Link { 300 pLast = p 301 switch p.As { 302 case obj.ATEXT: 303 autosize = int32(textstksiz) 304 305 if p.Mark&LEAF != 0 && autosize == 0 { 306 // A leaf function with no locals has no frame. 307 p.From.Sym.Set(obj.AttrNoFrame, true) 308 } 309 310 if !p.From.Sym.NoFrame() { 311 // If there is a stack frame at all, it includes 312 // space to save the LR. 313 autosize += int32(c.ctxt.FixedFrameSize()) 314 } 315 316 if p.Mark&LEAF != 0 && autosize < objabi.StackSmall { 317 // A leaf function with a small stack can be marked 318 // NOSPLIT, avoiding a stack check. 319 p.From.Sym.Set(obj.AttrNoSplit, true) 320 } 321 322 p.To.Offset = int64(autosize) 323 324 q := p 325 326 if !p.From.Sym.NoSplit() { 327 p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check 328 pPre = p 329 wasSplit = true //need post part of split 330 } 331 332 if autosize != 0 { 333 // Make sure to save link register for non-empty frame, even if 334 // it is a leaf function, so that traceback works. 335 // Store link register before decrementing SP, so if a signal comes 336 // during the execution of the function prologue, the traceback 337 // code will not see a half-updated stack frame. 338 q = obj.Appendp(p, c.newprog) 339 q.As = AMOVD 340 q.From.Type = obj.TYPE_REG 341 q.From.Reg = REG_LR 342 q.To.Type = obj.TYPE_MEM 343 q.To.Reg = REGSP 344 q.To.Offset = int64(-autosize) 345 346 q = obj.Appendp(q, c.newprog) 347 q.As = AMOVD 348 q.From.Type = obj.TYPE_ADDR 349 q.From.Offset = int64(-autosize) 350 q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided 351 q.To.Type = obj.TYPE_REG 352 q.To.Reg = REGSP 353 q.Spadj = autosize 354 } else if c.cursym.Func.Text.Mark&LEAF == 0 { 355 // A very few functions that do not return to their caller 356 // (e.g. gogo) are not identified as leaves but still have 357 // no frame. 358 c.cursym.Func.Text.Mark |= LEAF 359 } 360 361 if c.cursym.Func.Text.Mark&LEAF != 0 { 362 c.cursym.Set(obj.AttrLeaf, true) 363 break 364 } 365 366 if c.cursym.Func.Text.From.Sym.Wrapper() { 367 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 368 // 369 // MOVD g_panic(g), R3 370 // CMP R3, $0 371 // BEQ end 372 // MOVD panic_argp(R3), R4 373 // ADD $(autosize+8), R1, R5 374 // CMP R4, R5 375 // BNE end 376 // ADD $8, R1, R6 377 // MOVD R6, panic_argp(R3) 378 // end: 379 // NOP 380 // 381 // The NOP is needed to give the jumps somewhere to land. 382 // It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes. 383 384 q = obj.Appendp(q, c.newprog) 385 386 q.As = AMOVD 387 q.From.Type = obj.TYPE_MEM 388 q.From.Reg = REGG 389 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic 390 q.To.Type = obj.TYPE_REG 391 q.To.Reg = REG_R3 392 393 q = obj.Appendp(q, c.newprog) 394 q.As = ACMP 395 q.From.Type = obj.TYPE_REG 396 q.From.Reg = REG_R3 397 q.To.Type = obj.TYPE_CONST 398 q.To.Offset = 0 399 400 q = obj.Appendp(q, c.newprog) 401 q.As = ABEQ 402 q.To.Type = obj.TYPE_BRANCH 403 p1 := q 404 405 q = obj.Appendp(q, c.newprog) 406 q.As = AMOVD 407 q.From.Type = obj.TYPE_MEM 408 q.From.Reg = REG_R3 409 q.From.Offset = 0 // Panic.argp 410 q.To.Type = obj.TYPE_REG 411 q.To.Reg = REG_R4 412 413 q = obj.Appendp(q, c.newprog) 414 q.As = AADD 415 q.From.Type = obj.TYPE_CONST 416 q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize() 417 q.Reg = REGSP 418 q.To.Type = obj.TYPE_REG 419 q.To.Reg = REG_R5 420 421 q = obj.Appendp(q, c.newprog) 422 q.As = ACMP 423 q.From.Type = obj.TYPE_REG 424 q.From.Reg = REG_R4 425 q.To.Type = obj.TYPE_REG 426 q.To.Reg = REG_R5 427 428 q = obj.Appendp(q, c.newprog) 429 q.As = ABNE 430 q.To.Type = obj.TYPE_BRANCH 431 p2 := q 432 433 q = obj.Appendp(q, c.newprog) 434 q.As = AADD 435 q.From.Type = obj.TYPE_CONST 436 q.From.Offset = c.ctxt.FixedFrameSize() 437 q.Reg = REGSP 438 q.To.Type = obj.TYPE_REG 439 q.To.Reg = REG_R6 440 441 q = obj.Appendp(q, c.newprog) 442 q.As = AMOVD 443 q.From.Type = obj.TYPE_REG 444 q.From.Reg = REG_R6 445 q.To.Type = obj.TYPE_MEM 446 q.To.Reg = REG_R3 447 q.To.Offset = 0 // Panic.argp 448 449 q = obj.Appendp(q, c.newprog) 450 451 q.As = obj.ANOP 452 p1.Pcond = q 453 p2.Pcond = q 454 } 455 456 case obj.ARET: 457 retTarget := p.To.Sym 458 459 if c.cursym.Func.Text.Mark&LEAF != 0 { 460 if autosize == 0 { 461 p.As = ABR 462 p.From = obj.Addr{} 463 if retTarget == nil { 464 p.To.Type = obj.TYPE_REG 465 p.To.Reg = REG_LR 466 } else { 467 p.To.Type = obj.TYPE_BRANCH 468 p.To.Sym = retTarget 469 } 470 p.Mark |= BRANCH 471 break 472 } 473 474 p.As = AADD 475 p.From.Type = obj.TYPE_CONST 476 p.From.Offset = int64(autosize) 477 p.To.Type = obj.TYPE_REG 478 p.To.Reg = REGSP 479 p.Spadj = -autosize 480 481 q = obj.Appendp(p, c.newprog) 482 q.As = ABR 483 q.From = obj.Addr{} 484 q.To.Type = obj.TYPE_REG 485 q.To.Reg = REG_LR 486 q.Mark |= BRANCH 487 q.Spadj = autosize 488 break 489 } 490 491 p.As = AMOVD 492 p.From.Type = obj.TYPE_MEM 493 p.From.Reg = REGSP 494 p.From.Offset = 0 495 p.To.Type = obj.TYPE_REG 496 p.To.Reg = REG_LR 497 498 q = p 499 500 if autosize != 0 { 501 q = obj.Appendp(q, c.newprog) 502 q.As = AADD 503 q.From.Type = obj.TYPE_CONST 504 q.From.Offset = int64(autosize) 505 q.To.Type = obj.TYPE_REG 506 q.To.Reg = REGSP 507 q.Spadj = -autosize 508 } 509 510 q = obj.Appendp(q, c.newprog) 511 q.As = ABR 512 q.From = obj.Addr{} 513 if retTarget == nil { 514 q.To.Type = obj.TYPE_REG 515 q.To.Reg = REG_LR 516 } else { 517 q.To.Type = obj.TYPE_BRANCH 518 q.To.Sym = retTarget 519 } 520 q.Mark |= BRANCH 521 q.Spadj = autosize 522 523 case AADD: 524 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 525 p.Spadj = int32(-p.From.Offset) 526 } 527 } 528 } 529 if wasSplit { 530 c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check 531 } 532 } 533 534 func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) { 535 var q *obj.Prog 536 537 // MOVD g_stackguard(g), R3 538 p = obj.Appendp(p, c.newprog) 539 540 p.As = AMOVD 541 p.From.Type = obj.TYPE_MEM 542 p.From.Reg = REGG 543 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 544 if c.cursym.CFunc() { 545 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 546 } 547 p.To.Type = obj.TYPE_REG 548 p.To.Reg = REG_R3 549 550 q = nil 551 if framesize <= objabi.StackSmall { 552 // small stack: SP < stackguard 553 // CMP stackguard, SP 554 555 //p.To.Type = obj.TYPE_REG 556 //p.To.Reg = REGSP 557 558 // q1: BLT done 559 560 p = obj.Appendp(p, c.newprog) 561 //q1 = p 562 p.From.Type = obj.TYPE_REG 563 p.From.Reg = REG_R3 564 p.Reg = REGSP 565 p.As = ACMPUBGE 566 p.To.Type = obj.TYPE_BRANCH 567 //p = obj.Appendp(ctxt, p) 568 569 //p.As = ACMPU 570 //p.From.Type = obj.TYPE_REG 571 //p.From.Reg = REG_R3 572 //p.To.Type = obj.TYPE_REG 573 //p.To.Reg = REGSP 574 575 //p = obj.Appendp(ctxt, p) 576 //p.As = ABGE 577 //p.To.Type = obj.TYPE_BRANCH 578 579 } else if framesize <= objabi.StackBig { 580 // large stack: SP-framesize < stackguard-StackSmall 581 // ADD $-(framesize-StackSmall), SP, R4 582 // CMP stackguard, R4 583 p = obj.Appendp(p, c.newprog) 584 585 p.As = AADD 586 p.From.Type = obj.TYPE_CONST 587 p.From.Offset = -(int64(framesize) - objabi.StackSmall) 588 p.Reg = REGSP 589 p.To.Type = obj.TYPE_REG 590 p.To.Reg = REG_R4 591 592 p = obj.Appendp(p, c.newprog) 593 p.From.Type = obj.TYPE_REG 594 p.From.Reg = REG_R3 595 p.Reg = REG_R4 596 p.As = ACMPUBGE 597 p.To.Type = obj.TYPE_BRANCH 598 599 } else { 600 // Such a large stack we need to protect against wraparound. 601 // If SP is close to zero: 602 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 603 // The +StackGuard on both sides is required to keep the left side positive: 604 // SP is allowed to be slightly below stackguard. See stack.h. 605 // 606 // Preemption sets stackguard to StackPreempt, a very large value. 607 // That breaks the math above, so we have to check for that explicitly. 608 // // stackguard is R3 609 // CMP R3, $StackPreempt 610 // BEQ label-of-call-to-morestack 611 // ADD $StackGuard, SP, R4 612 // SUB R3, R4 613 // MOVD $(framesize+(StackGuard-StackSmall)), TEMP 614 // CMPUBGE TEMP, R4 615 p = obj.Appendp(p, c.newprog) 616 617 p.As = ACMP 618 p.From.Type = obj.TYPE_REG 619 p.From.Reg = REG_R3 620 p.To.Type = obj.TYPE_CONST 621 p.To.Offset = objabi.StackPreempt 622 623 p = obj.Appendp(p, c.newprog) 624 q = p 625 p.As = ABEQ 626 p.To.Type = obj.TYPE_BRANCH 627 628 p = obj.Appendp(p, c.newprog) 629 p.As = AADD 630 p.From.Type = obj.TYPE_CONST 631 p.From.Offset = objabi.StackGuard 632 p.Reg = REGSP 633 p.To.Type = obj.TYPE_REG 634 p.To.Reg = REG_R4 635 636 p = obj.Appendp(p, c.newprog) 637 p.As = ASUB 638 p.From.Type = obj.TYPE_REG 639 p.From.Reg = REG_R3 640 p.To.Type = obj.TYPE_REG 641 p.To.Reg = REG_R4 642 643 p = obj.Appendp(p, c.newprog) 644 p.As = AMOVD 645 p.From.Type = obj.TYPE_CONST 646 p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall 647 p.To.Type = obj.TYPE_REG 648 p.To.Reg = REGTMP 649 650 p = obj.Appendp(p, c.newprog) 651 p.From.Type = obj.TYPE_REG 652 p.From.Reg = REGTMP 653 p.Reg = REG_R4 654 p.As = ACMPUBGE 655 p.To.Type = obj.TYPE_BRANCH 656 } 657 658 return p, q 659 } 660 661 func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog { 662 // Now we are at the end of the function, but logically 663 // we are still in function prologue. We need to fix the 664 // SP data and PCDATA. 665 spfix := obj.Appendp(p, c.newprog) 666 spfix.As = obj.ANOP 667 spfix.Spadj = -framesize 668 669 pcdata := obj.Appendp(spfix, c.newprog) 670 pcdata.Pos = c.cursym.Func.Text.Pos 671 pcdata.As = obj.APCDATA 672 pcdata.From.Type = obj.TYPE_CONST 673 pcdata.From.Offset = objabi.PCDATA_StackMapIndex 674 pcdata.To.Type = obj.TYPE_CONST 675 pcdata.To.Offset = -1 // pcdata starts at -1 at function entry 676 677 // MOVD LR, R5 678 p = obj.Appendp(pcdata, c.newprog) 679 pPre.Pcond = p 680 p.As = AMOVD 681 p.From.Type = obj.TYPE_REG 682 p.From.Reg = REG_LR 683 p.To.Type = obj.TYPE_REG 684 p.To.Reg = REG_R5 685 if pPreempt != nil { 686 pPreempt.Pcond = p 687 } 688 689 // BL runtime.morestack(SB) 690 p = obj.Appendp(p, c.newprog) 691 692 p.As = ABL 693 p.To.Type = obj.TYPE_BRANCH 694 if c.cursym.CFunc() { 695 p.To.Sym = c.ctxt.Lookup("runtime.morestackc") 696 } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() { 697 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt") 698 } else { 699 p.To.Sym = c.ctxt.Lookup("runtime.morestack") 700 } 701 702 // BR start 703 p = obj.Appendp(p, c.newprog) 704 705 p.As = ABR 706 p.To.Type = obj.TYPE_BRANCH 707 p.Pcond = c.cursym.Func.Text.Link 708 return p 709 } 710 711 var unaryDst = map[obj.As]bool{ 712 ASTCK: true, 713 ASTCKC: true, 714 ASTCKE: true, 715 ASTCKF: true, 716 ANEG: true, 717 ANEGW: true, 718 AVONE: true, 719 AVZERO: true, 720 } 721 722 var Links390x = obj.LinkArch{ 723 Arch: sys.ArchS390X, 724 Init: buildop, 725 Preprocess: preprocess, 726 Assemble: spanz, 727 Progedit: progedit, 728 UnaryDst: unaryDst, 729 }