github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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 *obj.LSym:
   277  			wantreg = "SB"
   278  			gc.AddAux(&p.From, v)
   279  		case *gc.Node:
   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.OpARM64STP:
   328  		p := s.Prog(v.Op.Asm())
   329  		p.From.Type = obj.TYPE_REGREG
   330  		p.From.Reg = v.Args[1].Reg()
   331  		p.From.Offset = int64(v.Args[2].Reg())
   332  		p.To.Type = obj.TYPE_MEM
   333  		p.To.Reg = v.Args[0].Reg()
   334  		gc.AddAux(&p.To, v)
   335  	case ssa.OpARM64MOVBstorezero,
   336  		ssa.OpARM64MOVHstorezero,
   337  		ssa.OpARM64MOVWstorezero,
   338  		ssa.OpARM64MOVDstorezero:
   339  		p := s.Prog(v.Op.Asm())
   340  		p.From.Type = obj.TYPE_REG
   341  		p.From.Reg = arm64.REGZERO
   342  		p.To.Type = obj.TYPE_MEM
   343  		p.To.Reg = v.Args[0].Reg()
   344  		gc.AddAux(&p.To, v)
   345  	case ssa.OpARM64MOVQstorezero:
   346  		p := s.Prog(v.Op.Asm())
   347  		p.From.Type = obj.TYPE_REGREG
   348  		p.From.Reg = arm64.REGZERO
   349  		p.From.Offset = int64(arm64.REGZERO)
   350  		p.To.Type = obj.TYPE_MEM
   351  		p.To.Reg = v.Args[0].Reg()
   352  		gc.AddAux(&p.To, v)
   353  	case ssa.OpARM64LoweredAtomicExchange64,
   354  		ssa.OpARM64LoweredAtomicExchange32:
   355  		// LDAXR	(Rarg0), Rout
   356  		// STLXR	Rarg1, (Rarg0), Rtmp
   357  		// CBNZ		Rtmp, -2(PC)
   358  		ld := arm64.ALDAXR
   359  		st := arm64.ASTLXR
   360  		if v.Op == ssa.OpARM64LoweredAtomicExchange32 {
   361  			ld = arm64.ALDAXRW
   362  			st = arm64.ASTLXRW
   363  		}
   364  		r0 := v.Args[0].Reg()
   365  		r1 := v.Args[1].Reg()
   366  		out := v.Reg0()
   367  		p := s.Prog(ld)
   368  		p.From.Type = obj.TYPE_MEM
   369  		p.From.Reg = r0
   370  		p.To.Type = obj.TYPE_REG
   371  		p.To.Reg = out
   372  		p1 := s.Prog(st)
   373  		p1.From.Type = obj.TYPE_REG
   374  		p1.From.Reg = r1
   375  		p1.To.Type = obj.TYPE_MEM
   376  		p1.To.Reg = r0
   377  		p1.RegTo2 = arm64.REGTMP
   378  		p2 := s.Prog(arm64.ACBNZ)
   379  		p2.From.Type = obj.TYPE_REG
   380  		p2.From.Reg = arm64.REGTMP
   381  		p2.To.Type = obj.TYPE_BRANCH
   382  		gc.Patch(p2, p)
   383  	case ssa.OpARM64LoweredAtomicAdd64,
   384  		ssa.OpARM64LoweredAtomicAdd32:
   385  		// LDAXR	(Rarg0), Rout
   386  		// ADD		Rarg1, Rout
   387  		// STLXR	Rout, (Rarg0), Rtmp
   388  		// CBNZ		Rtmp, -3(PC)
   389  		ld := arm64.ALDAXR
   390  		st := arm64.ASTLXR
   391  		if v.Op == ssa.OpARM64LoweredAtomicAdd32 {
   392  			ld = arm64.ALDAXRW
   393  			st = arm64.ASTLXRW
   394  		}
   395  		r0 := v.Args[0].Reg()
   396  		r1 := v.Args[1].Reg()
   397  		out := v.Reg0()
   398  		p := s.Prog(ld)
   399  		p.From.Type = obj.TYPE_MEM
   400  		p.From.Reg = r0
   401  		p.To.Type = obj.TYPE_REG
   402  		p.To.Reg = out
   403  		p1 := s.Prog(arm64.AADD)
   404  		p1.From.Type = obj.TYPE_REG
   405  		p1.From.Reg = r1
   406  		p1.To.Type = obj.TYPE_REG
   407  		p1.To.Reg = out
   408  		p2 := s.Prog(st)
   409  		p2.From.Type = obj.TYPE_REG
   410  		p2.From.Reg = out
   411  		p2.To.Type = obj.TYPE_MEM
   412  		p2.To.Reg = r0
   413  		p2.RegTo2 = arm64.REGTMP
   414  		p3 := s.Prog(arm64.ACBNZ)
   415  		p3.From.Type = obj.TYPE_REG
   416  		p3.From.Reg = arm64.REGTMP
   417  		p3.To.Type = obj.TYPE_BRANCH
   418  		gc.Patch(p3, p)
   419  	case ssa.OpARM64LoweredAtomicCas64,
   420  		ssa.OpARM64LoweredAtomicCas32:
   421  		// LDAXR	(Rarg0), Rtmp
   422  		// CMP		Rarg1, Rtmp
   423  		// BNE		3(PC)
   424  		// STLXR	Rarg2, (Rarg0), Rtmp
   425  		// CBNZ		Rtmp, -4(PC)
   426  		// CSET		EQ, Rout
   427  		ld := arm64.ALDAXR
   428  		st := arm64.ASTLXR
   429  		cmp := arm64.ACMP
   430  		if v.Op == ssa.OpARM64LoweredAtomicCas32 {
   431  			ld = arm64.ALDAXRW
   432  			st = arm64.ASTLXRW
   433  			cmp = arm64.ACMPW
   434  		}
   435  		r0 := v.Args[0].Reg()
   436  		r1 := v.Args[1].Reg()
   437  		r2 := v.Args[2].Reg()
   438  		out := v.Reg0()
   439  		p := s.Prog(ld)
   440  		p.From.Type = obj.TYPE_MEM
   441  		p.From.Reg = r0
   442  		p.To.Type = obj.TYPE_REG
   443  		p.To.Reg = arm64.REGTMP
   444  		p1 := s.Prog(cmp)
   445  		p1.From.Type = obj.TYPE_REG
   446  		p1.From.Reg = r1
   447  		p1.Reg = arm64.REGTMP
   448  		p2 := s.Prog(arm64.ABNE)
   449  		p2.To.Type = obj.TYPE_BRANCH
   450  		p3 := s.Prog(st)
   451  		p3.From.Type = obj.TYPE_REG
   452  		p3.From.Reg = r2
   453  		p3.To.Type = obj.TYPE_MEM
   454  		p3.To.Reg = r0
   455  		p3.RegTo2 = arm64.REGTMP
   456  		p4 := s.Prog(arm64.ACBNZ)
   457  		p4.From.Type = obj.TYPE_REG
   458  		p4.From.Reg = arm64.REGTMP
   459  		p4.To.Type = obj.TYPE_BRANCH
   460  		gc.Patch(p4, p)
   461  		p5 := s.Prog(arm64.ACSET)
   462  		p5.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
   463  		p5.From.Reg = arm64.COND_EQ
   464  		p5.To.Type = obj.TYPE_REG
   465  		p5.To.Reg = out
   466  		gc.Patch(p2, p5)
   467  	case ssa.OpARM64LoweredAtomicAnd8,
   468  		ssa.OpARM64LoweredAtomicOr8:
   469  		// LDAXRB	(Rarg0), Rtmp
   470  		// AND/OR	Rarg1, Rtmp
   471  		// STLXRB	Rtmp, (Rarg0), Rtmp
   472  		// CBNZ		Rtmp, -3(PC)
   473  		r0 := v.Args[0].Reg()
   474  		r1 := v.Args[1].Reg()
   475  		p := s.Prog(arm64.ALDAXRB)
   476  		p.From.Type = obj.TYPE_MEM
   477  		p.From.Reg = r0
   478  		p.To.Type = obj.TYPE_REG
   479  		p.To.Reg = arm64.REGTMP
   480  		p1 := s.Prog(v.Op.Asm())
   481  		p1.From.Type = obj.TYPE_REG
   482  		p1.From.Reg = r1
   483  		p1.To.Type = obj.TYPE_REG
   484  		p1.To.Reg = arm64.REGTMP
   485  		p2 := s.Prog(arm64.ASTLXRB)
   486  		p2.From.Type = obj.TYPE_REG
   487  		p2.From.Reg = arm64.REGTMP
   488  		p2.To.Type = obj.TYPE_MEM
   489  		p2.To.Reg = r0
   490  		p2.RegTo2 = arm64.REGTMP
   491  		p3 := s.Prog(arm64.ACBNZ)
   492  		p3.From.Type = obj.TYPE_REG
   493  		p3.From.Reg = arm64.REGTMP
   494  		p3.To.Type = obj.TYPE_BRANCH
   495  		gc.Patch(p3, p)
   496  	case ssa.OpARM64MOVBreg,
   497  		ssa.OpARM64MOVBUreg,
   498  		ssa.OpARM64MOVHreg,
   499  		ssa.OpARM64MOVHUreg,
   500  		ssa.OpARM64MOVWreg,
   501  		ssa.OpARM64MOVWUreg:
   502  		a := v.Args[0]
   503  		for a.Op == ssa.OpCopy || a.Op == ssa.OpARM64MOVDreg {
   504  			a = a.Args[0]
   505  		}
   506  		if a.Op == ssa.OpLoadReg {
   507  			t := a.Type
   508  			switch {
   509  			case v.Op == ssa.OpARM64MOVBreg && t.Size() == 1 && t.IsSigned(),
   510  				v.Op == ssa.OpARM64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
   511  				v.Op == ssa.OpARM64MOVHreg && t.Size() == 2 && t.IsSigned(),
   512  				v.Op == ssa.OpARM64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
   513  				v.Op == ssa.OpARM64MOVWreg && t.Size() == 4 && t.IsSigned(),
   514  				v.Op == ssa.OpARM64MOVWUreg && t.Size() == 4 && !t.IsSigned():
   515  				// arg is a proper-typed load, already zero/sign-extended, don't extend again
   516  				if v.Reg() == v.Args[0].Reg() {
   517  					return
   518  				}
   519  				p := s.Prog(arm64.AMOVD)
   520  				p.From.Type = obj.TYPE_REG
   521  				p.From.Reg = v.Args[0].Reg()
   522  				p.To.Type = obj.TYPE_REG
   523  				p.To.Reg = v.Reg()
   524  				return
   525  			default:
   526  			}
   527  		}
   528  		fallthrough
   529  	case ssa.OpARM64MVN,
   530  		ssa.OpARM64NEG,
   531  		ssa.OpARM64FNEGS,
   532  		ssa.OpARM64FNEGD,
   533  		ssa.OpARM64FSQRTD,
   534  		ssa.OpARM64FCVTZSSW,
   535  		ssa.OpARM64FCVTZSDW,
   536  		ssa.OpARM64FCVTZUSW,
   537  		ssa.OpARM64FCVTZUDW,
   538  		ssa.OpARM64FCVTZSS,
   539  		ssa.OpARM64FCVTZSD,
   540  		ssa.OpARM64FCVTZUS,
   541  		ssa.OpARM64FCVTZUD,
   542  		ssa.OpARM64SCVTFWS,
   543  		ssa.OpARM64SCVTFWD,
   544  		ssa.OpARM64SCVTFS,
   545  		ssa.OpARM64SCVTFD,
   546  		ssa.OpARM64UCVTFWS,
   547  		ssa.OpARM64UCVTFWD,
   548  		ssa.OpARM64UCVTFS,
   549  		ssa.OpARM64UCVTFD,
   550  		ssa.OpARM64FCVTSD,
   551  		ssa.OpARM64FCVTDS,
   552  		ssa.OpARM64REV,
   553  		ssa.OpARM64REVW,
   554  		ssa.OpARM64REV16W,
   555  		ssa.OpARM64RBIT,
   556  		ssa.OpARM64RBITW,
   557  		ssa.OpARM64CLZ,
   558  		ssa.OpARM64CLZW:
   559  		p := s.Prog(v.Op.Asm())
   560  		p.From.Type = obj.TYPE_REG
   561  		p.From.Reg = v.Args[0].Reg()
   562  		p.To.Type = obj.TYPE_REG
   563  		p.To.Reg = v.Reg()
   564  	case ssa.OpARM64CSELULT,
   565  		ssa.OpARM64CSELULT0:
   566  		r1 := int16(arm64.REGZERO)
   567  		if v.Op == ssa.OpARM64CSELULT {
   568  			r1 = v.Args[1].Reg()
   569  		}
   570  		p := s.Prog(v.Op.Asm())
   571  		p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
   572  		p.From.Reg = arm64.COND_LO
   573  		p.Reg = v.Args[0].Reg()
   574  		p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r1})
   575  		p.To.Type = obj.TYPE_REG
   576  		p.To.Reg = v.Reg()
   577  	case ssa.OpARM64DUFFZERO:
   578  		// runtime.duffzero expects start address in R16
   579  		p := s.Prog(obj.ADUFFZERO)
   580  		p.To.Type = obj.TYPE_MEM
   581  		p.To.Name = obj.NAME_EXTERN
   582  		p.To.Sym = gc.Duffzero
   583  		p.To.Offset = v.AuxInt
   584  	case ssa.OpARM64LoweredZero:
   585  		// STP.P	(ZR,ZR), 16(R16)
   586  		// CMP	Rarg1, R16
   587  		// BLE	-2(PC)
   588  		// arg1 is the address of the last 16-byte unit to zero
   589  		p := s.Prog(arm64.ASTP)
   590  		p.Scond = arm64.C_XPOST
   591  		p.From.Type = obj.TYPE_REGREG
   592  		p.From.Reg = arm64.REGZERO
   593  		p.From.Offset = int64(arm64.REGZERO)
   594  		p.To.Type = obj.TYPE_MEM
   595  		p.To.Reg = arm64.REG_R16
   596  		p.To.Offset = 16
   597  		p2 := s.Prog(arm64.ACMP)
   598  		p2.From.Type = obj.TYPE_REG
   599  		p2.From.Reg = v.Args[1].Reg()
   600  		p2.Reg = arm64.REG_R16
   601  		p3 := s.Prog(arm64.ABLE)
   602  		p3.To.Type = obj.TYPE_BRANCH
   603  		gc.Patch(p3, p)
   604  	case ssa.OpARM64DUFFCOPY:
   605  		p := s.Prog(obj.ADUFFCOPY)
   606  		p.To.Type = obj.TYPE_MEM
   607  		p.To.Name = obj.NAME_EXTERN
   608  		p.To.Sym = gc.Duffcopy
   609  		p.To.Offset = v.AuxInt
   610  	case ssa.OpARM64LoweredMove:
   611  		// MOVD.P	8(R16), Rtmp
   612  		// MOVD.P	Rtmp, 8(R17)
   613  		// CMP	Rarg2, R16
   614  		// BLE	-3(PC)
   615  		// arg2 is the address of the last element of src
   616  		p := s.Prog(arm64.AMOVD)
   617  		p.Scond = arm64.C_XPOST
   618  		p.From.Type = obj.TYPE_MEM
   619  		p.From.Reg = arm64.REG_R16
   620  		p.From.Offset = 8
   621  		p.To.Type = obj.TYPE_REG
   622  		p.To.Reg = arm64.REGTMP
   623  		p2 := s.Prog(arm64.AMOVD)
   624  		p2.Scond = arm64.C_XPOST
   625  		p2.From.Type = obj.TYPE_REG
   626  		p2.From.Reg = arm64.REGTMP
   627  		p2.To.Type = obj.TYPE_MEM
   628  		p2.To.Reg = arm64.REG_R17
   629  		p2.To.Offset = 8
   630  		p3 := s.Prog(arm64.ACMP)
   631  		p3.From.Type = obj.TYPE_REG
   632  		p3.From.Reg = v.Args[2].Reg()
   633  		p3.Reg = arm64.REG_R16
   634  		p4 := s.Prog(arm64.ABLE)
   635  		p4.To.Type = obj.TYPE_BRANCH
   636  		gc.Patch(p4, p)
   637  	case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter:
   638  		s.Call(v)
   639  	case ssa.OpARM64LoweredNilCheck:
   640  		// Issue a load which will fault if arg is nil.
   641  		p := s.Prog(arm64.AMOVB)
   642  		p.From.Type = obj.TYPE_MEM
   643  		p.From.Reg = v.Args[0].Reg()
   644  		gc.AddAux(&p.From, v)
   645  		p.To.Type = obj.TYPE_REG
   646  		p.To.Reg = arm64.REGTMP
   647  		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Line==1 in generated wrappers
   648  			gc.Warnl(v.Pos, "generated nil check")
   649  		}
   650  	case ssa.OpARM64Equal,
   651  		ssa.OpARM64NotEqual,
   652  		ssa.OpARM64LessThan,
   653  		ssa.OpARM64LessEqual,
   654  		ssa.OpARM64GreaterThan,
   655  		ssa.OpARM64GreaterEqual,
   656  		ssa.OpARM64LessThanU,
   657  		ssa.OpARM64LessEqualU,
   658  		ssa.OpARM64GreaterThanU,
   659  		ssa.OpARM64GreaterEqualU:
   660  		// generate boolean values using CSET
   661  		p := s.Prog(arm64.ACSET)
   662  		p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
   663  		p.From.Reg = condBits[v.Op]
   664  		p.To.Type = obj.TYPE_REG
   665  		p.To.Reg = v.Reg()
   666  	case ssa.OpARM64LoweredGetClosurePtr:
   667  		// Closure pointer is R26 (arm64.REGCTXT).
   668  		gc.CheckLoweredGetClosurePtr(v)
   669  	case ssa.OpARM64LoweredGetCallerSP:
   670  		// caller's SP is FixedFrameSize below the address of the first arg
   671  		p := s.Prog(arm64.AMOVD)
   672  		p.From.Type = obj.TYPE_ADDR
   673  		p.From.Offset = -gc.Ctxt.FixedFrameSize()
   674  		p.From.Name = obj.NAME_PARAM
   675  		p.To.Type = obj.TYPE_REG
   676  		p.To.Reg = v.Reg()
   677  	case ssa.OpARM64FlagEQ,
   678  		ssa.OpARM64FlagLT_ULT,
   679  		ssa.OpARM64FlagLT_UGT,
   680  		ssa.OpARM64FlagGT_ULT,
   681  		ssa.OpARM64FlagGT_UGT:
   682  		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
   683  	case ssa.OpARM64InvertFlags:
   684  		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
   685  	case ssa.OpClobber:
   686  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   687  	default:
   688  		v.Fatalf("genValue not implemented: %s", v.LongString())
   689  	}
   690  }
   691  
   692  var condBits = map[ssa.Op]int16{
   693  	ssa.OpARM64Equal:         arm64.COND_EQ,
   694  	ssa.OpARM64NotEqual:      arm64.COND_NE,
   695  	ssa.OpARM64LessThan:      arm64.COND_LT,
   696  	ssa.OpARM64LessThanU:     arm64.COND_LO,
   697  	ssa.OpARM64LessEqual:     arm64.COND_LE,
   698  	ssa.OpARM64LessEqualU:    arm64.COND_LS,
   699  	ssa.OpARM64GreaterThan:   arm64.COND_GT,
   700  	ssa.OpARM64GreaterThanU:  arm64.COND_HI,
   701  	ssa.OpARM64GreaterEqual:  arm64.COND_GE,
   702  	ssa.OpARM64GreaterEqualU: arm64.COND_HS,
   703  }
   704  
   705  var blockJump = map[ssa.BlockKind]struct {
   706  	asm, invasm obj.As
   707  }{
   708  	ssa.BlockARM64EQ:   {arm64.ABEQ, arm64.ABNE},
   709  	ssa.BlockARM64NE:   {arm64.ABNE, arm64.ABEQ},
   710  	ssa.BlockARM64LT:   {arm64.ABLT, arm64.ABGE},
   711  	ssa.BlockARM64GE:   {arm64.ABGE, arm64.ABLT},
   712  	ssa.BlockARM64LE:   {arm64.ABLE, arm64.ABGT},
   713  	ssa.BlockARM64GT:   {arm64.ABGT, arm64.ABLE},
   714  	ssa.BlockARM64ULT:  {arm64.ABLO, arm64.ABHS},
   715  	ssa.BlockARM64UGE:  {arm64.ABHS, arm64.ABLO},
   716  	ssa.BlockARM64UGT:  {arm64.ABHI, arm64.ABLS},
   717  	ssa.BlockARM64ULE:  {arm64.ABLS, arm64.ABHI},
   718  	ssa.BlockARM64Z:    {arm64.ACBZ, arm64.ACBNZ},
   719  	ssa.BlockARM64NZ:   {arm64.ACBNZ, arm64.ACBZ},
   720  	ssa.BlockARM64ZW:   {arm64.ACBZW, arm64.ACBNZW},
   721  	ssa.BlockARM64NZW:  {arm64.ACBNZW, arm64.ACBZW},
   722  	ssa.BlockARM64TBZ:  {arm64.ATBZ, arm64.ATBNZ},
   723  	ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ},
   724  }
   725  
   726  func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   727  	switch b.Kind {
   728  	case ssa.BlockPlain:
   729  		if b.Succs[0].Block() != next {
   730  			p := s.Prog(obj.AJMP)
   731  			p.To.Type = obj.TYPE_BRANCH
   732  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   733  		}
   734  
   735  	case ssa.BlockDefer:
   736  		// defer returns in R0:
   737  		// 0 if we should continue executing
   738  		// 1 if we should jump to deferreturn call
   739  		p := s.Prog(arm64.ACMP)
   740  		p.From.Type = obj.TYPE_CONST
   741  		p.From.Offset = 0
   742  		p.Reg = arm64.REG_R0
   743  		p = s.Prog(arm64.ABNE)
   744  		p.To.Type = obj.TYPE_BRANCH
   745  		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   746  		if b.Succs[0].Block() != next {
   747  			p := s.Prog(obj.AJMP)
   748  			p.To.Type = obj.TYPE_BRANCH
   749  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   750  		}
   751  
   752  	case ssa.BlockExit:
   753  		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
   754  
   755  	case ssa.BlockRet:
   756  		s.Prog(obj.ARET)
   757  
   758  	case ssa.BlockRetJmp:
   759  		p := s.Prog(obj.ARET)
   760  		p.To.Type = obj.TYPE_MEM
   761  		p.To.Name = obj.NAME_EXTERN
   762  		p.To.Sym = b.Aux.(*obj.LSym)
   763  
   764  	case ssa.BlockARM64EQ, ssa.BlockARM64NE,
   765  		ssa.BlockARM64LT, ssa.BlockARM64GE,
   766  		ssa.BlockARM64LE, ssa.BlockARM64GT,
   767  		ssa.BlockARM64ULT, ssa.BlockARM64UGT,
   768  		ssa.BlockARM64ULE, ssa.BlockARM64UGE,
   769  		ssa.BlockARM64Z, ssa.BlockARM64NZ,
   770  		ssa.BlockARM64ZW, ssa.BlockARM64NZW:
   771  		jmp := blockJump[b.Kind]
   772  		var p *obj.Prog
   773  		switch next {
   774  		case b.Succs[0].Block():
   775  			p = s.Prog(jmp.invasm)
   776  			p.To.Type = obj.TYPE_BRANCH
   777  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   778  		case b.Succs[1].Block():
   779  			p = s.Prog(jmp.asm)
   780  			p.To.Type = obj.TYPE_BRANCH
   781  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   782  		default:
   783  			p = s.Prog(jmp.asm)
   784  			p.To.Type = obj.TYPE_BRANCH
   785  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   786  			q := s.Prog(obj.AJMP)
   787  			q.To.Type = obj.TYPE_BRANCH
   788  			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
   789  		}
   790  		if !b.Control.Type.IsFlags() {
   791  			p.From.Type = obj.TYPE_REG
   792  			p.From.Reg = b.Control.Reg()
   793  		}
   794  	case ssa.BlockARM64TBZ, ssa.BlockARM64TBNZ:
   795  		jmp := blockJump[b.Kind]
   796  		var p *obj.Prog
   797  		switch next {
   798  		case b.Succs[0].Block():
   799  			p = s.Prog(jmp.invasm)
   800  			p.To.Type = obj.TYPE_BRANCH
   801  			p.From.Offset = b.Aux.(int64)
   802  			p.From.Type = obj.TYPE_CONST
   803  			p.Reg = b.Control.Reg()
   804  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   805  		case b.Succs[1].Block():
   806  			p = s.Prog(jmp.asm)
   807  			p.To.Type = obj.TYPE_BRANCH
   808  			p.From.Offset = b.Aux.(int64)
   809  			p.From.Type = obj.TYPE_CONST
   810  			p.Reg = b.Control.Reg()
   811  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   812  		default:
   813  			p = s.Prog(jmp.asm)
   814  			p.To.Type = obj.TYPE_BRANCH
   815  			p.From.Offset = b.Aux.(int64)
   816  			p.From.Type = obj.TYPE_CONST
   817  			p.Reg = b.Control.Reg()
   818  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   819  			q := s.Prog(obj.AJMP)
   820  			q.To.Type = obj.TYPE_BRANCH
   821  			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
   822  		}
   823  
   824  	default:
   825  		b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
   826  	}
   827  }