github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/ssa/gen/MIPS64Ops.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  // +build ignore
     6  
     7  package main
     8  
     9  import "strings"
    10  
    11  // Notes:
    12  //  - Integer types live in the low portion of registers. Upper portions are junk.
    13  //  - Boolean types use the low-order byte of a register. 0=false, 1=true.
    14  //    Upper bytes are junk.
    15  //  - *const instructions may use a constant larger than the instuction can encode.
    16  //    In this case the assembler expands to multiple instructions and uses tmp
    17  //    register (R23).
    18  
    19  // Suffixes encode the bit width of various instructions.
    20  // V (vlong)     = 64 bit
    21  // WU (word)     = 32 bit unsigned
    22  // W (word)      = 32 bit
    23  // H (half word) = 16 bit
    24  // HU            = 16 bit unsigned
    25  // B (byte)      = 8 bit
    26  // BU            = 8 bit unsigned
    27  // F (float)     = 32 bit float
    28  // D (double)    = 64 bit float
    29  
    30  // Note: registers not used in regalloc are not included in this list,
    31  // so that regmask stays within int64
    32  // Be careful when hand coding regmasks.
    33  var regNamesMIPS64 = []string{
    34  	"R0", // constant 0
    35  	"R1",
    36  	"R2",
    37  	"R3",
    38  	"R4",
    39  	"R5",
    40  	"R6",
    41  	"R7",
    42  	"R8",
    43  	"R9",
    44  	"R10",
    45  	"R11",
    46  	"R12",
    47  	"R13",
    48  	"R14",
    49  	"R15",
    50  	"R16",
    51  	"R17",
    52  	"R18",
    53  	"R19",
    54  	"R20",
    55  	"R21",
    56  	"R22",
    57  	// R23 = REGTMP not used in regalloc
    58  	"R24",
    59  	"R25",
    60  	// R26 reserved by kernel
    61  	// R27 reserved by kernel
    62  	// R28 = REGSB not used in regalloc
    63  	"SP", // aka R29
    64  	"g",  // aka R30
    65  	// R31 = REGLINK not used in regalloc
    66  
    67  	"F0",
    68  	"F1",
    69  	"F2",
    70  	"F3",
    71  	"F4",
    72  	"F5",
    73  	"F6",
    74  	"F7",
    75  	"F8",
    76  	"F9",
    77  	"F10",
    78  	"F11",
    79  	"F12",
    80  	"F13",
    81  	"F14",
    82  	"F15",
    83  	"F16",
    84  	"F17",
    85  	"F18",
    86  	"F19",
    87  	"F20",
    88  	"F21",
    89  	"F22",
    90  	"F23",
    91  	"F24", // 0.0
    92  	"F25",
    93  	"F26", // 0.5
    94  	"F27",
    95  	"F28", // 1.0
    96  	"F29",
    97  	"F30", // 2.0
    98  	"F31",
    99  
   100  	"HI", // high bits of multiplication
   101  	"LO", // low bits of multiplication
   102  
   103  	// pseudo-registers
   104  	"SB",
   105  }
   106  
   107  func init() {
   108  	// Make map from reg names to reg integers.
   109  	if len(regNamesMIPS64) > 64 {
   110  		panic("too many registers")
   111  	}
   112  	num := map[string]int{}
   113  	for i, name := range regNamesMIPS64 {
   114  		num[name] = i
   115  	}
   116  	buildReg := func(s string) regMask {
   117  		m := regMask(0)
   118  		for _, r := range strings.Split(s, " ") {
   119  			if n, ok := num[r]; ok {
   120  				m |= regMask(1) << uint(n)
   121  				continue
   122  			}
   123  			panic("register " + r + " not found")
   124  		}
   125  		return m
   126  	}
   127  
   128  	// Common individual register masks
   129  	var (
   130  		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")
   131  		gpg        = gp | buildReg("g")
   132  		gpsp       = gp | buildReg("SP")
   133  		gpspg      = gpg | buildReg("SP")
   134  		gpspsbg    = gpspg | buildReg("SB")
   135  		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 F25 F27 F29 F31")
   136  		lo         = buildReg("LO")
   137  		hi         = buildReg("HI")
   138  		callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
   139  	)
   140  	// Common regInfo
   141  	var (
   142  		gp01     = regInfo{inputs: nil, outputs: []regMask{gp}}
   143  		gp11     = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
   144  		gp11sp   = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
   145  		gp21     = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
   146  		gp2hilo  = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
   147  		gpload   = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
   148  		gpstore  = regInfo{inputs: []regMask{gpspsbg, gpg}}
   149  		gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
   150  		fp01     = regInfo{inputs: nil, outputs: []regMask{fp}}
   151  		fp11     = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
   152  		//fp1flags  = regInfo{inputs: []regMask{fp}}
   153  		//fpgp      = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
   154  		//gpfp      = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
   155  		fp21      = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
   156  		fp2flags  = regInfo{inputs: []regMask{fp, fp}}
   157  		fpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
   158  		fpstore   = regInfo{inputs: []regMask{gpspsbg, fp}}
   159  		readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
   160  	)
   161  	ops := []opData{
   162  		// binary ops
   163  		{name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true},                             // arg0 + arg1
   164  		{name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"},                           // arg0 + auxInt
   165  		{name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"},                                                // arg0 - arg1
   166  		{name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"},                             // arg0 - auxInt
   167  		{name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"},     // arg0 * arg1, signed, results hi,lo
   168  		{name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo
   169  		{name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"},                        // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   170  		{name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"},                    // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   171  
   172  		{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
   173  		{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
   174  		{name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0 - arg1
   175  		{name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0 - arg1
   176  		{name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
   177  		{name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
   178  		{name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0 / arg1
   179  		{name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0 / arg1
   180  
   181  		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0 & arg1
   182  		{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"},                // arg0 & auxInt
   183  		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
   184  		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                  // arg0 | auxInt
   185  		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1
   186  		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt
   187  		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^(arg0 | arg1)
   188  		{name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"},                // ^(arg0 | auxInt)
   189  
   190  		{name: "NEGV", argLength: 1, reg: gp11},              // -arg0
   191  		{name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32
   192  		{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64
   193  
   194  		// shifts
   195  		{name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"},                    // arg0 << arg1, shift amount is mod 64
   196  		{name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt
   197  		{name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"},                    // arg0 >> arg1, unsigned, shift amount is mod 64
   198  		{name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned
   199  		{name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"},                    // arg0 >> arg1, signed, shift amount is mod 64
   200  		{name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed
   201  
   202  		// comparisons
   203  		{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
   204  		{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
   205  		{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
   206  		{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
   207  
   208  		{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
   209  		{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
   210  		{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
   211  		{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
   212  		{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
   213  		{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
   214  
   215  		// moves
   216  		{name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true},    // auxint
   217  		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
   218  		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
   219  
   220  		{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
   221  
   222  		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8"},     // load from arg0 + auxInt + aux.  arg1=mem.
   223  		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8"},  // load from arg0 + auxInt + aux.  arg1=mem.
   224  		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16"},    // load from arg0 + auxInt + aux.  arg1=mem.
   225  		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16"}, // load from arg0 + auxInt + aux.  arg1=mem.
   226  		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32"},    // load from arg0 + auxInt + aux.  arg1=mem.
   227  		{name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32"}, // load from arg0 + auxInt + aux.  arg1=mem.
   228  		{name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64"},   // load from arg0 + auxInt + aux.  arg1=mem.
   229  		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32"},  // load from arg0 + auxInt + aux.  arg1=mem.
   230  		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64"},  // load from arg0 + auxInt + aux.  arg1=mem.
   231  
   232  		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem"}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
   233  		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   234  		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   235  		{name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   236  		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   237  		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   238  
   239  		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem"}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
   240  		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem"}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
   241  		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem"}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
   242  		{name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem"}, // store 8 bytes of zero to arg0 + auxInt + aux.  ar12=mem.
   243  
   244  		// conversions
   245  		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
   246  		{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
   247  		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
   248  		{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
   249  		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0, sign-extended from word
   250  		{name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
   251  		{name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"},   // move from arg0
   252  
   253  		{name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
   254  
   255  		{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
   256  		{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
   257  		{name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"},     // int64 -> float32
   258  		{name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"},     // int64 -> float64
   259  		{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
   260  		{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
   261  		{name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64
   262  		{name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64
   263  		{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
   264  		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
   265  
   266  		// function calls
   267  		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true},                                              // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
   268  		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
   269  		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true},                                                // call deferproc.  arg0=mem, auxint=argsize, returns mem
   270  		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true},                                                   // call newproc.  arg0=mem, auxint=argsize, returns mem
   271  		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
   272  
   273  		// duffzero
   274  		// arg0 = address of memory to zero
   275  		// arg1 = mem
   276  		// auxint = offset into duffzero code to start executing
   277  		// returns mem
   278  		// R1 aka mips.REGRT1 changed as side effect
   279  		{
   280  			name:      "DUFFZERO",
   281  			aux:       "Int64",
   282  			argLength: 2,
   283  			reg: regInfo{
   284  				inputs:   []regMask{gp},
   285  				clobbers: buildReg("R1"),
   286  			},
   287  		},
   288  
   289  		// large or unaligned zeroing
   290  		// arg0 = address of memory to zero (in R1, changed as side effect)
   291  		// arg1 = address of the last element to zero
   292  		// arg2 = mem
   293  		// auxint = alignment
   294  		// returns mem
   295  		//	SUBV	$8, R1
   296  		//	MOVV	R0, 8(R1)
   297  		//	ADDV	$8, R1
   298  		//	BNE	Rarg1, R1, -2(PC)
   299  		{
   300  			name:      "LoweredZero",
   301  			aux:       "Int64",
   302  			argLength: 3,
   303  			reg: regInfo{
   304  				inputs:   []regMask{buildReg("R1"), gp},
   305  				clobbers: buildReg("R1"),
   306  			},
   307  			clobberFlags: true,
   308  		},
   309  
   310  		// large or unaligned move
   311  		// arg0 = address of dst memory (in R2, changed as side effect)
   312  		// arg1 = address of src memory (in R1, changed as side effect)
   313  		// arg2 = address of the last element of src
   314  		// arg3 = mem
   315  		// auxint = alignment
   316  		// returns mem
   317  		//	SUBV	$8, R1
   318  		//	MOVV	8(R1), Rtmp
   319  		//	MOVV	Rtmp, (R2)
   320  		//	ADDV	$8, R1
   321  		//	ADDV	$8, R2
   322  		//	BNE	Rarg2, R1, -4(PC)
   323  		{
   324  			name:      "LoweredMove",
   325  			aux:       "Int64",
   326  			argLength: 4,
   327  			reg: regInfo{
   328  				inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
   329  				clobbers: buildReg("R1 R2"),
   330  			},
   331  			clobberFlags: true,
   332  		},
   333  
   334  		// pseudo-ops
   335  		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}}, // panic if arg0 is nil.  arg1=mem.
   336  
   337  		{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
   338  		{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
   339  
   340  		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   341  		// and sorts it to the very beginning of the block to prevent other
   342  		// use of R22 (mips.REGCTXT, the closure pointer)
   343  		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}},
   344  
   345  		// MOVDconvert converts between pointers and integers.
   346  		// We have a special op for this so as to not confuse GC
   347  		// (particularly stack maps).  It takes a memory arg so it
   348  		// gets correctly ordered with respect to GC safepoints.
   349  		// arg0=ptr/int arg1=mem, output=int/ptr
   350  		{name: "MOVVconvert", argLength: 2, reg: gp11, asm: "MOVV"},
   351  	}
   352  
   353  	blocks := []blockData{
   354  		{name: "EQ"},
   355  		{name: "NE"},
   356  		{name: "LTZ"}, // < 0
   357  		{name: "LEZ"}, // <= 0
   358  		{name: "GTZ"}, // > 0
   359  		{name: "GEZ"}, // >= 0
   360  		{name: "FPT"}, // FP flag is true
   361  		{name: "FPF"}, // FP flag is false
   362  	}
   363  
   364  	archs = append(archs, arch{
   365  		name:            "MIPS64",
   366  		pkg:             "cmd/internal/obj/mips",
   367  		genfile:         "../../mips64/ssa.go",
   368  		ops:             ops,
   369  		blocks:          blocks,
   370  		regnames:        regNamesMIPS64,
   371  		gpregmask:       gp,
   372  		fpregmask:       fp,
   373  		specialregmask:  hi | lo,
   374  		framepointerreg: -1, // not used
   375  	})
   376  }