github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/arm64/ssa.go (about)

     1  // Copyright 2016 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 arm64
     6  
     7  import (
     8  	"math"
     9  
    10  	"github.com/go-asm/go/cmd/compile/base"
    11  	"github.com/go-asm/go/cmd/compile/ir"
    12  	"github.com/go-asm/go/cmd/compile/logopt"
    13  	"github.com/go-asm/go/cmd/compile/objw"
    14  	"github.com/go-asm/go/cmd/compile/ssa"
    15  	"github.com/go-asm/go/cmd/compile/ssagen"
    16  	"github.com/go-asm/go/cmd/compile/types"
    17  	"github.com/go-asm/go/cmd/obj"
    18  	"github.com/go-asm/go/cmd/obj/arm64"
    19  )
    20  
    21  // loadByType returns the load instruction of the given type.
    22  func loadByType(t *types.Type) obj.As {
    23  	if t.IsFloat() {
    24  		switch t.Size() {
    25  		case 4:
    26  			return arm64.AFMOVS
    27  		case 8:
    28  			return arm64.AFMOVD
    29  		}
    30  	} else {
    31  		switch t.Size() {
    32  		case 1:
    33  			if t.IsSigned() {
    34  				return arm64.AMOVB
    35  			} else {
    36  				return arm64.AMOVBU
    37  			}
    38  		case 2:
    39  			if t.IsSigned() {
    40  				return arm64.AMOVH
    41  			} else {
    42  				return arm64.AMOVHU
    43  			}
    44  		case 4:
    45  			if t.IsSigned() {
    46  				return arm64.AMOVW
    47  			} else {
    48  				return arm64.AMOVWU
    49  			}
    50  		case 8:
    51  			return arm64.AMOVD
    52  		}
    53  	}
    54  	panic("bad load type")
    55  }
    56  
    57  // storeByType returns the store instruction of the given type.
    58  func storeByType(t *types.Type) obj.As {
    59  	if t.IsFloat() {
    60  		switch t.Size() {
    61  		case 4:
    62  			return arm64.AFMOVS
    63  		case 8:
    64  			return arm64.AFMOVD
    65  		}
    66  	} else {
    67  		switch t.Size() {
    68  		case 1:
    69  			return arm64.AMOVB
    70  		case 2:
    71  			return arm64.AMOVH
    72  		case 4:
    73  			return arm64.AMOVW
    74  		case 8:
    75  			return arm64.AMOVD
    76  		}
    77  	}
    78  	panic("bad store type")
    79  }
    80  
    81  // makeshift encodes a register shifted by a constant, used as an Offset in Prog.
    82  func makeshift(v *ssa.Value, reg int16, typ int64, s int64) int64 {
    83  	if s < 0 || s >= 64 {
    84  		v.Fatalf("shift out of range: %d", s)
    85  	}
    86  	return int64(reg&31)<<16 | typ | (s&63)<<10
    87  }
    88  
    89  // genshift generates a Prog for r = r0 op (r1 shifted by n).
    90  func genshift(s *ssagen.State, v *ssa.Value, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
    91  	p := s.Prog(as)
    92  	p.From.Type = obj.TYPE_SHIFT
    93  	p.From.Offset = makeshift(v, r1, typ, n)
    94  	p.Reg = r0
    95  	if r != 0 {
    96  		p.To.Type = obj.TYPE_REG
    97  		p.To.Reg = r
    98  	}
    99  	return p
   100  }
   101  
   102  // generate the memory operand for the indexed load/store instructions.
   103  // base and idx are registers.
   104  func genIndexedOperand(op ssa.Op, base, idx int16) obj.Addr {
   105  	// Reg: base register, Index: (shifted) index register
   106  	mop := obj.Addr{Type: obj.TYPE_MEM, Reg: base}
   107  	switch op {
   108  	case ssa.OpARM64MOVDloadidx8, ssa.OpARM64MOVDstoreidx8, ssa.OpARM64MOVDstorezeroidx8,
   109  		ssa.OpARM64FMOVDloadidx8, ssa.OpARM64FMOVDstoreidx8:
   110  		mop.Index = arm64.REG_LSL | 3<<5 | idx&31
   111  	case ssa.OpARM64MOVWloadidx4, ssa.OpARM64MOVWUloadidx4, ssa.OpARM64MOVWstoreidx4, ssa.OpARM64MOVWstorezeroidx4,
   112  		ssa.OpARM64FMOVSloadidx4, ssa.OpARM64FMOVSstoreidx4:
   113  		mop.Index = arm64.REG_LSL | 2<<5 | idx&31
   114  	case ssa.OpARM64MOVHloadidx2, ssa.OpARM64MOVHUloadidx2, ssa.OpARM64MOVHstoreidx2, ssa.OpARM64MOVHstorezeroidx2:
   115  		mop.Index = arm64.REG_LSL | 1<<5 | idx&31
   116  	default: // not shifted
   117  		mop.Index = idx
   118  	}
   119  	return mop
   120  }
   121  
   122  func ssaGenValue(s *ssagen.State, v *ssa.Value) {
   123  	switch v.Op {
   124  	case ssa.OpCopy, ssa.OpARM64MOVDreg:
   125  		if v.Type.IsMemory() {
   126  			return
   127  		}
   128  		x := v.Args[0].Reg()
   129  		y := v.Reg()
   130  		if x == y {
   131  			return
   132  		}
   133  		as := arm64.AMOVD
   134  		if v.Type.IsFloat() {
   135  			switch v.Type.Size() {
   136  			case 4:
   137  				as = arm64.AFMOVS
   138  			case 8:
   139  				as = arm64.AFMOVD
   140  			default:
   141  				panic("bad float size")
   142  			}
   143  		}
   144  		p := s.Prog(as)
   145  		p.From.Type = obj.TYPE_REG
   146  		p.From.Reg = x
   147  		p.To.Type = obj.TYPE_REG
   148  		p.To.Reg = y
   149  	case ssa.OpARM64MOVDnop:
   150  		// nothing to do
   151  	case ssa.OpLoadReg:
   152  		if v.Type.IsFlags() {
   153  			v.Fatalf("load flags not implemented: %v", v.LongString())
   154  			return
   155  		}
   156  		p := s.Prog(loadByType(v.Type))
   157  		ssagen.AddrAuto(&p.From, v.Args[0])
   158  		p.To.Type = obj.TYPE_REG
   159  		p.To.Reg = v.Reg()
   160  	case ssa.OpStoreReg:
   161  		if v.Type.IsFlags() {
   162  			v.Fatalf("store flags not implemented: %v", v.LongString())
   163  			return
   164  		}
   165  		p := s.Prog(storeByType(v.Type))
   166  		p.From.Type = obj.TYPE_REG
   167  		p.From.Reg = v.Args[0].Reg()
   168  		ssagen.AddrAuto(&p.To, v)
   169  	case ssa.OpArgIntReg, ssa.OpArgFloatReg:
   170  		// The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill
   171  		// The loop only runs once.
   172  		for _, a := range v.Block.Func.RegArgs {
   173  			// Pass the spill/unspill information along to the assembler, offset by size of
   174  			// the saved LR slot.
   175  			addr := ssagen.SpillSlotAddr(a, arm64.REGSP, base.Ctxt.Arch.FixedFrameSize)
   176  			s.FuncInfo().AddSpill(
   177  				obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)})
   178  		}
   179  		v.Block.Func.RegArgs = nil
   180  		ssagen.CheckArgReg(v)
   181  	case ssa.OpARM64ADD,
   182  		ssa.OpARM64SUB,
   183  		ssa.OpARM64AND,
   184  		ssa.OpARM64OR,
   185  		ssa.OpARM64XOR,
   186  		ssa.OpARM64BIC,
   187  		ssa.OpARM64EON,
   188  		ssa.OpARM64ORN,
   189  		ssa.OpARM64MUL,
   190  		ssa.OpARM64MULW,
   191  		ssa.OpARM64MNEG,
   192  		ssa.OpARM64MNEGW,
   193  		ssa.OpARM64MULH,
   194  		ssa.OpARM64UMULH,
   195  		ssa.OpARM64MULL,
   196  		ssa.OpARM64UMULL,
   197  		ssa.OpARM64DIV,
   198  		ssa.OpARM64UDIV,
   199  		ssa.OpARM64DIVW,
   200  		ssa.OpARM64UDIVW,
   201  		ssa.OpARM64MOD,
   202  		ssa.OpARM64UMOD,
   203  		ssa.OpARM64MODW,
   204  		ssa.OpARM64UMODW,
   205  		ssa.OpARM64SLL,
   206  		ssa.OpARM64SRL,
   207  		ssa.OpARM64SRA,
   208  		ssa.OpARM64FADDS,
   209  		ssa.OpARM64FADDD,
   210  		ssa.OpARM64FSUBS,
   211  		ssa.OpARM64FSUBD,
   212  		ssa.OpARM64FMULS,
   213  		ssa.OpARM64FMULD,
   214  		ssa.OpARM64FNMULS,
   215  		ssa.OpARM64FNMULD,
   216  		ssa.OpARM64FDIVS,
   217  		ssa.OpARM64FDIVD,
   218  		ssa.OpARM64FMINS,
   219  		ssa.OpARM64FMIND,
   220  		ssa.OpARM64FMAXS,
   221  		ssa.OpARM64FMAXD,
   222  		ssa.OpARM64ROR,
   223  		ssa.OpARM64RORW:
   224  		r := v.Reg()
   225  		r1 := v.Args[0].Reg()
   226  		r2 := v.Args[1].Reg()
   227  		p := s.Prog(v.Op.Asm())
   228  		p.From.Type = obj.TYPE_REG
   229  		p.From.Reg = r2
   230  		p.Reg = r1
   231  		p.To.Type = obj.TYPE_REG
   232  		p.To.Reg = r
   233  	case ssa.OpARM64FMADDS,
   234  		ssa.OpARM64FMADDD,
   235  		ssa.OpARM64FNMADDS,
   236  		ssa.OpARM64FNMADDD,
   237  		ssa.OpARM64FMSUBS,
   238  		ssa.OpARM64FMSUBD,
   239  		ssa.OpARM64FNMSUBS,
   240  		ssa.OpARM64FNMSUBD,
   241  		ssa.OpARM64MADD,
   242  		ssa.OpARM64MADDW,
   243  		ssa.OpARM64MSUB,
   244  		ssa.OpARM64MSUBW:
   245  		rt := v.Reg()
   246  		ra := v.Args[0].Reg()
   247  		rm := v.Args[1].Reg()
   248  		rn := v.Args[2].Reg()
   249  		p := s.Prog(v.Op.Asm())
   250  		p.Reg = ra
   251  		p.From.Type = obj.TYPE_REG
   252  		p.From.Reg = rm
   253  		p.AddRestSourceReg(rn)
   254  		p.To.Type = obj.TYPE_REG
   255  		p.To.Reg = rt
   256  	case ssa.OpARM64ADDconst,
   257  		ssa.OpARM64SUBconst,
   258  		ssa.OpARM64ANDconst,
   259  		ssa.OpARM64ORconst,
   260  		ssa.OpARM64XORconst,
   261  		ssa.OpARM64SLLconst,
   262  		ssa.OpARM64SRLconst,
   263  		ssa.OpARM64SRAconst,
   264  		ssa.OpARM64RORconst,
   265  		ssa.OpARM64RORWconst:
   266  		p := s.Prog(v.Op.Asm())
   267  		p.From.Type = obj.TYPE_CONST
   268  		p.From.Offset = v.AuxInt
   269  		p.Reg = v.Args[0].Reg()
   270  		p.To.Type = obj.TYPE_REG
   271  		p.To.Reg = v.Reg()
   272  	case ssa.OpARM64ADDSconstflags:
   273  		p := s.Prog(v.Op.Asm())
   274  		p.From.Type = obj.TYPE_CONST
   275  		p.From.Offset = v.AuxInt
   276  		p.Reg = v.Args[0].Reg()
   277  		p.To.Type = obj.TYPE_REG
   278  		p.To.Reg = v.Reg0()
   279  	case ssa.OpARM64ADCzerocarry:
   280  		p := s.Prog(v.Op.Asm())
   281  		p.From.Type = obj.TYPE_REG
   282  		p.From.Reg = arm64.REGZERO
   283  		p.Reg = arm64.REGZERO
   284  		p.To.Type = obj.TYPE_REG
   285  		p.To.Reg = v.Reg()
   286  	case ssa.OpARM64ADCSflags,
   287  		ssa.OpARM64ADDSflags,
   288  		ssa.OpARM64SBCSflags,
   289  		ssa.OpARM64SUBSflags:
   290  		r := v.Reg0()
   291  		r1 := v.Args[0].Reg()
   292  		r2 := v.Args[1].Reg()
   293  		p := s.Prog(v.Op.Asm())
   294  		p.From.Type = obj.TYPE_REG
   295  		p.From.Reg = r2
   296  		p.Reg = r1
   297  		p.To.Type = obj.TYPE_REG
   298  		p.To.Reg = r
   299  	case ssa.OpARM64NEGSflags:
   300  		p := s.Prog(v.Op.Asm())
   301  		p.From.Type = obj.TYPE_REG
   302  		p.From.Reg = v.Args[0].Reg()
   303  		p.To.Type = obj.TYPE_REG
   304  		p.To.Reg = v.Reg0()
   305  	case ssa.OpARM64NGCzerocarry:
   306  		p := s.Prog(v.Op.Asm())
   307  		p.From.Type = obj.TYPE_REG
   308  		p.From.Reg = arm64.REGZERO
   309  		p.To.Type = obj.TYPE_REG
   310  		p.To.Reg = v.Reg()
   311  	case ssa.OpARM64EXTRconst,
   312  		ssa.OpARM64EXTRWconst:
   313  		p := s.Prog(v.Op.Asm())
   314  		p.From.Type = obj.TYPE_CONST
   315  		p.From.Offset = v.AuxInt
   316  		p.AddRestSourceReg(v.Args[0].Reg())
   317  		p.Reg = v.Args[1].Reg()
   318  		p.To.Type = obj.TYPE_REG
   319  		p.To.Reg = v.Reg()
   320  	case ssa.OpARM64MVNshiftLL, ssa.OpARM64NEGshiftLL:
   321  		genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
   322  	case ssa.OpARM64MVNshiftRL, ssa.OpARM64NEGshiftRL:
   323  		genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
   324  	case ssa.OpARM64MVNshiftRA, ssa.OpARM64NEGshiftRA:
   325  		genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
   326  	case ssa.OpARM64MVNshiftRO:
   327  		genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_ROR, v.AuxInt)
   328  	case ssa.OpARM64ADDshiftLL,
   329  		ssa.OpARM64SUBshiftLL,
   330  		ssa.OpARM64ANDshiftLL,
   331  		ssa.OpARM64ORshiftLL,
   332  		ssa.OpARM64XORshiftLL,
   333  		ssa.OpARM64EONshiftLL,
   334  		ssa.OpARM64ORNshiftLL,
   335  		ssa.OpARM64BICshiftLL:
   336  		genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
   337  	case ssa.OpARM64ADDshiftRL,
   338  		ssa.OpARM64SUBshiftRL,
   339  		ssa.OpARM64ANDshiftRL,
   340  		ssa.OpARM64ORshiftRL,
   341  		ssa.OpARM64XORshiftRL,
   342  		ssa.OpARM64EONshiftRL,
   343  		ssa.OpARM64ORNshiftRL,
   344  		ssa.OpARM64BICshiftRL:
   345  		genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
   346  	case ssa.OpARM64ADDshiftRA,
   347  		ssa.OpARM64SUBshiftRA,
   348  		ssa.OpARM64ANDshiftRA,
   349  		ssa.OpARM64ORshiftRA,
   350  		ssa.OpARM64XORshiftRA,
   351  		ssa.OpARM64EONshiftRA,
   352  		ssa.OpARM64ORNshiftRA,
   353  		ssa.OpARM64BICshiftRA:
   354  		genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
   355  	case ssa.OpARM64ANDshiftRO,
   356  		ssa.OpARM64ORshiftRO,
   357  		ssa.OpARM64XORshiftRO,
   358  		ssa.OpARM64EONshiftRO,
   359  		ssa.OpARM64ORNshiftRO,
   360  		ssa.OpARM64BICshiftRO:
   361  		genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_ROR, v.AuxInt)
   362  	case ssa.OpARM64MOVDconst:
   363  		p := s.Prog(v.Op.Asm())
   364  		p.From.Type = obj.TYPE_CONST
   365  		p.From.Offset = v.AuxInt
   366  		p.To.Type = obj.TYPE_REG
   367  		p.To.Reg = v.Reg()
   368  	case ssa.OpARM64FMOVSconst,
   369  		ssa.OpARM64FMOVDconst:
   370  		p := s.Prog(v.Op.Asm())
   371  		p.From.Type = obj.TYPE_FCONST
   372  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   373  		p.To.Type = obj.TYPE_REG
   374  		p.To.Reg = v.Reg()
   375  	case ssa.OpARM64FCMPS0,
   376  		ssa.OpARM64FCMPD0:
   377  		p := s.Prog(v.Op.Asm())
   378  		p.From.Type = obj.TYPE_FCONST
   379  		p.From.Val = math.Float64frombits(0)
   380  		p.Reg = v.Args[0].Reg()
   381  	case ssa.OpARM64CMP,
   382  		ssa.OpARM64CMPW,
   383  		ssa.OpARM64CMN,
   384  		ssa.OpARM64CMNW,
   385  		ssa.OpARM64TST,
   386  		ssa.OpARM64TSTW,
   387  		ssa.OpARM64FCMPS,
   388  		ssa.OpARM64FCMPD:
   389  		p := s.Prog(v.Op.Asm())
   390  		p.From.Type = obj.TYPE_REG
   391  		p.From.Reg = v.Args[1].Reg()
   392  		p.Reg = v.Args[0].Reg()
   393  	case ssa.OpARM64CMPconst,
   394  		ssa.OpARM64CMPWconst,
   395  		ssa.OpARM64CMNconst,
   396  		ssa.OpARM64CMNWconst,
   397  		ssa.OpARM64TSTconst,
   398  		ssa.OpARM64TSTWconst:
   399  		p := s.Prog(v.Op.Asm())
   400  		p.From.Type = obj.TYPE_CONST
   401  		p.From.Offset = v.AuxInt
   402  		p.Reg = v.Args[0].Reg()
   403  	case ssa.OpARM64CMPshiftLL, ssa.OpARM64CMNshiftLL, ssa.OpARM64TSTshiftLL:
   404  		genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LL, v.AuxInt)
   405  	case ssa.OpARM64CMPshiftRL, ssa.OpARM64CMNshiftRL, ssa.OpARM64TSTshiftRL:
   406  		genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LR, v.AuxInt)
   407  	case ssa.OpARM64CMPshiftRA, ssa.OpARM64CMNshiftRA, ssa.OpARM64TSTshiftRA:
   408  		genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_AR, v.AuxInt)
   409  	case ssa.OpARM64TSTshiftRO:
   410  		genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_ROR, v.AuxInt)
   411  	case ssa.OpARM64MOVDaddr:
   412  		p := s.Prog(arm64.AMOVD)
   413  		p.From.Type = obj.TYPE_ADDR
   414  		p.From.Reg = v.Args[0].Reg()
   415  		p.To.Type = obj.TYPE_REG
   416  		p.To.Reg = v.Reg()
   417  
   418  		var wantreg string
   419  		// MOVD $sym+off(base), R
   420  		// the assembler expands it as the following:
   421  		// - base is SP: add constant offset to SP (R13)
   422  		//               when constant is large, tmp register (R11) may be used
   423  		// - base is SB: load external address from constant pool (use relocation)
   424  		switch v.Aux.(type) {
   425  		default:
   426  			v.Fatalf("aux is of unknown type %T", v.Aux)
   427  		case *obj.LSym:
   428  			wantreg = "SB"
   429  			ssagen.AddAux(&p.From, v)
   430  		case *ir.Name:
   431  			wantreg = "SP"
   432  			ssagen.AddAux(&p.From, v)
   433  		case nil:
   434  			// No sym, just MOVD $off(SP), R
   435  			wantreg = "SP"
   436  			p.From.Offset = v.AuxInt
   437  		}
   438  		if reg := v.Args[0].RegName(); reg != wantreg {
   439  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   440  		}
   441  	case ssa.OpARM64MOVBload,
   442  		ssa.OpARM64MOVBUload,
   443  		ssa.OpARM64MOVHload,
   444  		ssa.OpARM64MOVHUload,
   445  		ssa.OpARM64MOVWload,
   446  		ssa.OpARM64MOVWUload,
   447  		ssa.OpARM64MOVDload,
   448  		ssa.OpARM64FMOVSload,
   449  		ssa.OpARM64FMOVDload:
   450  		p := s.Prog(v.Op.Asm())
   451  		p.From.Type = obj.TYPE_MEM
   452  		p.From.Reg = v.Args[0].Reg()
   453  		ssagen.AddAux(&p.From, v)
   454  		p.To.Type = obj.TYPE_REG
   455  		p.To.Reg = v.Reg()
   456  	case ssa.OpARM64LDP:
   457  		p := s.Prog(v.Op.Asm())
   458  		p.From.Type = obj.TYPE_MEM
   459  		p.From.Reg = v.Args[0].Reg()
   460  		ssagen.AddAux(&p.From, v)
   461  		p.To.Type = obj.TYPE_REGREG
   462  		p.To.Reg = v.Reg0()
   463  		p.To.Offset = int64(v.Reg1())
   464  	case ssa.OpARM64MOVBloadidx,
   465  		ssa.OpARM64MOVBUloadidx,
   466  		ssa.OpARM64MOVHloadidx,
   467  		ssa.OpARM64MOVHUloadidx,
   468  		ssa.OpARM64MOVWloadidx,
   469  		ssa.OpARM64MOVWUloadidx,
   470  		ssa.OpARM64MOVDloadidx,
   471  		ssa.OpARM64FMOVSloadidx,
   472  		ssa.OpARM64FMOVDloadidx,
   473  		ssa.OpARM64MOVHloadidx2,
   474  		ssa.OpARM64MOVHUloadidx2,
   475  		ssa.OpARM64MOVWloadidx4,
   476  		ssa.OpARM64MOVWUloadidx4,
   477  		ssa.OpARM64MOVDloadidx8,
   478  		ssa.OpARM64FMOVDloadidx8,
   479  		ssa.OpARM64FMOVSloadidx4:
   480  		p := s.Prog(v.Op.Asm())
   481  		p.From = genIndexedOperand(v.Op, v.Args[0].Reg(), v.Args[1].Reg())
   482  		p.To.Type = obj.TYPE_REG
   483  		p.To.Reg = v.Reg()
   484  	case ssa.OpARM64LDAR,
   485  		ssa.OpARM64LDARB,
   486  		ssa.OpARM64LDARW:
   487  		p := s.Prog(v.Op.Asm())
   488  		p.From.Type = obj.TYPE_MEM
   489  		p.From.Reg = v.Args[0].Reg()
   490  		ssagen.AddAux(&p.From, v)
   491  		p.To.Type = obj.TYPE_REG
   492  		p.To.Reg = v.Reg0()
   493  	case ssa.OpARM64MOVBstore,
   494  		ssa.OpARM64MOVHstore,
   495  		ssa.OpARM64MOVWstore,
   496  		ssa.OpARM64MOVDstore,
   497  		ssa.OpARM64FMOVSstore,
   498  		ssa.OpARM64FMOVDstore,
   499  		ssa.OpARM64STLRB,
   500  		ssa.OpARM64STLR,
   501  		ssa.OpARM64STLRW:
   502  		p := s.Prog(v.Op.Asm())
   503  		p.From.Type = obj.TYPE_REG
   504  		p.From.Reg = v.Args[1].Reg()
   505  		p.To.Type = obj.TYPE_MEM
   506  		p.To.Reg = v.Args[0].Reg()
   507  		ssagen.AddAux(&p.To, v)
   508  	case ssa.OpARM64MOVBstoreidx,
   509  		ssa.OpARM64MOVHstoreidx,
   510  		ssa.OpARM64MOVWstoreidx,
   511  		ssa.OpARM64MOVDstoreidx,
   512  		ssa.OpARM64FMOVSstoreidx,
   513  		ssa.OpARM64FMOVDstoreidx,
   514  		ssa.OpARM64MOVHstoreidx2,
   515  		ssa.OpARM64MOVWstoreidx4,
   516  		ssa.OpARM64FMOVSstoreidx4,
   517  		ssa.OpARM64MOVDstoreidx8,
   518  		ssa.OpARM64FMOVDstoreidx8:
   519  		p := s.Prog(v.Op.Asm())
   520  		p.To = genIndexedOperand(v.Op, v.Args[0].Reg(), v.Args[1].Reg())
   521  		p.From.Type = obj.TYPE_REG
   522  		p.From.Reg = v.Args[2].Reg()
   523  	case ssa.OpARM64STP:
   524  		p := s.Prog(v.Op.Asm())
   525  		p.From.Type = obj.TYPE_REGREG
   526  		p.From.Reg = v.Args[1].Reg()
   527  		p.From.Offset = int64(v.Args[2].Reg())
   528  		p.To.Type = obj.TYPE_MEM
   529  		p.To.Reg = v.Args[0].Reg()
   530  		ssagen.AddAux(&p.To, v)
   531  	case ssa.OpARM64MOVBstorezero,
   532  		ssa.OpARM64MOVHstorezero,
   533  		ssa.OpARM64MOVWstorezero,
   534  		ssa.OpARM64MOVDstorezero:
   535  		p := s.Prog(v.Op.Asm())
   536  		p.From.Type = obj.TYPE_REG
   537  		p.From.Reg = arm64.REGZERO
   538  		p.To.Type = obj.TYPE_MEM
   539  		p.To.Reg = v.Args[0].Reg()
   540  		ssagen.AddAux(&p.To, v)
   541  	case ssa.OpARM64MOVBstorezeroidx,
   542  		ssa.OpARM64MOVHstorezeroidx,
   543  		ssa.OpARM64MOVWstorezeroidx,
   544  		ssa.OpARM64MOVDstorezeroidx,
   545  		ssa.OpARM64MOVHstorezeroidx2,
   546  		ssa.OpARM64MOVWstorezeroidx4,
   547  		ssa.OpARM64MOVDstorezeroidx8:
   548  		p := s.Prog(v.Op.Asm())
   549  		p.To = genIndexedOperand(v.Op, v.Args[0].Reg(), v.Args[1].Reg())
   550  		p.From.Type = obj.TYPE_REG
   551  		p.From.Reg = arm64.REGZERO
   552  	case ssa.OpARM64MOVQstorezero:
   553  		p := s.Prog(v.Op.Asm())
   554  		p.From.Type = obj.TYPE_REGREG
   555  		p.From.Reg = arm64.REGZERO
   556  		p.From.Offset = int64(arm64.REGZERO)
   557  		p.To.Type = obj.TYPE_MEM
   558  		p.To.Reg = v.Args[0].Reg()
   559  		ssagen.AddAux(&p.To, v)
   560  	case ssa.OpARM64BFI,
   561  		ssa.OpARM64BFXIL:
   562  		p := s.Prog(v.Op.Asm())
   563  		p.From.Type = obj.TYPE_CONST
   564  		p.From.Offset = v.AuxInt >> 8
   565  		p.AddRestSourceConst(v.AuxInt & 0xff)
   566  		p.Reg = v.Args[1].Reg()
   567  		p.To.Type = obj.TYPE_REG
   568  		p.To.Reg = v.Reg()
   569  	case ssa.OpARM64SBFIZ,
   570  		ssa.OpARM64SBFX,
   571  		ssa.OpARM64UBFIZ,
   572  		ssa.OpARM64UBFX:
   573  		p := s.Prog(v.Op.Asm())
   574  		p.From.Type = obj.TYPE_CONST
   575  		p.From.Offset = v.AuxInt >> 8
   576  		p.AddRestSourceConst(v.AuxInt & 0xff)
   577  		p.Reg = v.Args[0].Reg()
   578  		p.To.Type = obj.TYPE_REG
   579  		p.To.Reg = v.Reg()
   580  	case ssa.OpARM64LoweredAtomicExchange64,
   581  		ssa.OpARM64LoweredAtomicExchange32:
   582  		// LDAXR	(Rarg0), Rout
   583  		// STLXR	Rarg1, (Rarg0), Rtmp
   584  		// CBNZ		Rtmp, -2(PC)
   585  		ld := arm64.ALDAXR
   586  		st := arm64.ASTLXR
   587  		if v.Op == ssa.OpARM64LoweredAtomicExchange32 {
   588  			ld = arm64.ALDAXRW
   589  			st = arm64.ASTLXRW
   590  		}
   591  		r0 := v.Args[0].Reg()
   592  		r1 := v.Args[1].Reg()
   593  		out := v.Reg0()
   594  		p := s.Prog(ld)
   595  		p.From.Type = obj.TYPE_MEM
   596  		p.From.Reg = r0
   597  		p.To.Type = obj.TYPE_REG
   598  		p.To.Reg = out
   599  		p1 := s.Prog(st)
   600  		p1.From.Type = obj.TYPE_REG
   601  		p1.From.Reg = r1
   602  		p1.To.Type = obj.TYPE_MEM
   603  		p1.To.Reg = r0
   604  		p1.RegTo2 = arm64.REGTMP
   605  		p2 := s.Prog(arm64.ACBNZ)
   606  		p2.From.Type = obj.TYPE_REG
   607  		p2.From.Reg = arm64.REGTMP
   608  		p2.To.Type = obj.TYPE_BRANCH
   609  		p2.To.SetTarget(p)
   610  	case ssa.OpARM64LoweredAtomicExchange64Variant,
   611  		ssa.OpARM64LoweredAtomicExchange32Variant:
   612  		swap := arm64.ASWPALD
   613  		if v.Op == ssa.OpARM64LoweredAtomicExchange32Variant {
   614  			swap = arm64.ASWPALW
   615  		}
   616  		r0 := v.Args[0].Reg()
   617  		r1 := v.Args[1].Reg()
   618  		out := v.Reg0()
   619  
   620  		// SWPALD	Rarg1, (Rarg0), Rout
   621  		p := s.Prog(swap)
   622  		p.From.Type = obj.TYPE_REG
   623  		p.From.Reg = r1
   624  		p.To.Type = obj.TYPE_MEM
   625  		p.To.Reg = r0
   626  		p.RegTo2 = out
   627  
   628  	case ssa.OpARM64LoweredAtomicAdd64,
   629  		ssa.OpARM64LoweredAtomicAdd32:
   630  		// LDAXR	(Rarg0), Rout
   631  		// ADD		Rarg1, Rout
   632  		// STLXR	Rout, (Rarg0), Rtmp
   633  		// CBNZ		Rtmp, -3(PC)
   634  		ld := arm64.ALDAXR
   635  		st := arm64.ASTLXR
   636  		if v.Op == ssa.OpARM64LoweredAtomicAdd32 {
   637  			ld = arm64.ALDAXRW
   638  			st = arm64.ASTLXRW
   639  		}
   640  		r0 := v.Args[0].Reg()
   641  		r1 := v.Args[1].Reg()
   642  		out := v.Reg0()
   643  		p := s.Prog(ld)
   644  		p.From.Type = obj.TYPE_MEM
   645  		p.From.Reg = r0
   646  		p.To.Type = obj.TYPE_REG
   647  		p.To.Reg = out
   648  		p1 := s.Prog(arm64.AADD)
   649  		p1.From.Type = obj.TYPE_REG
   650  		p1.From.Reg = r1
   651  		p1.To.Type = obj.TYPE_REG
   652  		p1.To.Reg = out
   653  		p2 := s.Prog(st)
   654  		p2.From.Type = obj.TYPE_REG
   655  		p2.From.Reg = out
   656  		p2.To.Type = obj.TYPE_MEM
   657  		p2.To.Reg = r0
   658  		p2.RegTo2 = arm64.REGTMP
   659  		p3 := s.Prog(arm64.ACBNZ)
   660  		p3.From.Type = obj.TYPE_REG
   661  		p3.From.Reg = arm64.REGTMP
   662  		p3.To.Type = obj.TYPE_BRANCH
   663  		p3.To.SetTarget(p)
   664  	case ssa.OpARM64LoweredAtomicAdd64Variant,
   665  		ssa.OpARM64LoweredAtomicAdd32Variant:
   666  		// LDADDAL	Rarg1, (Rarg0), Rout
   667  		// ADD		Rarg1, Rout
   668  		op := arm64.ALDADDALD
   669  		if v.Op == ssa.OpARM64LoweredAtomicAdd32Variant {
   670  			op = arm64.ALDADDALW
   671  		}
   672  		r0 := v.Args[0].Reg()
   673  		r1 := v.Args[1].Reg()
   674  		out := v.Reg0()
   675  		p := s.Prog(op)
   676  		p.From.Type = obj.TYPE_REG
   677  		p.From.Reg = r1
   678  		p.To.Type = obj.TYPE_MEM
   679  		p.To.Reg = r0
   680  		p.RegTo2 = out
   681  		p1 := s.Prog(arm64.AADD)
   682  		p1.From.Type = obj.TYPE_REG
   683  		p1.From.Reg = r1
   684  		p1.To.Type = obj.TYPE_REG
   685  		p1.To.Reg = out
   686  	case ssa.OpARM64LoweredAtomicCas64,
   687  		ssa.OpARM64LoweredAtomicCas32:
   688  		// LDAXR	(Rarg0), Rtmp
   689  		// CMP		Rarg1, Rtmp
   690  		// BNE		3(PC)
   691  		// STLXR	Rarg2, (Rarg0), Rtmp
   692  		// CBNZ		Rtmp, -4(PC)
   693  		// CSET		EQ, Rout
   694  		ld := arm64.ALDAXR
   695  		st := arm64.ASTLXR
   696  		cmp := arm64.ACMP
   697  		if v.Op == ssa.OpARM64LoweredAtomicCas32 {
   698  			ld = arm64.ALDAXRW
   699  			st = arm64.ASTLXRW
   700  			cmp = arm64.ACMPW
   701  		}
   702  		r0 := v.Args[0].Reg()
   703  		r1 := v.Args[1].Reg()
   704  		r2 := v.Args[2].Reg()
   705  		out := v.Reg0()
   706  		p := s.Prog(ld)
   707  		p.From.Type = obj.TYPE_MEM
   708  		p.From.Reg = r0
   709  		p.To.Type = obj.TYPE_REG
   710  		p.To.Reg = arm64.REGTMP
   711  		p1 := s.Prog(cmp)
   712  		p1.From.Type = obj.TYPE_REG
   713  		p1.From.Reg = r1
   714  		p1.Reg = arm64.REGTMP
   715  		p2 := s.Prog(arm64.ABNE)
   716  		p2.To.Type = obj.TYPE_BRANCH
   717  		p3 := s.Prog(st)
   718  		p3.From.Type = obj.TYPE_REG
   719  		p3.From.Reg = r2
   720  		p3.To.Type = obj.TYPE_MEM
   721  		p3.To.Reg = r0
   722  		p3.RegTo2 = arm64.REGTMP
   723  		p4 := s.Prog(arm64.ACBNZ)
   724  		p4.From.Type = obj.TYPE_REG
   725  		p4.From.Reg = arm64.REGTMP
   726  		p4.To.Type = obj.TYPE_BRANCH
   727  		p4.To.SetTarget(p)
   728  		p5 := s.Prog(arm64.ACSET)
   729  		p5.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
   730  		p5.From.Offset = int64(arm64.SPOP_EQ)
   731  		p5.To.Type = obj.TYPE_REG
   732  		p5.To.Reg = out
   733  		p2.To.SetTarget(p5)
   734  	case ssa.OpARM64LoweredAtomicCas64Variant,
   735  		ssa.OpARM64LoweredAtomicCas32Variant:
   736  		// Rarg0: ptr
   737  		// Rarg1: old
   738  		// Rarg2: new
   739  		// MOV  	Rarg1, Rtmp
   740  		// CASAL	Rtmp, (Rarg0), Rarg2
   741  		// CMP  	Rarg1, Rtmp
   742  		// CSET 	EQ, Rout
   743  		cas := arm64.ACASALD
   744  		cmp := arm64.ACMP
   745  		mov := arm64.AMOVD
   746  		if v.Op == ssa.OpARM64LoweredAtomicCas32Variant {
   747  			cas = arm64.ACASALW
   748  			cmp = arm64.ACMPW
   749  			mov = arm64.AMOVW
   750  		}
   751  		r0 := v.Args[0].Reg()
   752  		r1 := v.Args[1].Reg()
   753  		r2 := v.Args[2].Reg()
   754  		out := v.Reg0()
   755  
   756  		// MOV  	Rarg1, Rtmp
   757  		p := s.Prog(mov)
   758  		p.From.Type = obj.TYPE_REG
   759  		p.From.Reg = r1
   760  		p.To.Type = obj.TYPE_REG
   761  		p.To.Reg = arm64.REGTMP
   762  
   763  		// CASAL	Rtmp, (Rarg0), Rarg2
   764  		p1 := s.Prog(cas)
   765  		p1.From.Type = obj.TYPE_REG
   766  		p1.From.Reg = arm64.REGTMP
   767  		p1.To.Type = obj.TYPE_MEM
   768  		p1.To.Reg = r0
   769  		p1.RegTo2 = r2
   770  
   771  		// CMP  	Rarg1, Rtmp
   772  		p2 := s.Prog(cmp)
   773  		p2.From.Type = obj.TYPE_REG
   774  		p2.From.Reg = r1
   775  		p2.Reg = arm64.REGTMP
   776  
   777  		// CSET 	EQ, Rout
   778  		p3 := s.Prog(arm64.ACSET)
   779  		p3.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
   780  		p3.From.Offset = int64(arm64.SPOP_EQ)
   781  		p3.To.Type = obj.TYPE_REG
   782  		p3.To.Reg = out
   783  
   784  	case ssa.OpARM64LoweredAtomicAnd8,
   785  		ssa.OpARM64LoweredAtomicAnd32,
   786  		ssa.OpARM64LoweredAtomicOr8,
   787  		ssa.OpARM64LoweredAtomicOr32:
   788  		// LDAXRB/LDAXRW (Rarg0), Rout
   789  		// AND/OR	Rarg1, Rout
   790  		// STLXRB/STLXRB Rout, (Rarg0), Rtmp
   791  		// CBNZ		Rtmp, -3(PC)
   792  		ld := arm64.ALDAXRB
   793  		st := arm64.ASTLXRB
   794  		if v.Op == ssa.OpARM64LoweredAtomicAnd32 || v.Op == ssa.OpARM64LoweredAtomicOr32 {
   795  			ld = arm64.ALDAXRW
   796  			st = arm64.ASTLXRW
   797  		}
   798  		r0 := v.Args[0].Reg()
   799  		r1 := v.Args[1].Reg()
   800  		out := v.Reg0()
   801  		p := s.Prog(ld)
   802  		p.From.Type = obj.TYPE_MEM
   803  		p.From.Reg = r0
   804  		p.To.Type = obj.TYPE_REG
   805  		p.To.Reg = out
   806  		p1 := s.Prog(v.Op.Asm())
   807  		p1.From.Type = obj.TYPE_REG
   808  		p1.From.Reg = r1
   809  		p1.To.Type = obj.TYPE_REG
   810  		p1.To.Reg = out
   811  		p2 := s.Prog(st)
   812  		p2.From.Type = obj.TYPE_REG
   813  		p2.From.Reg = out
   814  		p2.To.Type = obj.TYPE_MEM
   815  		p2.To.Reg = r0
   816  		p2.RegTo2 = arm64.REGTMP
   817  		p3 := s.Prog(arm64.ACBNZ)
   818  		p3.From.Type = obj.TYPE_REG
   819  		p3.From.Reg = arm64.REGTMP
   820  		p3.To.Type = obj.TYPE_BRANCH
   821  		p3.To.SetTarget(p)
   822  	case ssa.OpARM64LoweredAtomicAnd8Variant,
   823  		ssa.OpARM64LoweredAtomicAnd32Variant:
   824  		atomic_clear := arm64.ALDCLRALW
   825  		if v.Op == ssa.OpARM64LoweredAtomicAnd8Variant {
   826  			atomic_clear = arm64.ALDCLRALB
   827  		}
   828  		r0 := v.Args[0].Reg()
   829  		r1 := v.Args[1].Reg()
   830  		out := v.Reg0()
   831  
   832  		// MNV       Rarg1 Rtemp
   833  		p := s.Prog(arm64.AMVN)
   834  		p.From.Type = obj.TYPE_REG
   835  		p.From.Reg = r1
   836  		p.To.Type = obj.TYPE_REG
   837  		p.To.Reg = arm64.REGTMP
   838  
   839  		// LDCLRALW  Rtemp, (Rarg0), Rout
   840  		p1 := s.Prog(atomic_clear)
   841  		p1.From.Type = obj.TYPE_REG
   842  		p1.From.Reg = arm64.REGTMP
   843  		p1.To.Type = obj.TYPE_MEM
   844  		p1.To.Reg = r0
   845  		p1.RegTo2 = out
   846  
   847  		// AND       Rarg1, Rout
   848  		p2 := s.Prog(arm64.AAND)
   849  		p2.From.Type = obj.TYPE_REG
   850  		p2.From.Reg = r1
   851  		p2.To.Type = obj.TYPE_REG
   852  		p2.To.Reg = out
   853  
   854  	case ssa.OpARM64LoweredAtomicOr8Variant,
   855  		ssa.OpARM64LoweredAtomicOr32Variant:
   856  		atomic_or := arm64.ALDORALW
   857  		if v.Op == ssa.OpARM64LoweredAtomicOr8Variant {
   858  			atomic_or = arm64.ALDORALB
   859  		}
   860  		r0 := v.Args[0].Reg()
   861  		r1 := v.Args[1].Reg()
   862  		out := v.Reg0()
   863  
   864  		// LDORALW  Rarg1, (Rarg0), Rout
   865  		p := s.Prog(atomic_or)
   866  		p.From.Type = obj.TYPE_REG
   867  		p.From.Reg = r1
   868  		p.To.Type = obj.TYPE_MEM
   869  		p.To.Reg = r0
   870  		p.RegTo2 = out
   871  
   872  		// ORR       Rarg1, Rout
   873  		p2 := s.Prog(arm64.AORR)
   874  		p2.From.Type = obj.TYPE_REG
   875  		p2.From.Reg = r1
   876  		p2.To.Type = obj.TYPE_REG
   877  		p2.To.Reg = out
   878  
   879  	case ssa.OpARM64MOVBreg,
   880  		ssa.OpARM64MOVBUreg,
   881  		ssa.OpARM64MOVHreg,
   882  		ssa.OpARM64MOVHUreg,
   883  		ssa.OpARM64MOVWreg,
   884  		ssa.OpARM64MOVWUreg:
   885  		a := v.Args[0]
   886  		for a.Op == ssa.OpCopy || a.Op == ssa.OpARM64MOVDreg {
   887  			a = a.Args[0]
   888  		}
   889  		if a.Op == ssa.OpLoadReg {
   890  			t := a.Type
   891  			switch {
   892  			case v.Op == ssa.OpARM64MOVBreg && t.Size() == 1 && t.IsSigned(),
   893  				v.Op == ssa.OpARM64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
   894  				v.Op == ssa.OpARM64MOVHreg && t.Size() == 2 && t.IsSigned(),
   895  				v.Op == ssa.OpARM64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
   896  				v.Op == ssa.OpARM64MOVWreg && t.Size() == 4 && t.IsSigned(),
   897  				v.Op == ssa.OpARM64MOVWUreg && t.Size() == 4 && !t.IsSigned():
   898  				// arg is a proper-typed load, already zero/sign-extended, don't extend again
   899  				if v.Reg() == v.Args[0].Reg() {
   900  					return
   901  				}
   902  				p := s.Prog(arm64.AMOVD)
   903  				p.From.Type = obj.TYPE_REG
   904  				p.From.Reg = v.Args[0].Reg()
   905  				p.To.Type = obj.TYPE_REG
   906  				p.To.Reg = v.Reg()
   907  				return
   908  			default:
   909  			}
   910  		}
   911  		fallthrough
   912  	case ssa.OpARM64MVN,
   913  		ssa.OpARM64NEG,
   914  		ssa.OpARM64FABSD,
   915  		ssa.OpARM64FMOVDfpgp,
   916  		ssa.OpARM64FMOVDgpfp,
   917  		ssa.OpARM64FMOVSfpgp,
   918  		ssa.OpARM64FMOVSgpfp,
   919  		ssa.OpARM64FNEGS,
   920  		ssa.OpARM64FNEGD,
   921  		ssa.OpARM64FSQRTS,
   922  		ssa.OpARM64FSQRTD,
   923  		ssa.OpARM64FCVTZSSW,
   924  		ssa.OpARM64FCVTZSDW,
   925  		ssa.OpARM64FCVTZUSW,
   926  		ssa.OpARM64FCVTZUDW,
   927  		ssa.OpARM64FCVTZSS,
   928  		ssa.OpARM64FCVTZSD,
   929  		ssa.OpARM64FCVTZUS,
   930  		ssa.OpARM64FCVTZUD,
   931  		ssa.OpARM64SCVTFWS,
   932  		ssa.OpARM64SCVTFWD,
   933  		ssa.OpARM64SCVTFS,
   934  		ssa.OpARM64SCVTFD,
   935  		ssa.OpARM64UCVTFWS,
   936  		ssa.OpARM64UCVTFWD,
   937  		ssa.OpARM64UCVTFS,
   938  		ssa.OpARM64UCVTFD,
   939  		ssa.OpARM64FCVTSD,
   940  		ssa.OpARM64FCVTDS,
   941  		ssa.OpARM64REV,
   942  		ssa.OpARM64REVW,
   943  		ssa.OpARM64REV16,
   944  		ssa.OpARM64REV16W,
   945  		ssa.OpARM64RBIT,
   946  		ssa.OpARM64RBITW,
   947  		ssa.OpARM64CLZ,
   948  		ssa.OpARM64CLZW,
   949  		ssa.OpARM64FRINTAD,
   950  		ssa.OpARM64FRINTMD,
   951  		ssa.OpARM64FRINTND,
   952  		ssa.OpARM64FRINTPD,
   953  		ssa.OpARM64FRINTZD:
   954  		p := s.Prog(v.Op.Asm())
   955  		p.From.Type = obj.TYPE_REG
   956  		p.From.Reg = v.Args[0].Reg()
   957  		p.To.Type = obj.TYPE_REG
   958  		p.To.Reg = v.Reg()
   959  	case ssa.OpARM64LoweredRound32F, ssa.OpARM64LoweredRound64F:
   960  		// input is already rounded
   961  	case ssa.OpARM64VCNT:
   962  		p := s.Prog(v.Op.Asm())
   963  		p.From.Type = obj.TYPE_REG
   964  		p.From.Reg = (v.Args[0].Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
   965  		p.To.Type = obj.TYPE_REG
   966  		p.To.Reg = (v.Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
   967  	case ssa.OpARM64VUADDLV:
   968  		p := s.Prog(v.Op.Asm())
   969  		p.From.Type = obj.TYPE_REG
   970  		p.From.Reg = (v.Args[0].Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
   971  		p.To.Type = obj.TYPE_REG
   972  		p.To.Reg = v.Reg() - arm64.REG_F0 + arm64.REG_V0
   973  	case ssa.OpARM64CSEL, ssa.OpARM64CSEL0:
   974  		r1 := int16(arm64.REGZERO)
   975  		if v.Op != ssa.OpARM64CSEL0 {
   976  			r1 = v.Args[1].Reg()
   977  		}
   978  		p := s.Prog(v.Op.Asm())
   979  		p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
   980  		condCode := condBits[ssa.Op(v.AuxInt)]
   981  		p.From.Offset = int64(condCode)
   982  		p.Reg = v.Args[0].Reg()
   983  		p.AddRestSourceReg(r1)
   984  		p.To.Type = obj.TYPE_REG
   985  		p.To.Reg = v.Reg()
   986  	case ssa.OpARM64CSINC, ssa.OpARM64CSINV, ssa.OpARM64CSNEG:
   987  		p := s.Prog(v.Op.Asm())
   988  		p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
   989  		condCode := condBits[ssa.Op(v.AuxInt)]
   990  		p.From.Offset = int64(condCode)
   991  		p.Reg = v.Args[0].Reg()
   992  		p.AddRestSourceReg(v.Args[1].Reg())
   993  		p.To.Type = obj.TYPE_REG
   994  		p.To.Reg = v.Reg()
   995  	case ssa.OpARM64CSETM:
   996  		p := s.Prog(arm64.ACSETM)
   997  		p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
   998  		condCode := condBits[ssa.Op(v.AuxInt)]
   999  		p.From.Offset = int64(condCode)
  1000  		p.To.Type = obj.TYPE_REG
  1001  		p.To.Reg = v.Reg()
  1002  	case ssa.OpARM64DUFFZERO:
  1003  		// runtime.duffzero expects start address in R20
  1004  		p := s.Prog(obj.ADUFFZERO)
  1005  		p.To.Type = obj.TYPE_MEM
  1006  		p.To.Name = obj.NAME_EXTERN
  1007  		p.To.Sym = ir.Syms.Duffzero
  1008  		p.To.Offset = v.AuxInt
  1009  	case ssa.OpARM64LoweredZero:
  1010  		// STP.P	(ZR,ZR), 16(R16)
  1011  		// CMP	Rarg1, R16
  1012  		// BLE	-2(PC)
  1013  		// arg1 is the address of the last 16-byte unit to zero
  1014  		p := s.Prog(arm64.ASTP)
  1015  		p.Scond = arm64.C_XPOST
  1016  		p.From.Type = obj.TYPE_REGREG
  1017  		p.From.Reg = arm64.REGZERO
  1018  		p.From.Offset = int64(arm64.REGZERO)
  1019  		p.To.Type = obj.TYPE_MEM
  1020  		p.To.Reg = arm64.REG_R16
  1021  		p.To.Offset = 16
  1022  		p2 := s.Prog(arm64.ACMP)
  1023  		p2.From.Type = obj.TYPE_REG
  1024  		p2.From.Reg = v.Args[1].Reg()
  1025  		p2.Reg = arm64.REG_R16
  1026  		p3 := s.Prog(arm64.ABLE)
  1027  		p3.To.Type = obj.TYPE_BRANCH
  1028  		p3.To.SetTarget(p)
  1029  	case ssa.OpARM64DUFFCOPY:
  1030  		p := s.Prog(obj.ADUFFCOPY)
  1031  		p.To.Type = obj.TYPE_MEM
  1032  		p.To.Name = obj.NAME_EXTERN
  1033  		p.To.Sym = ir.Syms.Duffcopy
  1034  		p.To.Offset = v.AuxInt
  1035  	case ssa.OpARM64LoweredMove:
  1036  		// LDP.P	16(R16), (R25, Rtmp)
  1037  		// STP.P	(R25, Rtmp), 16(R17)
  1038  		// CMP	Rarg2, R16
  1039  		// BLE	-3(PC)
  1040  		// arg2 is the address of the last element of src
  1041  		p := s.Prog(arm64.ALDP)
  1042  		p.Scond = arm64.C_XPOST
  1043  		p.From.Type = obj.TYPE_MEM
  1044  		p.From.Reg = arm64.REG_R16
  1045  		p.From.Offset = 16
  1046  		p.To.Type = obj.TYPE_REGREG
  1047  		p.To.Reg = arm64.REG_R25
  1048  		p.To.Offset = int64(arm64.REGTMP)
  1049  		p2 := s.Prog(arm64.ASTP)
  1050  		p2.Scond = arm64.C_XPOST
  1051  		p2.From.Type = obj.TYPE_REGREG
  1052  		p2.From.Reg = arm64.REG_R25
  1053  		p2.From.Offset = int64(arm64.REGTMP)
  1054  		p2.To.Type = obj.TYPE_MEM
  1055  		p2.To.Reg = arm64.REG_R17
  1056  		p2.To.Offset = 16
  1057  		p3 := s.Prog(arm64.ACMP)
  1058  		p3.From.Type = obj.TYPE_REG
  1059  		p3.From.Reg = v.Args[2].Reg()
  1060  		p3.Reg = arm64.REG_R16
  1061  		p4 := s.Prog(arm64.ABLE)
  1062  		p4.To.Type = obj.TYPE_BRANCH
  1063  		p4.To.SetTarget(p)
  1064  	case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter:
  1065  		s.Call(v)
  1066  	case ssa.OpARM64CALLtail:
  1067  		s.TailCall(v)
  1068  	case ssa.OpARM64LoweredWB:
  1069  		p := s.Prog(obj.ACALL)
  1070  		p.To.Type = obj.TYPE_MEM
  1071  		p.To.Name = obj.NAME_EXTERN
  1072  		// AuxInt encodes how many buffer entries we need.
  1073  		p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
  1074  
  1075  	case ssa.OpARM64LoweredPanicBoundsA, ssa.OpARM64LoweredPanicBoundsB, ssa.OpARM64LoweredPanicBoundsC:
  1076  		p := s.Prog(obj.ACALL)
  1077  		p.To.Type = obj.TYPE_MEM
  1078  		p.To.Name = obj.NAME_EXTERN
  1079  		p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
  1080  		s.UseArgs(16) // space used in callee args area by assembly stubs
  1081  	case ssa.OpARM64LoweredNilCheck:
  1082  		// Issue a load which will fault if arg is nil.
  1083  		p := s.Prog(arm64.AMOVB)
  1084  		p.From.Type = obj.TYPE_MEM
  1085  		p.From.Reg = v.Args[0].Reg()
  1086  		ssagen.AddAux(&p.From, v)
  1087  		p.To.Type = obj.TYPE_REG
  1088  		p.To.Reg = arm64.REGTMP
  1089  		if logopt.Enabled() {
  1090  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
  1091  		}
  1092  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Line==1 in generated wrappers
  1093  			base.WarnfAt(v.Pos, "generated nil check")
  1094  		}
  1095  	case ssa.OpARM64Equal,
  1096  		ssa.OpARM64NotEqual,
  1097  		ssa.OpARM64LessThan,
  1098  		ssa.OpARM64LessEqual,
  1099  		ssa.OpARM64GreaterThan,
  1100  		ssa.OpARM64GreaterEqual,
  1101  		ssa.OpARM64LessThanU,
  1102  		ssa.OpARM64LessEqualU,
  1103  		ssa.OpARM64GreaterThanU,
  1104  		ssa.OpARM64GreaterEqualU,
  1105  		ssa.OpARM64LessThanF,
  1106  		ssa.OpARM64LessEqualF,
  1107  		ssa.OpARM64GreaterThanF,
  1108  		ssa.OpARM64GreaterEqualF,
  1109  		ssa.OpARM64NotLessThanF,
  1110  		ssa.OpARM64NotLessEqualF,
  1111  		ssa.OpARM64NotGreaterThanF,
  1112  		ssa.OpARM64NotGreaterEqualF,
  1113  		ssa.OpARM64LessThanNoov,
  1114  		ssa.OpARM64GreaterEqualNoov:
  1115  		// generate boolean values using CSET
  1116  		p := s.Prog(arm64.ACSET)
  1117  		p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
  1118  		condCode := condBits[v.Op]
  1119  		p.From.Offset = int64(condCode)
  1120  		p.To.Type = obj.TYPE_REG
  1121  		p.To.Reg = v.Reg()
  1122  	case ssa.OpARM64PRFM:
  1123  		p := s.Prog(v.Op.Asm())
  1124  		p.From.Type = obj.TYPE_MEM
  1125  		p.From.Reg = v.Args[0].Reg()
  1126  		p.To.Type = obj.TYPE_CONST
  1127  		p.To.Offset = v.AuxInt
  1128  	case ssa.OpARM64LoweredGetClosurePtr:
  1129  		// Closure pointer is R26 (arm64.REGCTXT).
  1130  		ssagen.CheckLoweredGetClosurePtr(v)
  1131  	case ssa.OpARM64LoweredGetCallerSP:
  1132  		// caller's SP is FixedFrameSize below the address of the first arg
  1133  		p := s.Prog(arm64.AMOVD)
  1134  		p.From.Type = obj.TYPE_ADDR
  1135  		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize
  1136  		p.From.Name = obj.NAME_PARAM
  1137  		p.To.Type = obj.TYPE_REG
  1138  		p.To.Reg = v.Reg()
  1139  	case ssa.OpARM64LoweredGetCallerPC:
  1140  		p := s.Prog(obj.AGETCALLERPC)
  1141  		p.To.Type = obj.TYPE_REG
  1142  		p.To.Reg = v.Reg()
  1143  	case ssa.OpARM64DMB:
  1144  		p := s.Prog(v.Op.Asm())
  1145  		p.From.Type = obj.TYPE_CONST
  1146  		p.From.Offset = v.AuxInt
  1147  	case ssa.OpARM64FlagConstant:
  1148  		v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
  1149  	case ssa.OpARM64InvertFlags:
  1150  		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
  1151  	case ssa.OpClobber:
  1152  		// MOVW	$0xdeaddead, REGTMP
  1153  		// MOVW	REGTMP, (slot)
  1154  		// MOVW	REGTMP, 4(slot)
  1155  		p := s.Prog(arm64.AMOVW)
  1156  		p.From.Type = obj.TYPE_CONST
  1157  		p.From.Offset = 0xdeaddead
  1158  		p.To.Type = obj.TYPE_REG
  1159  		p.To.Reg = arm64.REGTMP
  1160  		p = s.Prog(arm64.AMOVW)
  1161  		p.From.Type = obj.TYPE_REG
  1162  		p.From.Reg = arm64.REGTMP
  1163  		p.To.Type = obj.TYPE_MEM
  1164  		p.To.Reg = arm64.REGSP
  1165  		ssagen.AddAux(&p.To, v)
  1166  		p = s.Prog(arm64.AMOVW)
  1167  		p.From.Type = obj.TYPE_REG
  1168  		p.From.Reg = arm64.REGTMP
  1169  		p.To.Type = obj.TYPE_MEM
  1170  		p.To.Reg = arm64.REGSP
  1171  		ssagen.AddAux2(&p.To, v, v.AuxInt+4)
  1172  	case ssa.OpClobberReg:
  1173  		x := uint64(0xdeaddeaddeaddead)
  1174  		p := s.Prog(arm64.AMOVD)
  1175  		p.From.Type = obj.TYPE_CONST
  1176  		p.From.Offset = int64(x)
  1177  		p.To.Type = obj.TYPE_REG
  1178  		p.To.Reg = v.Reg()
  1179  	default:
  1180  		v.Fatalf("genValue not implemented: %s", v.LongString())
  1181  	}
  1182  }
  1183  
  1184  var condBits = map[ssa.Op]arm64.SpecialOperand{
  1185  	ssa.OpARM64Equal:         arm64.SPOP_EQ,
  1186  	ssa.OpARM64NotEqual:      arm64.SPOP_NE,
  1187  	ssa.OpARM64LessThan:      arm64.SPOP_LT,
  1188  	ssa.OpARM64LessThanU:     arm64.SPOP_LO,
  1189  	ssa.OpARM64LessEqual:     arm64.SPOP_LE,
  1190  	ssa.OpARM64LessEqualU:    arm64.SPOP_LS,
  1191  	ssa.OpARM64GreaterThan:   arm64.SPOP_GT,
  1192  	ssa.OpARM64GreaterThanU:  arm64.SPOP_HI,
  1193  	ssa.OpARM64GreaterEqual:  arm64.SPOP_GE,
  1194  	ssa.OpARM64GreaterEqualU: arm64.SPOP_HS,
  1195  	ssa.OpARM64LessThanF:     arm64.SPOP_MI, // Less than
  1196  	ssa.OpARM64LessEqualF:    arm64.SPOP_LS, // Less than or equal to
  1197  	ssa.OpARM64GreaterThanF:  arm64.SPOP_GT, // Greater than
  1198  	ssa.OpARM64GreaterEqualF: arm64.SPOP_GE, // Greater than or equal to
  1199  
  1200  	// The following condition codes have unordered to handle comparisons related to NaN.
  1201  	ssa.OpARM64NotLessThanF:     arm64.SPOP_PL, // Greater than, equal to, or unordered
  1202  	ssa.OpARM64NotLessEqualF:    arm64.SPOP_HI, // Greater than or unordered
  1203  	ssa.OpARM64NotGreaterThanF:  arm64.SPOP_LE, // Less than, equal to or unordered
  1204  	ssa.OpARM64NotGreaterEqualF: arm64.SPOP_LT, // Less than or unordered
  1205  
  1206  	ssa.OpARM64LessThanNoov:     arm64.SPOP_MI, // Less than but without honoring overflow
  1207  	ssa.OpARM64GreaterEqualNoov: arm64.SPOP_PL, // Greater than or equal to but without honoring overflow
  1208  }
  1209  
  1210  var blockJump = map[ssa.BlockKind]struct {
  1211  	asm, invasm obj.As
  1212  }{
  1213  	ssa.BlockARM64EQ:     {arm64.ABEQ, arm64.ABNE},
  1214  	ssa.BlockARM64NE:     {arm64.ABNE, arm64.ABEQ},
  1215  	ssa.BlockARM64LT:     {arm64.ABLT, arm64.ABGE},
  1216  	ssa.BlockARM64GE:     {arm64.ABGE, arm64.ABLT},
  1217  	ssa.BlockARM64LE:     {arm64.ABLE, arm64.ABGT},
  1218  	ssa.BlockARM64GT:     {arm64.ABGT, arm64.ABLE},
  1219  	ssa.BlockARM64ULT:    {arm64.ABLO, arm64.ABHS},
  1220  	ssa.BlockARM64UGE:    {arm64.ABHS, arm64.ABLO},
  1221  	ssa.BlockARM64UGT:    {arm64.ABHI, arm64.ABLS},
  1222  	ssa.BlockARM64ULE:    {arm64.ABLS, arm64.ABHI},
  1223  	ssa.BlockARM64Z:      {arm64.ACBZ, arm64.ACBNZ},
  1224  	ssa.BlockARM64NZ:     {arm64.ACBNZ, arm64.ACBZ},
  1225  	ssa.BlockARM64ZW:     {arm64.ACBZW, arm64.ACBNZW},
  1226  	ssa.BlockARM64NZW:    {arm64.ACBNZW, arm64.ACBZW},
  1227  	ssa.BlockARM64TBZ:    {arm64.ATBZ, arm64.ATBNZ},
  1228  	ssa.BlockARM64TBNZ:   {arm64.ATBNZ, arm64.ATBZ},
  1229  	ssa.BlockARM64FLT:    {arm64.ABMI, arm64.ABPL},
  1230  	ssa.BlockARM64FGE:    {arm64.ABGE, arm64.ABLT},
  1231  	ssa.BlockARM64FLE:    {arm64.ABLS, arm64.ABHI},
  1232  	ssa.BlockARM64FGT:    {arm64.ABGT, arm64.ABLE},
  1233  	ssa.BlockARM64LTnoov: {arm64.ABMI, arm64.ABPL},
  1234  	ssa.BlockARM64GEnoov: {arm64.ABPL, arm64.ABMI},
  1235  }
  1236  
  1237  // To model a 'LEnoov' ('<=' without overflow checking) branching.
  1238  var leJumps = [2][2]ssagen.IndexJump{
  1239  	{{Jump: arm64.ABEQ, Index: 0}, {Jump: arm64.ABPL, Index: 1}}, // next == b.Succs[0]
  1240  	{{Jump: arm64.ABMI, Index: 0}, {Jump: arm64.ABEQ, Index: 0}}, // next == b.Succs[1]
  1241  }
  1242  
  1243  // To model a 'GTnoov' ('>' without overflow checking) branching.
  1244  var gtJumps = [2][2]ssagen.IndexJump{
  1245  	{{Jump: arm64.ABMI, Index: 1}, {Jump: arm64.ABEQ, Index: 1}}, // next == b.Succs[0]
  1246  	{{Jump: arm64.ABEQ, Index: 1}, {Jump: arm64.ABPL, Index: 0}}, // next == b.Succs[1]
  1247  }
  1248  
  1249  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
  1250  	switch b.Kind {
  1251  	case ssa.BlockPlain:
  1252  		if b.Succs[0].Block() != next {
  1253  			p := s.Prog(obj.AJMP)
  1254  			p.To.Type = obj.TYPE_BRANCH
  1255  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
  1256  		}
  1257  
  1258  	case ssa.BlockDefer:
  1259  		// defer returns in R0:
  1260  		// 0 if we should continue executing
  1261  		// 1 if we should jump to deferreturn call
  1262  		p := s.Prog(arm64.ACMP)
  1263  		p.From.Type = obj.TYPE_CONST
  1264  		p.From.Offset = 0
  1265  		p.Reg = arm64.REG_R0
  1266  		p = s.Prog(arm64.ABNE)
  1267  		p.To.Type = obj.TYPE_BRANCH
  1268  		s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()})
  1269  		if b.Succs[0].Block() != next {
  1270  			p := s.Prog(obj.AJMP)
  1271  			p.To.Type = obj.TYPE_BRANCH
  1272  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
  1273  		}
  1274  
  1275  	case ssa.BlockExit, ssa.BlockRetJmp:
  1276  
  1277  	case ssa.BlockRet:
  1278  		s.Prog(obj.ARET)
  1279  
  1280  	case ssa.BlockARM64EQ, ssa.BlockARM64NE,
  1281  		ssa.BlockARM64LT, ssa.BlockARM64GE,
  1282  		ssa.BlockARM64LE, ssa.BlockARM64GT,
  1283  		ssa.BlockARM64ULT, ssa.BlockARM64UGT,
  1284  		ssa.BlockARM64ULE, ssa.BlockARM64UGE,
  1285  		ssa.BlockARM64Z, ssa.BlockARM64NZ,
  1286  		ssa.BlockARM64ZW, ssa.BlockARM64NZW,
  1287  		ssa.BlockARM64FLT, ssa.BlockARM64FGE,
  1288  		ssa.BlockARM64FLE, ssa.BlockARM64FGT,
  1289  		ssa.BlockARM64LTnoov, ssa.BlockARM64GEnoov:
  1290  		jmp := blockJump[b.Kind]
  1291  		var p *obj.Prog
  1292  		switch next {
  1293  		case b.Succs[0].Block():
  1294  			p = s.Br(jmp.invasm, b.Succs[1].Block())
  1295  		case b.Succs[1].Block():
  1296  			p = s.Br(jmp.asm, b.Succs[0].Block())
  1297  		default:
  1298  			if b.Likely != ssa.BranchUnlikely {
  1299  				p = s.Br(jmp.asm, b.Succs[0].Block())
  1300  				s.Br(obj.AJMP, b.Succs[1].Block())
  1301  			} else {
  1302  				p = s.Br(jmp.invasm, b.Succs[1].Block())
  1303  				s.Br(obj.AJMP, b.Succs[0].Block())
  1304  			}
  1305  		}
  1306  		if !b.Controls[0].Type.IsFlags() {
  1307  			p.From.Type = obj.TYPE_REG
  1308  			p.From.Reg = b.Controls[0].Reg()
  1309  		}
  1310  	case ssa.BlockARM64TBZ, ssa.BlockARM64TBNZ:
  1311  		jmp := blockJump[b.Kind]
  1312  		var p *obj.Prog
  1313  		switch next {
  1314  		case b.Succs[0].Block():
  1315  			p = s.Br(jmp.invasm, b.Succs[1].Block())
  1316  		case b.Succs[1].Block():
  1317  			p = s.Br(jmp.asm, b.Succs[0].Block())
  1318  		default:
  1319  			if b.Likely != ssa.BranchUnlikely {
  1320  				p = s.Br(jmp.asm, b.Succs[0].Block())
  1321  				s.Br(obj.AJMP, b.Succs[1].Block())
  1322  			} else {
  1323  				p = s.Br(jmp.invasm, b.Succs[1].Block())
  1324  				s.Br(obj.AJMP, b.Succs[0].Block())
  1325  			}
  1326  		}
  1327  		p.From.Offset = b.AuxInt
  1328  		p.From.Type = obj.TYPE_CONST
  1329  		p.Reg = b.Controls[0].Reg()
  1330  
  1331  	case ssa.BlockARM64LEnoov:
  1332  		s.CombJump(b, next, &leJumps)
  1333  	case ssa.BlockARM64GTnoov:
  1334  		s.CombJump(b, next, &gtJumps)
  1335  
  1336  	case ssa.BlockARM64JUMPTABLE:
  1337  		// MOVD	(TABLE)(IDX<<3), Rtmp
  1338  		// JMP	(Rtmp)
  1339  		p := s.Prog(arm64.AMOVD)
  1340  		p.From = genIndexedOperand(ssa.OpARM64MOVDloadidx8, b.Controls[1].Reg(), b.Controls[0].Reg())
  1341  		p.To.Type = obj.TYPE_REG
  1342  		p.To.Reg = arm64.REGTMP
  1343  		p = s.Prog(obj.AJMP)
  1344  		p.To.Type = obj.TYPE_MEM
  1345  		p.To.Reg = arm64.REGTMP
  1346  		// Save jump tables for later resolution of the target blocks.
  1347  		s.JumpTables = append(s.JumpTables, b)
  1348  
  1349  	default:
  1350  		b.Fatalf("branch not implemented: %s", b.LongString())
  1351  	}
  1352  }
  1353  
  1354  func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
  1355  	p := s.Prog(loadByType(t))
  1356  	p.From.Type = obj.TYPE_MEM
  1357  	p.From.Name = obj.NAME_AUTO
  1358  	p.From.Sym = n.Linksym()
  1359  	p.From.Offset = n.FrameOffset() + off
  1360  	p.To.Type = obj.TYPE_REG
  1361  	p.To.Reg = reg
  1362  	return p
  1363  }
  1364  
  1365  func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
  1366  	p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off)
  1367  	p.To.Name = obj.NAME_PARAM
  1368  	p.To.Sym = n.Linksym()
  1369  	p.Pos = p.Pos.WithNotStmt()
  1370  	return p
  1371  }