...

Source file src/pkg/cmd/internal/obj/s390x/objz.go

     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			case obj.AGETCALLERPC:
   529				if cursym.Leaf() {
   530					/* MOVD LR, Rd */
   531					p.As = AMOVD
   532					p.From.Type = obj.TYPE_REG
   533					p.From.Reg = REG_LR
   534				} else {
   535					/* MOVD (RSP), Rd */
   536					p.As = AMOVD
   537					p.From.Type = obj.TYPE_MEM
   538					p.From.Reg = REGSP
   539				}
   540			}
   541		}
   542		if wasSplit {
   543			c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check
   544		}
   545	}
   546	
   547	func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
   548		var q *obj.Prog
   549	
   550		// MOVD	g_stackguard(g), R3
   551		p = obj.Appendp(p, c.newprog)
   552	
   553		p.As = AMOVD
   554		p.From.Type = obj.TYPE_MEM
   555		p.From.Reg = REGG
   556		p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
   557		if c.cursym.CFunc() {
   558			p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
   559		}
   560		p.To.Type = obj.TYPE_REG
   561		p.To.Reg = REG_R3
   562	
   563		q = nil
   564		if framesize <= objabi.StackSmall {
   565			// small stack: SP < stackguard
   566			//	CMP	stackguard, SP
   567	
   568			//p.To.Type = obj.TYPE_REG
   569			//p.To.Reg = REGSP
   570	
   571			// q1: BLT	done
   572	
   573			p = obj.Appendp(p, c.newprog)
   574			//q1 = p
   575			p.From.Type = obj.TYPE_REG
   576			p.From.Reg = REG_R3
   577			p.Reg = REGSP
   578			p.As = ACMPUBGE
   579			p.To.Type = obj.TYPE_BRANCH
   580			//p = obj.Appendp(ctxt, p)
   581	
   582			//p.As = ACMPU
   583			//p.From.Type = obj.TYPE_REG
   584			//p.From.Reg = REG_R3
   585			//p.To.Type = obj.TYPE_REG
   586			//p.To.Reg = REGSP
   587	
   588			//p = obj.Appendp(ctxt, p)
   589			//p.As = ABGE
   590			//p.To.Type = obj.TYPE_BRANCH
   591	
   592		} else if framesize <= objabi.StackBig {
   593			// large stack: SP-framesize < stackguard-StackSmall
   594			//	ADD $-(framesize-StackSmall), SP, R4
   595			//	CMP stackguard, R4
   596			p = obj.Appendp(p, c.newprog)
   597	
   598			p.As = AADD
   599			p.From.Type = obj.TYPE_CONST
   600			p.From.Offset = -(int64(framesize) - objabi.StackSmall)
   601			p.Reg = REGSP
   602			p.To.Type = obj.TYPE_REG
   603			p.To.Reg = REG_R4
   604	
   605			p = obj.Appendp(p, c.newprog)
   606			p.From.Type = obj.TYPE_REG
   607			p.From.Reg = REG_R3
   608			p.Reg = REG_R4
   609			p.As = ACMPUBGE
   610			p.To.Type = obj.TYPE_BRANCH
   611	
   612		} else {
   613			// Such a large stack we need to protect against wraparound.
   614			// If SP is close to zero:
   615			//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   616			// The +StackGuard on both sides is required to keep the left side positive:
   617			// SP is allowed to be slightly below stackguard. See stack.h.
   618			//
   619			// Preemption sets stackguard to StackPreempt, a very large value.
   620			// That breaks the math above, so we have to check for that explicitly.
   621			//	// stackguard is R3
   622			//	CMP	R3, $StackPreempt
   623			//	BEQ	label-of-call-to-morestack
   624			//	ADD	$StackGuard, SP, R4
   625			//	SUB	R3, R4
   626			//	MOVD	$(framesize+(StackGuard-StackSmall)), TEMP
   627			//	CMPUBGE	TEMP, R4
   628			p = obj.Appendp(p, c.newprog)
   629	
   630			p.As = ACMP
   631			p.From.Type = obj.TYPE_REG
   632			p.From.Reg = REG_R3
   633			p.To.Type = obj.TYPE_CONST
   634			p.To.Offset = objabi.StackPreempt
   635	
   636			p = obj.Appendp(p, c.newprog)
   637			q = p
   638			p.As = ABEQ
   639			p.To.Type = obj.TYPE_BRANCH
   640	
   641			p = obj.Appendp(p, c.newprog)
   642			p.As = AADD
   643			p.From.Type = obj.TYPE_CONST
   644			p.From.Offset = int64(objabi.StackGuard)
   645			p.Reg = REGSP
   646			p.To.Type = obj.TYPE_REG
   647			p.To.Reg = REG_R4
   648	
   649			p = obj.Appendp(p, c.newprog)
   650			p.As = ASUB
   651			p.From.Type = obj.TYPE_REG
   652			p.From.Reg = REG_R3
   653			p.To.Type = obj.TYPE_REG
   654			p.To.Reg = REG_R4
   655	
   656			p = obj.Appendp(p, c.newprog)
   657			p.As = AMOVD
   658			p.From.Type = obj.TYPE_CONST
   659			p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
   660			p.To.Type = obj.TYPE_REG
   661			p.To.Reg = REGTMP
   662	
   663			p = obj.Appendp(p, c.newprog)
   664			p.From.Type = obj.TYPE_REG
   665			p.From.Reg = REGTMP
   666			p.Reg = REG_R4
   667			p.As = ACMPUBGE
   668			p.To.Type = obj.TYPE_BRANCH
   669		}
   670	
   671		return p, q
   672	}
   673	
   674	func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
   675		// Now we are at the end of the function, but logically
   676		// we are still in function prologue. We need to fix the
   677		// SP data and PCDATA.
   678		spfix := obj.Appendp(p, c.newprog)
   679		spfix.As = obj.ANOP
   680		spfix.Spadj = -framesize
   681	
   682		pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
   683	
   684		// MOVD	LR, R5
   685		p = obj.Appendp(pcdata, c.newprog)
   686		pPre.Pcond = p
   687		p.As = AMOVD
   688		p.From.Type = obj.TYPE_REG
   689		p.From.Reg = REG_LR
   690		p.To.Type = obj.TYPE_REG
   691		p.To.Reg = REG_R5
   692		if pPreempt != nil {
   693			pPreempt.Pcond = p
   694		}
   695	
   696		// BL	runtime.morestack(SB)
   697		p = obj.Appendp(p, c.newprog)
   698	
   699		p.As = ABL
   700		p.To.Type = obj.TYPE_BRANCH
   701		if c.cursym.CFunc() {
   702			p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
   703		} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
   704			p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
   705		} else {
   706			p.To.Sym = c.ctxt.Lookup("runtime.morestack")
   707		}
   708	
   709		// BR	start
   710		p = obj.Appendp(p, c.newprog)
   711	
   712		p.As = ABR
   713		p.To.Type = obj.TYPE_BRANCH
   714		p.Pcond = c.cursym.Func.Text.Link
   715		return p
   716	}
   717	
   718	var unaryDst = map[obj.As]bool{
   719		ASTCK:  true,
   720		ASTCKC: true,
   721		ASTCKE: true,
   722		ASTCKF: true,
   723		ANEG:   true,
   724		ANEGW:  true,
   725		AVONE:  true,
   726		AVZERO: true,
   727	}
   728	
   729	var Links390x = obj.LinkArch{
   730		Arch:           sys.ArchS390X,
   731		Init:           buildop,
   732		Preprocess:     preprocess,
   733		Assemble:       spanz,
   734		Progedit:       progedit,
   735		UnaryDst:       unaryDst,
   736		DWARFRegisters: S390XDWARFRegisters,
   737	}
   738	

View as plain text