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

View as plain text