Help us shape the future of Go! Take the 2026 Go Developer Survey

Source file src/cmd/internal/obj/loong64/obj.go

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package loong64
     6  
     7  import (
     8  	"cmd/internal/obj"
     9  	"cmd/internal/objabi"
    10  	"cmd/internal/src"
    11  	"cmd/internal/sys"
    12  	"internal/abi"
    13  	"log"
    14  	"math"
    15  )
    16  
    17  func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    18  	// Rewrite JMP/JAL to symbol as TYPE_BRANCH.
    19  	switch p.As {
    20  	case AJMP, AJAL, ARET:
    21  		if p.To.Sym != nil {
    22  			p.To.Type = obj.TYPE_BRANCH
    23  		}
    24  	}
    25  
    26  	// Rewrite float constants to values stored in memory.
    27  	switch p.As {
    28  	case AMOVF:
    29  		if p.From.Type == obj.TYPE_FCONST {
    30  			f32 := float32(p.From.Val.(float64))
    31  			if math.Float32bits(f32) == 0 {
    32  				p.As = AMOVW
    33  				p.From.Type = obj.TYPE_REG
    34  				p.From.Reg = REGZERO
    35  				break
    36  			}
    37  			p.From.Type = obj.TYPE_MEM
    38  			p.From.Sym = ctxt.Float32Sym(f32)
    39  			p.From.Name = obj.NAME_EXTERN
    40  			p.From.Offset = 0
    41  		}
    42  
    43  	case AMOVD:
    44  		if p.From.Type == obj.TYPE_FCONST {
    45  			f64 := p.From.Val.(float64)
    46  			if math.Float64bits(f64) == 0 {
    47  				p.As = AMOVV
    48  				p.From.Type = obj.TYPE_REG
    49  				p.From.Reg = REGZERO
    50  				break
    51  			}
    52  			p.From.Type = obj.TYPE_MEM
    53  			p.From.Sym = ctxt.Float64Sym(f64)
    54  			p.From.Name = obj.NAME_EXTERN
    55  			p.From.Offset = 0
    56  		}
    57  	}
    58  
    59  	// Rewrite SUB constants into ADD.
    60  	switch p.As {
    61  	case ASUB:
    62  		if p.From.Type == obj.TYPE_CONST {
    63  			p.From.Offset = -p.From.Offset
    64  			p.As = AADD
    65  		}
    66  
    67  	case ASUBV:
    68  		if p.From.Type == obj.TYPE_CONST {
    69  			p.From.Offset = -p.From.Offset
    70  			p.As = AADDV
    71  		}
    72  
    73  	case ASUBVU:
    74  		if p.From.Type == obj.TYPE_CONST {
    75  			p.From.Offset = -p.From.Offset
    76  			p.As = AADDVU
    77  		}
    78  	}
    79  
    80  	if ctxt.Flag_dynlink {
    81  		rewriteToUseGot(ctxt, p, newprog)
    82  	}
    83  }
    84  
    85  func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    86  	// We only care about global data: NAME_EXTERN means a global
    87  	// symbol in the Go sense, and p.Sym.Local is true for a few
    88  	// internally defined symbols.
    89  	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
    90  		// MOVV $sym, Rx becomes MOVV sym@GOT, Rx
    91  		// MOVV $sym+<off>, Rx becomes MOVV sym@GOT, Rx; ADD <off>, Rx
    92  		if p.As != AMOVV {
    93  			ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -shared", p)
    94  		}
    95  		if p.To.Type != obj.TYPE_REG {
    96  			ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -shared", p)
    97  		}
    98  		p.From.Type = obj.TYPE_MEM
    99  		p.From.Name = obj.NAME_GOTREF
   100  		if p.From.Offset != 0 {
   101  			q := obj.Appendp(p, newprog)
   102  			q.As = AADDV
   103  			q.From.Type = obj.TYPE_CONST
   104  			q.From.Offset = p.From.Offset
   105  			q.To = p.To
   106  			p.From.Offset = 0
   107  		}
   108  	}
   109  	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
   110  		ctxt.Diag("don't know how to handle %v with -shared", p)
   111  	}
   112  
   113  	var source *obj.Addr
   114  	// MOVx sym, Ry becomes MOVV sym@GOT, REGTMP; MOVx (REGTMP), Ry
   115  	// MOVx Ry, sym becomes MOVV sym@GOT, REGTMP; MOVx Ry, (REGTMP)
   116  	// An addition may be inserted between the two MOVs if there is an offset.
   117  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   118  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   119  			ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -shared", p)
   120  		}
   121  		source = &p.From
   122  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   123  		source = &p.To
   124  	} else {
   125  		return
   126  	}
   127  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   128  		return
   129  	}
   130  	if source.Sym.Type == objabi.STLSBSS {
   131  		return
   132  	}
   133  	if source.Type != obj.TYPE_MEM {
   134  		ctxt.Diag("don't know how to handle %v with -shared", p)
   135  	}
   136  	p1 := obj.Appendp(p, newprog)
   137  	p2 := obj.Appendp(p1, newprog)
   138  	p1.As = AMOVV
   139  	p1.From.Type = obj.TYPE_MEM
   140  	p1.From.Sym = source.Sym
   141  	p1.From.Name = obj.NAME_GOTREF
   142  	p1.To.Type = obj.TYPE_REG
   143  	p1.To.Reg = REGTMP
   144  
   145  	p2.As = p.As
   146  	p2.From = p.From
   147  	p2.To = p.To
   148  	if p.From.Name == obj.NAME_EXTERN {
   149  		p2.From.Reg = REGTMP
   150  		p2.From.Name = obj.NAME_NONE
   151  		p2.From.Sym = nil
   152  	} else if p.To.Name == obj.NAME_EXTERN {
   153  		p2.To.Reg = REGTMP
   154  		p2.To.Name = obj.NAME_NONE
   155  		p2.To.Sym = nil
   156  	} else {
   157  		return
   158  	}
   159  
   160  	obj.Nopout(p)
   161  }
   162  
   163  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   164  	c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym}
   165  	p := c.cursym.Func().Text
   166  
   167  	if p == nil || p.Link == nil {
   168  		return
   169  	}
   170  
   171  	if p.As != obj.ATEXT {
   172  		c.ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
   173  		return
   174  	}
   175  
   176  	textstksiz := p.To.Offset
   177  	if textstksiz == -ctxt.Arch.FixedFrameSize {
   178  		// Historical way to mark NOFRAME.
   179  		p.From.Sym.Set(obj.AttrNoFrame, true)
   180  		textstksiz = 0
   181  	}
   182  
   183  	if textstksiz < 0 {
   184  		c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
   185  	}
   186  
   187  	if p.From.Sym.NoFrame() {
   188  		if textstksiz != 0 {
   189  			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
   190  		}
   191  	}
   192  
   193  	if textstksiz%8 != 0 {
   194  		c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
   195  	}
   196  
   197  	c.cursym.Func().Args = p.To.Val.(int32)
   198  	c.cursym.Func().Locals = int32(textstksiz)
   199  
   200  	/*
   201  	 * find leaf subroutines
   202  	 */
   203  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   204  		switch p.As {
   205  		case obj.ATEXT:
   206  			p.Mark |= LEAF
   207  
   208  		case AJAL:
   209  			c.cursym.Func().Text.Mark &^= LEAF
   210  		}
   211  	}
   212  
   213  	var q, q1 *obj.Prog
   214  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   215  		o := p.As
   216  		switch o {
   217  		case obj.ATEXT:
   218  			c.autosize = int32(textstksiz)
   219  			if p.Mark&LEAF != 0 && c.autosize == 0 {
   220  				// A leaf function with no locals has no frame.
   221  				p.From.Sym.Set(obj.AttrNoFrame, true)
   222  			}
   223  
   224  			if !p.From.Sym.NoFrame() {
   225  				// If there is a stack frame at all, it includes
   226  				// space to save the LR.
   227  				c.autosize += int32(c.ctxt.Arch.FixedFrameSize)
   228  			}
   229  
   230  			if p.Mark&LEAF != 0 && c.autosize < abi.StackSmall {
   231  				// A leaf function with a small stack can be marked
   232  				// NOSPLIT, avoiding a stack check.
   233  				p.From.Sym.Set(obj.AttrNoSplit, true)
   234  			}
   235  
   236  			if c.autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
   237  				if c.cursym.Func().Text.From.Sym.NoSplit() {
   238  					if ctxt.Debugvlog {
   239  						ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
   240  					}
   241  
   242  					c.cursym.Func().Text.Mark |= LEAF
   243  				}
   244  			}
   245  
   246  			p.To.Offset = int64(c.autosize) - ctxt.Arch.FixedFrameSize
   247  
   248  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   249  				c.cursym.Set(obj.AttrLeaf, true)
   250  				if p.From.Sym.NoFrame() {
   251  					break
   252  				}
   253  			}
   254  
   255  			if !p.From.Sym.NoSplit() {
   256  				p = c.stacksplit(p, c.autosize) // emit split check
   257  			}
   258  
   259  			q = p
   260  
   261  			if c.autosize != 0 {
   262  				// Make sure to save link register for non-empty frame, even if
   263  				// it is a leaf function, so that traceback works.
   264  				// Store link register before decrement SP, so if a signal comes
   265  				// during the execution of the function prologue, the traceback
   266  				// code will not see a half-updated stack frame.
   267  				// This sequence is not async preemptible, as if we open a frame
   268  				// at the current SP, it will clobber the saved LR.
   269  				q = c.ctxt.StartUnsafePoint(q, c.newprog)
   270  
   271  				// MOVV  REGLINK, -c.autosize(REGSP)
   272  				q = obj.Appendp(q, newprog)
   273  				q.As = AMOVV
   274  				q.Pos = p.Pos
   275  				q.From.Type = obj.TYPE_REG
   276  				q.From.Reg = REGLINK
   277  				q.To.Type = obj.TYPE_MEM
   278  				q.To.Offset = int64(-c.autosize)
   279  				q.To.Reg = REGSP
   280  
   281  				// ADDV  -c.autosize, REGSP
   282  				q = obj.Appendp(q, newprog)
   283  				q.As = AADDV
   284  				q.Pos = p.Pos
   285  				q.Pos = q.Pos.WithXlogue(src.PosPrologueEnd)
   286  				q.From.Type = obj.TYPE_CONST
   287  				q.From.Offset = int64(-c.autosize)
   288  				q.To.Type = obj.TYPE_REG
   289  				q.To.Reg = REGSP
   290  				q.Spadj = +c.autosize
   291  
   292  				q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
   293  
   294  				// On Linux, in a cgo binary we may get a SIGSETXID signal early on
   295  				// before the signal stack is set, as glibc doesn't allow us to block
   296  				// SIGSETXID. So a signal may land on the current stack and clobber
   297  				// the content below the SP. We store the LR again after the SP is
   298  				// decremented.
   299  				//
   300  				// MOVV  REGLINK, (REGSP)
   301  				q = obj.Appendp(q, newprog)
   302  				q.As = AMOVV
   303  				q.Pos = p.Pos
   304  				q.From.Type = obj.TYPE_REG
   305  				q.From.Reg = REGLINK
   306  				q.To.Type = obj.TYPE_MEM
   307  				q.To.Offset = 0
   308  				q.To.Reg = REGSP
   309  			}
   310  
   311  		case ARET:
   312  			if p.From.Type == obj.TYPE_CONST {
   313  				ctxt.Diag("using BECOME (%v) is not supported!", p)
   314  				break
   315  			}
   316  
   317  			retSym, retReg := p.To.Sym, p.To.Reg
   318  			if retReg == obj.REG_NONE {
   319  				retReg = REGLINK
   320  			}
   321  			p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
   322  			p.To.Sym = nil
   323  			p.To.Reg = obj.REG_NONE
   324  
   325  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   326  				if c.autosize == 0 {
   327  					p.As = AJMP
   328  					p.From = obj.Addr{}
   329  					if retSym != nil { // retjmp
   330  						p.To.Type = obj.TYPE_BRANCH
   331  						p.To.Name = obj.NAME_EXTERN
   332  						p.To.Sym = retSym
   333  					} else {
   334  						p.To.Type = obj.TYPE_MEM
   335  						p.To.Reg = retReg
   336  						p.To.Offset = 0
   337  					}
   338  					break
   339  				}
   340  
   341  				p.As = AADDV
   342  				p.From.Type = obj.TYPE_CONST
   343  				p.From.Offset = int64(c.autosize)
   344  				p.To.Type = obj.TYPE_REG
   345  				p.To.Reg = REGSP
   346  				p.Spadj = -c.autosize
   347  
   348  				q = c.newprog()
   349  				q.As = AJMP
   350  				q.Pos = p.Pos
   351  				if retSym != nil { // retjmp
   352  					q.To.Type = obj.TYPE_BRANCH
   353  					q.To.Name = obj.NAME_EXTERN
   354  					q.To.Sym = retSym
   355  				} else {
   356  					q.To.Type = obj.TYPE_MEM
   357  					q.To.Offset = 0
   358  					q.To.Reg = retReg
   359  				}
   360  				q.Spadj = +c.autosize
   361  
   362  				q.Link = p.Link
   363  				p.Link = q
   364  				break
   365  			}
   366  
   367  			p.As = AMOVV
   368  			p.From.Type = obj.TYPE_MEM
   369  			p.From.Offset = 0
   370  			p.From.Reg = REGSP
   371  			p.To.Type = obj.TYPE_REG
   372  			p.To.Reg = REGLINK
   373  
   374  			if c.autosize != 0 {
   375  				q = c.newprog()
   376  				q.As = AADDV
   377  				q.Pos = p.Pos
   378  				q.From.Type = obj.TYPE_CONST
   379  				q.From.Offset = int64(c.autosize)
   380  				q.To.Type = obj.TYPE_REG
   381  				q.To.Reg = REGSP
   382  				q.Spadj = -c.autosize
   383  
   384  				q.Link = p.Link
   385  				p.Link = q
   386  			}
   387  
   388  			q1 = c.newprog()
   389  			q1.As = AJMP
   390  			q1.Pos = p.Pos
   391  			if retSym != nil { // retjmp
   392  				q1.To.Type = obj.TYPE_BRANCH
   393  				q1.To.Name = obj.NAME_EXTERN
   394  				q1.To.Sym = retSym
   395  			} else {
   396  				q1.To.Type = obj.TYPE_MEM
   397  				q1.To.Offset = 0
   398  				q1.To.Reg = retReg
   399  			}
   400  			q1.Spadj = +c.autosize
   401  
   402  			q1.Link = q.Link
   403  			q.Link = q1
   404  
   405  		case AADD, AADDV, AADDVU:
   406  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   407  				p.Spadj = int32(-p.From.Offset)
   408  			}
   409  
   410  		case obj.AGETCALLERPC:
   411  			if cursym.Leaf() {
   412  				// MOV LR, Rd
   413  				p.As = AMOVV
   414  				p.From.Type = obj.TYPE_REG
   415  				p.From.Reg = REGLINK
   416  			} else {
   417  				// MOV (RSP), Rd
   418  				p.As = AMOVV
   419  				p.From.Type = obj.TYPE_MEM
   420  				p.From.Reg = REGSP
   421  			}
   422  		}
   423  
   424  		if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
   425  			f := c.cursym.Func()
   426  			if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
   427  				c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
   428  				if ctxt.Debugvlog || !ctxt.IsAsm {
   429  					ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
   430  					if !ctxt.IsAsm {
   431  						ctxt.Diag("invalid auto-SPWRITE in non-assembly")
   432  						ctxt.DiagFlush()
   433  						log.Fatalf("bad SPWRITE")
   434  					}
   435  				}
   436  			}
   437  		}
   438  	}
   439  }
   440  
   441  func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
   442  	if c.ctxt.Flag_maymorestack != "" {
   443  		// Save LR and REGCTXT.
   444  		frameSize := 2 * c.ctxt.Arch.PtrSize
   445  
   446  		p = c.ctxt.StartUnsafePoint(p, c.newprog)
   447  
   448  		// Spill Arguments. This has to happen before we open
   449  		// any more frame space.
   450  		p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
   451  
   452  		// MOVV	REGLINK, -16(SP)
   453  		p = obj.Appendp(p, c.newprog)
   454  		p.As = AMOVV
   455  		p.From.Type = obj.TYPE_REG
   456  		p.From.Reg = REGLINK
   457  		p.To.Type = obj.TYPE_MEM
   458  		p.To.Offset = int64(-frameSize)
   459  		p.To.Reg = REGSP
   460  
   461  		// MOVV	REGCTXT, -8(SP)
   462  		p = obj.Appendp(p, c.newprog)
   463  		p.As = AMOVV
   464  		p.From.Type = obj.TYPE_REG
   465  		p.From.Reg = REGCTXT
   466  		p.To.Type = obj.TYPE_MEM
   467  		p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
   468  		p.To.Reg = REGSP
   469  
   470  		// ADDV	$-16, SP
   471  		p = obj.Appendp(p, c.newprog)
   472  		p.As = AADDV
   473  		p.From.Type = obj.TYPE_CONST
   474  		p.From.Offset = int64(-frameSize)
   475  		p.To.Type = obj.TYPE_REG
   476  		p.To.Reg = REGSP
   477  		p.Spadj = int32(frameSize)
   478  
   479  		// JAL	maymorestack
   480  		p = obj.Appendp(p, c.newprog)
   481  		p.As = AJAL
   482  		p.To.Type = obj.TYPE_BRANCH
   483  		// See ../x86/obj6.go
   484  		p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
   485  
   486  		// Restore LR and REGCTXT.
   487  
   488  		// MOVV	0(SP), REGLINK
   489  		p = obj.Appendp(p, c.newprog)
   490  		p.As = AMOVV
   491  		p.From.Type = obj.TYPE_MEM
   492  		p.From.Offset = 0
   493  		p.From.Reg = REGSP
   494  		p.To.Type = obj.TYPE_REG
   495  		p.To.Reg = REGLINK
   496  
   497  		// MOVV	8(SP), REGCTXT
   498  		p = obj.Appendp(p, c.newprog)
   499  		p.As = AMOVV
   500  		p.From.Type = obj.TYPE_MEM
   501  		p.From.Offset = int64(c.ctxt.Arch.PtrSize)
   502  		p.From.Reg = REGSP
   503  		p.To.Type = obj.TYPE_REG
   504  		p.To.Reg = REGCTXT
   505  
   506  		// ADDV	$16, SP
   507  		p = obj.Appendp(p, c.newprog)
   508  		p.As = AADDV
   509  		p.From.Type = obj.TYPE_CONST
   510  		p.From.Offset = int64(frameSize)
   511  		p.To.Type = obj.TYPE_REG
   512  		p.To.Reg = REGSP
   513  		p.Spadj = int32(-frameSize)
   514  
   515  		// Unspill arguments
   516  		p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
   517  		p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
   518  	}
   519  
   520  	// Jump back to here after morestack returns.
   521  	startPred := p
   522  
   523  	// MOVV	g_stackguard(g), R20
   524  	p = obj.Appendp(p, c.newprog)
   525  	p.As = AMOVV
   526  	p.From.Type = obj.TYPE_MEM
   527  	p.From.Reg = REGG
   528  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
   529  	if c.cursym.CFunc() {
   530  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
   531  	}
   532  	p.To.Type = obj.TYPE_REG
   533  	p.To.Reg = REGRT1
   534  
   535  	// Mark the stack bound check and morestack call async nonpreemptible.
   536  	// If we get preempted here, when resumed the preemption request is
   537  	// cleared, but we'll still call morestack, which will double the stack
   538  	// unnecessarily. See issue #35470.
   539  	p = c.ctxt.StartUnsafePoint(p, c.newprog)
   540  
   541  	to_more0 := (*obj.Prog)(nil)
   542  	to_more1 := (*obj.Prog)(nil)
   543  
   544  	if framesize <= abi.StackSmall {
   545  		// small stack:
   546  		//	// if stackguard >= SP { goto morestack }
   547  		//	BGEU	stackguard, SP, label-of-call-to-morestack
   548  		p = obj.Appendp(p, c.newprog)
   549  		p.As = ABGEU
   550  		p.From.Type = obj.TYPE_REG
   551  		p.From.Reg = REGRT1
   552  		p.Reg = REGSP
   553  		p.To.Type = obj.TYPE_BRANCH
   554  		to_more0 = p
   555  	} else {
   556  		// large stack: SP-framesize < stackguard-StackSmall
   557  		offset := int64(framesize) - abi.StackSmall
   558  		if framesize > abi.StackBig {
   559  			// Such a large stack we need to protect against underflow.
   560  			// The runtime guarantees SP > objabi.StackBig, but
   561  			// framesize is large enough that SP-framesize may
   562  			// underflow, causing a direct comparison with the
   563  			// stack guard to incorrectly succeed. We explicitly
   564  			// guard against underflow.
   565  			//
   566  			//	// if $(framesize-StackSmall) > SP { goto morestack }
   567  			//	MOVV	$(framesize-StackSmall), REGRT2
   568  			//	BLTU	SP, REGRT2, label-of-call-to-morestack
   569  			p = obj.Appendp(p, c.newprog)
   570  			p.As = AMOVV
   571  			p.From.Type = obj.TYPE_CONST
   572  			p.From.Offset = offset
   573  			p.To.Type = obj.TYPE_REG
   574  			p.To.Reg = REGRT2
   575  
   576  			p = obj.Appendp(p, c.newprog)
   577  			p.As = ABLTU
   578  			p.From.Type = obj.TYPE_REG
   579  			p.From.Reg = REGSP
   580  			p.Reg = REGRT2
   581  			p.To.Type = obj.TYPE_BRANCH
   582  			to_more0 = p
   583  		}
   584  
   585  		// Check against the stack guard. We've ensured this won't underflow.
   586  		//
   587  		//	// if SP - (framesize-StackSmall) <= stackguard { goto morestack }
   588  		//	ADDV	$-(framesize-StackSmall), SP, RT2
   589  		//	BGEU	stackguard, RT2, label-of-call-to-morestack
   590  		if framesize > abi.StackBig {
   591  			p = obj.Appendp(p, c.newprog)
   592  			p.As = ASUBV
   593  			p.From.Type = obj.TYPE_REG
   594  			p.From.Reg = REGRT2
   595  			p.Reg = REGSP
   596  			p.To.Type = obj.TYPE_REG
   597  			p.To.Reg = REGRT2
   598  		} else {
   599  			p = obj.Appendp(p, c.newprog)
   600  			p.As = AADDV
   601  			p.From.Type = obj.TYPE_CONST
   602  			p.From.Offset = -offset
   603  			p.Reg = REGSP
   604  			p.To.Type = obj.TYPE_REG
   605  			p.To.Reg = REGRT2
   606  		}
   607  
   608  		p = obj.Appendp(p, c.newprog)
   609  		p.As = ABGEU
   610  		p.From.Type = obj.TYPE_REG
   611  		p.From.Reg = REGRT1
   612  		p.Reg = REGRT2
   613  		p.To.Type = obj.TYPE_BRANCH
   614  		to_more1 = p
   615  	}
   616  
   617  	end := c.ctxt.EndUnsafePoint(p, c.newprog, -1)
   618  
   619  	var last *obj.Prog
   620  	for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
   621  	}
   622  
   623  	// Now we are at the end of the function, but logically
   624  	// we are still in function prologue. We need to fix the
   625  	// SP data and PCDATA.
   626  	spfix := obj.Appendp(last, c.newprog)
   627  	spfix.As = obj.ANOP
   628  	spfix.Spadj = -framesize
   629  
   630  	pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
   631  	pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
   632  
   633  	if to_more0 != nil {
   634  		to_more0.To.SetTarget(pcdata)
   635  	}
   636  
   637  	if to_more1 != nil {
   638  		to_more1.To.SetTarget(pcdata)
   639  	}
   640  
   641  	p = c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
   642  
   643  	// MOVV	LINK, R31
   644  	p = obj.Appendp(p, c.newprog)
   645  	p.As = AMOVV
   646  	p.From.Type = obj.TYPE_REG
   647  	p.From.Reg = REGLINK
   648  	p.To.Type = obj.TYPE_REG
   649  	p.To.Reg = REG_R31
   650  
   651  	// JAL	runtime.morestack(SB)
   652  	call := obj.Appendp(p, c.newprog)
   653  	call.As = AJAL
   654  	call.To.Type = obj.TYPE_BRANCH
   655  
   656  	morestack := "runtime.morestack"
   657  	if c.cursym.CFunc() {
   658  		morestack = "runtime.morestackc"
   659  	} else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
   660  		morestack = "runtime.morestack_noctxt"
   661  	}
   662  	call.To.Sym = c.ctxt.Lookup(morestack)
   663  
   664  	// The instructions which unspill regs should be preemptible.
   665  	pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
   666  	unspill := c.cursym.Func().UnspillRegisterArgs(pcdata, c.newprog)
   667  
   668  	// JMP	start
   669  	jmp := obj.Appendp(unspill, c.newprog)
   670  	jmp.As = AJMP
   671  	jmp.To.Type = obj.TYPE_BRANCH
   672  	jmp.To.SetTarget(startPred.Link)
   673  	jmp.Spadj = +framesize
   674  
   675  	return end
   676  }
   677  
   678  var Linkloong64 = obj.LinkArch{
   679  	Arch:           sys.ArchLoong64,
   680  	Init:           buildop,
   681  	Preprocess:     preprocess,
   682  	Assemble:       span0,
   683  	Progedit:       progedit,
   684  	UnaryDst:       unaryDst,
   685  	DWARFRegisters: LOONG64DWARFRegisters,
   686  }
   687  

View as plain text