...

Source file src/cmd/compile/internal/riscv64/ssa.go

Documentation: cmd/compile/internal/riscv64

     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 riscv64
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  	"cmd/compile/internal/objw"
    11  	"cmd/compile/internal/ssa"
    12  	"cmd/compile/internal/ssagen"
    13  	"cmd/compile/internal/types"
    14  	"cmd/internal/obj"
    15  	"cmd/internal/obj/riscv"
    16  )
    17  
    18  // ssaRegToReg maps ssa register numbers to obj register numbers.
    19  var ssaRegToReg = []int16{
    20  	riscv.REG_X0,
    21  	// X1 (LR): unused
    22  	riscv.REG_X2,
    23  	riscv.REG_X3,
    24  	riscv.REG_X4,
    25  	riscv.REG_X5,
    26  	riscv.REG_X6,
    27  	riscv.REG_X7,
    28  	riscv.REG_X8,
    29  	riscv.REG_X9,
    30  	riscv.REG_X10,
    31  	riscv.REG_X11,
    32  	riscv.REG_X12,
    33  	riscv.REG_X13,
    34  	riscv.REG_X14,
    35  	riscv.REG_X15,
    36  	riscv.REG_X16,
    37  	riscv.REG_X17,
    38  	riscv.REG_X18,
    39  	riscv.REG_X19,
    40  	riscv.REG_X20,
    41  	riscv.REG_X21,
    42  	riscv.REG_X22,
    43  	riscv.REG_X23,
    44  	riscv.REG_X24,
    45  	riscv.REG_X25,
    46  	riscv.REG_X26,
    47  	riscv.REG_X27,
    48  	riscv.REG_X28,
    49  	riscv.REG_X29,
    50  	riscv.REG_X30,
    51  	riscv.REG_X31,
    52  	riscv.REG_F0,
    53  	riscv.REG_F1,
    54  	riscv.REG_F2,
    55  	riscv.REG_F3,
    56  	riscv.REG_F4,
    57  	riscv.REG_F5,
    58  	riscv.REG_F6,
    59  	riscv.REG_F7,
    60  	riscv.REG_F8,
    61  	riscv.REG_F9,
    62  	riscv.REG_F10,
    63  	riscv.REG_F11,
    64  	riscv.REG_F12,
    65  	riscv.REG_F13,
    66  	riscv.REG_F14,
    67  	riscv.REG_F15,
    68  	riscv.REG_F16,
    69  	riscv.REG_F17,
    70  	riscv.REG_F18,
    71  	riscv.REG_F19,
    72  	riscv.REG_F20,
    73  	riscv.REG_F21,
    74  	riscv.REG_F22,
    75  	riscv.REG_F23,
    76  	riscv.REG_F24,
    77  	riscv.REG_F25,
    78  	riscv.REG_F26,
    79  	riscv.REG_F27,
    80  	riscv.REG_F28,
    81  	riscv.REG_F29,
    82  	riscv.REG_F30,
    83  	riscv.REG_F31,
    84  	0, // SB isn't a real register.  We fill an Addr.Reg field with 0 in this case.
    85  }
    86  
    87  func loadByType(t *types.Type) obj.As {
    88  	width := t.Size()
    89  
    90  	if t.IsFloat() {
    91  		switch width {
    92  		case 4:
    93  			return riscv.AMOVF
    94  		case 8:
    95  			return riscv.AMOVD
    96  		default:
    97  			base.Fatalf("unknown float width for load %d in type %v", width, t)
    98  			return 0
    99  		}
   100  	}
   101  
   102  	switch width {
   103  	case 1:
   104  		if t.IsSigned() {
   105  			return riscv.AMOVB
   106  		} else {
   107  			return riscv.AMOVBU
   108  		}
   109  	case 2:
   110  		if t.IsSigned() {
   111  			return riscv.AMOVH
   112  		} else {
   113  			return riscv.AMOVHU
   114  		}
   115  	case 4:
   116  		if t.IsSigned() {
   117  			return riscv.AMOVW
   118  		} else {
   119  			return riscv.AMOVWU
   120  		}
   121  	case 8:
   122  		return riscv.AMOV
   123  	default:
   124  		base.Fatalf("unknown width for load %d in type %v", width, t)
   125  		return 0
   126  	}
   127  }
   128  
   129  // storeByType returns the store instruction of the given type.
   130  func storeByType(t *types.Type) obj.As {
   131  	width := t.Size()
   132  
   133  	if t.IsFloat() {
   134  		switch width {
   135  		case 4:
   136  			return riscv.AMOVF
   137  		case 8:
   138  			return riscv.AMOVD
   139  		default:
   140  			base.Fatalf("unknown float width for store %d in type %v", width, t)
   141  			return 0
   142  		}
   143  	}
   144  
   145  	switch width {
   146  	case 1:
   147  		return riscv.AMOVB
   148  	case 2:
   149  		return riscv.AMOVH
   150  	case 4:
   151  		return riscv.AMOVW
   152  	case 8:
   153  		return riscv.AMOV
   154  	default:
   155  		base.Fatalf("unknown width for store %d in type %v", width, t)
   156  		return 0
   157  	}
   158  }
   159  
   160  // largestMove returns the largest move instruction possible and its size,
   161  // given the alignment of the total size of the move.
   162  //
   163  // e.g., a 16-byte move may use MOV, but an 11-byte move must use MOVB.
   164  //
   165  // Note that the moves may not be on naturally aligned addresses depending on
   166  // the source and destination.
   167  //
   168  // This matches the calculation in ssa.moveSize.
   169  func largestMove(alignment int64) (obj.As, int64) {
   170  	switch {
   171  	case alignment%8 == 0:
   172  		return riscv.AMOV, 8
   173  	case alignment%4 == 0:
   174  		return riscv.AMOVW, 4
   175  	case alignment%2 == 0:
   176  		return riscv.AMOVH, 2
   177  	default:
   178  		return riscv.AMOVB, 1
   179  	}
   180  }
   181  
   182  // ssaMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
   183  // RISC-V has no flags, so this is a no-op.
   184  func ssaMarkMoves(s *ssagen.State, b *ssa.Block) {}
   185  
   186  func ssaGenValue(s *ssagen.State, v *ssa.Value) {
   187  	s.SetPos(v.Pos)
   188  
   189  	switch v.Op {
   190  	case ssa.OpInitMem:
   191  		// memory arg needs no code
   192  	case ssa.OpArg:
   193  		// input args need no code
   194  	case ssa.OpPhi:
   195  		ssagen.CheckLoweredPhi(v)
   196  	case ssa.OpCopy, ssa.OpRISCV64MOVDreg:
   197  		if v.Type.IsMemory() {
   198  			return
   199  		}
   200  		rs := v.Args[0].Reg()
   201  		rd := v.Reg()
   202  		if rs == rd {
   203  			return
   204  		}
   205  		as := riscv.AMOV
   206  		if v.Type.IsFloat() {
   207  			as = riscv.AMOVD
   208  		}
   209  		p := s.Prog(as)
   210  		p.From.Type = obj.TYPE_REG
   211  		p.From.Reg = rs
   212  		p.To.Type = obj.TYPE_REG
   213  		p.To.Reg = rd
   214  	case ssa.OpRISCV64MOVDnop:
   215  		// nothing to do
   216  	case ssa.OpLoadReg:
   217  		if v.Type.IsFlags() {
   218  			v.Fatalf("load flags not implemented: %v", v.LongString())
   219  			return
   220  		}
   221  		p := s.Prog(loadByType(v.Type))
   222  		ssagen.AddrAuto(&p.From, v.Args[0])
   223  		p.To.Type = obj.TYPE_REG
   224  		p.To.Reg = v.Reg()
   225  	case ssa.OpStoreReg:
   226  		if v.Type.IsFlags() {
   227  			v.Fatalf("store flags not implemented: %v", v.LongString())
   228  			return
   229  		}
   230  		p := s.Prog(storeByType(v.Type))
   231  		p.From.Type = obj.TYPE_REG
   232  		p.From.Reg = v.Args[0].Reg()
   233  		ssagen.AddrAuto(&p.To, v)
   234  	case ssa.OpArgIntReg, ssa.OpArgFloatReg:
   235  		// The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill
   236  		// The loop only runs once.
   237  		for _, a := range v.Block.Func.RegArgs {
   238  			// Pass the spill/unspill information along to the assembler, offset by size of
   239  			// the saved LR slot.
   240  			addr := ssagen.SpillSlotAddr(a, riscv.REG_SP, base.Ctxt.Arch.FixedFrameSize)
   241  			s.FuncInfo().AddSpill(
   242  				obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)})
   243  		}
   244  		v.Block.Func.RegArgs = nil
   245  
   246  		ssagen.CheckArgReg(v)
   247  	case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
   248  		// nothing to do
   249  	case ssa.OpRISCV64MOVBreg, ssa.OpRISCV64MOVHreg, ssa.OpRISCV64MOVWreg,
   250  		ssa.OpRISCV64MOVBUreg, ssa.OpRISCV64MOVHUreg, ssa.OpRISCV64MOVWUreg:
   251  		a := v.Args[0]
   252  		for a.Op == ssa.OpCopy || a.Op == ssa.OpRISCV64MOVDreg {
   253  			a = a.Args[0]
   254  		}
   255  		as := v.Op.Asm()
   256  		rs := v.Args[0].Reg()
   257  		rd := v.Reg()
   258  		if a.Op == ssa.OpLoadReg {
   259  			t := a.Type
   260  			switch {
   261  			case v.Op == ssa.OpRISCV64MOVBreg && t.Size() == 1 && t.IsSigned(),
   262  				v.Op == ssa.OpRISCV64MOVHreg && t.Size() == 2 && t.IsSigned(),
   263  				v.Op == ssa.OpRISCV64MOVWreg && t.Size() == 4 && t.IsSigned(),
   264  				v.Op == ssa.OpRISCV64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
   265  				v.Op == ssa.OpRISCV64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
   266  				v.Op == ssa.OpRISCV64MOVWUreg && t.Size() == 4 && !t.IsSigned():
   267  				// arg is a proper-typed load and already sign/zero-extended
   268  				if rs == rd {
   269  					return
   270  				}
   271  				as = riscv.AMOV
   272  			default:
   273  			}
   274  		}
   275  		p := s.Prog(as)
   276  		p.From.Type = obj.TYPE_REG
   277  		p.From.Reg = rs
   278  		p.To.Type = obj.TYPE_REG
   279  		p.To.Reg = rd
   280  	case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND,
   281  		ssa.OpRISCV64SLL, ssa.OpRISCV64SLLW, ssa.OpRISCV64SRA, ssa.OpRISCV64SRAW, ssa.OpRISCV64SRL, ssa.OpRISCV64SRLW,
   282  		ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH,
   283  		ssa.OpRISCV64MULHU, ssa.OpRISCV64DIV, ssa.OpRISCV64DIVU, ssa.OpRISCV64DIVW,
   284  		ssa.OpRISCV64DIVUW, ssa.OpRISCV64REM, ssa.OpRISCV64REMU, ssa.OpRISCV64REMW,
   285  		ssa.OpRISCV64REMUW,
   286  		ssa.OpRISCV64ROL, ssa.OpRISCV64ROLW, ssa.OpRISCV64ROR, ssa.OpRISCV64RORW,
   287  		ssa.OpRISCV64FADDS, ssa.OpRISCV64FSUBS, ssa.OpRISCV64FMULS, ssa.OpRISCV64FDIVS,
   288  		ssa.OpRISCV64FEQS, ssa.OpRISCV64FNES, ssa.OpRISCV64FLTS, ssa.OpRISCV64FLES,
   289  		ssa.OpRISCV64FADDD, ssa.OpRISCV64FSUBD, ssa.OpRISCV64FMULD, ssa.OpRISCV64FDIVD,
   290  		ssa.OpRISCV64FEQD, ssa.OpRISCV64FNED, ssa.OpRISCV64FLTD, ssa.OpRISCV64FLED,
   291  		ssa.OpRISCV64FSGNJD:
   292  		r := v.Reg()
   293  		r1 := v.Args[0].Reg()
   294  		r2 := v.Args[1].Reg()
   295  		p := s.Prog(v.Op.Asm())
   296  		p.From.Type = obj.TYPE_REG
   297  		p.From.Reg = r2
   298  		p.Reg = r1
   299  		p.To.Type = obj.TYPE_REG
   300  		p.To.Reg = r
   301  
   302  	case ssa.OpRISCV64LoweredFMAXD, ssa.OpRISCV64LoweredFMIND, ssa.OpRISCV64LoweredFMAXS, ssa.OpRISCV64LoweredFMINS:
   303  		// Most of FMIN/FMAX result match Go's required behaviour, unless one of the
   304  		// inputs is a NaN. As such, we need to explicitly test for NaN
   305  		// before using FMIN/FMAX.
   306  
   307  		// FADD Rarg0, Rarg1, Rout // FADD is used to propagate a NaN to the result in these cases.
   308  		// FEQ  Rarg0, Rarg0, Rtmp
   309  		// BEQZ Rtmp, end
   310  		// FEQ  Rarg1, Rarg1, Rtmp
   311  		// BEQZ Rtmp, end
   312  		// F(MIN | MAX)
   313  
   314  		r0 := v.Args[0].Reg()
   315  		r1 := v.Args[1].Reg()
   316  		out := v.Reg()
   317  		add, feq := riscv.AFADDD, riscv.AFEQD
   318  		if v.Op == ssa.OpRISCV64LoweredFMAXS || v.Op == ssa.OpRISCV64LoweredFMINS {
   319  			add = riscv.AFADDS
   320  			feq = riscv.AFEQS
   321  		}
   322  
   323  		p1 := s.Prog(add)
   324  		p1.From.Type = obj.TYPE_REG
   325  		p1.From.Reg = r0
   326  		p1.Reg = r1
   327  		p1.To.Type = obj.TYPE_REG
   328  		p1.To.Reg = out
   329  
   330  		p2 := s.Prog(feq)
   331  		p2.From.Type = obj.TYPE_REG
   332  		p2.From.Reg = r0
   333  		p2.Reg = r0
   334  		p2.To.Type = obj.TYPE_REG
   335  		p2.To.Reg = riscv.REG_TMP
   336  
   337  		p3 := s.Prog(riscv.ABEQ)
   338  		p3.From.Type = obj.TYPE_REG
   339  		p3.From.Reg = riscv.REG_ZERO
   340  		p3.Reg = riscv.REG_TMP
   341  		p3.To.Type = obj.TYPE_BRANCH
   342  
   343  		p4 := s.Prog(feq)
   344  		p4.From.Type = obj.TYPE_REG
   345  		p4.From.Reg = r1
   346  		p4.Reg = r1
   347  		p4.To.Type = obj.TYPE_REG
   348  		p4.To.Reg = riscv.REG_TMP
   349  
   350  		p5 := s.Prog(riscv.ABEQ)
   351  		p5.From.Type = obj.TYPE_REG
   352  		p5.From.Reg = riscv.REG_ZERO
   353  		p5.Reg = riscv.REG_TMP
   354  		p5.To.Type = obj.TYPE_BRANCH
   355  
   356  		p6 := s.Prog(v.Op.Asm())
   357  		p6.From.Type = obj.TYPE_REG
   358  		p6.From.Reg = r1
   359  		p6.Reg = r0
   360  		p6.To.Type = obj.TYPE_REG
   361  		p6.To.Reg = out
   362  
   363  		nop := s.Prog(obj.ANOP)
   364  		p3.To.SetTarget(nop)
   365  		p5.To.SetTarget(nop)
   366  
   367  	case ssa.OpRISCV64LoweredMuluhilo:
   368  		r0 := v.Args[0].Reg()
   369  		r1 := v.Args[1].Reg()
   370  		p := s.Prog(riscv.AMULHU)
   371  		p.From.Type = obj.TYPE_REG
   372  		p.From.Reg = r1
   373  		p.Reg = r0
   374  		p.To.Type = obj.TYPE_REG
   375  		p.To.Reg = v.Reg0()
   376  		p1 := s.Prog(riscv.AMUL)
   377  		p1.From.Type = obj.TYPE_REG
   378  		p1.From.Reg = r1
   379  		p1.Reg = r0
   380  		p1.To.Type = obj.TYPE_REG
   381  		p1.To.Reg = v.Reg1()
   382  	case ssa.OpRISCV64LoweredMuluover:
   383  		r0 := v.Args[0].Reg()
   384  		r1 := v.Args[1].Reg()
   385  		p := s.Prog(riscv.AMULHU)
   386  		p.From.Type = obj.TYPE_REG
   387  		p.From.Reg = r1
   388  		p.Reg = r0
   389  		p.To.Type = obj.TYPE_REG
   390  		p.To.Reg = v.Reg1()
   391  		p1 := s.Prog(riscv.AMUL)
   392  		p1.From.Type = obj.TYPE_REG
   393  		p1.From.Reg = r1
   394  		p1.Reg = r0
   395  		p1.To.Type = obj.TYPE_REG
   396  		p1.To.Reg = v.Reg0()
   397  		p2 := s.Prog(riscv.ASNEZ)
   398  		p2.From.Type = obj.TYPE_REG
   399  		p2.From.Reg = v.Reg1()
   400  		p2.To.Type = obj.TYPE_REG
   401  		p2.To.Reg = v.Reg1()
   402  	case ssa.OpRISCV64FMADDD, ssa.OpRISCV64FMSUBD, ssa.OpRISCV64FNMADDD, ssa.OpRISCV64FNMSUBD,
   403  		ssa.OpRISCV64FMADDS, ssa.OpRISCV64FMSUBS, ssa.OpRISCV64FNMADDS, ssa.OpRISCV64FNMSUBS:
   404  		r := v.Reg()
   405  		r1 := v.Args[0].Reg()
   406  		r2 := v.Args[1].Reg()
   407  		r3 := v.Args[2].Reg()
   408  		p := s.Prog(v.Op.Asm())
   409  		p.From.Type = obj.TYPE_REG
   410  		p.From.Reg = r2
   411  		p.Reg = r1
   412  		p.AddRestSource(obj.Addr{Type: obj.TYPE_REG, Reg: r3})
   413  		p.To.Type = obj.TYPE_REG
   414  		p.To.Reg = r
   415  	case ssa.OpRISCV64FSQRTS, ssa.OpRISCV64FNEGS, ssa.OpRISCV64FABSD, ssa.OpRISCV64FSQRTD, ssa.OpRISCV64FNEGD,
   416  		ssa.OpRISCV64FMVSX, ssa.OpRISCV64FMVDX,
   417  		ssa.OpRISCV64FCVTSW, ssa.OpRISCV64FCVTSL, ssa.OpRISCV64FCVTWS, ssa.OpRISCV64FCVTLS,
   418  		ssa.OpRISCV64FCVTDW, ssa.OpRISCV64FCVTDL, ssa.OpRISCV64FCVTWD, ssa.OpRISCV64FCVTLD, ssa.OpRISCV64FCVTDS, ssa.OpRISCV64FCVTSD,
   419  		ssa.OpRISCV64NOT, ssa.OpRISCV64NEG, ssa.OpRISCV64NEGW:
   420  		p := s.Prog(v.Op.Asm())
   421  		p.From.Type = obj.TYPE_REG
   422  		p.From.Reg = v.Args[0].Reg()
   423  		p.To.Type = obj.TYPE_REG
   424  		p.To.Reg = v.Reg()
   425  	case ssa.OpRISCV64ADDI, ssa.OpRISCV64ADDIW, ssa.OpRISCV64XORI, ssa.OpRISCV64ORI, ssa.OpRISCV64ANDI,
   426  		ssa.OpRISCV64SLLI, ssa.OpRISCV64SLLIW, ssa.OpRISCV64SRAI, ssa.OpRISCV64SRAIW,
   427  		ssa.OpRISCV64SRLI, ssa.OpRISCV64SRLIW, ssa.OpRISCV64SLTI, ssa.OpRISCV64SLTIU,
   428  		ssa.OpRISCV64RORI, ssa.OpRISCV64RORIW:
   429  		p := s.Prog(v.Op.Asm())
   430  		p.From.Type = obj.TYPE_CONST
   431  		p.From.Offset = v.AuxInt
   432  		p.Reg = v.Args[0].Reg()
   433  		p.To.Type = obj.TYPE_REG
   434  		p.To.Reg = v.Reg()
   435  	case ssa.OpRISCV64MOVDconst:
   436  		p := s.Prog(v.Op.Asm())
   437  		p.From.Type = obj.TYPE_CONST
   438  		p.From.Offset = v.AuxInt
   439  		p.To.Type = obj.TYPE_REG
   440  		p.To.Reg = v.Reg()
   441  	case ssa.OpRISCV64MOVaddr:
   442  		p := s.Prog(v.Op.Asm())
   443  		p.From.Type = obj.TYPE_ADDR
   444  		p.To.Type = obj.TYPE_REG
   445  		p.To.Reg = v.Reg()
   446  
   447  		var wantreg string
   448  		// MOVW $sym+off(base), R
   449  		switch v.Aux.(type) {
   450  		default:
   451  			v.Fatalf("aux is of unknown type %T", v.Aux)
   452  		case *obj.LSym:
   453  			wantreg = "SB"
   454  			ssagen.AddAux(&p.From, v)
   455  		case *ir.Name:
   456  			wantreg = "SP"
   457  			ssagen.AddAux(&p.From, v)
   458  		case nil:
   459  			// No sym, just MOVW $off(SP), R
   460  			wantreg = "SP"
   461  			p.From.Reg = riscv.REG_SP
   462  			p.From.Offset = v.AuxInt
   463  		}
   464  		if reg := v.Args[0].RegName(); reg != wantreg {
   465  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   466  		}
   467  	case ssa.OpRISCV64MOVBload, ssa.OpRISCV64MOVHload, ssa.OpRISCV64MOVWload, ssa.OpRISCV64MOVDload,
   468  		ssa.OpRISCV64MOVBUload, ssa.OpRISCV64MOVHUload, ssa.OpRISCV64MOVWUload,
   469  		ssa.OpRISCV64FMOVWload, ssa.OpRISCV64FMOVDload:
   470  		p := s.Prog(v.Op.Asm())
   471  		p.From.Type = obj.TYPE_MEM
   472  		p.From.Reg = v.Args[0].Reg()
   473  		ssagen.AddAux(&p.From, v)
   474  		p.To.Type = obj.TYPE_REG
   475  		p.To.Reg = v.Reg()
   476  	case ssa.OpRISCV64MOVBstore, ssa.OpRISCV64MOVHstore, ssa.OpRISCV64MOVWstore, ssa.OpRISCV64MOVDstore,
   477  		ssa.OpRISCV64FMOVWstore, ssa.OpRISCV64FMOVDstore:
   478  		p := s.Prog(v.Op.Asm())
   479  		p.From.Type = obj.TYPE_REG
   480  		p.From.Reg = v.Args[1].Reg()
   481  		p.To.Type = obj.TYPE_MEM
   482  		p.To.Reg = v.Args[0].Reg()
   483  		ssagen.AddAux(&p.To, v)
   484  	case ssa.OpRISCV64MOVBstorezero, ssa.OpRISCV64MOVHstorezero, ssa.OpRISCV64MOVWstorezero, ssa.OpRISCV64MOVDstorezero:
   485  		p := s.Prog(v.Op.Asm())
   486  		p.From.Type = obj.TYPE_REG
   487  		p.From.Reg = riscv.REG_ZERO
   488  		p.To.Type = obj.TYPE_MEM
   489  		p.To.Reg = v.Args[0].Reg()
   490  		ssagen.AddAux(&p.To, v)
   491  	case ssa.OpRISCV64SEQZ, ssa.OpRISCV64SNEZ:
   492  		p := s.Prog(v.Op.Asm())
   493  		p.From.Type = obj.TYPE_REG
   494  		p.From.Reg = v.Args[0].Reg()
   495  		p.To.Type = obj.TYPE_REG
   496  		p.To.Reg = v.Reg()
   497  	case ssa.OpRISCV64CALLstatic, ssa.OpRISCV64CALLclosure, ssa.OpRISCV64CALLinter:
   498  		s.Call(v)
   499  	case ssa.OpRISCV64CALLtail:
   500  		s.TailCall(v)
   501  	case ssa.OpRISCV64LoweredWB:
   502  		p := s.Prog(obj.ACALL)
   503  		p.To.Type = obj.TYPE_MEM
   504  		p.To.Name = obj.NAME_EXTERN
   505  		// AuxInt encodes how many buffer entries we need.
   506  		p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
   507  	case ssa.OpRISCV64LoweredPanicBoundsA, ssa.OpRISCV64LoweredPanicBoundsB, ssa.OpRISCV64LoweredPanicBoundsC:
   508  		p := s.Prog(obj.ACALL)
   509  		p.To.Type = obj.TYPE_MEM
   510  		p.To.Name = obj.NAME_EXTERN
   511  		p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
   512  		s.UseArgs(16) // space used in callee args area by assembly stubs
   513  
   514  	case ssa.OpRISCV64LoweredAtomicLoad8:
   515  		s.Prog(riscv.AFENCE)
   516  		p := s.Prog(riscv.AMOVBU)
   517  		p.From.Type = obj.TYPE_MEM
   518  		p.From.Reg = v.Args[0].Reg()
   519  		p.To.Type = obj.TYPE_REG
   520  		p.To.Reg = v.Reg0()
   521  		s.Prog(riscv.AFENCE)
   522  
   523  	case ssa.OpRISCV64LoweredAtomicLoad32, ssa.OpRISCV64LoweredAtomicLoad64:
   524  		as := riscv.ALRW
   525  		if v.Op == ssa.OpRISCV64LoweredAtomicLoad64 {
   526  			as = riscv.ALRD
   527  		}
   528  		p := s.Prog(as)
   529  		p.From.Type = obj.TYPE_MEM
   530  		p.From.Reg = v.Args[0].Reg()
   531  		p.To.Type = obj.TYPE_REG
   532  		p.To.Reg = v.Reg0()
   533  
   534  	case ssa.OpRISCV64LoweredAtomicStore8:
   535  		s.Prog(riscv.AFENCE)
   536  		p := s.Prog(riscv.AMOVB)
   537  		p.From.Type = obj.TYPE_REG
   538  		p.From.Reg = v.Args[1].Reg()
   539  		p.To.Type = obj.TYPE_MEM
   540  		p.To.Reg = v.Args[0].Reg()
   541  		s.Prog(riscv.AFENCE)
   542  
   543  	case ssa.OpRISCV64LoweredAtomicStore32, ssa.OpRISCV64LoweredAtomicStore64:
   544  		as := riscv.AAMOSWAPW
   545  		if v.Op == ssa.OpRISCV64LoweredAtomicStore64 {
   546  			as = riscv.AAMOSWAPD
   547  		}
   548  		p := s.Prog(as)
   549  		p.From.Type = obj.TYPE_REG
   550  		p.From.Reg = v.Args[1].Reg()
   551  		p.To.Type = obj.TYPE_MEM
   552  		p.To.Reg = v.Args[0].Reg()
   553  		p.RegTo2 = riscv.REG_ZERO
   554  
   555  	case ssa.OpRISCV64LoweredAtomicAdd32, ssa.OpRISCV64LoweredAtomicAdd64:
   556  		as := riscv.AAMOADDW
   557  		if v.Op == ssa.OpRISCV64LoweredAtomicAdd64 {
   558  			as = riscv.AAMOADDD
   559  		}
   560  		p := s.Prog(as)
   561  		p.From.Type = obj.TYPE_REG
   562  		p.From.Reg = v.Args[1].Reg()
   563  		p.To.Type = obj.TYPE_MEM
   564  		p.To.Reg = v.Args[0].Reg()
   565  		p.RegTo2 = riscv.REG_TMP
   566  
   567  		p2 := s.Prog(riscv.AADD)
   568  		p2.From.Type = obj.TYPE_REG
   569  		p2.From.Reg = riscv.REG_TMP
   570  		p2.Reg = v.Args[1].Reg()
   571  		p2.To.Type = obj.TYPE_REG
   572  		p2.To.Reg = v.Reg0()
   573  
   574  	case ssa.OpRISCV64LoweredAtomicExchange32, ssa.OpRISCV64LoweredAtomicExchange64:
   575  		as := riscv.AAMOSWAPW
   576  		if v.Op == ssa.OpRISCV64LoweredAtomicExchange64 {
   577  			as = riscv.AAMOSWAPD
   578  		}
   579  		p := s.Prog(as)
   580  		p.From.Type = obj.TYPE_REG
   581  		p.From.Reg = v.Args[1].Reg()
   582  		p.To.Type = obj.TYPE_MEM
   583  		p.To.Reg = v.Args[0].Reg()
   584  		p.RegTo2 = v.Reg0()
   585  
   586  	case ssa.OpRISCV64LoweredAtomicCas32, ssa.OpRISCV64LoweredAtomicCas64:
   587  		// MOV  ZERO, Rout
   588  		// LR	(Rarg0), Rtmp
   589  		// BNE	Rtmp, Rarg1, 3(PC)
   590  		// SC	Rarg2, (Rarg0), Rtmp
   591  		// BNE	Rtmp, ZERO, -3(PC)
   592  		// MOV	$1, Rout
   593  
   594  		lr := riscv.ALRW
   595  		sc := riscv.ASCW
   596  		if v.Op == ssa.OpRISCV64LoweredAtomicCas64 {
   597  			lr = riscv.ALRD
   598  			sc = riscv.ASCD
   599  		}
   600  
   601  		r0 := v.Args[0].Reg()
   602  		r1 := v.Args[1].Reg()
   603  		r2 := v.Args[2].Reg()
   604  		out := v.Reg0()
   605  
   606  		p := s.Prog(riscv.AMOV)
   607  		p.From.Type = obj.TYPE_REG
   608  		p.From.Reg = riscv.REG_ZERO
   609  		p.To.Type = obj.TYPE_REG
   610  		p.To.Reg = out
   611  
   612  		p1 := s.Prog(lr)
   613  		p1.From.Type = obj.TYPE_MEM
   614  		p1.From.Reg = r0
   615  		p1.To.Type = obj.TYPE_REG
   616  		p1.To.Reg = riscv.REG_TMP
   617  
   618  		p2 := s.Prog(riscv.ABNE)
   619  		p2.From.Type = obj.TYPE_REG
   620  		p2.From.Reg = r1
   621  		p2.Reg = riscv.REG_TMP
   622  		p2.To.Type = obj.TYPE_BRANCH
   623  
   624  		p3 := s.Prog(sc)
   625  		p3.From.Type = obj.TYPE_REG
   626  		p3.From.Reg = r2
   627  		p3.To.Type = obj.TYPE_MEM
   628  		p3.To.Reg = r0
   629  		p3.RegTo2 = riscv.REG_TMP
   630  
   631  		p4 := s.Prog(riscv.ABNE)
   632  		p4.From.Type = obj.TYPE_REG
   633  		p4.From.Reg = riscv.REG_TMP
   634  		p4.Reg = riscv.REG_ZERO
   635  		p4.To.Type = obj.TYPE_BRANCH
   636  		p4.To.SetTarget(p1)
   637  
   638  		p5 := s.Prog(riscv.AMOV)
   639  		p5.From.Type = obj.TYPE_CONST
   640  		p5.From.Offset = 1
   641  		p5.To.Type = obj.TYPE_REG
   642  		p5.To.Reg = out
   643  
   644  		p6 := s.Prog(obj.ANOP)
   645  		p2.To.SetTarget(p6)
   646  
   647  	case ssa.OpRISCV64LoweredAtomicAnd32, ssa.OpRISCV64LoweredAtomicOr32:
   648  		p := s.Prog(v.Op.Asm())
   649  		p.From.Type = obj.TYPE_REG
   650  		p.From.Reg = v.Args[1].Reg()
   651  		p.To.Type = obj.TYPE_MEM
   652  		p.To.Reg = v.Args[0].Reg()
   653  		p.RegTo2 = riscv.REG_ZERO
   654  
   655  	case ssa.OpRISCV64LoweredZero:
   656  		mov, sz := largestMove(v.AuxInt)
   657  
   658  		//	mov	ZERO, (Rarg0)
   659  		//	ADD	$sz, Rarg0
   660  		//	BGEU	Rarg1, Rarg0, -2(PC)
   661  
   662  		p := s.Prog(mov)
   663  		p.From.Type = obj.TYPE_REG
   664  		p.From.Reg = riscv.REG_ZERO
   665  		p.To.Type = obj.TYPE_MEM
   666  		p.To.Reg = v.Args[0].Reg()
   667  
   668  		p2 := s.Prog(riscv.AADD)
   669  		p2.From.Type = obj.TYPE_CONST
   670  		p2.From.Offset = sz
   671  		p2.To.Type = obj.TYPE_REG
   672  		p2.To.Reg = v.Args[0].Reg()
   673  
   674  		p3 := s.Prog(riscv.ABGEU)
   675  		p3.To.Type = obj.TYPE_BRANCH
   676  		p3.Reg = v.Args[0].Reg()
   677  		p3.From.Type = obj.TYPE_REG
   678  		p3.From.Reg = v.Args[1].Reg()
   679  		p3.To.SetTarget(p)
   680  
   681  	case ssa.OpRISCV64LoweredMove:
   682  		mov, sz := largestMove(v.AuxInt)
   683  
   684  		//	mov	(Rarg1), T2
   685  		//	mov	T2, (Rarg0)
   686  		//	ADD	$sz, Rarg0
   687  		//	ADD	$sz, Rarg1
   688  		//	BGEU	Rarg2, Rarg0, -4(PC)
   689  
   690  		p := s.Prog(mov)
   691  		p.From.Type = obj.TYPE_MEM
   692  		p.From.Reg = v.Args[1].Reg()
   693  		p.To.Type = obj.TYPE_REG
   694  		p.To.Reg = riscv.REG_T2
   695  
   696  		p2 := s.Prog(mov)
   697  		p2.From.Type = obj.TYPE_REG
   698  		p2.From.Reg = riscv.REG_T2
   699  		p2.To.Type = obj.TYPE_MEM
   700  		p2.To.Reg = v.Args[0].Reg()
   701  
   702  		p3 := s.Prog(riscv.AADD)
   703  		p3.From.Type = obj.TYPE_CONST
   704  		p3.From.Offset = sz
   705  		p3.To.Type = obj.TYPE_REG
   706  		p3.To.Reg = v.Args[0].Reg()
   707  
   708  		p4 := s.Prog(riscv.AADD)
   709  		p4.From.Type = obj.TYPE_CONST
   710  		p4.From.Offset = sz
   711  		p4.To.Type = obj.TYPE_REG
   712  		p4.To.Reg = v.Args[1].Reg()
   713  
   714  		p5 := s.Prog(riscv.ABGEU)
   715  		p5.To.Type = obj.TYPE_BRANCH
   716  		p5.Reg = v.Args[1].Reg()
   717  		p5.From.Type = obj.TYPE_REG
   718  		p5.From.Reg = v.Args[2].Reg()
   719  		p5.To.SetTarget(p)
   720  
   721  	case ssa.OpRISCV64LoweredNilCheck:
   722  		// Issue a load which will fault if arg is nil.
   723  		// TODO: optimizations. See arm and amd64 LoweredNilCheck.
   724  		p := s.Prog(riscv.AMOVB)
   725  		p.From.Type = obj.TYPE_MEM
   726  		p.From.Reg = v.Args[0].Reg()
   727  		ssagen.AddAux(&p.From, v)
   728  		p.To.Type = obj.TYPE_REG
   729  		p.To.Reg = riscv.REG_ZERO
   730  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos == 1 in generated wrappers
   731  			base.WarnfAt(v.Pos, "generated nil check")
   732  		}
   733  
   734  	case ssa.OpRISCV64LoweredGetClosurePtr:
   735  		// Closure pointer is S10 (riscv.REG_CTXT).
   736  		ssagen.CheckLoweredGetClosurePtr(v)
   737  
   738  	case ssa.OpRISCV64LoweredGetCallerSP:
   739  		// caller's SP is FixedFrameSize below the address of the first arg
   740  		p := s.Prog(riscv.AMOV)
   741  		p.From.Type = obj.TYPE_ADDR
   742  		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize
   743  		p.From.Name = obj.NAME_PARAM
   744  		p.To.Type = obj.TYPE_REG
   745  		p.To.Reg = v.Reg()
   746  
   747  	case ssa.OpRISCV64LoweredGetCallerPC:
   748  		p := s.Prog(obj.AGETCALLERPC)
   749  		p.To.Type = obj.TYPE_REG
   750  		p.To.Reg = v.Reg()
   751  
   752  	case ssa.OpRISCV64DUFFZERO:
   753  		p := s.Prog(obj.ADUFFZERO)
   754  		p.To.Type = obj.TYPE_MEM
   755  		p.To.Name = obj.NAME_EXTERN
   756  		p.To.Sym = ir.Syms.Duffzero
   757  		p.To.Offset = v.AuxInt
   758  
   759  	case ssa.OpRISCV64DUFFCOPY:
   760  		p := s.Prog(obj.ADUFFCOPY)
   761  		p.To.Type = obj.TYPE_MEM
   762  		p.To.Name = obj.NAME_EXTERN
   763  		p.To.Sym = ir.Syms.Duffcopy
   764  		p.To.Offset = v.AuxInt
   765  
   766  	case ssa.OpRISCV64LoweredPubBarrier:
   767  		// FENCE
   768  		s.Prog(v.Op.Asm())
   769  
   770  	case ssa.OpRISCV64LoweredRound32F, ssa.OpRISCV64LoweredRound64F:
   771  		// input is already rounded
   772  
   773  	case ssa.OpClobber, ssa.OpClobberReg:
   774  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   775  
   776  	default:
   777  		v.Fatalf("Unhandled op %v", v.Op)
   778  	}
   779  }
   780  
   781  var blockBranch = [...]obj.As{
   782  	ssa.BlockRISCV64BEQ:  riscv.ABEQ,
   783  	ssa.BlockRISCV64BEQZ: riscv.ABEQZ,
   784  	ssa.BlockRISCV64BGE:  riscv.ABGE,
   785  	ssa.BlockRISCV64BGEU: riscv.ABGEU,
   786  	ssa.BlockRISCV64BGEZ: riscv.ABGEZ,
   787  	ssa.BlockRISCV64BGTZ: riscv.ABGTZ,
   788  	ssa.BlockRISCV64BLEZ: riscv.ABLEZ,
   789  	ssa.BlockRISCV64BLT:  riscv.ABLT,
   790  	ssa.BlockRISCV64BLTU: riscv.ABLTU,
   791  	ssa.BlockRISCV64BLTZ: riscv.ABLTZ,
   792  	ssa.BlockRISCV64BNE:  riscv.ABNE,
   793  	ssa.BlockRISCV64BNEZ: riscv.ABNEZ,
   794  }
   795  
   796  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
   797  	s.SetPos(b.Pos)
   798  
   799  	switch b.Kind {
   800  	case ssa.BlockDefer:
   801  		// defer returns in A0:
   802  		// 0 if we should continue executing
   803  		// 1 if we should jump to deferreturn call
   804  		p := s.Prog(riscv.ABNE)
   805  		p.To.Type = obj.TYPE_BRANCH
   806  		p.From.Type = obj.TYPE_REG
   807  		p.From.Reg = riscv.REG_ZERO
   808  		p.Reg = riscv.REG_A0
   809  		s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()})
   810  		if b.Succs[0].Block() != next {
   811  			p := s.Prog(obj.AJMP)
   812  			p.To.Type = obj.TYPE_BRANCH
   813  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   814  		}
   815  	case ssa.BlockPlain:
   816  		if b.Succs[0].Block() != next {
   817  			p := s.Prog(obj.AJMP)
   818  			p.To.Type = obj.TYPE_BRANCH
   819  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
   820  		}
   821  	case ssa.BlockExit, ssa.BlockRetJmp:
   822  	case ssa.BlockRet:
   823  		s.Prog(obj.ARET)
   824  	case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BNEZ,
   825  		ssa.BlockRISCV64BLT, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BGEZ,
   826  		ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
   827  
   828  		as := blockBranch[b.Kind]
   829  		invAs := riscv.InvertBranch(as)
   830  
   831  		var p *obj.Prog
   832  		switch next {
   833  		case b.Succs[0].Block():
   834  			p = s.Br(invAs, b.Succs[1].Block())
   835  		case b.Succs[1].Block():
   836  			p = s.Br(as, b.Succs[0].Block())
   837  		default:
   838  			if b.Likely != ssa.BranchUnlikely {
   839  				p = s.Br(as, b.Succs[0].Block())
   840  				s.Br(obj.AJMP, b.Succs[1].Block())
   841  			} else {
   842  				p = s.Br(invAs, b.Succs[1].Block())
   843  				s.Br(obj.AJMP, b.Succs[0].Block())
   844  			}
   845  		}
   846  
   847  		p.From.Type = obj.TYPE_REG
   848  		switch b.Kind {
   849  		case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BLT, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
   850  			if b.NumControls() != 2 {
   851  				b.Fatalf("Unexpected number of controls (%d != 2): %s", b.NumControls(), b.LongString())
   852  			}
   853  			p.From.Reg = b.Controls[0].Reg()
   854  			p.Reg = b.Controls[1].Reg()
   855  
   856  		case ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNEZ, ssa.BlockRISCV64BGEZ, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ:
   857  			if b.NumControls() != 1 {
   858  				b.Fatalf("Unexpected number of controls (%d != 1): %s", b.NumControls(), b.LongString())
   859  			}
   860  			p.From.Reg = b.Controls[0].Reg()
   861  		}
   862  
   863  	default:
   864  		b.Fatalf("Unhandled block: %s", b.LongString())
   865  	}
   866  }
   867  
   868  func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
   869  	p := s.Prog(loadByType(t))
   870  	p.From.Type = obj.TYPE_MEM
   871  	p.From.Name = obj.NAME_AUTO
   872  	p.From.Sym = n.Linksym()
   873  	p.From.Offset = n.FrameOffset() + off
   874  	p.To.Type = obj.TYPE_REG
   875  	p.To.Reg = reg
   876  	return p
   877  }
   878  
   879  func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
   880  	p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off)
   881  	p.To.Name = obj.NAME_PARAM
   882  	p.To.Sym = n.Linksym()
   883  	p.Pos = p.Pos.WithNotStmt()
   884  	return p
   885  }
   886  

View as plain text