Source file src/cmd/compile/internal/ssa/gen/MIPS64Ops.go

     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  //go:build ignore
     6  // +build ignore
     7  
     8  package main
     9  
    10  import "strings"
    11  
    12  // Notes:
    13  //  - Integer types live in the low portion of registers. Upper portions are junk.
    14  //  - Boolean types use the low-order byte of a register. 0=false, 1=true.
    15  //    Upper bytes are junk.
    16  //  - *const instructions may use a constant larger than the instruction can encode.
    17  //    In this case the assembler expands to multiple instructions and uses tmp
    18  //    register (R23).
    19  
    20  // Suffixes encode the bit width of various instructions.
    21  // V (vlong)     = 64 bit
    22  // WU (word)     = 32 bit unsigned
    23  // W (word)      = 32 bit
    24  // H (half word) = 16 bit
    25  // HU            = 16 bit unsigned
    26  // B (byte)      = 8 bit
    27  // BU            = 8 bit unsigned
    28  // F (float)     = 32 bit float
    29  // D (double)    = 64 bit float
    30  
    31  // Note: registers not used in regalloc are not included in this list,
    32  // so that regmask stays within int64
    33  // Be careful when hand coding regmasks.
    34  var regNamesMIPS64 = []string{
    35  	"R0", // constant 0
    36  	"R1",
    37  	"R2",
    38  	"R3",
    39  	"R4",
    40  	"R5",
    41  	"R6",
    42  	"R7",
    43  	"R8",
    44  	"R9",
    45  	"R10",
    46  	"R11",
    47  	"R12",
    48  	"R13",
    49  	"R14",
    50  	"R15",
    51  	"R16",
    52  	"R17",
    53  	"R18",
    54  	"R19",
    55  	"R20",
    56  	"R21",
    57  	"R22",
    58  	// R23 = REGTMP not used in regalloc
    59  	"R24",
    60  	"R25",
    61  	// R26 reserved by kernel
    62  	// R27 reserved by kernel
    63  	// R28 = REGSB not used in regalloc
    64  	"SP",  // aka R29
    65  	"g",   // aka R30
    66  	"R31", // aka REGLINK
    67  
    68  	"F0",
    69  	"F1",
    70  	"F2",
    71  	"F3",
    72  	"F4",
    73  	"F5",
    74  	"F6",
    75  	"F7",
    76  	"F8",
    77  	"F9",
    78  	"F10",
    79  	"F11",
    80  	"F12",
    81  	"F13",
    82  	"F14",
    83  	"F15",
    84  	"F16",
    85  	"F17",
    86  	"F18",
    87  	"F19",
    88  	"F20",
    89  	"F21",
    90  	"F22",
    91  	"F23",
    92  	"F24",
    93  	"F25",
    94  	"F26",
    95  	"F27",
    96  	"F28",
    97  	"F29",
    98  	"F30",
    99  	"F31",
   100  
   101  	"HI", // high bits of multiplication
   102  	"LO", // low bits of multiplication
   103  
   104  	// If you add registers, update asyncPreempt in runtime.
   105  
   106  	// pseudo-registers
   107  	"SB",
   108  }
   109  
   110  func init() {
   111  	// Make map from reg names to reg integers.
   112  	if len(regNamesMIPS64) > 64 {
   113  		panic("too many registers")
   114  	}
   115  	num := map[string]int{}
   116  	for i, name := range regNamesMIPS64 {
   117  		num[name] = i
   118  	}
   119  	buildReg := func(s string) regMask {
   120  		m := regMask(0)
   121  		for _, r := range strings.Split(s, " ") {
   122  			if n, ok := num[r]; ok {
   123  				m |= regMask(1) << uint(n)
   124  				continue
   125  			}
   126  			panic("register " + r + " not found")
   127  		}
   128  		return m
   129  	}
   130  
   131  	// Common individual register masks
   132  	var (
   133  		gp         = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31")
   134  		gpg        = gp | buildReg("g")
   135  		gpsp       = gp | buildReg("SP")
   136  		gpspg      = gpg | buildReg("SP")
   137  		gpspsbg    = gpspg | buildReg("SB")
   138  		fp         = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
   139  		lo         = buildReg("LO")
   140  		hi         = buildReg("HI")
   141  		callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
   142  		r1         = buildReg("R1")
   143  		r2         = buildReg("R2")
   144  		r3         = buildReg("R3")
   145  		r4         = buildReg("R4")
   146  	)
   147  	// Common regInfo
   148  	var (
   149  		gp01     = regInfo{inputs: nil, outputs: []regMask{gp}}
   150  		gp11     = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
   151  		gp11sp   = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
   152  		gp21     = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
   153  		gp2hilo  = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
   154  		gpload   = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
   155  		gpstore  = regInfo{inputs: []regMask{gpspsbg, gpg}}
   156  		gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
   157  		gpxchg   = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
   158  		gpcas    = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
   159  		fp01     = regInfo{inputs: nil, outputs: []regMask{fp}}
   160  		fp11     = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
   161  		//fp1flags  = regInfo{inputs: []regMask{fp}}
   162  		//fpgp      = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
   163  		//gpfp      = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
   164  		fp21      = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
   165  		fp2flags  = regInfo{inputs: []regMask{fp, fp}}
   166  		fpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
   167  		fpstore   = regInfo{inputs: []regMask{gpspsbg, fp}}
   168  		readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
   169  	)
   170  	ops := []opData{
   171  		// binary ops
   172  		{name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true},                             // arg0 + arg1
   173  		{name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"},                           // arg0 + auxInt. auxInt is 32-bit, also in other *const ops.
   174  		{name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"},                                                // arg0 - arg1
   175  		{name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"},                             // arg0 - auxInt
   176  		{name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"},     // arg0 * arg1, signed, results hi,lo
   177  		{name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo
   178  		{name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"},                        // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   179  		{name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"},                    // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   180  
   181  		{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
   182  		{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
   183  		{name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0 - arg1
   184  		{name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0 - arg1
   185  		{name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
   186  		{name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
   187  		{name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0 / arg1
   188  		{name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0 / arg1
   189  
   190  		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0 & arg1
   191  		{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"},                // arg0 & auxInt
   192  		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
   193  		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                  // arg0 | auxInt
   194  		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1
   195  		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt
   196  		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^(arg0 | arg1)
   197  		{name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"},                // ^(arg0 | auxInt)
   198  
   199  		{name: "NEGV", argLength: 1, reg: gp11},                // -arg0
   200  		{name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"},   // -arg0, float32
   201  		{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0, float64
   202  		{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
   203  		{name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32
   204  
   205  		// shifts
   206  		{name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"},                    // arg0 << arg1, shift amount is mod 64
   207  		{name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt
   208  		{name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"},                    // arg0 >> arg1, unsigned, shift amount is mod 64
   209  		{name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned
   210  		{name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"},                    // arg0 >> arg1, signed, shift amount is mod 64
   211  		{name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed
   212  
   213  		// comparisons
   214  		{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
   215  		{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
   216  		{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
   217  		{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
   218  
   219  		{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
   220  		{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
   221  		{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
   222  		{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
   223  		{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
   224  		{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
   225  
   226  		// moves
   227  		{name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true},    // auxint
   228  		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
   229  		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
   230  
   231  		{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
   232  
   233  		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
   234  		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   235  		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
   236  		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
   237  		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
   238  		{name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
   239  		{name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
   240  		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   241  		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   242  
   243  		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
   244  		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   245  		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   246  		{name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   247  		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   248  		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   249  
   250  		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
   251  		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
   252  		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
   253  		{name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of zero to arg0 + auxInt + aux.  ar12=mem.
   254  
   255  		// conversions
   256  		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
   257  		{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
   258  		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
   259  		{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
   260  		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0, sign-extended from word
   261  		{name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
   262  		{name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"},   // move from arg0
   263  
   264  		{name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
   265  
   266  		{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
   267  		{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
   268  		{name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"},     // int64 -> float32
   269  		{name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"},     // int64 -> float64
   270  		{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
   271  		{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
   272  		{name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64
   273  		{name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64
   274  		{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
   275  		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
   276  
   277  		// function calls
   278  		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                               // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
   279  		{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                                 // tail call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
   280  		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
   281  		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
   282  
   283  		// duffzero
   284  		// arg0 = address of memory to zero
   285  		// arg1 = mem
   286  		// auxint = offset into duffzero code to start executing
   287  		// returns mem
   288  		// R1 aka mips.REGRT1 changed as side effect
   289  		{
   290  			name:      "DUFFZERO",
   291  			aux:       "Int64",
   292  			argLength: 2,
   293  			reg: regInfo{
   294  				inputs:   []regMask{gp},
   295  				clobbers: buildReg("R1 R31"),
   296  			},
   297  			faultOnNilArg0: true,
   298  		},
   299  
   300  		// duffcopy
   301  		// arg0 = address of dst memory (in R2, changed as side effect)
   302  		// arg1 = address of src memory (in R1, changed as side effect)
   303  		// arg2 = mem
   304  		// auxint = offset into duffcopy code to start executing
   305  		// returns mem
   306  		{
   307  			name:      "DUFFCOPY",
   308  			aux:       "Int64",
   309  			argLength: 3,
   310  			reg: regInfo{
   311  				inputs:   []regMask{buildReg("R2"), buildReg("R1")},
   312  				clobbers: buildReg("R1 R2 R31"),
   313  			},
   314  			faultOnNilArg0: true,
   315  			faultOnNilArg1: true,
   316  		},
   317  
   318  		// large or unaligned zeroing
   319  		// arg0 = address of memory to zero (in R1, changed as side effect)
   320  		// arg1 = address of the last element to zero
   321  		// arg2 = mem
   322  		// auxint = alignment
   323  		// returns mem
   324  		//	SUBV	$8, R1
   325  		//	MOVV	R0, 8(R1)
   326  		//	ADDV	$8, R1
   327  		//	BNE	Rarg1, R1, -2(PC)
   328  		{
   329  			name:      "LoweredZero",
   330  			aux:       "Int64",
   331  			argLength: 3,
   332  			reg: regInfo{
   333  				inputs:   []regMask{buildReg("R1"), gp},
   334  				clobbers: buildReg("R1"),
   335  			},
   336  			clobberFlags:   true,
   337  			faultOnNilArg0: true,
   338  		},
   339  
   340  		// large or unaligned move
   341  		// arg0 = address of dst memory (in R2, changed as side effect)
   342  		// arg1 = address of src memory (in R1, changed as side effect)
   343  		// arg2 = address of the last element of src
   344  		// arg3 = mem
   345  		// auxint = alignment
   346  		// returns mem
   347  		//	SUBV	$8, R1
   348  		//	MOVV	8(R1), Rtmp
   349  		//	MOVV	Rtmp, (R2)
   350  		//	ADDV	$8, R1
   351  		//	ADDV	$8, R2
   352  		//	BNE	Rarg2, R1, -4(PC)
   353  		{
   354  			name:      "LoweredMove",
   355  			aux:       "Int64",
   356  			argLength: 4,
   357  			reg: regInfo{
   358  				inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
   359  				clobbers: buildReg("R1 R2"),
   360  			},
   361  			clobberFlags:   true,
   362  			faultOnNilArg0: true,
   363  			faultOnNilArg1: true,
   364  		},
   365  
   366  		// atomic loads.
   367  		// load from arg0. arg1=mem.
   368  		// returns <value,memory> so they can be properly ordered with other loads.
   369  		{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
   370  		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
   371  		{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true},
   372  
   373  		// atomic stores.
   374  		// store arg1 to arg0. arg2=mem. returns memory.
   375  		{name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   376  		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   377  		{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   378  		// store zero to arg0. arg1=mem. returns memory.
   379  		{name: "LoweredAtomicStorezero32", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   380  		{name: "LoweredAtomicStorezero64", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   381  
   382  		// atomic exchange.
   383  		// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
   384  		// SYNC
   385  		// LL	(Rarg0), Rout
   386  		// MOVV Rarg1, Rtmp
   387  		// SC	Rtmp, (Rarg0)
   388  		// BEQ	Rtmp, -3(PC)
   389  		// SYNC
   390  		{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   391  		{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   392  
   393  		// atomic add.
   394  		// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
   395  		// SYNC
   396  		// LL	(Rarg0), Rout
   397  		// ADDV Rarg1, Rout, Rtmp
   398  		// SC	Rtmp, (Rarg0)
   399  		// BEQ	Rtmp, -3(PC)
   400  		// SYNC
   401  		// ADDV Rarg1, Rout
   402  		{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   403  		{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   404  		// *arg0 += auxint. arg1=mem. returns <new content of *arg0, memory>. auxint is 32-bit.
   405  		{name: "LoweredAtomicAddconst32", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   406  		{name: "LoweredAtomicAddconst64", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int64", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   407  
   408  		// atomic compare and swap.
   409  		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
   410  		// if *arg0 == arg1 {
   411  		//   *arg0 = arg2
   412  		//   return (true, memory)
   413  		// } else {
   414  		//   return (false, memory)
   415  		// }
   416  		// SYNC
   417  		// MOVV $0, Rout
   418  		// LL	(Rarg0), Rtmp
   419  		// BNE	Rtmp, Rarg1, 4(PC)
   420  		// MOVV Rarg2, Rout
   421  		// SC	Rout, (Rarg0)
   422  		// BEQ	Rout, -4(PC)
   423  		// SYNC
   424  		{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   425  		{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   426  
   427  		// pseudo-ops
   428  		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
   429  
   430  		{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
   431  		{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
   432  
   433  		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   434  		// and sorts it to the very beginning of the block to prevent other
   435  		// use of R22 (mips.REGCTXT, the closure pointer)
   436  		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
   437  
   438  		// LoweredGetCallerSP returns the SP of the caller of the current function.
   439  		{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
   440  
   441  		// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
   442  		// I.e., if f calls g "calls" getcallerpc,
   443  		// the result should be the PC within f that g will return to.
   444  		// See runtime/stubs.go for a more detailed discussion.
   445  		{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
   446  
   447  		// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
   448  		// It saves all GP registers if necessary,
   449  		// but clobbers R31 (LR) because it's a call
   450  		// and R23 (REGTMP).
   451  		{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
   452  
   453  		// There are three of these functions so that they can have three different register inputs.
   454  		// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
   455  		// default registers to match so we don't need to copy registers around unnecessarily.
   456  		{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   457  		{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   458  		{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   459  	}
   460  
   461  	blocks := []blockData{
   462  		{name: "EQ", controls: 1},
   463  		{name: "NE", controls: 1},
   464  		{name: "LTZ", controls: 1}, // < 0
   465  		{name: "LEZ", controls: 1}, // <= 0
   466  		{name: "GTZ", controls: 1}, // > 0
   467  		{name: "GEZ", controls: 1}, // >= 0
   468  		{name: "FPT", controls: 1}, // FP flag is true
   469  		{name: "FPF", controls: 1}, // FP flag is false
   470  	}
   471  
   472  	archs = append(archs, arch{
   473  		name:            "MIPS64",
   474  		pkg:             "cmd/internal/obj/mips",
   475  		genfile:         "../../mips64/ssa.go",
   476  		ops:             ops,
   477  		blocks:          blocks,
   478  		regnames:        regNamesMIPS64,
   479  		gpregmask:       gp,
   480  		fpregmask:       fp,
   481  		specialregmask:  hi | lo,
   482  		framepointerreg: -1, // not used
   483  		linkreg:         int8(num["R31"]),
   484  	})
   485  }
   486  

View as plain text