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  
   166  	p := c.cursym.Func().Text
   167  	textstksiz := p.To.Offset
   168  
   169  	if textstksiz < 0 {
   170  		c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
   171  	}
   172  	if p.From.Sym.NoFrame() {
   173  		if textstksiz != 0 {
   174  			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
   175  		}
   176  	}
   177  
   178  	c.cursym.Func().Args = p.To.Val.(int32)
   179  	c.cursym.Func().Locals = int32(textstksiz)
   180  
   181  	/*
   182  	 * find leaf subroutines
   183  	 * expand RET
   184  	 */
   185  
   186  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   187  		switch p.As {
   188  		case obj.ATEXT:
   189  			p.Mark |= LABEL | LEAF | SYNC
   190  			if p.Link != nil {
   191  				p.Link.Mark |= LABEL
   192  			}
   193  
   194  		case AMOVW,
   195  			AMOVV:
   196  			if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL {
   197  				p.Mark |= LABEL | SYNC
   198  				break
   199  			}
   200  			if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL {
   201  				p.Mark |= LABEL | SYNC
   202  			}
   203  
   204  		case ASYSCALL,
   205  			AWORD:
   206  			p.Mark |= LABEL | SYNC
   207  
   208  		case ANOR:
   209  			if p.To.Type == obj.TYPE_REG {
   210  				if p.To.Reg == REGZERO {
   211  					p.Mark |= LABEL | SYNC
   212  				}
   213  			}
   214  
   215  		case AJAL:
   216  			c.cursym.Func().Text.Mark &^= LEAF
   217  			fallthrough
   218  
   219  		case AJMP,
   220  			ABEQ,
   221  			ABGEU,
   222  			ABLTU,
   223  			ABLTZ,
   224  			ABNE,
   225  			ABFPT, ABFPF:
   226  			p.Mark |= BRANCH
   227  			q1 := p.To.Target()
   228  			if q1 != nil {
   229  				for q1.As == obj.ANOP {
   230  					q1 = q1.Link
   231  					p.To.SetTarget(q1)
   232  				}
   233  
   234  				if q1.Mark&LEAF == 0 {
   235  					q1.Mark |= LABEL
   236  				}
   237  			}
   238  			q1 = p.Link
   239  			if q1 != nil {
   240  				q1.Mark |= LABEL
   241  			}
   242  
   243  		case ARET:
   244  			if p.Link != nil {
   245  				p.Link.Mark |= LABEL
   246  			}
   247  		}
   248  	}
   249  
   250  	var mov, add obj.As
   251  
   252  	add = AADDV
   253  	mov = AMOVV
   254  
   255  	var q *obj.Prog
   256  	var q1 *obj.Prog
   257  	autosize := int32(0)
   258  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   259  		o := p.As
   260  		switch o {
   261  		case obj.ATEXT:
   262  			autosize = int32(textstksiz)
   263  
   264  			if p.Mark&LEAF != 0 && autosize == 0 {
   265  				// A leaf function with no locals has no frame.
   266  				p.From.Sym.Set(obj.AttrNoFrame, true)
   267  			}
   268  
   269  			if !p.From.Sym.NoFrame() {
   270  				// If there is a stack frame at all, it includes
   271  				// space to save the LR.
   272  				autosize += int32(c.ctxt.Arch.FixedFrameSize)
   273  			}
   274  
   275  			if p.Mark&LEAF != 0 && autosize < abi.StackSmall {
   276  				// A leaf function with a small stack can be marked
   277  				// NOSPLIT, avoiding a stack check.
   278  				p.From.Sym.Set(obj.AttrNoSplit, true)
   279  			}
   280  
   281  			if autosize&4 != 0 {
   282  				autosize += 4
   283  			}
   284  
   285  			if autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
   286  				if c.cursym.Func().Text.From.Sym.NoSplit() {
   287  					if ctxt.Debugvlog {
   288  						ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
   289  					}
   290  
   291  					c.cursym.Func().Text.Mark |= LEAF
   292  				}
   293  			}
   294  
   295  			p.To.Offset = int64(autosize) - ctxt.Arch.FixedFrameSize
   296  
   297  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   298  				c.cursym.Set(obj.AttrLeaf, true)
   299  				if p.From.Sym.NoFrame() {
   300  					break
   301  				}
   302  			}
   303  
   304  			if !p.From.Sym.NoSplit() {
   305  				p = c.stacksplit(p, autosize) // emit split check
   306  			}
   307  
   308  			q = p
   309  
   310  			if autosize != 0 {
   311  				// Make sure to save link register for non-empty frame, even if
   312  				// it is a leaf function, so that traceback works.
   313  				// Store link register before decrement SP, so if a signal comes
   314  				// during the execution of the function prologue, the traceback
   315  				// code will not see a half-updated stack frame.
   316  				// This sequence is not async preemptible, as if we open a frame
   317  				// at the current SP, it will clobber the saved LR.
   318  				q = c.ctxt.StartUnsafePoint(q, c.newprog)
   319  
   320  				q = obj.Appendp(q, newprog)
   321  				q.As = mov
   322  				q.Pos = p.Pos
   323  				q.From.Type = obj.TYPE_REG
   324  				q.From.Reg = REGLINK
   325  				q.To.Type = obj.TYPE_MEM
   326  				q.To.Offset = int64(-autosize)
   327  				q.To.Reg = REGSP
   328  
   329  				q = obj.Appendp(q, newprog)
   330  				q.As = add
   331  				q.Pos = p.Pos
   332  				q.Pos = q.Pos.WithXlogue(src.PosPrologueEnd)
   333  				q.From.Type = obj.TYPE_CONST
   334  				q.From.Offset = int64(-autosize)
   335  				q.To.Type = obj.TYPE_REG
   336  				q.To.Reg = REGSP
   337  				q.Spadj = +autosize
   338  
   339  				q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
   340  
   341  				// On Linux, in a cgo binary we may get a SIGSETXID signal early on
   342  				// before the signal stack is set, as glibc doesn't allow us to block
   343  				// SIGSETXID. So a signal may land on the current stack and clobber
   344  				// the content below the SP. We store the LR again after the SP is
   345  				// decremented.
   346  				q = obj.Appendp(q, newprog)
   347  				q.As = mov
   348  				q.Pos = p.Pos
   349  				q.From.Type = obj.TYPE_REG
   350  				q.From.Reg = REGLINK
   351  				q.To.Type = obj.TYPE_MEM
   352  				q.To.Offset = 0
   353  				q.To.Reg = REGSP
   354  			}
   355  
   356  		case ARET:
   357  			if p.From.Type == obj.TYPE_CONST {
   358  				ctxt.Diag("using BECOME (%v) is not supported!", p)
   359  				break
   360  			}
   361  
   362  			retSym, retReg := p.To.Sym, p.To.Reg
   363  			if retReg == obj.REG_NONE {
   364  				retReg = REGLINK
   365  			}
   366  			p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
   367  			p.To.Sym = nil
   368  			p.To.Reg = obj.REG_NONE
   369  
   370  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   371  				if autosize == 0 {
   372  					p.As = AJMP
   373  					p.From = obj.Addr{}
   374  					if retSym != nil { // retjmp
   375  						p.To.Type = obj.TYPE_BRANCH
   376  						p.To.Name = obj.NAME_EXTERN
   377  						p.To.Sym = retSym
   378  					} else {
   379  						p.To.Type = obj.TYPE_MEM
   380  						p.To.Reg = retReg
   381  						p.To.Offset = 0
   382  					}
   383  					p.Mark |= BRANCH
   384  					break
   385  				}
   386  
   387  				p.As = add
   388  				p.From.Type = obj.TYPE_CONST
   389  				p.From.Offset = int64(autosize)
   390  				p.To.Type = obj.TYPE_REG
   391  				p.To.Reg = REGSP
   392  				p.Spadj = -autosize
   393  
   394  				q = c.newprog()
   395  				q.As = AJMP
   396  				q.Pos = p.Pos
   397  				if retSym != nil { // retjmp
   398  					q.To.Type = obj.TYPE_BRANCH
   399  					q.To.Name = obj.NAME_EXTERN
   400  					q.To.Sym = retSym
   401  				} else {
   402  					q.To.Type = obj.TYPE_MEM
   403  					q.To.Offset = 0
   404  					q.To.Reg = retReg
   405  				}
   406  				q.Mark |= BRANCH
   407  				q.Spadj = +autosize
   408  
   409  				q.Link = p.Link
   410  				p.Link = q
   411  				break
   412  			}
   413  
   414  			p.As = mov
   415  			p.From.Type = obj.TYPE_MEM
   416  			p.From.Offset = 0
   417  			p.From.Reg = REGSP
   418  			p.To.Type = obj.TYPE_REG
   419  			p.To.Reg = REGLINK
   420  
   421  			if autosize != 0 {
   422  				q = c.newprog()
   423  				q.As = add
   424  				q.Pos = p.Pos
   425  				q.From.Type = obj.TYPE_CONST
   426  				q.From.Offset = int64(autosize)
   427  				q.To.Type = obj.TYPE_REG
   428  				q.To.Reg = REGSP
   429  				q.Spadj = -autosize
   430  
   431  				q.Link = p.Link
   432  				p.Link = q
   433  			}
   434  
   435  			q1 = c.newprog()
   436  			q1.As = AJMP
   437  			q1.Pos = p.Pos
   438  			if retSym != nil { // retjmp
   439  				q1.To.Type = obj.TYPE_BRANCH
   440  				q1.To.Name = obj.NAME_EXTERN
   441  				q1.To.Sym = retSym
   442  			} else {
   443  				q1.To.Type = obj.TYPE_MEM
   444  				q1.To.Offset = 0
   445  				q1.To.Reg = retReg
   446  			}
   447  			q1.Mark |= BRANCH
   448  			q1.Spadj = +autosize
   449  
   450  			q1.Link = q.Link
   451  			q.Link = q1
   452  
   453  		case AADD,
   454  			AADDV,
   455  			AADDVU:
   456  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   457  				p.Spadj = int32(-p.From.Offset)
   458  			}
   459  
   460  		case obj.AGETCALLERPC:
   461  			if cursym.Leaf() {
   462  				// MOV LR, Rd
   463  				p.As = mov
   464  				p.From.Type = obj.TYPE_REG
   465  				p.From.Reg = REGLINK
   466  			} else {
   467  				// MOV (RSP), Rd
   468  				p.As = mov
   469  				p.From.Type = obj.TYPE_MEM
   470  				p.From.Reg = REGSP
   471  			}
   472  		}
   473  
   474  		if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
   475  			f := c.cursym.Func()
   476  			if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
   477  				c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
   478  				if ctxt.Debugvlog || !ctxt.IsAsm {
   479  					ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
   480  					if !ctxt.IsAsm {
   481  						ctxt.Diag("invalid auto-SPWRITE in non-assembly")
   482  						ctxt.DiagFlush()
   483  						log.Fatalf("bad SPWRITE")
   484  					}
   485  				}
   486  			}
   487  		}
   488  	}
   489  }
   490  
   491  func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
   492  	var mov, add obj.As
   493  
   494  	add = AADDV
   495  	mov = AMOVV
   496  	if c.ctxt.Flag_maymorestack != "" {
   497  		// Save LR and REGCTXT.
   498  		frameSize := 2 * c.ctxt.Arch.PtrSize
   499  
   500  		p = c.ctxt.StartUnsafePoint(p, c.newprog)
   501  
   502  		// Spill Arguments. This has to happen before we open
   503  		// any more frame space.
   504  		p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
   505  
   506  		// MOV	REGLINK, -8/-16(SP)
   507  		p = obj.Appendp(p, c.newprog)
   508  		p.As = mov
   509  		p.From.Type = obj.TYPE_REG
   510  		p.From.Reg = REGLINK
   511  		p.To.Type = obj.TYPE_MEM
   512  		p.To.Offset = int64(-frameSize)
   513  		p.To.Reg = REGSP
   514  
   515  		// MOV	REGCTXT, -4/-8(SP)
   516  		p = obj.Appendp(p, c.newprog)
   517  		p.As = mov
   518  		p.From.Type = obj.TYPE_REG
   519  		p.From.Reg = REGCTXT
   520  		p.To.Type = obj.TYPE_MEM
   521  		p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
   522  		p.To.Reg = REGSP
   523  
   524  		// ADD	$-8/$-16, SP
   525  		p = obj.Appendp(p, c.newprog)
   526  		p.As = add
   527  		p.From.Type = obj.TYPE_CONST
   528  		p.From.Offset = int64(-frameSize)
   529  		p.To.Type = obj.TYPE_REG
   530  		p.To.Reg = REGSP
   531  		p.Spadj = int32(frameSize)
   532  
   533  		// JAL	maymorestack
   534  		p = obj.Appendp(p, c.newprog)
   535  		p.As = AJAL
   536  		p.To.Type = obj.TYPE_BRANCH
   537  		// See ../x86/obj6.go
   538  		p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
   539  		p.Mark |= BRANCH
   540  
   541  		// Restore LR and REGCTXT.
   542  
   543  		// MOV	0(SP), REGLINK
   544  		p = obj.Appendp(p, c.newprog)
   545  		p.As = mov
   546  		p.From.Type = obj.TYPE_MEM
   547  		p.From.Offset = 0
   548  		p.From.Reg = REGSP
   549  		p.To.Type = obj.TYPE_REG
   550  		p.To.Reg = REGLINK
   551  
   552  		// MOV	4/8(SP), REGCTXT
   553  		p = obj.Appendp(p, c.newprog)
   554  		p.As = mov
   555  		p.From.Type = obj.TYPE_MEM
   556  		p.From.Offset = int64(c.ctxt.Arch.PtrSize)
   557  		p.From.Reg = REGSP
   558  		p.To.Type = obj.TYPE_REG
   559  		p.To.Reg = REGCTXT
   560  
   561  		// ADD	$8/$16, SP
   562  		p = obj.Appendp(p, c.newprog)
   563  		p.As = add
   564  		p.From.Type = obj.TYPE_CONST
   565  		p.From.Offset = int64(frameSize)
   566  		p.To.Type = obj.TYPE_REG
   567  		p.To.Reg = REGSP
   568  		p.Spadj = int32(-frameSize)
   569  
   570  		// Unspill arguments
   571  		p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
   572  		p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
   573  	}
   574  
   575  	// Jump back to here after morestack returns.
   576  	startPred := p
   577  
   578  	// MOV	g_stackguard(g), R20
   579  	p = obj.Appendp(p, c.newprog)
   580  
   581  	p.As = mov
   582  	p.From.Type = obj.TYPE_MEM
   583  	p.From.Reg = REGG
   584  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
   585  	if c.cursym.CFunc() {
   586  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
   587  	}
   588  	p.To.Type = obj.TYPE_REG
   589  	p.To.Reg = REG_R20
   590  
   591  	// Mark the stack bound check and morestack call async nonpreemptible.
   592  	// If we get preempted here, when resumed the preemption request is
   593  	// cleared, but we'll still call morestack, which will double the stack
   594  	// unnecessarily. See issue #35470.
   595  	p = c.ctxt.StartUnsafePoint(p, c.newprog)
   596  
   597  	var q *obj.Prog
   598  	if framesize <= abi.StackSmall {
   599  		// small stack: SP < stackguard
   600  		//	SGTU	SP, stackguard, R20
   601  		p = obj.Appendp(p, c.newprog)
   602  
   603  		p.As = ASGTU
   604  		p.From.Type = obj.TYPE_REG
   605  		p.From.Reg = REGSP
   606  		p.Reg = REG_R20
   607  		p.To.Type = obj.TYPE_REG
   608  		p.To.Reg = REG_R20
   609  	} else {
   610  		// large stack: SP-framesize < stackguard-StackSmall
   611  		offset := int64(framesize) - abi.StackSmall
   612  		if framesize > abi.StackBig {
   613  			// Such a large stack we need to protect against underflow.
   614  			// The runtime guarantees SP > objabi.StackBig, but
   615  			// framesize is large enough that SP-framesize may
   616  			// underflow, causing a direct comparison with the
   617  			// stack guard to incorrectly succeed. We explicitly
   618  			// guard against underflow.
   619  			//
   620  			//      SGTU    $(framesize-StackSmall), SP, R24
   621  			//      BNE     R24, label-of-call-to-morestack
   622  
   623  			p = obj.Appendp(p, c.newprog)
   624  			p.As = ASGTU
   625  			p.From.Type = obj.TYPE_CONST
   626  			p.From.Offset = offset
   627  			p.Reg = REGSP
   628  			p.To.Type = obj.TYPE_REG
   629  			p.To.Reg = REG_R24
   630  
   631  			p = obj.Appendp(p, c.newprog)
   632  			q = p
   633  			p.As = ABNE
   634  			p.From.Type = obj.TYPE_REG
   635  			p.From.Reg = REG_R24
   636  			p.To.Type = obj.TYPE_BRANCH
   637  			p.Mark |= BRANCH
   638  		}
   639  
   640  		p = obj.Appendp(p, c.newprog)
   641  
   642  		p.As = add
   643  		p.From.Type = obj.TYPE_CONST
   644  		p.From.Offset = -offset
   645  		p.Reg = REGSP
   646  		p.To.Type = obj.TYPE_REG
   647  		p.To.Reg = REG_R24
   648  
   649  		p = obj.Appendp(p, c.newprog)
   650  		p.As = ASGTU
   651  		p.From.Type = obj.TYPE_REG
   652  		p.From.Reg = REG_R24
   653  		p.Reg = REG_R20
   654  		p.To.Type = obj.TYPE_REG
   655  		p.To.Reg = REG_R20
   656  	}
   657  
   658  	// q1: BEQ	R20, morestack
   659  	p = obj.Appendp(p, c.newprog)
   660  	q1 := p
   661  
   662  	p.As = ABEQ
   663  	p.From.Type = obj.TYPE_REG
   664  	p.From.Reg = REG_R20
   665  	p.To.Type = obj.TYPE_BRANCH
   666  	p.Mark |= BRANCH
   667  
   668  	end := c.ctxt.EndUnsafePoint(p, c.newprog, -1)
   669  
   670  	var last *obj.Prog
   671  	for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
   672  	}
   673  
   674  	// Now we are at the end of the function, but logically
   675  	// we are still in function prologue. We need to fix the
   676  	// SP data and PCDATA.
   677  	spfix := obj.Appendp(last, c.newprog)
   678  	spfix.As = obj.ANOP
   679  	spfix.Spadj = -framesize
   680  
   681  	pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
   682  	pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
   683  
   684  	if q != nil {
   685  		q.To.SetTarget(pcdata)
   686  	}
   687  	q1.To.SetTarget(pcdata)
   688  
   689  	p = c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
   690  
   691  	// MOV  LINK, R31
   692  	p = obj.Appendp(p, c.newprog)
   693  	p.As = mov
   694  	p.From.Type = obj.TYPE_REG
   695  	p.From.Reg = REGLINK
   696  	p.To.Type = obj.TYPE_REG
   697  	p.To.Reg = REG_R31
   698  	if q != nil {
   699  		q.To.SetTarget(p)
   700  		p.Mark |= LABEL
   701  	}
   702  
   703  	// JAL runtime.morestack(SB)
   704  	call := obj.Appendp(p, c.newprog)
   705  	call.As = AJAL
   706  	call.To.Type = obj.TYPE_BRANCH
   707  
   708  	if c.cursym.CFunc() {
   709  		call.To.Sym = c.ctxt.Lookup("runtime.morestackc")
   710  	} else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
   711  		call.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
   712  	} else {
   713  		call.To.Sym = c.ctxt.Lookup("runtime.morestack")
   714  	}
   715  	call.Mark |= BRANCH
   716  
   717  	// The instructions which unspill regs should be preemptible.
   718  	pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
   719  	unspill := c.cursym.Func().UnspillRegisterArgs(pcdata, c.newprog)
   720  
   721  	// JMP start
   722  	jmp := obj.Appendp(unspill, c.newprog)
   723  	jmp.As = AJMP
   724  	jmp.To.Type = obj.TYPE_BRANCH
   725  	jmp.To.SetTarget(startPred.Link)
   726  	jmp.Spadj = +framesize
   727  
   728  	return end
   729  }
   730  
   731  var Linkloong64 = obj.LinkArch{
   732  	Arch:           sys.ArchLoong64,
   733  	Init:           buildop,
   734  	Preprocess:     preprocess,
   735  	Assemble:       span0,
   736  	Progedit:       progedit,
   737  	DWARFRegisters: LOONG64DWARFRegisters,
   738  }
   739  

View as plain text