github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/cmd/compile/internal/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  	"cmd/compile/internal/gc"
    11  	"cmd/compile/internal/ssa"
    12  	"cmd/compile/internal/types"
    13  	"cmd/internal/obj"
    14  	"cmd/internal/obj/arm64"
    15  )
    16  
    17  // loadByType returns the load instruction of the given type.
    18  func loadByType(t *types.Type) obj.As {
    19  	if t.IsFloat() {
    20  		switch t.Size() {
    21  		case 4:
    22  			return arm64.AFMOVS
    23  		case 8:
    24  			return arm64.AFMOVD
    25  		}
    26  	} else {
    27  		switch t.Size() {
    28  		case 1:
    29  			if t.IsSigned() {
    30  				return arm64.AMOVB
    31  			} else {
    32  				return arm64.AMOVBU
    33  			}
    34  		case 2:
    35  			if t.IsSigned() {
    36  				return arm64.AMOVH
    37  			} else {
    38  				return arm64.AMOVHU
    39  			}
    40  		case 4:
    41  			if t.IsSigned() {
    42  				return arm64.AMOVW
    43  			} else {
    44  				return arm64.AMOVWU
    45  			}
    46  		case 8:
    47  			return arm64.AMOVD
    48  		}
    49  	}
    50  	panic("bad load type")
    51  }
    52  
    53  // storeByType returns the store instruction of the given type.
    54  func storeByType(t *types.Type) obj.As {
    55  	if t.IsFloat() {
    56  		switch t.Size() {
    57  		case 4:
    58  			return arm64.AFMOVS
    59  		case 8:
    60  			return arm64.AFMOVD
    61  		}
    62  	} else {
    63  		switch t.Size() {
    64  		case 1:
    65  			return arm64.AMOVB
    66  		case 2:
    67  			return arm64.AMOVH
    68  		case 4:
    69  			return arm64.AMOVW
    70  		case 8:
    71  			return arm64.AMOVD
    72  		}
    73  	}
    74  	panic("bad store type")
    75  }
    76  
    77  // makeshift encodes a register shifted by a constant, used as an Offset in Prog
    78  func makeshift(reg int16, typ int64, s int64) int64 {
    79  	return int64(reg&31)<<16 | typ | (s&63)<<10
    80  }
    81  
    82  // genshift generates a Prog for r = r0 op (r1 shifted by n)
    83  func genshift(s *gc.SSAGenState, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
    84  	p := s.Prog(as)
    85  	p.From.Type = obj.TYPE_SHIFT
    86  	p.From.Offset = makeshift(r1, typ, n)
    87  	p.Reg = r0
    88  	if r != 0 {
    89  		p.To.Type = obj.TYPE_REG
    90  		p.To.Reg = r
    91  	}
    92  	return p
    93  }
    94  
    95  func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
    96  	switch v.Op {
    97  	case ssa.OpCopy, ssa.OpARM64MOVDconvert, ssa.OpARM64MOVDreg:
    98  		if v.Type.IsMemory() {
    99  			return
   100  		}
   101  		x := v.Args[0].Reg()
   102  		y := v.Reg()
   103  		if x == y {
   104  			return
   105  		}
   106  		as := arm64.AMOVD
   107  		if v.Type.IsFloat() {
   108  			switch v.Type.Size() {
   109  			case 4:
   110  				as = arm64.AFMOVS
   111  			case 8:
   112  				as = arm64.AFMOVD
   113  			default:
   114  				panic("bad float size")
   115  			}
   116  		}
   117  		p := s.Prog(as)
   118  		p.From.Type = obj.TYPE_REG
   119  		p.From.Reg = x
   120  		p.To.Type = obj.TYPE_REG
   121  		p.To.Reg = y
   122  	case ssa.OpARM64MOVDnop:
   123  		if v.Reg() != v.Args[0].Reg() {
   124  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   125  		}
   126  		// nothing to do
   127  	case ssa.OpLoadReg:
   128  		if v.Type.IsFlags() {
   129  			v.Fatalf("load flags not implemented: %v", v.LongString())
   130  			return
   131  		}
   132  		p := s.Prog(loadByType(v.Type))
   133  		gc.AddrAuto(&p.From, v.Args[0])
   134  		p.To.Type = obj.TYPE_REG
   135  		p.To.Reg = v.Reg()
   136  	case ssa.OpStoreReg:
   137  		if v.Type.IsFlags() {
   138  			v.Fatalf("store flags not implemented: %v", v.LongString())
   139  			return
   140  		}
   141  		p := s.Prog(storeByType(v.Type))
   142  		p.From.Type = obj.TYPE_REG
   143  		p.From.Reg = v.Args[0].Reg()
   144  		gc.AddrAuto(&p.To, v)
   145  	case ssa.OpARM64ADD,
   146  		ssa.OpARM64SUB,
   147  		ssa.OpARM64AND,
   148  		ssa.OpARM64OR,
   149  		ssa.OpARM64XOR,
   150  		ssa.OpARM64BIC,
   151  		ssa.OpARM64MUL,
   152  		ssa.OpARM64MULW,
   153  		ssa.OpARM64MULH,
   154  		ssa.OpARM64UMULH,
   155  		ssa.OpARM64MULL,
   156  		ssa.OpARM64UMULL,
   157  		ssa.OpARM64DIV,
   158  		ssa.OpARM64UDIV,
   159  		ssa.OpARM64DIVW,
   160  		ssa.OpARM64UDIVW,
   161  		ssa.OpARM64MOD,
   162  		ssa.OpARM64UMOD,
   163  		ssa.OpARM64MODW,
   164  		ssa.OpARM64UMODW,
   165  		ssa.OpARM64SLL,
   166  		ssa.OpARM64SRL,
   167  		ssa.OpARM64SRA,
   168  		ssa.OpARM64FADDS,
   169  		ssa.OpARM64FADDD,
   170  		ssa.OpARM64FSUBS,
   171  		ssa.OpARM64FSUBD,
   172  		ssa.OpARM64FMULS,
   173  		ssa.OpARM64FMULD,
   174  		ssa.OpARM64FDIVS,
   175  		ssa.OpARM64FDIVD:
   176  		r := v.Reg()
   177  		r1 := v.Args[0].Reg()
   178  		r2 := v.Args[1].Reg()
   179  		p := s.Prog(v.Op.Asm())
   180  		p.From.Type = obj.TYPE_REG
   181  		p.From.Reg = r2
   182  		p.Reg = r1
   183  		p.To.Type = obj.TYPE_REG
   184  		p.To.Reg = r
   185  	case ssa.OpARM64ADDconst,
   186  		ssa.OpARM64SUBconst,
   187  		ssa.OpARM64ANDconst,
   188  		ssa.OpARM64ORconst,
   189  		ssa.OpARM64XORconst,
   190  		ssa.OpARM64BICconst,
   191  		ssa.OpARM64SLLconst,
   192  		ssa.OpARM64SRLconst,
   193  		ssa.OpARM64SRAconst,
   194  		ssa.OpARM64RORconst,
   195  		ssa.OpARM64RORWconst:
   196  		p := s.Prog(v.Op.Asm())
   197  		p.From.Type = obj.TYPE_CONST
   198  		p.From.Offset = v.AuxInt
   199  		p.Reg = v.Args[0].Reg()
   200  		p.To.Type = obj.TYPE_REG
   201  		p.To.Reg = v.Reg()
   202  	case ssa.OpARM64ADDshiftLL,
   203  		ssa.OpARM64SUBshiftLL,
   204  		ssa.OpARM64ANDshiftLL,
   205  		ssa.OpARM64ORshiftLL,
   206  		ssa.OpARM64XORshiftLL,
   207  		ssa.OpARM64BICshiftLL:
   208  		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
   209  	case ssa.OpARM64ADDshiftRL,
   210  		ssa.OpARM64SUBshiftRL,
   211  		ssa.OpARM64ANDshiftRL,
   212  		ssa.OpARM64ORshiftRL,
   213  		ssa.OpARM64XORshiftRL,
   214  		ssa.OpARM64BICshiftRL:
   215  		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
   216  	case ssa.OpARM64ADDshiftRA,
   217  		ssa.OpARM64SUBshiftRA,
   218  		ssa.OpARM64ANDshiftRA,
   219  		ssa.OpARM64ORshiftRA,
   220  		ssa.OpARM64XORshiftRA,
   221  		ssa.OpARM64BICshiftRA:
   222  		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
   223  	case ssa.OpARM64MOVDconst:
   224  		p := s.Prog(v.Op.Asm())
   225  		p.From.Type = obj.TYPE_CONST
   226  		p.From.Offset = v.AuxInt
   227  		p.To.Type = obj.TYPE_REG
   228  		p.To.Reg = v.Reg()
   229  	case ssa.OpARM64FMOVSconst,
   230  		ssa.OpARM64FMOVDconst:
   231  		p := s.Prog(v.Op.Asm())
   232  		p.From.Type = obj.TYPE_FCONST
   233  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   234  		p.To.Type = obj.TYPE_REG
   235  		p.To.Reg = v.Reg()
   236  	case ssa.OpARM64CMP,
   237  		ssa.OpARM64CMPW,
   238  		ssa.OpARM64CMN,
   239  		ssa.OpARM64CMNW,
   240  		ssa.OpARM64FCMPS,
   241  		ssa.OpARM64FCMPD:
   242  		p := s.Prog(v.Op.Asm())
   243  		p.From.Type = obj.TYPE_REG
   244  		p.From.Reg = v.Args[1].Reg()
   245  		p.Reg = v.Args[0].Reg()
   246  	case ssa.OpARM64CMPconst,
   247  		ssa.OpARM64CMPWconst,
   248  		ssa.OpARM64CMNconst,
   249  		ssa.OpARM64CMNWconst:
   250  		p := s.Prog(v.Op.Asm())
   251  		p.From.Type = obj.TYPE_CONST
   252  		p.From.Offset = v.AuxInt
   253  		p.Reg = v.Args[0].Reg()
   254  	case ssa.OpARM64CMPshiftLL:
   255  		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LL, v.AuxInt)
   256  	case ssa.OpARM64CMPshiftRL:
   257  		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LR, v.AuxInt)
   258  	case ssa.OpARM64CMPshiftRA:
   259  		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_AR, v.AuxInt)
   260  	case ssa.OpARM64MOVDaddr:
   261  		p := s.Prog(arm64.AMOVD)
   262  		p.From.Type = obj.TYPE_ADDR
   263  		p.From.Reg = v.Args[0].Reg()
   264  		p.To.Type = obj.TYPE_REG
   265  		p.To.Reg = v.Reg()
   266  
   267  		var wantreg string
   268  		// MOVD $sym+off(base), R
   269  		// the assembler expands it as the following:
   270  		// - base is SP: add constant offset to SP (R13)
   271  		//               when constant is large, tmp register (R11) may be used
   272  		// - base is SB: load external address from constant pool (use relocation)
   273  		switch v.Aux.(type) {
   274  		default:
   275  			v.Fatalf("aux is of unknown type %T", v.Aux)
   276  		case *ssa.ExternSymbol:
   277  			wantreg = "SB"
   278  			gc.AddAux(&p.From, v)
   279  		case *ssa.ArgSymbol, *ssa.AutoSymbol:
   280  			wantreg = "SP"
   281  			gc.AddAux(&p.From, v)
   282  		case nil:
   283  			// No sym, just MOVD $off(SP), R
   284  			wantreg = "SP"
   285  			p.From.Offset = v.AuxInt
   286  		}
   287  		if reg := v.Args[0].RegName(); reg != wantreg {
   288  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   289  		}
   290  	case ssa.OpARM64MOVBload,
   291  		ssa.OpARM64MOVBUload,
   292  		ssa.OpARM64MOVHload,
   293  		ssa.OpARM64MOVHUload,
   294  		ssa.OpARM64MOVWload,
   295  		ssa.OpARM64MOVWUload,
   296  		ssa.OpARM64MOVDload,
   297  		ssa.OpARM64FMOVSload,
   298  		ssa.OpARM64FMOVDload:
   299  		p := s.Prog(v.Op.Asm())
   300  		p.From.Type = obj.TYPE_MEM
   301  		p.From.Reg = v.Args[0].Reg()
   302  		gc.AddAux(&p.From, v)
   303  		p.To.Type = obj.TYPE_REG
   304  		p.To.Reg = v.Reg()
   305  	case ssa.OpARM64LDAR,
   306  		ssa.OpARM64LDARW:
   307  		p := s.Prog(v.Op.Asm())
   308  		p.From.Type = obj.TYPE_MEM
   309  		p.From.Reg = v.Args[0].Reg()
   310  		gc.AddAux(&p.From, v)
   311  		p.To.Type = obj.TYPE_REG
   312  		p.To.Reg = v.Reg0()
   313  	case ssa.OpARM64MOVBstore,
   314  		ssa.OpARM64MOVHstore,
   315  		ssa.OpARM64MOVWstore,
   316  		ssa.OpARM64MOVDstore,
   317  		ssa.OpARM64FMOVSstore,
   318  		ssa.OpARM64FMOVDstore,
   319  		ssa.OpARM64STLR,
   320  		ssa.OpARM64STLRW:
   321  		p := s.Prog(v.Op.Asm())
   322  		p.From.Type = obj.TYPE_REG
   323  		p.From.Reg = v.Args[1].Reg()
   324  		p.To.Type = obj.TYPE_MEM
   325  		p.To.Reg = v.Args[0].Reg()
   326  		gc.AddAux(&p.To, v)
   327  	case ssa.OpARM64MOVBstorezero,
   328  		ssa.OpARM64MOVHstorezero,
   329  		ssa.OpARM64MOVWstorezero,
   330  		ssa.OpARM64MOVDstorezero:
   331  		p := s.Prog(v.Op.Asm())
   332  		p.From.Type = obj.TYPE_REG
   333  		p.From.Reg = arm64.REGZERO
   334  		p.To.Type = obj.TYPE_MEM
   335  		p.To.Reg = v.Args[0].Reg()
   336  		gc.AddAux(&p.To, v)
   337  	case ssa.OpARM64LoweredAtomicExchange64,
   338  		ssa.OpARM64LoweredAtomicExchange32:
   339  		// LDAXR	(Rarg0), Rout
   340  		// STLXR	Rarg1, (Rarg0), Rtmp
   341  		// CBNZ		Rtmp, -2(PC)
   342  		ld := arm64.ALDAXR
   343  		st := arm64.ASTLXR
   344  		if v.Op == ssa.OpARM64LoweredAtomicExchange32 {
   345  			ld = arm64.ALDAXRW
   346  			st = arm64.ASTLXRW
   347  		}
   348  		r0 := v.Args[0].Reg()
   349  		r1 := v.Args[1].Reg()
   350  		out := v.Reg0()
   351  		p := s.Prog(ld)
   352  		p.From.Type = obj.TYPE_MEM
   353  		p.From.Reg = r0
   354  		p.To.Type = obj.TYPE_REG
   355  		p.To.Reg = out
   356  		p1 := s.Prog(st)
   357  		p1.From.Type = obj.TYPE_REG
   358  		p1.From.Reg = r1
   359  		p1.To.Type = obj.TYPE_MEM
   360  		p1.To.Reg = r0
   361  		p1.RegTo2 = arm64.REGTMP
   362  		p2 := s.Prog(arm64.ACBNZ)
   363  		p2.From.Type = obj.TYPE_REG
   364  		p2.From.Reg = arm64.REGTMP
   365  		p2.To.Type = obj.TYPE_BRANCH
   366  		gc.Patch(p2, p)
   367  	case ssa.OpARM64LoweredAtomicAdd64,
   368  		ssa.OpARM64LoweredAtomicAdd32:
   369  		// LDAXR	(Rarg0), Rout
   370  		// ADD		Rarg1, Rout
   371  		// STLXR	Rout, (Rarg0), Rtmp
   372  		// CBNZ		Rtmp, -3(PC)
   373  		ld := arm64.ALDAXR
   374  		st := arm64.ASTLXR
   375  		if v.Op == ssa.OpARM64LoweredAtomicAdd32 {
   376  			ld = arm64.ALDAXRW
   377  			st = arm64.ASTLXRW
   378  		}
   379  		r0 := v.Args[0].Reg()
   380  		r1 := v.Args[1].Reg()
   381  		out := v.Reg0()
   382  		p := s.Prog(ld)
   383  		p.From.Type = obj.TYPE_MEM
   384  		p.From.Reg = r0
   385  		p.To.Type = obj.TYPE_REG
   386  		p.To.Reg = out
   387  		p1 := s.Prog(arm64.AADD)
   388  		p1.From.Type = obj.TYPE_REG
   389  		p1.From.Reg = r1
   390  		p1.To.Type = obj.TYPE_REG
   391  		p1.To.Reg = out
   392  		p2 := s.Prog(st)
   393  		p2.From.Type = obj.TYPE_REG
   394  		p2.From.Reg = out
   395  		p2.To.Type = obj.TYPE_MEM
   396  		p2.To.Reg = r0
   397  		p2.RegTo2 = arm64.REGTMP
   398  		p3 := s.Prog(arm64.ACBNZ)
   399  		p3.From.Type = obj.TYPE_REG
   400  		p3.From.Reg = arm64.REGTMP
   401  		p3.To.Type = obj.TYPE_BRANCH
   402  		gc.Patch(p3, p)
   403  	case ssa.OpARM64LoweredAtomicCas64,
   404  		ssa.OpARM64LoweredAtomicCas32:
   405  		// LDAXR	(Rarg0), Rtmp
   406  		// CMP		Rarg1, Rtmp
   407  		// BNE		3(PC)
   408  		// STLXR	Rarg2, (Rarg0), Rtmp
   409  		// CBNZ		Rtmp, -4(PC)
   410  		// CSET		EQ, Rout
   411  		ld := arm64.ALDAXR
   412  		st := arm64.ASTLXR
   413  		cmp := arm64.ACMP
   414  		if v.Op == ssa.OpARM64LoweredAtomicCas32 {
   415  			ld = arm64.ALDAXRW
   416  			st = arm64.ASTLXRW
   417  			cmp = arm64.ACMPW
   418  		}
   419  		r0 := v.Args[0].Reg()
   420  		r1 := v.Args[1].Reg()
   421  		r2 := v.Args[2].Reg()
   422  		out := v.Reg0()
   423  		p := s.Prog(ld)
   424  		p.From.Type = obj.TYPE_MEM
   425  		p.From.Reg = r0
   426  		p.To.Type = obj.TYPE_REG
   427  		p.To.Reg = arm64.REGTMP
   428  		p1 := s.Prog(cmp)
   429  		p1.From.Type = obj.TYPE_REG
   430  		p1.From.Reg = r1
   431  		p1.Reg = arm64.REGTMP
   432  		p2 := s.Prog(arm64.ABNE)
   433  		p2.To.Type = obj.TYPE_BRANCH
   434  		p3 := s.Prog(st)
   435  		p3.From.Type = obj.TYPE_REG
   436  		p3.From.Reg = r2
   437  		p3.To.Type = obj.TYPE_MEM
   438  		p3.To.Reg = r0
   439  		p3.RegTo2 = arm64.REGTMP
   440  		p4 := s.Prog(arm64.ACBNZ)
   441  		p4.From.Type = obj.TYPE_REG
   442  		p4.From.Reg = arm64.REGTMP
   443  		p4.To.Type = obj.TYPE_BRANCH
   444  		gc.Patch(p4, p)
   445  		p5 := s.Prog(arm64.ACSET)
   446  		p5.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
   447  		p5.From.Reg = arm64.COND_EQ
   448  		p5.To.Type = obj.TYPE_REG
   449  		p5.To.Reg = out
   450  		gc.Patch(p2, p5)
   451  	case ssa.OpARM64LoweredAtomicAnd8,
   452  		ssa.OpARM64LoweredAtomicOr8:
   453  		// LDAXRB	(Rarg0), Rtmp
   454  		// AND/OR	Rarg1, Rtmp
   455  		// STLXRB	Rtmp, (Rarg0), Rtmp
   456  		// CBNZ		Rtmp, -3(PC)
   457  		r0 := v.Args[0].Reg()
   458  		r1 := v.Args[1].Reg()
   459  		p := s.Prog(arm64.ALDAXRB)
   460  		p.From.Type = obj.TYPE_MEM
   461  		p.From.Reg = r0
   462  		p.To.Type = obj.TYPE_REG
   463  		p.To.Reg = arm64.REGTMP
   464  		p1 := s.Prog(v.Op.Asm())
   465  		p1.From.Type = obj.TYPE_REG
   466  		p1.From.Reg = r1
   467  		p1.To.Type = obj.TYPE_REG
   468  		p1.To.Reg = arm64.REGTMP
   469  		p2 := s.Prog(arm64.ASTLXRB)
   470  		p2.From.Type = obj.TYPE_REG
   471  		p2.From.Reg = arm64.REGTMP
   472  		p2.To.Type = obj.TYPE_MEM
   473  		p2.To.Reg = r0
   474  		p2.RegTo2 = arm64.REGTMP
   475  		p3 := s.Prog(arm64.ACBNZ)
   476  		p3.From.Type = obj.TYPE_REG
   477  		p3.From.Reg = arm64.REGTMP
   478  		p3.To.Type = obj.TYPE_BRANCH
   479  		gc.Patch(p3, p)
   480  	case ssa.OpARM64MOVBreg,
   481  		ssa.OpARM64MOVBUreg,
   482  		ssa.OpARM64MOVHreg,
   483  		ssa.OpARM64MOVHUreg,
   484  		ssa.OpARM64MOVWreg,
   485  		ssa.OpARM64MOVWUreg:
   486  		a := v.Args[0]
   487  		for a.Op == ssa.OpCopy || a.Op == ssa.OpARM64MOVDreg {
   488  			a = a.Args[0]
   489  		}
   490  		if a.Op == ssa.OpLoadReg {
   491  			t := a.Type
   492  			switch {
   493  			case v.Op == ssa.OpARM64MOVBreg && t.Size() == 1 && t.IsSigned(),
   494  				v.Op == ssa.OpARM64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
   495  				v.Op == ssa.OpARM64MOVHreg && t.Size() == 2 && t.IsSigned(),
   496  				v.Op == ssa.OpARM64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
   497  				v.Op == ssa.OpARM64MOVWreg && t.Size() == 4 && t.IsSigned(),
   498  				v.Op == ssa.OpARM64MOVWUreg && t.Size() == 4 && !t.IsSigned():
   499  				// arg is a proper-typed load, already zero/sign-extended, don't extend again
   500  				if v.Reg() == v.Args[0].Reg() {
   501  					return
   502  				}
   503  				p := s.Prog(arm64.AMOVD)
   504  				p.From.Type = obj.TYPE_REG
   505  				p.From.Reg = v.Args[0].Reg()
   506  				p.To.Type = obj.TYPE_REG
   507  				p.To.Reg = v.Reg()
   508  				return
   509  			default:
   510  			}
   511  		}
   512  		fallthrough
   513  	case ssa.OpARM64MVN,
   514  		ssa.OpARM64NEG,
   515  		ssa.OpARM64FNEGS,
   516  		ssa.OpARM64FNEGD,
   517  		ssa.OpARM64FSQRTD,
   518  		ssa.OpARM64FCVTZSSW,
   519  		ssa.OpARM64FCVTZSDW,
   520  		ssa.OpARM64FCVTZUSW,
   521  		ssa.OpARM64FCVTZUDW,
   522  		ssa.OpARM64FCVTZSS,
   523  		ssa.OpARM64FCVTZSD,
   524  		ssa.OpARM64FCVTZUS,
   525  		ssa.OpARM64FCVTZUD,
   526  		ssa.OpARM64SCVTFWS,
   527  		ssa.OpARM64SCVTFWD,
   528  		ssa.OpARM64SCVTFS,
   529  		ssa.OpARM64SCVTFD,
   530  		ssa.OpARM64UCVTFWS,
   531  		ssa.OpARM64UCVTFWD,
   532  		ssa.OpARM64UCVTFS,
   533  		ssa.OpARM64UCVTFD,
   534  		ssa.OpARM64FCVTSD,
   535  		ssa.OpARM64FCVTDS,
   536  		ssa.OpARM64REV,
   537  		ssa.OpARM64REVW,
   538  		ssa.OpARM64REV16W,
   539  		ssa.OpARM64RBIT,
   540  		ssa.OpARM64RBITW,
   541  		ssa.OpARM64CLZ,
   542  		ssa.OpARM64CLZW:
   543  		p := s.Prog(v.Op.Asm())
   544  		p.From.Type = obj.TYPE_REG
   545  		p.From.Reg = v.Args[0].Reg()
   546  		p.To.Type = obj.TYPE_REG
   547  		p.To.Reg = v.Reg()
   548  	case ssa.OpARM64CSELULT,
   549  		ssa.OpARM64CSELULT0:
   550  		r1 := int16(arm64.REGZERO)
   551  		if v.Op == ssa.OpARM64CSELULT {
   552  			r1 = v.Args[1].Reg()
   553  		}
   554  		p := s.Prog(v.Op.Asm())
   555  		p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
   556  		p.From.Reg = arm64.COND_LO
   557  		p.Reg = v.Args[0].Reg()
   558  		p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r1}
   559  		p.To.Type = obj.TYPE_REG
   560  		p.To.Reg = v.Reg()
   561  	case ssa.OpARM64DUFFZERO:
   562  		// runtime.duffzero expects start address - 8 in R16
   563  		p := s.Prog(arm64.ASUB)
   564  		p.From.Type = obj.TYPE_CONST
   565  		p.From.Offset = 8
   566  		p.Reg = v.Args[0].Reg()
   567  		p.To.Type = obj.TYPE_REG
   568  		p.To.Reg = arm64.REG_R16
   569  		p = s.Prog(obj.ADUFFZERO)
   570  		p.To.Type = obj.TYPE_MEM
   571  		p.To.Name = obj.NAME_EXTERN
   572  		p.To.Sym = gc.Duffzero
   573  		p.To.Offset = v.AuxInt
   574  	case ssa.OpARM64LoweredZero:
   575  		// MOVD.P	ZR, 8(R16)
   576  		// CMP	Rarg1, R16
   577  		// BLE	-2(PC)
   578  		// arg1 is the address of the last element to zero
   579  		p := s.Prog(arm64.AMOVD)
   580  		p.Scond = arm64.C_XPOST
   581  		p.From.Type = obj.TYPE_REG
   582  		p.From.Reg = arm64.REGZERO
   583  		p.To.Type = obj.TYPE_MEM
   584  		p.To.Reg = arm64.REG_R16
   585  		p.To.Offset = 8
   586  		p2 := s.Prog(arm64.ACMP)
   587  		p2.From.Type = obj.TYPE_REG
   588  		p2.From.Reg = v.Args[1].Reg()
   589  		p2.Reg = arm64.REG_R16
   590  		p3 := s.Prog(arm64.ABLE)
   591  		p3.To.Type = obj.TYPE_BRANCH
   592  		gc.Patch(p3, p)
   593  	case ssa.OpARM64DUFFCOPY:
   594  		p := s.Prog(obj.ADUFFCOPY)
   595  		p.To.Type = obj.TYPE_MEM
   596  		p.To.Name = obj.NAME_EXTERN
   597  		p.To.Sym = gc.Duffcopy
   598  		p.To.Offset = v.AuxInt
   599  	case ssa.OpARM64LoweredMove:
   600  		// MOVD.P	8(R16), Rtmp
   601  		// MOVD.P	Rtmp, 8(R17)
   602  		// CMP	Rarg2, R16
   603  		// BLE	-3(PC)
   604  		// arg2 is the address of the last element of src
   605  		p := s.Prog(arm64.AMOVD)
   606  		p.Scond = arm64.C_XPOST
   607  		p.From.Type = obj.TYPE_MEM
   608  		p.From.Reg = arm64.REG_R16
   609  		p.From.Offset = 8
   610  		p.To.Type = obj.TYPE_REG
   611  		p.To.Reg = arm64.REGTMP
   612  		p2 := s.Prog(arm64.AMOVD)
   613  		p2.Scond = arm64.C_XPOST
   614  		p2.From.Type = obj.TYPE_REG
   615  		p2.From.Reg = arm64.REGTMP
   616  		p2.To.Type = obj.TYPE_MEM
   617  		p2.To.Reg = arm64.REG_R17
   618  		p2.To.Offset = 8
   619  		p3 := s.Prog(arm64.ACMP)
   620  		p3.From.Type = obj.TYPE_REG
   621  		p3.From.Reg = v.Args[2].Reg()
   622  		p3.Reg = arm64.REG_R16
   623  		p4 := s.Prog(arm64.ABLE)
   624  		p4.To.Type = obj.TYPE_BRANCH
   625  		gc.Patch(p4, p)
   626  	case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter:
   627  		s.Call(v)
   628  	case ssa.OpARM64LoweredNilCheck:
   629  		// Issue a load which will fault if arg is nil.
   630  		p := s.Prog(arm64.AMOVB)
   631  		p.From.Type = obj.TYPE_MEM
   632  		p.From.Reg = v.Args[0].Reg()
   633  		gc.AddAux(&p.From, v)
   634  		p.To.Type = obj.TYPE_REG
   635  		p.To.Reg = arm64.REGTMP
   636  		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Line==1 in generated wrappers
   637  			gc.Warnl(v.Pos, "generated nil check")
   638  		}
   639  	case ssa.OpARM64Equal,
   640  		ssa.OpARM64NotEqual,
   641  		ssa.OpARM64LessThan,
   642  		ssa.OpARM64LessEqual,
   643  		ssa.OpARM64GreaterThan,
   644  		ssa.OpARM64GreaterEqual,
   645  		ssa.OpARM64LessThanU,
   646  		ssa.OpARM64LessEqualU,
   647  		ssa.OpARM64GreaterThanU,
   648  		ssa.OpARM64GreaterEqualU:
   649  		// generate boolean values using CSET
   650  		p := s.Prog(arm64.ACSET)
   651  		p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
   652  		p.From.Reg = condBits[v.Op]
   653  		p.To.Type = obj.TYPE_REG
   654  		p.To.Reg = v.Reg()
   655  	case ssa.OpARM64LoweredGetClosurePtr:
   656  		// Closure pointer is R26 (arm64.REGCTXT).
   657  		gc.CheckLoweredGetClosurePtr(v)
   658  	case ssa.OpARM64FlagEQ,
   659  		ssa.OpARM64FlagLT_ULT,
   660  		ssa.OpARM64FlagLT_UGT,
   661  		ssa.OpARM64FlagGT_ULT,
   662  		ssa.OpARM64FlagGT_UGT:
   663  		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
   664  	case ssa.OpARM64InvertFlags:
   665  		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
   666  	case ssa.OpClobber:
   667  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   668  	default:
   669  		v.Fatalf("genValue not implemented: %s", v.LongString())
   670  	}
   671  }
   672  
   673  var condBits = map[ssa.Op]int16{
   674  	ssa.OpARM64Equal:         arm64.COND_EQ,
   675  	ssa.OpARM64NotEqual:      arm64.COND_NE,
   676  	ssa.OpARM64LessThan:      arm64.COND_LT,
   677  	ssa.OpARM64LessThanU:     arm64.COND_LO,
   678  	ssa.OpARM64LessEqual:     arm64.COND_LE,
   679  	ssa.OpARM64LessEqualU:    arm64.COND_LS,
   680  	ssa.OpARM64GreaterThan:   arm64.COND_GT,
   681  	ssa.OpARM64GreaterThanU:  arm64.COND_HI,
   682  	ssa.OpARM64GreaterEqual:  arm64.COND_GE,
   683  	ssa.OpARM64GreaterEqualU: arm64.COND_HS,
   684  }
   685  
   686  var blockJump = map[ssa.BlockKind]struct {
   687  	asm, invasm obj.As
   688  }{
   689  	ssa.BlockARM64EQ:  {arm64.ABEQ, arm64.ABNE},
   690  	ssa.BlockARM64NE:  {arm64.ABNE, arm64.ABEQ},
   691  	ssa.BlockARM64LT:  {arm64.ABLT, arm64.ABGE},
   692  	ssa.BlockARM64GE:  {arm64.ABGE, arm64.ABLT},
   693  	ssa.BlockARM64LE:  {arm64.ABLE, arm64.ABGT},
   694  	ssa.BlockARM64GT:  {arm64.ABGT, arm64.ABLE},
   695  	ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
   696  	ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
   697  	ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
   698  	ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
   699  	ssa.BlockARM64Z:   {arm64.ACBZ, arm64.ACBNZ},
   700  	ssa.BlockARM64NZ:  {arm64.ACBNZ, arm64.ACBZ},
   701  	ssa.BlockARM64ZW:  {arm64.ACBZW, arm64.ACBNZW},
   702  	ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
   703  }
   704  
   705  func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   706  	switch b.Kind {
   707  	case ssa.BlockPlain:
   708  		if b.Succs[0].Block() != next {
   709  			p := s.Prog(obj.AJMP)
   710  			p.To.Type = obj.TYPE_BRANCH
   711  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   712  		}
   713  
   714  	case ssa.BlockDefer:
   715  		// defer returns in R0:
   716  		// 0 if we should continue executing
   717  		// 1 if we should jump to deferreturn call
   718  		p := s.Prog(arm64.ACMP)
   719  		p.From.Type = obj.TYPE_CONST
   720  		p.From.Offset = 0
   721  		p.Reg = arm64.REG_R0
   722  		p = s.Prog(arm64.ABNE)
   723  		p.To.Type = obj.TYPE_BRANCH
   724  		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   725  		if b.Succs[0].Block() != next {
   726  			p := s.Prog(obj.AJMP)
   727  			p.To.Type = obj.TYPE_BRANCH
   728  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   729  		}
   730  
   731  	case ssa.BlockExit:
   732  		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
   733  
   734  	case ssa.BlockRet:
   735  		s.Prog(obj.ARET)
   736  
   737  	case ssa.BlockRetJmp:
   738  		p := s.Prog(obj.ARET)
   739  		p.To.Type = obj.TYPE_MEM
   740  		p.To.Name = obj.NAME_EXTERN
   741  		p.To.Sym = b.Aux.(*obj.LSym)
   742  
   743  	case ssa.BlockARM64EQ, ssa.BlockARM64NE,
   744  		ssa.BlockARM64LT, ssa.BlockARM64GE,
   745  		ssa.BlockARM64LE, ssa.BlockARM64GT,
   746  		ssa.BlockARM64ULT, ssa.BlockARM64UGT,
   747  		ssa.BlockARM64ULE, ssa.BlockARM64UGE,
   748  		ssa.BlockARM64Z, ssa.BlockARM64NZ,
   749  		ssa.BlockARM64ZW, ssa.BlockARM64NZW:
   750  		jmp := blockJump[b.Kind]
   751  		var p *obj.Prog
   752  		switch next {
   753  		case b.Succs[0].Block():
   754  			p = s.Prog(jmp.invasm)
   755  			p.To.Type = obj.TYPE_BRANCH
   756  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   757  		case b.Succs[1].Block():
   758  			p = s.Prog(jmp.asm)
   759  			p.To.Type = obj.TYPE_BRANCH
   760  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   761  		default:
   762  			p = s.Prog(jmp.asm)
   763  			p.To.Type = obj.TYPE_BRANCH
   764  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   765  			q := s.Prog(obj.AJMP)
   766  			q.To.Type = obj.TYPE_BRANCH
   767  			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
   768  		}
   769  		if !b.Control.Type.IsFlags() {
   770  			p.From.Type = obj.TYPE_REG
   771  			p.From.Reg = b.Control.Reg()
   772  		}
   773  
   774  	default:
   775  		b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
   776  	}
   777  }