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  	"HI", // high bits of multiplication
    99  	"LO", // low bits of multiplication
   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(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 R31")
   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 F24 F25 F26 F27 F28 F29 F30 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  		first16    = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16")
   140  		rz         = buildReg("ZERO")
   141  	)
   142  	// Common regInfo
   143  	var (
   144  		gp01   = regInfo{inputs: nil, outputs: []regMask{gp}}
   145  		gp11   = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
   146  		gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
   147  		gp21   = regInfo{inputs: []regMask{gpg, gpg | rz}, outputs: []regMask{gp}}
   148  		// Multiply/divide move their results out of HI/LO into general
   149  		// registers as part of the op itself: a value living in HI/LO
   150  		// cannot be spilled, as spilling needs REGTMP as the data
   151  		// register, which collides with REGTMP-based address
   152  		// materialization when the frame is too large for 16-bit offsets.
   153  		gp22clobbershilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, gp}, clobbers: hi | lo}
   154  		gpload           = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
   155  		gpstore          = regInfo{inputs: []regMask{gpspsbg, gpg | rz}}
   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: gp22clobbershilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"},     // arg0 * arg1, signed, results high,low
   177  		{name: "MULVU", argLength: 2, reg: gp22clobbershilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results high,low
   178  		{name: "DIVV", argLength: 2, reg: gp22clobbershilo, asm: "DIVV", typ: "(Int64,Int64)"},                        // arg0 / arg1, signed, results arg0%arg1,arg0/arg1
   179  		{name: "DIVVU", argLength: 2, reg: gp22clobbershilo, asm: "DIVVU", typ: "(UInt64,UInt64)"},                    // arg0 / arg1, unsigned, results arg0%arg1,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: "ABSD", argLength: 1, reg: fp11, asm: "ABSD"},   // abs(arg0), float64
   203  		{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
   204  		{name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32
   205  
   206  		// shifts
   207  		{name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"},                    // arg0 << arg1, shift amount is mod 64
   208  		{name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt
   209  		{name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"},                    // arg0 >> arg1, unsigned, shift amount is mod 64
   210  		{name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned
   211  		{name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"},                    // arg0 >> arg1, signed, shift amount is mod 64
   212  		{name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed
   213  
   214  		// comparisons
   215  		{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
   216  		{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
   217  		{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
   218  		{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
   219  
   220  		{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
   221  		{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
   222  		{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
   223  		{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
   224  		{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
   225  		{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
   226  
   227  		// moves
   228  		{name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true},    // auxint
   229  		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
   230  		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
   231  
   232  		{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
   233  
   234  		{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.
   235  		{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.
   236  		{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.
   237  		{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.
   238  		{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.
   239  		{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.
   240  		{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.
   241  		{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.
   242  		{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.
   243  
   244  		{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.
   245  		{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.
   246  		{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.
   247  		{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.
   248  		{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.
   249  		{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.
   250  
   251  		{name: "ZERO", zeroWidth: true, fixedReg: true},
   252  
   253  		// moves (no conversion)
   254  		{name: "MOVWfpgp", argLength: 1, reg: fpgp, asm: "MOVW"}, // move float32 to int32 (no conversion). MIPS64 will perform sign-extend to 64-bit by default
   255  		{name: "MOVWgpfp", argLength: 1, reg: gpfp, asm: "MOVW"}, // move int32 to float32 (no conversion). MIPS64 will perform sign-extend to 64-bit by default
   256  		{name: "MOVVfpgp", argLength: 1, reg: fpgp, asm: "MOVV"}, // move float64 to int64 (no conversion).
   257  		{name: "MOVVgpfp", argLength: 1, reg: gpfp, asm: "MOVV"}, // move int64 to float64 (no conversion).
   258  
   259  		// conversions
   260  		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
   261  		{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
   262  		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
   263  		{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
   264  		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0, sign-extended from word
   265  		{name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
   266  		{name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"},   // move from arg0
   267  
   268  		{name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
   269  
   270  		{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
   271  		{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
   272  		{name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"},     // int64 -> float32
   273  		{name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"},     // int64 -> float64
   274  		{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
   275  		{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
   276  		{name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64
   277  		{name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64
   278  		{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
   279  		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
   280  
   281  		// function calls
   282  		{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
   283  		{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
   284  		{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
   285  		{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
   286  
   287  		// duffzero
   288  		// arg0 = address of memory to zero
   289  		// arg1 = mem
   290  		// auxint = offset into duffzero code to start executing
   291  		// returns mem
   292  		// R1 aka mips.REGRT1 changed as side effect
   293  		{
   294  			name:      "DUFFZERO",
   295  			aux:       "Int64",
   296  			argLength: 2,
   297  			reg: regInfo{
   298  				inputs:   []regMask{gp},
   299  				clobbers: buildReg("R1 R31"),
   300  			},
   301  			faultOnNilArg0: true,
   302  			addrSinkArg0:   true,
   303  		},
   304  
   305  		// duffcopy
   306  		// arg0 = address of dst memory (in R2, changed as side effect)
   307  		// arg1 = address of src memory (in R1, changed as side effect)
   308  		// arg2 = mem
   309  		// auxint = offset into duffcopy code to start executing
   310  		// returns mem
   311  		{
   312  			name:      "DUFFCOPY",
   313  			aux:       "Int64",
   314  			argLength: 3,
   315  			reg: regInfo{
   316  				inputs:   []regMask{buildReg("R2"), buildReg("R1")},
   317  				clobbers: buildReg("R1 R2 R31"),
   318  			},
   319  			faultOnNilArg0: true,
   320  			faultOnNilArg1: true,
   321  			addrSinkArg0:   true,
   322  			addrSinkArg1:   true,
   323  		},
   324  
   325  		// large or unaligned zeroing
   326  		// arg0 = address of memory to zero (in R1, changed as side effect)
   327  		// arg1 = address of the last element to zero
   328  		// arg2 = mem
   329  		// auxint = alignment
   330  		// returns mem
   331  		//	SUBV	$8, R1
   332  		//	MOVV	R0, 8(R1)
   333  		//	ADDV	$8, R1
   334  		//	BNE	Rarg1, R1, -2(PC)
   335  		{
   336  			name:      "LoweredZero",
   337  			aux:       "Int64",
   338  			argLength: 3,
   339  			reg: regInfo{
   340  				inputs:   []regMask{buildReg("R1"), gp},
   341  				clobbers: buildReg("R1"),
   342  			},
   343  			clobberFlags:   true,
   344  			faultOnNilArg0: true,
   345  			addrSinkArg0:   true,
   346  			addrSinkArg1:   true,
   347  		},
   348  
   349  		// large or unaligned move
   350  		// arg0 = address of dst memory (in R2, changed as side effect)
   351  		// arg1 = address of src memory (in R1, changed as side effect)
   352  		// arg2 = address of the last element of src
   353  		// arg3 = mem
   354  		// auxint = alignment
   355  		// returns mem
   356  		//	SUBV	$8, R1
   357  		//	MOVV	8(R1), Rtmp
   358  		//	MOVV	Rtmp, (R2)
   359  		//	ADDV	$8, R1
   360  		//	ADDV	$8, R2
   361  		//	BNE	Rarg2, R1, -4(PC)
   362  		{
   363  			name:      "LoweredMove",
   364  			aux:       "Int64",
   365  			argLength: 4,
   366  			reg: regInfo{
   367  				inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
   368  				clobbers: buildReg("R1 R2"),
   369  			},
   370  			clobberFlags:   true,
   371  			faultOnNilArg0: true,
   372  			faultOnNilArg1: true,
   373  			addrSinkArg0:   true,
   374  			addrSinkArg1:   true,
   375  			// TODO: could use addrSinkArg2 here.
   376  		},
   377  
   378  		// atomic and/or.
   379  		// *arg0 &= (|=) arg1. arg2=mem. returns memory.
   380  		// SYNC
   381  		// LL	(Rarg0), Rtmp
   382  		// AND	Rarg1, Rtmp
   383  		// SC	Rtmp, (Rarg0)
   384  		// BEQ	Rtmp, -3(PC)
   385  		// SYNC
   386  		{name: "LoweredAtomicAnd32", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   387  		{name: "LoweredAtomicOr32", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   388  
   389  		// atomic loads.
   390  		// load from arg0. arg1=mem.
   391  		// returns <value,memory> so they can be properly ordered with other loads.
   392  		{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
   393  		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
   394  		{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true},
   395  
   396  		// atomic stores.
   397  		// store arg1 to arg0. arg2=mem. returns memory.
   398  		{name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   399  		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   400  		{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   401  		// store zero to arg0. arg1=mem. returns memory.
   402  		{name: "LoweredAtomicStorezero32", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   403  		{name: "LoweredAtomicStorezero64", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   404  
   405  		// atomic exchange.
   406  		// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
   407  		// SYNC
   408  		// LL	(Rarg0), Rout
   409  		// MOVV Rarg1, Rtmp
   410  		// SC	Rtmp, (Rarg0)
   411  		// BEQ	Rtmp, -3(PC)
   412  		// SYNC
   413  		{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   414  		{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   415  
   416  		// atomic add.
   417  		// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
   418  		// SYNC
   419  		// LL	(Rarg0), Rout
   420  		// ADDV Rarg1, Rout, Rtmp
   421  		// SC	Rtmp, (Rarg0)
   422  		// BEQ	Rtmp, -3(PC)
   423  		// SYNC
   424  		// ADDV Rarg1, Rout
   425  		{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   426  		{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   427  		// *arg0 += auxint. arg1=mem. returns <new content of *arg0, memory>. auxint is 32-bit.
   428  		{name: "LoweredAtomicAddconst32", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   429  		{name: "LoweredAtomicAddconst64", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int64", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   430  
   431  		// atomic compare and swap.
   432  		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
   433  		// if *arg0 == arg1 {
   434  		//   *arg0 = arg2
   435  		//   return (true, memory)
   436  		// } else {
   437  		//   return (false, memory)
   438  		// }
   439  		// SYNC
   440  		// MOVV $0, Rout
   441  		// LL	(Rarg0), Rtmp
   442  		// BNE	Rtmp, Rarg1, 4(PC)
   443  		// MOVV Rarg2, Rout
   444  		// SC	Rout, (Rarg0)
   445  		// BEQ	Rout, -4(PC)
   446  		// SYNC
   447  		{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   448  		{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   449  
   450  		// pseudo-ops
   451  		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
   452  
   453  		{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
   454  		{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
   455  
   456  		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   457  		// and sorts it to the very beginning of the block to prevent other
   458  		// use of R22 (mips.REGCTXT, the closure pointer)
   459  		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
   460  
   461  		// LoweredGetCallerSP returns the SP of the caller of the current function. arg0=mem.
   462  		{name: "LoweredGetCallerSP", argLength: 1, reg: gp01, rematerializeable: true},
   463  
   464  		// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
   465  		// I.e., if f calls g "calls" sys.GetCallerPC,
   466  		// the result should be the PC within f that g will return to.
   467  		// See runtime/stubs.go for a more detailed discussion.
   468  		{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
   469  
   470  		// LoweredWB invokes runtime.gcWriteBarrier. arg0=mem, auxint=# of buffer entries needed
   471  		// It saves all GP registers if necessary,
   472  		// but clobbers R31 (LR) because it's a call
   473  		// and R23 (REGTMP).
   474  		// Returns a pointer to a write barrier buffer in R25.
   475  		{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R31"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
   476  
   477  		// Do data barrier. arg0=memorys
   478  		{name: "LoweredPubBarrier", argLength: 1, asm: "SYNC", hasSideEffects: true},
   479  
   480  		// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
   481  		// the RC and CR versions are used when one of the arguments is a constant. CC is used
   482  		// when both are constant (normally both 0, as prove derives the fact that a [0] bounds
   483  		// failure means the length must have also been 0).
   484  		// AuxInt contains a report code (see PanicBounds in genericOps.go).
   485  		{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{first16, first16}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
   486  		{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first16}}, typ: "Mem", call: true},   // arg0=x, arg1=mem, returns memory.
   487  		{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first16}}, typ: "Mem", call: true},   // arg0=y, arg1=mem, returns memory.
   488  		{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true},                            // arg0=mem, returns memory.
   489  	}
   490  
   491  	blocks := []blockData{
   492  		{name: "EQ", controls: 1},
   493  		{name: "NE", controls: 1},
   494  		{name: "LTZ", controls: 1}, // < 0
   495  		{name: "LEZ", controls: 1}, // <= 0
   496  		{name: "GTZ", controls: 1}, // > 0
   497  		{name: "GEZ", controls: 1}, // >= 0
   498  		{name: "FPT", controls: 1}, // FP flag is true
   499  		{name: "FPF", controls: 1}, // FP flag is false
   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  		specialregmask:  hi | lo,
   512  		framepointerreg: -1, // not used
   513  		linkreg:         int8(num["R31"]),
   514  	})
   515  }
   516  

View as plain text