github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/riscv64/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 riscv64
     6  
     7  import (
     8  	"github.com/gagliardetto/golang-go/cmd/compile/internal/gc"
     9  	"github.com/gagliardetto/golang-go/cmd/compile/internal/ssa"
    10  	"github.com/gagliardetto/golang-go/cmd/compile/internal/types"
    11  	"github.com/gagliardetto/golang-go/cmd/internal/obj"
    12  	"github.com/gagliardetto/golang-go/cmd/internal/obj/riscv"
    13  )
    14  
    15  // ssaRegToReg maps ssa register numbers to obj register numbers.
    16  var ssaRegToReg = []int16{
    17  	riscv.REG_X0,
    18  	// X1 (LR): unused
    19  	riscv.REG_X2,
    20  	riscv.REG_X3,
    21  	riscv.REG_X4,
    22  	riscv.REG_X5,
    23  	riscv.REG_X6,
    24  	riscv.REG_X7,
    25  	riscv.REG_X8,
    26  	riscv.REG_X9,
    27  	riscv.REG_X10,
    28  	riscv.REG_X11,
    29  	riscv.REG_X12,
    30  	riscv.REG_X13,
    31  	riscv.REG_X14,
    32  	riscv.REG_X15,
    33  	riscv.REG_X16,
    34  	riscv.REG_X17,
    35  	riscv.REG_X18,
    36  	riscv.REG_X19,
    37  	riscv.REG_X20,
    38  	riscv.REG_X21,
    39  	riscv.REG_X22,
    40  	riscv.REG_X23,
    41  	riscv.REG_X24,
    42  	riscv.REG_X25,
    43  	riscv.REG_X26,
    44  	riscv.REG_X27,
    45  	riscv.REG_X28,
    46  	riscv.REG_X29,
    47  	riscv.REG_X30,
    48  	riscv.REG_X31,
    49  	riscv.REG_F0,
    50  	riscv.REG_F1,
    51  	riscv.REG_F2,
    52  	riscv.REG_F3,
    53  	riscv.REG_F4,
    54  	riscv.REG_F5,
    55  	riscv.REG_F6,
    56  	riscv.REG_F7,
    57  	riscv.REG_F8,
    58  	riscv.REG_F9,
    59  	riscv.REG_F10,
    60  	riscv.REG_F11,
    61  	riscv.REG_F12,
    62  	riscv.REG_F13,
    63  	riscv.REG_F14,
    64  	riscv.REG_F15,
    65  	riscv.REG_F16,
    66  	riscv.REG_F17,
    67  	riscv.REG_F18,
    68  	riscv.REG_F19,
    69  	riscv.REG_F20,
    70  	riscv.REG_F21,
    71  	riscv.REG_F22,
    72  	riscv.REG_F23,
    73  	riscv.REG_F24,
    74  	riscv.REG_F25,
    75  	riscv.REG_F26,
    76  	riscv.REG_F27,
    77  	riscv.REG_F28,
    78  	riscv.REG_F29,
    79  	riscv.REG_F30,
    80  	riscv.REG_F31,
    81  	0, // SB isn't a real register.  We fill an Addr.Reg field with 0 in this case.
    82  }
    83  
    84  func loadByType(t *types.Type) obj.As {
    85  	width := t.Size()
    86  
    87  	if t.IsFloat() {
    88  		switch width {
    89  		case 4:
    90  			return riscv.AMOVF
    91  		case 8:
    92  			return riscv.AMOVD
    93  		default:
    94  			gc.Fatalf("unknown float width for load %d in type %v", width, t)
    95  			return 0
    96  		}
    97  	}
    98  
    99  	switch width {
   100  	case 1:
   101  		if t.IsSigned() {
   102  			return riscv.AMOVB
   103  		} else {
   104  			return riscv.AMOVBU
   105  		}
   106  	case 2:
   107  		if t.IsSigned() {
   108  			return riscv.AMOVH
   109  		} else {
   110  			return riscv.AMOVHU
   111  		}
   112  	case 4:
   113  		if t.IsSigned() {
   114  			return riscv.AMOVW
   115  		} else {
   116  			return riscv.AMOVWU
   117  		}
   118  	case 8:
   119  		return riscv.AMOV
   120  	default:
   121  		gc.Fatalf("unknown width for load %d in type %v", width, t)
   122  		return 0
   123  	}
   124  }
   125  
   126  // storeByType returns the store instruction of the given type.
   127  func storeByType(t *types.Type) obj.As {
   128  	width := t.Size()
   129  
   130  	if t.IsFloat() {
   131  		switch width {
   132  		case 4:
   133  			return riscv.AMOVF
   134  		case 8:
   135  			return riscv.AMOVD
   136  		default:
   137  			gc.Fatalf("unknown float width for store %d in type %v", width, t)
   138  			return 0
   139  		}
   140  	}
   141  
   142  	switch width {
   143  	case 1:
   144  		return riscv.AMOVB
   145  	case 2:
   146  		return riscv.AMOVH
   147  	case 4:
   148  		return riscv.AMOVW
   149  	case 8:
   150  		return riscv.AMOV
   151  	default:
   152  		gc.Fatalf("unknown width for store %d in type %v", width, t)
   153  		return 0
   154  	}
   155  }
   156  
   157  // largestMove returns the largest move instruction possible and its size,
   158  // given the alignment of the total size of the move.
   159  //
   160  // e.g., a 16-byte move may use MOV, but an 11-byte move must use MOVB.
   161  //
   162  // Note that the moves may not be on naturally aligned addresses depending on
   163  // the source and destination.
   164  //
   165  // This matches the calculation in ssa.moveSize.
   166  func largestMove(alignment int64) (obj.As, int64) {
   167  	switch {
   168  	case alignment%8 == 0:
   169  		return riscv.AMOV, 8
   170  	case alignment%4 == 0:
   171  		return riscv.AMOVW, 4
   172  	case alignment%2 == 0:
   173  		return riscv.AMOVH, 2
   174  	default:
   175  		return riscv.AMOVB, 1
   176  	}
   177  }
   178  
   179  // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
   180  // RISC-V has no flags, so this is a no-op.
   181  func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {}
   182  
   183  func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
   184  	s.SetPos(v.Pos)
   185  
   186  	switch v.Op {
   187  	case ssa.OpInitMem:
   188  		// memory arg needs no code
   189  	case ssa.OpArg:
   190  		// input args need no code
   191  	case ssa.OpPhi:
   192  		gc.CheckLoweredPhi(v)
   193  	case ssa.OpCopy, ssa.OpRISCV64MOVconvert:
   194  		if v.Type.IsMemory() {
   195  			return
   196  		}
   197  		rs := v.Args[0].Reg()
   198  		rd := v.Reg()
   199  		if rs == rd {
   200  			return
   201  		}
   202  		as := riscv.AMOV
   203  		if v.Type.IsFloat() {
   204  			as = riscv.AMOVD
   205  		}
   206  		p := s.Prog(as)
   207  		p.From.Type = obj.TYPE_REG
   208  		p.From.Reg = rs
   209  		p.To.Type = obj.TYPE_REG
   210  		p.To.Reg = rd
   211  	case ssa.OpLoadReg:
   212  		if v.Type.IsFlags() {
   213  			v.Fatalf("load flags not implemented: %v", v.LongString())
   214  			return
   215  		}
   216  		p := s.Prog(loadByType(v.Type))
   217  		gc.AddrAuto(&p.From, v.Args[0])
   218  		p.To.Type = obj.TYPE_REG
   219  		p.To.Reg = v.Reg()
   220  	case ssa.OpStoreReg:
   221  		if v.Type.IsFlags() {
   222  			v.Fatalf("store flags not implemented: %v", v.LongString())
   223  			return
   224  		}
   225  		p := s.Prog(storeByType(v.Type))
   226  		p.From.Type = obj.TYPE_REG
   227  		p.From.Reg = v.Args[0].Reg()
   228  		gc.AddrAuto(&p.To, v)
   229  	case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
   230  		// nothing to do
   231  	case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND,
   232  		ssa.OpRISCV64SLL, ssa.OpRISCV64SRA, ssa.OpRISCV64SRL,
   233  		ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH,
   234  		ssa.OpRISCV64MULHU, ssa.OpRISCV64DIV, ssa.OpRISCV64DIVU, ssa.OpRISCV64DIVW,
   235  		ssa.OpRISCV64DIVUW, ssa.OpRISCV64REM, ssa.OpRISCV64REMU, ssa.OpRISCV64REMW,
   236  		ssa.OpRISCV64REMUW,
   237  		ssa.OpRISCV64FADDS, ssa.OpRISCV64FSUBS, ssa.OpRISCV64FMULS, ssa.OpRISCV64FDIVS,
   238  		ssa.OpRISCV64FEQS, ssa.OpRISCV64FNES, ssa.OpRISCV64FLTS, ssa.OpRISCV64FLES,
   239  		ssa.OpRISCV64FADDD, ssa.OpRISCV64FSUBD, ssa.OpRISCV64FMULD, ssa.OpRISCV64FDIVD,
   240  		ssa.OpRISCV64FEQD, ssa.OpRISCV64FNED, ssa.OpRISCV64FLTD, ssa.OpRISCV64FLED:
   241  		r := v.Reg()
   242  		r1 := v.Args[0].Reg()
   243  		r2 := v.Args[1].Reg()
   244  		p := s.Prog(v.Op.Asm())
   245  		p.From.Type = obj.TYPE_REG
   246  		p.From.Reg = r2
   247  		p.Reg = r1
   248  		p.To.Type = obj.TYPE_REG
   249  		p.To.Reg = r
   250  	case ssa.OpRISCV64FSQRTS, ssa.OpRISCV64FNEGS, ssa.OpRISCV64FSQRTD, ssa.OpRISCV64FNEGD,
   251  		ssa.OpRISCV64FMVSX, ssa.OpRISCV64FMVDX,
   252  		ssa.OpRISCV64FCVTSW, ssa.OpRISCV64FCVTSL, ssa.OpRISCV64FCVTWS, ssa.OpRISCV64FCVTLS,
   253  		ssa.OpRISCV64FCVTDW, ssa.OpRISCV64FCVTDL, ssa.OpRISCV64FCVTWD, ssa.OpRISCV64FCVTLD, ssa.OpRISCV64FCVTDS, ssa.OpRISCV64FCVTSD:
   254  		p := s.Prog(v.Op.Asm())
   255  		p.From.Type = obj.TYPE_REG
   256  		p.From.Reg = v.Args[0].Reg()
   257  		p.To.Type = obj.TYPE_REG
   258  		p.To.Reg = v.Reg()
   259  	case ssa.OpRISCV64ADDI, ssa.OpRISCV64XORI, ssa.OpRISCV64ORI, ssa.OpRISCV64ANDI,
   260  		ssa.OpRISCV64SLLI, ssa.OpRISCV64SRAI, ssa.OpRISCV64SRLI, ssa.OpRISCV64SLTI,
   261  		ssa.OpRISCV64SLTIU:
   262  		p := s.Prog(v.Op.Asm())
   263  		p.From.Type = obj.TYPE_CONST
   264  		p.From.Offset = v.AuxInt
   265  		p.Reg = v.Args[0].Reg()
   266  		p.To.Type = obj.TYPE_REG
   267  		p.To.Reg = v.Reg()
   268  	case ssa.OpRISCV64MOVBconst, ssa.OpRISCV64MOVHconst, ssa.OpRISCV64MOVWconst, ssa.OpRISCV64MOVDconst:
   269  		p := s.Prog(v.Op.Asm())
   270  		p.From.Type = obj.TYPE_CONST
   271  		p.From.Offset = v.AuxInt
   272  		p.To.Type = obj.TYPE_REG
   273  		p.To.Reg = v.Reg()
   274  	case ssa.OpRISCV64MOVaddr:
   275  		p := s.Prog(v.Op.Asm())
   276  		p.From.Type = obj.TYPE_ADDR
   277  		p.To.Type = obj.TYPE_REG
   278  		p.To.Reg = v.Reg()
   279  
   280  		var wantreg string
   281  		// MOVW $sym+off(base), R
   282  		switch v.Aux.(type) {
   283  		default:
   284  			v.Fatalf("aux is of unknown type %T", v.Aux)
   285  		case *obj.LSym:
   286  			wantreg = "SB"
   287  			gc.AddAux(&p.From, v)
   288  		case *gc.Node:
   289  			wantreg = "SP"
   290  			gc.AddAux(&p.From, v)
   291  		case nil:
   292  			// No sym, just MOVW $off(SP), R
   293  			wantreg = "SP"
   294  			p.From.Reg = riscv.REG_SP
   295  			p.From.Offset = v.AuxInt
   296  		}
   297  		if reg := v.Args[0].RegName(); reg != wantreg {
   298  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   299  		}
   300  	case ssa.OpRISCV64MOVBload, ssa.OpRISCV64MOVHload, ssa.OpRISCV64MOVWload, ssa.OpRISCV64MOVDload,
   301  		ssa.OpRISCV64MOVBUload, ssa.OpRISCV64MOVHUload, ssa.OpRISCV64MOVWUload,
   302  		ssa.OpRISCV64FMOVWload, ssa.OpRISCV64FMOVDload:
   303  		p := s.Prog(v.Op.Asm())
   304  		p.From.Type = obj.TYPE_MEM
   305  		p.From.Reg = v.Args[0].Reg()
   306  		gc.AddAux(&p.From, v)
   307  		p.To.Type = obj.TYPE_REG
   308  		p.To.Reg = v.Reg()
   309  	case ssa.OpRISCV64MOVBstore, ssa.OpRISCV64MOVHstore, ssa.OpRISCV64MOVWstore, ssa.OpRISCV64MOVDstore,
   310  		ssa.OpRISCV64FMOVWstore, ssa.OpRISCV64FMOVDstore:
   311  		p := s.Prog(v.Op.Asm())
   312  		p.From.Type = obj.TYPE_REG
   313  		p.From.Reg = v.Args[1].Reg()
   314  		p.To.Type = obj.TYPE_MEM
   315  		p.To.Reg = v.Args[0].Reg()
   316  		gc.AddAux(&p.To, v)
   317  	case ssa.OpRISCV64SEQZ, ssa.OpRISCV64SNEZ:
   318  		p := s.Prog(v.Op.Asm())
   319  		p.From.Type = obj.TYPE_REG
   320  		p.From.Reg = v.Args[0].Reg()
   321  		p.To.Type = obj.TYPE_REG
   322  		p.To.Reg = v.Reg()
   323  	case ssa.OpRISCV64CALLstatic, ssa.OpRISCV64CALLclosure, ssa.OpRISCV64CALLinter:
   324  		s.Call(v)
   325  	case ssa.OpRISCV64LoweredWB:
   326  		p := s.Prog(obj.ACALL)
   327  		p.To.Type = obj.TYPE_MEM
   328  		p.To.Name = obj.NAME_EXTERN
   329  		p.To.Sym = v.Aux.(*obj.LSym)
   330  	case ssa.OpRISCV64LoweredPanicBoundsA, ssa.OpRISCV64LoweredPanicBoundsB, ssa.OpRISCV64LoweredPanicBoundsC:
   331  		p := s.Prog(obj.ACALL)
   332  		p.To.Type = obj.TYPE_MEM
   333  		p.To.Name = obj.NAME_EXTERN
   334  		p.To.Sym = gc.BoundsCheckFunc[v.AuxInt]
   335  		s.UseArgs(16) // space used in callee args area by assembly stubs
   336  	case ssa.OpRISCV64LoweredZero:
   337  		mov, sz := largestMove(v.AuxInt)
   338  
   339  		//	mov	ZERO, (Rarg0)
   340  		//	ADD	$sz, Rarg0
   341  		//	BGEU	Rarg1, Rarg0, -2(PC)
   342  
   343  		p := s.Prog(mov)
   344  		p.From.Type = obj.TYPE_REG
   345  		p.From.Reg = riscv.REG_ZERO
   346  		p.To.Type = obj.TYPE_MEM
   347  		p.To.Reg = v.Args[0].Reg()
   348  
   349  		p2 := s.Prog(riscv.AADD)
   350  		p2.From.Type = obj.TYPE_CONST
   351  		p2.From.Offset = sz
   352  		p2.To.Type = obj.TYPE_REG
   353  		p2.To.Reg = v.Args[0].Reg()
   354  
   355  		p3 := s.Prog(riscv.ABGEU)
   356  		p3.To.Type = obj.TYPE_BRANCH
   357  		p3.Reg = v.Args[0].Reg()
   358  		p3.From.Type = obj.TYPE_REG
   359  		p3.From.Reg = v.Args[1].Reg()
   360  		gc.Patch(p3, p)
   361  
   362  	case ssa.OpRISCV64LoweredMove:
   363  		mov, sz := largestMove(v.AuxInt)
   364  
   365  		//	mov	(Rarg1), T2
   366  		//	mov	T2, (Rarg0)
   367  		//	ADD	$sz, Rarg0
   368  		//	ADD	$sz, Rarg1
   369  		//	BGEU	Rarg2, Rarg0, -4(PC)
   370  
   371  		p := s.Prog(mov)
   372  		p.From.Type = obj.TYPE_MEM
   373  		p.From.Reg = v.Args[1].Reg()
   374  		p.To.Type = obj.TYPE_REG
   375  		p.To.Reg = riscv.REG_T2
   376  
   377  		p2 := s.Prog(mov)
   378  		p2.From.Type = obj.TYPE_REG
   379  		p2.From.Reg = riscv.REG_T2
   380  		p2.To.Type = obj.TYPE_MEM
   381  		p2.To.Reg = v.Args[0].Reg()
   382  
   383  		p3 := s.Prog(riscv.AADD)
   384  		p3.From.Type = obj.TYPE_CONST
   385  		p3.From.Offset = sz
   386  		p3.To.Type = obj.TYPE_REG
   387  		p3.To.Reg = v.Args[0].Reg()
   388  
   389  		p4 := s.Prog(riscv.AADD)
   390  		p4.From.Type = obj.TYPE_CONST
   391  		p4.From.Offset = sz
   392  		p4.To.Type = obj.TYPE_REG
   393  		p4.To.Reg = v.Args[1].Reg()
   394  
   395  		p5 := s.Prog(riscv.ABGEU)
   396  		p5.To.Type = obj.TYPE_BRANCH
   397  		p5.Reg = v.Args[1].Reg()
   398  		p5.From.Type = obj.TYPE_REG
   399  		p5.From.Reg = v.Args[2].Reg()
   400  		gc.Patch(p5, p)
   401  
   402  	case ssa.OpRISCV64LoweredNilCheck:
   403  		// Issue a load which will fault if arg is nil.
   404  		// TODO: optimizations. See arm and amd64 LoweredNilCheck.
   405  		p := s.Prog(riscv.AMOVB)
   406  		p.From.Type = obj.TYPE_MEM
   407  		p.From.Reg = v.Args[0].Reg()
   408  		gc.AddAux(&p.From, v)
   409  		p.To.Type = obj.TYPE_REG
   410  		p.To.Reg = riscv.REG_ZERO
   411  		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos == 1 in generated wrappers
   412  			gc.Warnl(v.Pos, "generated nil check")
   413  		}
   414  
   415  	case ssa.OpRISCV64LoweredGetClosurePtr:
   416  		// Closure pointer is S4 (riscv.REG_CTXT).
   417  		gc.CheckLoweredGetClosurePtr(v)
   418  
   419  	case ssa.OpRISCV64LoweredGetCallerSP:
   420  		// caller's SP is FixedFrameSize below the address of the first arg
   421  		p := s.Prog(riscv.AMOV)
   422  		p.From.Type = obj.TYPE_ADDR
   423  		p.From.Offset = -gc.Ctxt.FixedFrameSize()
   424  		p.From.Name = obj.NAME_PARAM
   425  		p.To.Type = obj.TYPE_REG
   426  		p.To.Reg = v.Reg()
   427  
   428  	case ssa.OpRISCV64LoweredGetCallerPC:
   429  		p := s.Prog(obj.AGETCALLERPC)
   430  		p.To.Type = obj.TYPE_REG
   431  		p.To.Reg = v.Reg()
   432  
   433  	default:
   434  		v.Fatalf("Unhandled op %v", v.Op)
   435  	}
   436  }
   437  
   438  func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   439  	s.SetPos(b.Pos)
   440  
   441  	switch b.Kind {
   442  	case ssa.BlockDefer:
   443  		// defer returns in A0:
   444  		// 0 if we should continue executing
   445  		// 1 if we should jump to deferreturn call
   446  		p := s.Prog(riscv.ABNE)
   447  		p.To.Type = obj.TYPE_BRANCH
   448  		p.From.Type = obj.TYPE_REG
   449  		p.From.Reg = riscv.REG_ZERO
   450  		p.Reg = riscv.REG_A0
   451  		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   452  		if b.Succs[0].Block() != next {
   453  			p := s.Prog(obj.AJMP)
   454  			p.To.Type = obj.TYPE_BRANCH
   455  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   456  		}
   457  	case ssa.BlockPlain:
   458  		if b.Succs[0].Block() != next {
   459  			p := s.Prog(obj.AJMP)
   460  			p.To.Type = obj.TYPE_BRANCH
   461  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   462  		}
   463  	case ssa.BlockExit:
   464  	case ssa.BlockRet:
   465  		s.Prog(obj.ARET)
   466  	case ssa.BlockRetJmp:
   467  		p := s.Prog(obj.AJMP)
   468  		p.To.Type = obj.TYPE_MEM
   469  		p.To.Name = obj.NAME_EXTERN
   470  		p.To.Sym = b.Aux.(*obj.LSym)
   471  	case ssa.BlockRISCV64BNE:
   472  		var p *obj.Prog
   473  		switch next {
   474  		case b.Succs[0].Block():
   475  			p = s.Br(riscv.ABNE, b.Succs[1].Block())
   476  			p.As = riscv.InvertBranch(p.As)
   477  		case b.Succs[1].Block():
   478  			p = s.Br(riscv.ABNE, b.Succs[0].Block())
   479  		default:
   480  			if b.Likely != ssa.BranchUnlikely {
   481  				p = s.Br(riscv.ABNE, b.Succs[0].Block())
   482  				s.Br(obj.AJMP, b.Succs[1].Block())
   483  			} else {
   484  				p = s.Br(riscv.ABNE, b.Succs[1].Block())
   485  				p.As = riscv.InvertBranch(p.As)
   486  				s.Br(obj.AJMP, b.Succs[0].Block())
   487  			}
   488  		}
   489  		p.Reg = b.Controls[0].Reg()
   490  		p.From.Type = obj.TYPE_REG
   491  		p.From.Reg = riscv.REG_ZERO
   492  
   493  	default:
   494  		b.Fatalf("Unhandled block: %s", b.LongString())
   495  	}
   496  }