...

Source file src/github.com/twitchyliquid64/golang-asm/obj/s390x/objz.go

Documentation: github.com/twitchyliquid64/golang-asm/obj/s390x

     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  	"github.com/twitchyliquid64/golang-asm/obj"
    34  	"github.com/twitchyliquid64/golang-asm/objabi"
    35  	"github.com/twitchyliquid64/golang-asm/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  			ABRC,
   253  			ABEQ,
   254  			ABGE,
   255  			ABGT,
   256  			ABLE,
   257  			ABLT,
   258  			ABLEU,
   259  			ABLTU,
   260  			ABNE,
   261  			ABR,
   262  			ABVC,
   263  			ABVS,
   264  			ACRJ,
   265  			ACGRJ,
   266  			ACLRJ,
   267  			ACLGRJ,
   268  			ACIJ,
   269  			ACGIJ,
   270  			ACLIJ,
   271  			ACLGIJ,
   272  			ACMPBEQ,
   273  			ACMPBGE,
   274  			ACMPBGT,
   275  			ACMPBLE,
   276  			ACMPBLT,
   277  			ACMPBNE,
   278  			ACMPUBEQ,
   279  			ACMPUBGE,
   280  			ACMPUBGT,
   281  			ACMPUBLE,
   282  			ACMPUBLT,
   283  			ACMPUBNE:
   284  			q = p
   285  			p.Mark |= BRANCH
   286  
   287  		default:
   288  			q = p
   289  		}
   290  	}
   291  
   292  	autosize := int32(0)
   293  	var pLast *obj.Prog
   294  	var pPre *obj.Prog
   295  	var pPreempt *obj.Prog
   296  	wasSplit := false
   297  	for p := c.cursym.Func.Text; p != nil; p = p.Link {
   298  		pLast = p
   299  		switch p.As {
   300  		case obj.ATEXT:
   301  			autosize = int32(textstksiz)
   302  
   303  			if p.Mark&LEAF != 0 && autosize == 0 {
   304  				// A leaf function with no locals has no frame.
   305  				p.From.Sym.Set(obj.AttrNoFrame, true)
   306  			}
   307  
   308  			if !p.From.Sym.NoFrame() {
   309  				// If there is a stack frame at all, it includes
   310  				// space to save the LR.
   311  				autosize += int32(c.ctxt.FixedFrameSize())
   312  			}
   313  
   314  			if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
   315  				// A leaf function with a small stack can be marked
   316  				// NOSPLIT, avoiding a stack check.
   317  				p.From.Sym.Set(obj.AttrNoSplit, true)
   318  			}
   319  
   320  			p.To.Offset = int64(autosize)
   321  
   322  			q := p
   323  
   324  			if !p.From.Sym.NoSplit() {
   325  				p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check
   326  				pPre = p
   327  				p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
   328  				wasSplit = true //need post part of split
   329  			}
   330  
   331  			if autosize != 0 {
   332  				// Make sure to save link register for non-empty frame, even if
   333  				// it is a leaf function, so that traceback works.
   334  				// Store link register before decrementing SP, so if a signal comes
   335  				// during the execution of the function prologue, the traceback
   336  				// code will not see a half-updated stack frame.
   337  				// This sequence is not async preemptible, as if we open a frame
   338  				// at the current SP, it will clobber the saved LR.
   339  				q = c.ctxt.StartUnsafePoint(p, c.newprog)
   340  
   341  				q = obj.Appendp(q, c.newprog)
   342  				q.As = AMOVD
   343  				q.From.Type = obj.TYPE_REG
   344  				q.From.Reg = REG_LR
   345  				q.To.Type = obj.TYPE_MEM
   346  				q.To.Reg = REGSP
   347  				q.To.Offset = int64(-autosize)
   348  
   349  				q = obj.Appendp(q, c.newprog)
   350  				q.As = AMOVD
   351  				q.From.Type = obj.TYPE_ADDR
   352  				q.From.Offset = int64(-autosize)
   353  				q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided
   354  				q.To.Type = obj.TYPE_REG
   355  				q.To.Reg = REGSP
   356  				q.Spadj = autosize
   357  
   358  				q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
   359  			} else if c.cursym.Func.Text.Mark&LEAF == 0 {
   360  				// A very few functions that do not return to their caller
   361  				// (e.g. gogo) are not identified as leaves but still have
   362  				// no frame.
   363  				c.cursym.Func.Text.Mark |= LEAF
   364  			}
   365  
   366  			if c.cursym.Func.Text.Mark&LEAF != 0 {
   367  				c.cursym.Set(obj.AttrLeaf, true)
   368  				break
   369  			}
   370  
   371  			if c.cursym.Func.Text.From.Sym.Wrapper() {
   372  				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
   373  				//
   374  				//	MOVD g_panic(g), R3
   375  				//	CMP R3, $0
   376  				//	BEQ end
   377  				//	MOVD panic_argp(R3), R4
   378  				//	ADD $(autosize+8), R1, R5
   379  				//	CMP R4, R5
   380  				//	BNE end
   381  				//	ADD $8, R1, R6
   382  				//	MOVD R6, panic_argp(R3)
   383  				// end:
   384  				//	NOP
   385  				//
   386  				// The NOP is needed to give the jumps somewhere to land.
   387  				// It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes.
   388  
   389  				q = obj.Appendp(q, c.newprog)
   390  
   391  				q.As = AMOVD
   392  				q.From.Type = obj.TYPE_MEM
   393  				q.From.Reg = REGG
   394  				q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
   395  				q.To.Type = obj.TYPE_REG
   396  				q.To.Reg = REG_R3
   397  
   398  				q = obj.Appendp(q, c.newprog)
   399  				q.As = ACMP
   400  				q.From.Type = obj.TYPE_REG
   401  				q.From.Reg = REG_R3
   402  				q.To.Type = obj.TYPE_CONST
   403  				q.To.Offset = 0
   404  
   405  				q = obj.Appendp(q, c.newprog)
   406  				q.As = ABEQ
   407  				q.To.Type = obj.TYPE_BRANCH
   408  				p1 := q
   409  
   410  				q = obj.Appendp(q, c.newprog)
   411  				q.As = AMOVD
   412  				q.From.Type = obj.TYPE_MEM
   413  				q.From.Reg = REG_R3
   414  				q.From.Offset = 0 // Panic.argp
   415  				q.To.Type = obj.TYPE_REG
   416  				q.To.Reg = REG_R4
   417  
   418  				q = obj.Appendp(q, c.newprog)
   419  				q.As = AADD
   420  				q.From.Type = obj.TYPE_CONST
   421  				q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
   422  				q.Reg = REGSP
   423  				q.To.Type = obj.TYPE_REG
   424  				q.To.Reg = REG_R5
   425  
   426  				q = obj.Appendp(q, c.newprog)
   427  				q.As = ACMP
   428  				q.From.Type = obj.TYPE_REG
   429  				q.From.Reg = REG_R4
   430  				q.To.Type = obj.TYPE_REG
   431  				q.To.Reg = REG_R5
   432  
   433  				q = obj.Appendp(q, c.newprog)
   434  				q.As = ABNE
   435  				q.To.Type = obj.TYPE_BRANCH
   436  				p2 := q
   437  
   438  				q = obj.Appendp(q, c.newprog)
   439  				q.As = AADD
   440  				q.From.Type = obj.TYPE_CONST
   441  				q.From.Offset = c.ctxt.FixedFrameSize()
   442  				q.Reg = REGSP
   443  				q.To.Type = obj.TYPE_REG
   444  				q.To.Reg = REG_R6
   445  
   446  				q = obj.Appendp(q, c.newprog)
   447  				q.As = AMOVD
   448  				q.From.Type = obj.TYPE_REG
   449  				q.From.Reg = REG_R6
   450  				q.To.Type = obj.TYPE_MEM
   451  				q.To.Reg = REG_R3
   452  				q.To.Offset = 0 // Panic.argp
   453  
   454  				q = obj.Appendp(q, c.newprog)
   455  
   456  				q.As = obj.ANOP
   457  				p1.To.SetTarget(q)
   458  				p2.To.SetTarget(q)
   459  			}
   460  
   461  		case obj.ARET:
   462  			retTarget := p.To.Sym
   463  
   464  			if c.cursym.Func.Text.Mark&LEAF != 0 {
   465  				if autosize == 0 {
   466  					p.As = ABR
   467  					p.From = obj.Addr{}
   468  					if retTarget == nil {
   469  						p.To.Type = obj.TYPE_REG
   470  						p.To.Reg = REG_LR
   471  					} else {
   472  						p.To.Type = obj.TYPE_BRANCH
   473  						p.To.Sym = retTarget
   474  					}
   475  					p.Mark |= BRANCH
   476  					break
   477  				}
   478  
   479  				p.As = AADD
   480  				p.From.Type = obj.TYPE_CONST
   481  				p.From.Offset = int64(autosize)
   482  				p.To.Type = obj.TYPE_REG
   483  				p.To.Reg = REGSP
   484  				p.Spadj = -autosize
   485  
   486  				q = obj.Appendp(p, c.newprog)
   487  				q.As = ABR
   488  				q.From = obj.Addr{}
   489  				q.To.Type = obj.TYPE_REG
   490  				q.To.Reg = REG_LR
   491  				q.Mark |= BRANCH
   492  				q.Spadj = autosize
   493  				break
   494  			}
   495  
   496  			p.As = AMOVD
   497  			p.From.Type = obj.TYPE_MEM
   498  			p.From.Reg = REGSP
   499  			p.From.Offset = 0
   500  			p.To.Type = obj.TYPE_REG
   501  			p.To.Reg = REG_LR
   502  
   503  			q = p
   504  
   505  			if autosize != 0 {
   506  				q = obj.Appendp(q, c.newprog)
   507  				q.As = AADD
   508  				q.From.Type = obj.TYPE_CONST
   509  				q.From.Offset = int64(autosize)
   510  				q.To.Type = obj.TYPE_REG
   511  				q.To.Reg = REGSP
   512  				q.Spadj = -autosize
   513  			}
   514  
   515  			q = obj.Appendp(q, c.newprog)
   516  			q.As = ABR
   517  			q.From = obj.Addr{}
   518  			if retTarget == nil {
   519  				q.To.Type = obj.TYPE_REG
   520  				q.To.Reg = REG_LR
   521  			} else {
   522  				q.To.Type = obj.TYPE_BRANCH
   523  				q.To.Sym = retTarget
   524  			}
   525  			q.Mark |= BRANCH
   526  			q.Spadj = autosize
   527  
   528  		case AADD:
   529  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   530  				p.Spadj = int32(-p.From.Offset)
   531  			}
   532  
   533  		case obj.AGETCALLERPC:
   534  			if cursym.Leaf() {
   535  				/* MOVD LR, Rd */
   536  				p.As = AMOVD
   537  				p.From.Type = obj.TYPE_REG
   538  				p.From.Reg = REG_LR
   539  			} else {
   540  				/* MOVD (RSP), Rd */
   541  				p.As = AMOVD
   542  				p.From.Type = obj.TYPE_MEM
   543  				p.From.Reg = REGSP
   544  			}
   545  		}
   546  	}
   547  	if wasSplit {
   548  		c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check
   549  	}
   550  }
   551  
   552  func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
   553  	var q *obj.Prog
   554  
   555  	// MOVD	g_stackguard(g), R3
   556  	p = obj.Appendp(p, c.newprog)
   557  
   558  	p.As = AMOVD
   559  	p.From.Type = obj.TYPE_MEM
   560  	p.From.Reg = REGG
   561  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
   562  	if c.cursym.CFunc() {
   563  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
   564  	}
   565  	p.To.Type = obj.TYPE_REG
   566  	p.To.Reg = REG_R3
   567  
   568  	// Mark the stack bound check and morestack call async nonpreemptible.
   569  	// If we get preempted here, when resumed the preemption request is
   570  	// cleared, but we'll still call morestack, which will double the stack
   571  	// unnecessarily. See issue #35470.
   572  	p = c.ctxt.StartUnsafePoint(p, c.newprog)
   573  
   574  	q = nil
   575  	if framesize <= objabi.StackSmall {
   576  		// small stack: SP < stackguard
   577  		//	CMPUBGE	stackguard, SP, label-of-call-to-morestack
   578  
   579  		p = obj.Appendp(p, c.newprog)
   580  		//q1 = p
   581  		p.From.Type = obj.TYPE_REG
   582  		p.From.Reg = REG_R3
   583  		p.Reg = REGSP
   584  		p.As = ACMPUBGE
   585  		p.To.Type = obj.TYPE_BRANCH
   586  
   587  	} else if framesize <= objabi.StackBig {
   588  		// large stack: SP-framesize < stackguard-StackSmall
   589  		//	ADD $-(framesize-StackSmall), SP, R4
   590  		//	CMPUBGE stackguard, R4, label-of-call-to-morestack
   591  		p = obj.Appendp(p, c.newprog)
   592  
   593  		p.As = AADD
   594  		p.From.Type = obj.TYPE_CONST
   595  		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
   596  		p.Reg = REGSP
   597  		p.To.Type = obj.TYPE_REG
   598  		p.To.Reg = REG_R4
   599  
   600  		p = obj.Appendp(p, c.newprog)
   601  		p.From.Type = obj.TYPE_REG
   602  		p.From.Reg = REG_R3
   603  		p.Reg = REG_R4
   604  		p.As = ACMPUBGE
   605  		p.To.Type = obj.TYPE_BRANCH
   606  
   607  	} else {
   608  		// Such a large stack we need to protect against wraparound.
   609  		// If SP is close to zero:
   610  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   611  		// The +StackGuard on both sides is required to keep the left side positive:
   612  		// SP is allowed to be slightly below stackguard. See stack.h.
   613  		//
   614  		// Preemption sets stackguard to StackPreempt, a very large value.
   615  		// That breaks the math above, so we have to check for that explicitly.
   616  		//	// stackguard is R3
   617  		//	CMP	R3, $StackPreempt
   618  		//	BEQ	label-of-call-to-morestack
   619  		//	ADD	$StackGuard, SP, R4
   620  		//	SUB	R3, R4
   621  		//	MOVD	$(framesize+(StackGuard-StackSmall)), TEMP
   622  		//	CMPUBGE	TEMP, R4, label-of-call-to-morestack
   623  		p = obj.Appendp(p, c.newprog)
   624  
   625  		p.As = ACMP
   626  		p.From.Type = obj.TYPE_REG
   627  		p.From.Reg = REG_R3
   628  		p.To.Type = obj.TYPE_CONST
   629  		p.To.Offset = objabi.StackPreempt
   630  
   631  		p = obj.Appendp(p, c.newprog)
   632  		q = p
   633  		p.As = ABEQ
   634  		p.To.Type = obj.TYPE_BRANCH
   635  
   636  		p = obj.Appendp(p, c.newprog)
   637  		p.As = AADD
   638  		p.From.Type = obj.TYPE_CONST
   639  		p.From.Offset = int64(objabi.StackGuard)
   640  		p.Reg = REGSP
   641  		p.To.Type = obj.TYPE_REG
   642  		p.To.Reg = REG_R4
   643  
   644  		p = obj.Appendp(p, c.newprog)
   645  		p.As = ASUB
   646  		p.From.Type = obj.TYPE_REG
   647  		p.From.Reg = REG_R3
   648  		p.To.Type = obj.TYPE_REG
   649  		p.To.Reg = REG_R4
   650  
   651  		p = obj.Appendp(p, c.newprog)
   652  		p.As = AMOVD
   653  		p.From.Type = obj.TYPE_CONST
   654  		p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
   655  		p.To.Type = obj.TYPE_REG
   656  		p.To.Reg = REGTMP
   657  
   658  		p = obj.Appendp(p, c.newprog)
   659  		p.From.Type = obj.TYPE_REG
   660  		p.From.Reg = REGTMP
   661  		p.Reg = REG_R4
   662  		p.As = ACMPUBGE
   663  		p.To.Type = obj.TYPE_BRANCH
   664  	}
   665  
   666  	return p, q
   667  }
   668  
   669  func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
   670  	// Now we are at the end of the function, but logically
   671  	// we are still in function prologue. We need to fix the
   672  	// SP data and PCDATA.
   673  	spfix := obj.Appendp(p, c.newprog)
   674  	spfix.As = obj.ANOP
   675  	spfix.Spadj = -framesize
   676  
   677  	pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
   678  	pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
   679  
   680  	// MOVD	LR, R5
   681  	p = obj.Appendp(pcdata, c.newprog)
   682  	pPre.To.SetTarget(p)
   683  	p.As = AMOVD
   684  	p.From.Type = obj.TYPE_REG
   685  	p.From.Reg = REG_LR
   686  	p.To.Type = obj.TYPE_REG
   687  	p.To.Reg = REG_R5
   688  	if pPreempt != nil {
   689  		pPreempt.To.SetTarget(p)
   690  	}
   691  
   692  	// BL	runtime.morestack(SB)
   693  	p = obj.Appendp(p, c.newprog)
   694  
   695  	p.As = ABL
   696  	p.To.Type = obj.TYPE_BRANCH
   697  	if c.cursym.CFunc() {
   698  		p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
   699  	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
   700  		p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
   701  	} else {
   702  		p.To.Sym = c.ctxt.Lookup("runtime.morestack")
   703  	}
   704  
   705  	p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
   706  
   707  	// BR	start
   708  	p = obj.Appendp(p, c.newprog)
   709  
   710  	p.As = ABR
   711  	p.To.Type = obj.TYPE_BRANCH
   712  	p.To.SetTarget(c.cursym.Func.Text.Link)
   713  	return p
   714  }
   715  
   716  var unaryDst = map[obj.As]bool{
   717  	ASTCK:  true,
   718  	ASTCKC: true,
   719  	ASTCKE: true,
   720  	ASTCKF: true,
   721  	ANEG:   true,
   722  	ANEGW:  true,
   723  	AVONE:  true,
   724  	AVZERO: true,
   725  }
   726  
   727  var Links390x = obj.LinkArch{
   728  	Arch:           sys.ArchS390X,
   729  	Init:           buildop,
   730  	Preprocess:     preprocess,
   731  	Assemble:       spanz,
   732  	Progedit:       progedit,
   733  	UnaryDst:       unaryDst,
   734  	DWARFRegisters: S390XDWARFRegisters,
   735  }
   736  

View as plain text