github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/internal/obj/arm64/obj7.go (about)

     1  // cmd/7l/noop.c, cmd/7l/obj.c, cmd/ld/pass.c from Vita Nuova.
     2  // https://code.google.com/p/ken-cc/source/browse/
     3  //
     4  // 	Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
     5  // 	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  // 	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  // 	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  // 	Portions Copyright © 2004,2006 Bruce Ellis
     9  // 	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  // 	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  // 	Portions Copyright © 2009 The Go Authors. All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package arm64
    32  
    33  import (
    34  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/obj"
    35  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/objabi"
    36  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/src"
    37  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/sys"
    38  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/abi"
    39  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/buildcfg"
    40  	"log"
    41  	"math"
    42  )
    43  
    44  
    45  
    46  var zrReplace = map[obj.As]bool{
    47  	AMOVD:  true,
    48  	AMOVW:  true,
    49  	AMOVWU: true,
    50  	AMOVH:  true,
    51  	AMOVHU: true,
    52  	AMOVB:  true,
    53  	AMOVBU: true,
    54  	ASBC:   true,
    55  	ASBCW:  true,
    56  	ASBCS:  true,
    57  	ASBCSW: true,
    58  	AADC:   true,
    59  	AADCW:  true,
    60  	AADCS:  true,
    61  	AADCSW: true,
    62  	AFMOVD: true,
    63  	AFMOVS: true,
    64  	AMSR:   true,
    65  }
    66  
    67  func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
    68  	if c.ctxt.Flag_maymorestack != "" {
    69  		p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
    70  
    71  		
    72  		
    73  		const frameSize = 32
    74  		p = obj.Appendp(p, c.newprog)
    75  		p.As = AMOVD
    76  		p.From.Type = obj.TYPE_REG
    77  		p.From.Reg = REGLINK
    78  		p.To.Type = obj.TYPE_MEM
    79  		p.Scond = C_XPRE
    80  		p.To.Offset = -frameSize
    81  		p.To.Reg = REGSP
    82  		p.Spadj = frameSize
    83  
    84  		
    85  		p = obj.Appendp(p, c.newprog)
    86  		p.As = AMOVD
    87  		p.From.Type = obj.TYPE_REG
    88  		p.From.Reg = REGFP
    89  		p.To.Type = obj.TYPE_MEM
    90  		p.To.Reg = REGSP
    91  		p.To.Offset = -8
    92  
    93  		p = obj.Appendp(p, c.newprog)
    94  		p.As = ASUB
    95  		p.From.Type = obj.TYPE_CONST
    96  		p.From.Offset = 8
    97  		p.Reg = REGSP
    98  		p.To.Type = obj.TYPE_REG
    99  		p.To.Reg = REGFP
   100  
   101  		
   102  		
   103  		p = obj.Appendp(p, c.newprog)
   104  		p.As = AMOVD
   105  		p.From.Type = obj.TYPE_REG
   106  		p.From.Reg = REGCTXT
   107  		p.To.Type = obj.TYPE_MEM
   108  		p.To.Reg = REGSP
   109  		p.To.Offset = 8
   110  
   111  		
   112  		p = obj.Appendp(p, c.newprog)
   113  		p.As = ABL
   114  		p.To.Type = obj.TYPE_BRANCH
   115  		
   116  		p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
   117  
   118  		
   119  		p = obj.Appendp(p, c.newprog)
   120  		p.As = AMOVD
   121  		p.From.Type = obj.TYPE_MEM
   122  		p.From.Reg = REGSP
   123  		p.From.Offset = 8
   124  		p.To.Type = obj.TYPE_REG
   125  		p.To.Reg = REGCTXT
   126  
   127  		
   128  		p = obj.Appendp(p, c.newprog)
   129  		p.As = AMOVD
   130  		p.From.Type = obj.TYPE_MEM
   131  		p.From.Reg = REGSP
   132  		p.From.Offset = -8
   133  		p.To.Type = obj.TYPE_REG
   134  		p.To.Reg = REGFP
   135  
   136  		
   137  		p = obj.Appendp(p, c.newprog)
   138  		p.As = AMOVD
   139  		p.From.Type = obj.TYPE_MEM
   140  		p.Scond = C_XPOST
   141  		p.From.Offset = frameSize
   142  		p.From.Reg = REGSP
   143  		p.To.Type = obj.TYPE_REG
   144  		p.To.Reg = REGLINK
   145  		p.Spadj = -frameSize
   146  
   147  		p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
   148  	}
   149  
   150  	
   151  	startPred := p
   152  
   153  	
   154  	p = obj.Appendp(p, c.newprog)
   155  
   156  	p.As = AMOVD
   157  	p.From.Type = obj.TYPE_MEM
   158  	p.From.Reg = REGG
   159  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) 
   160  	if c.cursym.CFunc() {
   161  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) 
   162  	}
   163  	p.To.Type = obj.TYPE_REG
   164  	p.To.Reg = REGRT1
   165  
   166  	
   167  	
   168  	
   169  	
   170  	p = c.ctxt.StartUnsafePoint(p, c.newprog)
   171  
   172  	q := (*obj.Prog)(nil)
   173  	if framesize <= abi.StackSmall {
   174  		
   175  		
   176  
   177  		p = obj.Appendp(p, c.newprog)
   178  		p.As = ACMP
   179  		p.From.Type = obj.TYPE_REG
   180  		p.From.Reg = REGRT1
   181  		p.Reg = REGSP
   182  	} else if framesize <= abi.StackBig {
   183  		
   184  		
   185  		
   186  		p = obj.Appendp(p, c.newprog)
   187  
   188  		p.As = ASUB
   189  		p.From.Type = obj.TYPE_CONST
   190  		p.From.Offset = int64(framesize) - abi.StackSmall
   191  		p.Reg = REGSP
   192  		p.To.Type = obj.TYPE_REG
   193  		p.To.Reg = REGRT2
   194  
   195  		p = obj.Appendp(p, c.newprog)
   196  		p.As = ACMP
   197  		p.From.Type = obj.TYPE_REG
   198  		p.From.Reg = REGRT1
   199  		p.Reg = REGRT2
   200  	} else {
   201  		
   202  		
   203  		
   204  		
   205  		
   206  		
   207  		
   208  		
   209  		
   210  		
   211  		
   212  
   213  		p = obj.Appendp(p, c.newprog)
   214  		p.As = ASUBS
   215  		p.From.Type = obj.TYPE_CONST
   216  		p.From.Offset = int64(framesize) - abi.StackSmall
   217  		p.Reg = REGSP
   218  		p.To.Type = obj.TYPE_REG
   219  		p.To.Reg = REGRT2
   220  
   221  		p = obj.Appendp(p, c.newprog)
   222  		q = p
   223  		p.As = ABLO
   224  		p.To.Type = obj.TYPE_BRANCH
   225  
   226  		p = obj.Appendp(p, c.newprog)
   227  		p.As = ACMP
   228  		p.From.Type = obj.TYPE_REG
   229  		p.From.Reg = REGRT1
   230  		p.Reg = REGRT2
   231  	}
   232  
   233  	
   234  	bls := obj.Appendp(p, c.newprog)
   235  	bls.As = ABLS
   236  	bls.To.Type = obj.TYPE_BRANCH
   237  
   238  	end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
   239  
   240  	var last *obj.Prog
   241  	for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
   242  	}
   243  
   244  	
   245  	
   246  	
   247  	spfix := obj.Appendp(last, c.newprog)
   248  	spfix.As = obj.ANOP
   249  	spfix.Spadj = -framesize
   250  
   251  	pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
   252  	pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
   253  
   254  	if q != nil {
   255  		q.To.SetTarget(pcdata)
   256  	}
   257  	bls.To.SetTarget(pcdata)
   258  
   259  	spill := c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
   260  
   261  	
   262  	movlr := obj.Appendp(spill, c.newprog)
   263  	movlr.As = AMOVD
   264  	movlr.From.Type = obj.TYPE_REG
   265  	movlr.From.Reg = REGLINK
   266  	movlr.To.Type = obj.TYPE_REG
   267  	movlr.To.Reg = REG_R3
   268  
   269  	debug := movlr
   270  	if false {
   271  		debug = obj.Appendp(debug, c.newprog)
   272  		debug.As = AMOVD
   273  		debug.From.Type = obj.TYPE_CONST
   274  		debug.From.Offset = int64(framesize)
   275  		debug.To.Type = obj.TYPE_REG
   276  		debug.To.Reg = REGTMP
   277  	}
   278  
   279  	
   280  	call := obj.Appendp(debug, c.newprog)
   281  	call.As = ABL
   282  	call.To.Type = obj.TYPE_BRANCH
   283  	morestack := "runtime.morestack"
   284  	switch {
   285  	case c.cursym.CFunc():
   286  		morestack = "runtime.morestackc"
   287  	case !c.cursym.Func().Text.From.Sym.NeedCtxt():
   288  		morestack = "runtime.morestack_noctxt"
   289  	}
   290  	call.To.Sym = c.ctxt.Lookup(morestack)
   291  
   292  	unspill := c.cursym.Func().UnspillRegisterArgs(call, c.newprog)
   293  	pcdata = c.ctxt.EndUnsafePoint(unspill, c.newprog, -1)
   294  
   295  	
   296  	jmp := obj.Appendp(pcdata, c.newprog)
   297  	jmp.As = AB
   298  	jmp.To.Type = obj.TYPE_BRANCH
   299  	jmp.To.SetTarget(startPred.Link)
   300  	jmp.Spadj = +framesize
   301  
   302  	return end
   303  }
   304  
   305  func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
   306  	c := ctxt7{ctxt: ctxt, newprog: newprog}
   307  
   308  	p.From.Class = 0
   309  	p.To.Class = 0
   310  
   311  	
   312  	
   313  	
   314  	if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 && zrReplace[p.As] {
   315  		p.From.Type = obj.TYPE_REG
   316  		p.From.Reg = REGZERO
   317  	}
   318  
   319  	
   320  	switch p.As {
   321  	case AB,
   322  		ABL,
   323  		obj.ARET,
   324  		obj.ADUFFZERO,
   325  		obj.ADUFFCOPY:
   326  		if p.To.Sym != nil {
   327  			p.To.Type = obj.TYPE_BRANCH
   328  		}
   329  		break
   330  	}
   331  
   332  	
   333  	switch p.As {
   334  	case AFMOVS:
   335  		if p.From.Type == obj.TYPE_FCONST {
   336  			f64 := p.From.Val.(float64)
   337  			f32 := float32(f64)
   338  			if c.chipfloat7(f64) > 0 {
   339  				break
   340  			}
   341  			if math.Float32bits(f32) == 0 {
   342  				p.From.Type = obj.TYPE_REG
   343  				p.From.Reg = REGZERO
   344  				break
   345  			}
   346  			p.From.Type = obj.TYPE_MEM
   347  			p.From.Sym = c.ctxt.Float32Sym(f32)
   348  			p.From.Name = obj.NAME_EXTERN
   349  			p.From.Offset = 0
   350  		}
   351  
   352  	case AFMOVD:
   353  		if p.From.Type == obj.TYPE_FCONST {
   354  			f64 := p.From.Val.(float64)
   355  			if c.chipfloat7(f64) > 0 {
   356  				break
   357  			}
   358  			if math.Float64bits(f64) == 0 {
   359  				p.From.Type = obj.TYPE_REG
   360  				p.From.Reg = REGZERO
   361  				break
   362  			}
   363  			p.From.Type = obj.TYPE_MEM
   364  			p.From.Sym = c.ctxt.Float64Sym(f64)
   365  			p.From.Name = obj.NAME_EXTERN
   366  			p.From.Offset = 0
   367  		}
   368  
   369  		break
   370  	}
   371  
   372  	if c.ctxt.Flag_dynlink {
   373  		c.rewriteToUseGot(p)
   374  	}
   375  }
   376  
   377  
   378  func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
   379  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   380  		
   381  		
   382  		
   383  		
   384  		
   385  		var sym *obj.LSym
   386  		if p.As == obj.ADUFFZERO {
   387  			sym = c.ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
   388  		} else {
   389  			sym = c.ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
   390  		}
   391  		offset := p.To.Offset
   392  		p.As = AMOVD
   393  		p.From.Type = obj.TYPE_MEM
   394  		p.From.Name = obj.NAME_GOTREF
   395  		p.From.Sym = sym
   396  		p.To.Type = obj.TYPE_REG
   397  		p.To.Reg = REGTMP
   398  		p.To.Name = obj.NAME_NONE
   399  		p.To.Offset = 0
   400  		p.To.Sym = nil
   401  		p1 := obj.Appendp(p, c.newprog)
   402  		p1.As = AADD
   403  		p1.From.Type = obj.TYPE_CONST
   404  		p1.From.Offset = offset
   405  		p1.To.Type = obj.TYPE_REG
   406  		p1.To.Reg = REGTMP
   407  		p2 := obj.Appendp(p1, c.newprog)
   408  		p2.As = obj.ACALL
   409  		p2.To.Type = obj.TYPE_REG
   410  		p2.To.Reg = REGTMP
   411  	}
   412  
   413  	
   414  	
   415  	
   416  	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   417  		
   418  		
   419  		if p.As != AMOVD {
   420  			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
   421  		}
   422  		if p.To.Type != obj.TYPE_REG {
   423  			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
   424  		}
   425  		p.From.Type = obj.TYPE_MEM
   426  		p.From.Name = obj.NAME_GOTREF
   427  		if p.From.Offset != 0 {
   428  			q := obj.Appendp(p, c.newprog)
   429  			q.As = AADD
   430  			q.From.Type = obj.TYPE_CONST
   431  			q.From.Offset = p.From.Offset
   432  			q.To = p.To
   433  			p.From.Offset = 0
   434  		}
   435  	}
   436  	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
   437  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   438  	}
   439  	var source *obj.Addr
   440  	
   441  	
   442  	
   443  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   444  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   445  			c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
   446  		}
   447  		source = &p.From
   448  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   449  		source = &p.To
   450  	} else {
   451  		return
   452  	}
   453  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   454  		return
   455  	}
   456  	if source.Sym.Type == objabi.STLSBSS {
   457  		return
   458  	}
   459  	if source.Type != obj.TYPE_MEM {
   460  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   461  	}
   462  	p1 := obj.Appendp(p, c.newprog)
   463  	p2 := obj.Appendp(p1, c.newprog)
   464  	p1.As = AMOVD
   465  	p1.From.Type = obj.TYPE_MEM
   466  	p1.From.Sym = source.Sym
   467  	p1.From.Name = obj.NAME_GOTREF
   468  	p1.To.Type = obj.TYPE_REG
   469  	p1.To.Reg = REGTMP
   470  
   471  	p2.As = p.As
   472  	p2.From = p.From
   473  	p2.To = p.To
   474  	if p.From.Name == obj.NAME_EXTERN {
   475  		p2.From.Reg = REGTMP
   476  		p2.From.Name = obj.NAME_NONE
   477  		p2.From.Sym = nil
   478  	} else if p.To.Name == obj.NAME_EXTERN {
   479  		p2.To.Reg = REGTMP
   480  		p2.To.Name = obj.NAME_NONE
   481  		p2.To.Sym = nil
   482  	} else {
   483  		return
   484  	}
   485  	obj.Nopout(p)
   486  }
   487  
   488  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   489  	if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
   490  		return
   491  	}
   492  
   493  	c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym}
   494  
   495  	p := c.cursym.Func().Text
   496  	textstksiz := p.To.Offset
   497  	if textstksiz == -8 {
   498  		
   499  		p.From.Sym.Set(obj.AttrNoFrame, true)
   500  		textstksiz = 0
   501  	}
   502  	if textstksiz < 0 {
   503  		c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
   504  	}
   505  	if p.From.Sym.NoFrame() {
   506  		if textstksiz != 0 {
   507  			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
   508  		}
   509  	}
   510  
   511  	c.cursym.Func().Args = p.To.Val.(int32)
   512  	c.cursym.Func().Locals = int32(textstksiz)
   513  
   514  	
   515  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   516  		switch p.As {
   517  		case obj.ATEXT:
   518  			p.Mark |= LEAF
   519  
   520  		case ABL,
   521  			obj.ADUFFZERO,
   522  			obj.ADUFFCOPY:
   523  			c.cursym.Func().Text.Mark &^= LEAF
   524  		}
   525  	}
   526  
   527  	var q *obj.Prog
   528  	var q1 *obj.Prog
   529  	var retjmp *obj.LSym
   530  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   531  		o := p.As
   532  		switch o {
   533  		case obj.ATEXT:
   534  			c.cursym.Func().Text = p
   535  			c.autosize = int32(textstksiz)
   536  
   537  			if p.Mark&LEAF != 0 && c.autosize == 0 {
   538  				
   539  				p.From.Sym.Set(obj.AttrNoFrame, true)
   540  			}
   541  
   542  			if !p.From.Sym.NoFrame() {
   543  				
   544  				
   545  				c.autosize += 8
   546  			}
   547  
   548  			if c.autosize != 0 {
   549  				extrasize := int32(0)
   550  				if c.autosize%16 == 8 {
   551  					
   552  					extrasize = 8
   553  				} else if c.autosize&(16-1) == 0 {
   554  					
   555  					extrasize = 16
   556  				} else {
   557  					c.ctxt.Diag("%v: unaligned frame size %d - must be 16 aligned", p, c.autosize-8)
   558  				}
   559  				c.autosize += extrasize
   560  				c.cursym.Func().Locals += extrasize
   561  
   562  				
   563  				
   564  				p.To.Offset = int64(c.autosize) | int64(extrasize)<<32
   565  			} else {
   566  				
   567  				p.To.Offset = 0
   568  			}
   569  
   570  			if c.autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
   571  				if c.ctxt.Debugvlog {
   572  					c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func().Text.From.Sym.Name)
   573  				}
   574  				c.cursym.Func().Text.Mark |= LEAF
   575  			}
   576  
   577  			if cursym.Func().Text.Mark&LEAF != 0 {
   578  				cursym.Set(obj.AttrLeaf, true)
   579  				if p.From.Sym.NoFrame() {
   580  					break
   581  				}
   582  			}
   583  
   584  			if p.Mark&LEAF != 0 && c.autosize < abi.StackSmall {
   585  				
   586  				
   587  				p.From.Sym.Set(obj.AttrNoSplit, true)
   588  			}
   589  
   590  			if !p.From.Sym.NoSplit() {
   591  				p = c.stacksplit(p, c.autosize) 
   592  			}
   593  
   594  			var prologueEnd *obj.Prog
   595  
   596  			aoffset := c.autosize
   597  			if aoffset > 0xf0 {
   598  				
   599  				
   600  				aoffset = 0xf0
   601  			}
   602  
   603  			
   604  			
   605  			q = p
   606  			if c.autosize > aoffset {
   607  				
   608  				
   609  				
   610  				
   611  
   612  				
   613  				q1 = obj.Appendp(q, c.newprog)
   614  				q1.Pos = p.Pos
   615  				q1.As = ASUB
   616  				q1.From.Type = obj.TYPE_CONST
   617  				q1.From.Offset = int64(c.autosize)
   618  				q1.Reg = REGSP
   619  				q1.To.Type = obj.TYPE_REG
   620  				q1.To.Reg = REG_R20
   621  
   622  				prologueEnd = q1
   623  
   624  				
   625  				q1 = obj.Appendp(q1, c.newprog)
   626  				q1.Pos = p.Pos
   627  				q1.As = ASTP
   628  				q1.From.Type = obj.TYPE_REGREG
   629  				q1.From.Reg = REGFP
   630  				q1.From.Offset = REGLINK
   631  				q1.To.Type = obj.TYPE_MEM
   632  				q1.To.Reg = REG_R20
   633  				q1.To.Offset = -8
   634  
   635  				
   636  				
   637  				q1 = c.ctxt.StartUnsafePoint(q1, c.newprog)
   638  
   639  				
   640  				q1 = obj.Appendp(q1, c.newprog)
   641  				q1.Pos = p.Pos
   642  				q1.As = AMOVD
   643  				q1.From.Type = obj.TYPE_REG
   644  				q1.From.Reg = REG_R20
   645  				q1.To.Type = obj.TYPE_REG
   646  				q1.To.Reg = REGSP
   647  				q1.Spadj = c.autosize
   648  
   649  				q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1)
   650  
   651  				if buildcfg.GOOS == "ios" {
   652  					
   653  					
   654  					
   655  					
   656  					q1 = obj.Appendp(q1, c.newprog)
   657  					q1.Pos = p.Pos
   658  					q1.As = ASTP
   659  					q1.From.Type = obj.TYPE_REGREG
   660  					q1.From.Reg = REGFP
   661  					q1.From.Offset = REGLINK
   662  					q1.To.Type = obj.TYPE_MEM
   663  					q1.To.Reg = REGSP
   664  					q1.To.Offset = -8
   665  				}
   666  			} else {
   667  				
   668  				
   669  				
   670  				
   671  				
   672  				
   673  				
   674  				
   675  				
   676  				q1 = obj.Appendp(q, c.newprog)
   677  				q1.As = AMOVD
   678  				q1.Pos = p.Pos
   679  				q1.From.Type = obj.TYPE_REG
   680  				q1.From.Reg = REGLINK
   681  				q1.To.Type = obj.TYPE_MEM
   682  				q1.Scond = C_XPRE
   683  				q1.To.Offset = int64(-aoffset)
   684  				q1.To.Reg = REGSP
   685  				q1.Spadj = aoffset
   686  
   687  				prologueEnd = q1
   688  
   689  				
   690  				q1 = obj.Appendp(q1, c.newprog)
   691  				q1.Pos = p.Pos
   692  				q1.As = AMOVD
   693  				q1.From.Type = obj.TYPE_REG
   694  				q1.From.Reg = REGFP
   695  				q1.To.Type = obj.TYPE_MEM
   696  				q1.To.Reg = REGSP
   697  				q1.To.Offset = -8
   698  			}
   699  
   700  			prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
   701  
   702  			q1 = obj.Appendp(q1, c.newprog)
   703  			q1.Pos = p.Pos
   704  			q1.As = ASUB
   705  			q1.From.Type = obj.TYPE_CONST
   706  			q1.From.Offset = 8
   707  			q1.Reg = REGSP
   708  			q1.To.Type = obj.TYPE_REG
   709  			q1.To.Reg = REGFP
   710  
   711  			if c.cursym.Func().Text.From.Sym.Wrapper() {
   712  				
   713  				
   714  				
   715  				
   716  				
   717  				
   718  				
   719  				
   720  				
   721  				
   722  				
   723  				
   724  				
   725  				
   726  				
   727  				
   728  				
   729  				
   730  				q = q1
   731  
   732  				
   733  				q = obj.Appendp(q, c.newprog)
   734  				q.As = AMOVD
   735  				q.From.Type = obj.TYPE_MEM
   736  				q.From.Reg = REGG
   737  				q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) 
   738  				q.To.Type = obj.TYPE_REG
   739  				q.To.Reg = REGRT1
   740  
   741  				
   742  				cbnz := obj.Appendp(q, c.newprog)
   743  				cbnz.As = ACBNZ
   744  				cbnz.From.Type = obj.TYPE_REG
   745  				cbnz.From.Reg = REGRT1
   746  				cbnz.To.Type = obj.TYPE_BRANCH
   747  
   748  				
   749  				end := obj.Appendp(cbnz, c.newprog)
   750  				end.As = obj.ANOP
   751  
   752  				
   753  				var last *obj.Prog
   754  				for last = end; last.Link != nil; last = last.Link {
   755  				}
   756  
   757  				
   758  				mov := obj.Appendp(last, c.newprog)
   759  				mov.As = AMOVD
   760  				mov.From.Type = obj.TYPE_MEM
   761  				mov.From.Reg = REGRT1
   762  				mov.From.Offset = 0 
   763  				mov.To.Type = obj.TYPE_REG
   764  				mov.To.Reg = REGRT2
   765  
   766  				
   767  				cbnz.To.SetTarget(mov)
   768  
   769  				
   770  				q = obj.Appendp(mov, c.newprog)
   771  				q.As = AADD
   772  				q.From.Type = obj.TYPE_CONST
   773  				q.From.Offset = int64(c.autosize) + 8
   774  				q.Reg = REGSP
   775  				q.To.Type = obj.TYPE_REG
   776  				q.To.Reg = REG_R20
   777  
   778  				
   779  				q = obj.Appendp(q, c.newprog)
   780  				q.As = ACMP
   781  				q.From.Type = obj.TYPE_REG
   782  				q.From.Reg = REGRT2
   783  				q.Reg = REG_R20
   784  
   785  				
   786  				q = obj.Appendp(q, c.newprog)
   787  				q.As = ABNE
   788  				q.To.Type = obj.TYPE_BRANCH
   789  				q.To.SetTarget(end)
   790  
   791  				
   792  				q = obj.Appendp(q, c.newprog)
   793  				q.As = AADD
   794  				q.From.Type = obj.TYPE_CONST
   795  				q.From.Offset = 8
   796  				q.Reg = REGSP
   797  				q.To.Type = obj.TYPE_REG
   798  				q.To.Reg = REG_R20
   799  
   800  				
   801  				q = obj.Appendp(q, c.newprog)
   802  				q.As = AMOVD
   803  				q.From.Type = obj.TYPE_REG
   804  				q.From.Reg = REG_R20
   805  				q.To.Type = obj.TYPE_MEM
   806  				q.To.Reg = REGRT1
   807  				q.To.Offset = 0 
   808  
   809  				
   810  				q = obj.Appendp(q, c.newprog)
   811  				q.As = AB
   812  				q.To.Type = obj.TYPE_BRANCH
   813  				q.To.SetTarget(end)
   814  			}
   815  
   816  		case obj.ARET:
   817  			nocache(p)
   818  			if p.From.Type == obj.TYPE_CONST {
   819  				c.ctxt.Diag("using BECOME (%v) is not supported!", p)
   820  				break
   821  			}
   822  
   823  			retjmp = p.To.Sym
   824  			p.To = obj.Addr{}
   825  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   826  				if c.autosize != 0 {
   827  					p.As = AADD
   828  					p.From.Type = obj.TYPE_CONST
   829  					p.From.Offset = int64(c.autosize)
   830  					p.To.Type = obj.TYPE_REG
   831  					p.To.Reg = REGSP
   832  					p.Spadj = -c.autosize
   833  
   834  					
   835  					p = obj.Appendp(p, c.newprog)
   836  					p.As = ASUB
   837  					p.From.Type = obj.TYPE_CONST
   838  					p.From.Offset = 8
   839  					p.Reg = REGSP
   840  					p.To.Type = obj.TYPE_REG
   841  					p.To.Reg = REGFP
   842  				}
   843  			} else {
   844  				aoffset := c.autosize
   845  				
   846  				p.As = ALDP
   847  				p.From.Type = obj.TYPE_MEM
   848  				p.From.Offset = -8
   849  				p.From.Reg = REGSP
   850  				p.To.Type = obj.TYPE_REGREG
   851  				p.To.Reg = REGFP
   852  				p.To.Offset = REGLINK
   853  
   854  				
   855  				q = newprog()
   856  				q.As = AADD
   857  				q.From.Type = obj.TYPE_CONST
   858  				q.From.Offset = int64(aoffset)
   859  				q.To.Type = obj.TYPE_REG
   860  				q.To.Reg = REGSP
   861  				q.Spadj = -aoffset
   862  				q.Pos = p.Pos
   863  				q.Link = p.Link
   864  				p.Link = q
   865  				p = q
   866  			}
   867  
   868  			
   869  			
   870  			
   871  			
   872  			
   873  			const debugRETZERO = false
   874  			if debugRETZERO {
   875  				if p.As != obj.ARET {
   876  					q = newprog()
   877  					q.Pos = p.Pos
   878  					q.Link = p.Link
   879  					p.Link = q
   880  					p = q
   881  				}
   882  				p.As = AADR
   883  				p.From.Type = obj.TYPE_BRANCH
   884  				p.From.Offset = 0
   885  				p.To.Type = obj.TYPE_REG
   886  				p.To.Reg = REGTMP
   887  
   888  			}
   889  
   890  			if p.As != obj.ARET {
   891  				q = newprog()
   892  				q.Pos = p.Pos
   893  				q.Link = p.Link
   894  				p.Link = q
   895  				p = q
   896  			}
   897  
   898  			if retjmp != nil { 
   899  				p.As = AB
   900  				p.To.Type = obj.TYPE_BRANCH
   901  				p.To.Sym = retjmp
   902  				p.Spadj = +c.autosize
   903  				break
   904  			}
   905  
   906  			p.As = obj.ARET
   907  			p.To.Type = obj.TYPE_MEM
   908  			p.To.Offset = 0
   909  			p.To.Reg = REGLINK
   910  			p.Spadj = +c.autosize
   911  
   912  		case AADD, ASUB:
   913  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   914  				if p.As == AADD {
   915  					p.Spadj = int32(-p.From.Offset)
   916  				} else {
   917  					p.Spadj = int32(+p.From.Offset)
   918  				}
   919  			}
   920  
   921  		case obj.AGETCALLERPC:
   922  			if cursym.Leaf() {
   923  				
   924  				p.As = AMOVD
   925  				p.From.Type = obj.TYPE_REG
   926  				p.From.Reg = REGLINK
   927  			} else {
   928  				
   929  				p.As = AMOVD
   930  				p.From.Type = obj.TYPE_MEM
   931  				p.From.Reg = REGSP
   932  			}
   933  
   934  		case obj.ADUFFCOPY:
   935  			
   936  			
   937  			
   938  			
   939  			
   940  			
   941  
   942  			q1 := p
   943  			
   944  			q4 := obj.Appendp(p, c.newprog)
   945  			q4.Pos = p.Pos
   946  			q4.As = obj.ADUFFCOPY
   947  			q4.To = p.To
   948  
   949  			q1.As = AADR
   950  			q1.From.Type = obj.TYPE_BRANCH
   951  			q1.To.Type = obj.TYPE_REG
   952  			q1.To.Reg = REG_R27
   953  
   954  			q2 := obj.Appendp(q1, c.newprog)
   955  			q2.Pos = p.Pos
   956  			q2.As = ASTP
   957  			q2.From.Type = obj.TYPE_REGREG
   958  			q2.From.Reg = REGFP
   959  			q2.From.Offset = int64(REG_R27)
   960  			q2.To.Type = obj.TYPE_MEM
   961  			q2.To.Reg = REGSP
   962  			q2.To.Offset = -24
   963  
   964  			
   965  			q3 := obj.Appendp(q2, c.newprog)
   966  			q3.Pos = p.Pos
   967  			q3.As = ASUB
   968  			q3.From.Type = obj.TYPE_CONST
   969  			q3.From.Offset = 24
   970  			q3.Reg = REGSP
   971  			q3.To.Type = obj.TYPE_REG
   972  			q3.To.Reg = REGFP
   973  
   974  			q5 := obj.Appendp(q4, c.newprog)
   975  			q5.Pos = p.Pos
   976  			q5.As = ASUB
   977  			q5.From.Type = obj.TYPE_CONST
   978  			q5.From.Offset = 8
   979  			q5.Reg = REGSP
   980  			q5.To.Type = obj.TYPE_REG
   981  			q5.To.Reg = REGFP
   982  			q1.From.SetTarget(q5)
   983  			p = q5
   984  
   985  		case obj.ADUFFZERO:
   986  			
   987  			
   988  			
   989  			
   990  			
   991  			
   992  
   993  			q1 := p
   994  			
   995  			q4 := obj.Appendp(p, c.newprog)
   996  			q4.Pos = p.Pos
   997  			q4.As = obj.ADUFFZERO
   998  			q4.To = p.To
   999  
  1000  			q1.As = AADR
  1001  			q1.From.Type = obj.TYPE_BRANCH
  1002  			q1.To.Type = obj.TYPE_REG
  1003  			q1.To.Reg = REG_R27
  1004  
  1005  			q2 := obj.Appendp(q1, c.newprog)
  1006  			q2.Pos = p.Pos
  1007  			q2.As = ASTP
  1008  			q2.From.Type = obj.TYPE_REGREG
  1009  			q2.From.Reg = REGFP
  1010  			q2.From.Offset = int64(REG_R27)
  1011  			q2.To.Type = obj.TYPE_MEM
  1012  			q2.To.Reg = REGSP
  1013  			q2.To.Offset = -24
  1014  
  1015  			
  1016  			q3 := obj.Appendp(q2, c.newprog)
  1017  			q3.Pos = p.Pos
  1018  			q3.As = ASUB
  1019  			q3.From.Type = obj.TYPE_CONST
  1020  			q3.From.Offset = 24
  1021  			q3.Reg = REGSP
  1022  			q3.To.Type = obj.TYPE_REG
  1023  			q3.To.Reg = REGFP
  1024  
  1025  			q5 := obj.Appendp(q4, c.newprog)
  1026  			q5.Pos = p.Pos
  1027  			q5.As = ASUB
  1028  			q5.From.Type = obj.TYPE_CONST
  1029  			q5.From.Offset = 8
  1030  			q5.Reg = REGSP
  1031  			q5.To.Type = obj.TYPE_REG
  1032  			q5.To.Reg = REGFP
  1033  			q1.From.SetTarget(q5)
  1034  			p = q5
  1035  		}
  1036  
  1037  		if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
  1038  			f := c.cursym.Func()
  1039  			if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
  1040  				c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
  1041  				if ctxt.Debugvlog || !ctxt.IsAsm {
  1042  					ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
  1043  					if !ctxt.IsAsm {
  1044  						ctxt.Diag("invalid auto-SPWRITE in non-assembly")
  1045  						ctxt.DiagFlush()
  1046  						log.Fatalf("bad SPWRITE")
  1047  					}
  1048  				}
  1049  			}
  1050  		}
  1051  		if p.From.Type == obj.TYPE_SHIFT && (p.To.Reg == REG_RSP || p.Reg == REG_RSP) {
  1052  			offset := p.From.Offset
  1053  			op := offset & (3 << 22)
  1054  			if op != SHIFT_LL {
  1055  				ctxt.Diag("illegal combination: %v", p)
  1056  			}
  1057  			r := (offset >> 16) & 31
  1058  			shift := (offset >> 10) & 63
  1059  			if shift > 4 {
  1060  				
  1061  				
  1062  				
  1063  				shift = 7
  1064  			}
  1065  			p.From.Type = obj.TYPE_REG
  1066  			p.From.Reg = int16(REG_LSL + r + (shift&7)<<5)
  1067  			p.From.Offset = 0
  1068  		}
  1069  	}
  1070  }
  1071  
  1072  func nocache(p *obj.Prog) {
  1073  	p.Optab = 0
  1074  	p.From.Class = 0
  1075  	p.To.Class = 0
  1076  }
  1077  
  1078  var unaryDst = map[obj.As]bool{
  1079  	AWORD:  true,
  1080  	ADWORD: true,
  1081  	ABL:    true,
  1082  	AB:     true,
  1083  	ACLREX: true,
  1084  }
  1085  
  1086  var Linkarm64 = obj.LinkArch{
  1087  	Arch:           sys.ArchARM64,
  1088  	Init:           buildop,
  1089  	Preprocess:     preprocess,
  1090  	Assemble:       span7,
  1091  	Progedit:       progedit,
  1092  	UnaryDst:       unaryDst,
  1093  	DWARFRegisters: ARM64DWARFRegisters,
  1094  }