Source file src/cmd/compile/internal/ssa/_gen/MIPSOps.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  //  - Unused portions of AuxInt are filled by sign-extending the used portion.
    14  //  - *const instructions may use a constant larger than the instruction can encode.
    15  //    In this case the assembler expands to multiple instructions and uses tmp
    16  //    register (R23).
    17  
    18  // Suffixes encode the bit width of various instructions.
    19  // W (word)      = 32 bit
    20  // H (half word) = 16 bit
    21  // HU            = 16 bit unsigned
    22  // B (byte)      = 8 bit
    23  // BU            = 8 bit unsigned
    24  // F (float)     = 32 bit float
    25  // D (double)    = 64 bit float
    26  
    27  // Note: registers not used in regalloc are not included in this list,
    28  // so that regmask stays within int64
    29  // Be careful when hand coding regmasks.
    30  var regNamesMIPS = []string{
    31  	"R0", // constant 0
    32  	"R1",
    33  	"R2",
    34  	"R3",
    35  	"R4",
    36  	"R5",
    37  	"R6",
    38  	"R7",
    39  	"R8",
    40  	"R9",
    41  	"R10",
    42  	"R11",
    43  	"R12",
    44  	"R13",
    45  	"R14",
    46  	"R15",
    47  	"R16",
    48  	"R17",
    49  	"R18",
    50  	"R19",
    51  	"R20",
    52  	"R21",
    53  	"R22",
    54  	//REGTMP
    55  	"R24",
    56  	"R25",
    57  	// R26 reserved by kernel
    58  	// R27 reserved by kernel
    59  	"R28",
    60  	"SP",  // aka R29
    61  	"g",   // aka R30
    62  	"R31", // REGLINK
    63  
    64  	// odd FP registers contain high parts of 64-bit FP values
    65  	"F0",
    66  	"F2",
    67  	"F4",
    68  	"F6",
    69  	"F8",
    70  	"F10",
    71  	"F12",
    72  	"F14",
    73  	"F16",
    74  	"F18",
    75  	"F20",
    76  	"F22",
    77  	"F24",
    78  	"F26",
    79  	"F28",
    80  	"F30",
    81  
    82  	"HI", // high bits of multiplication
    83  	"LO", // low bits of multiplication
    84  
    85  	// If you add registers, update asyncPreempt in runtime.
    86  
    87  	// pseudo-registers
    88  	"SB",
    89  }
    90  
    91  func init() {
    92  	// Make map from reg names to reg integers.
    93  	if len(regNamesMIPS) > 64 {
    94  		panic("too many registers")
    95  	}
    96  	num := map[string]int{}
    97  	for i, name := range regNamesMIPS {
    98  		num[name] = i
    99  	}
   100  	buildReg := func(s string) regMask {
   101  		m := regMask(0)
   102  		for _, r := range strings.Split(s, " ") {
   103  			if n, ok := num[r]; ok {
   104  				m |= regMask(1) << uint(n)
   105  				continue
   106  			}
   107  			panic("register " + r + " not found")
   108  		}
   109  		return m
   110  	}
   111  
   112  	// Common individual register masks
   113  	var (
   114  		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 R28 R31")
   115  		gpg        = gp | buildReg("g")
   116  		gpsp       = gp | buildReg("SP")
   117  		gpspg      = gpg | buildReg("SP")
   118  		gpspsbg    = gpspg | buildReg("SB")
   119  		fp         = buildReg("F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30")
   120  		lo         = buildReg("LO")
   121  		hi         = buildReg("HI")
   122  		callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
   123  		first16    = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16")
   124  		first4     = buildReg("R1 R2 R3 R4")
   125  	)
   126  	// Common regInfo
   127  	var (
   128  		gp01   = regInfo{inputs: nil, outputs: []regMask{gp}}
   129  		gp11   = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
   130  		gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
   131  		gp21   = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
   132  		gp31   = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
   133  		// See MIPS64Ops.go: results must not stay homed in HI/LO.
   134  		gp22clobbershilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, gp}, clobbers: hi | lo}
   135  		gpload           = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
   136  		gpstore          = regInfo{inputs: []regMask{gpspsbg, gpg}}
   137  		gpxchg           = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
   138  		gpcas            = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
   139  		gpstore0         = regInfo{inputs: []regMask{gpspsbg}}
   140  		fpgp             = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
   141  		gpfp             = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
   142  		fp01             = regInfo{inputs: nil, outputs: []regMask{fp}}
   143  		fp11             = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
   144  		fp21             = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
   145  		fp2flags         = regInfo{inputs: []regMask{fp, fp}}
   146  		fpload           = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
   147  		fpstore          = regInfo{inputs: []regMask{gpspsbg, fp}}
   148  		readflags        = regInfo{inputs: nil, outputs: []regMask{gp}}
   149  	)
   150  	ops := []opData{
   151  		{name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true},                                                                           // arg0 + arg1
   152  		{name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"},                                                                         // arg0 + auxInt
   153  		{name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"},                                                                                              // arg0 - arg1
   154  		{name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"},                                                                           // arg0 - auxInt
   155  		{name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi | lo}, asm: "MUL", commutative: true}, // arg0 * arg1
   156  		{name: "MULT", argLength: 2, reg: gp22clobbershilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"},                                         // arg0 * arg1, signed, results high,low
   157  		{name: "MULTU", argLength: 2, reg: gp22clobbershilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"},                                     // arg0 * arg1, unsigned, results high,low
   158  		{name: "DIV", argLength: 2, reg: gp22clobbershilo, asm: "DIV", typ: "(Int32,Int32)"},                                                             // arg0 / arg1, signed, results arg0%arg1,arg0/arg1
   159  		{name: "DIVU", argLength: 2, reg: gp22clobbershilo, asm: "DIVU", typ: "(UInt32,UInt32)"},                                                         // arg0 / arg1, signed, results arg0%arg1,arg0/arg1
   160  
   161  		{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
   162  		{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
   163  		{name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0 - arg1
   164  		{name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0 - arg1
   165  		{name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
   166  		{name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
   167  		{name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0 / arg1
   168  		{name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0 / arg1
   169  
   170  		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0 & arg1
   171  		{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int32"},                // arg0 & auxInt
   172  		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
   173  		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int32"},                  // arg0 | auxInt
   174  		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt32"}, // arg0 ^ arg1
   175  		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int32", typ: "UInt32"}, // arg0 ^ auxInt
   176  		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^(arg0 | arg1)
   177  		{name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int32"},                // ^(arg0 | auxInt)
   178  
   179  		{name: "NEG", argLength: 1, reg: gp11},                 // -arg0
   180  		{name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"},   // -arg0, float32
   181  		{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0, float64
   182  		{name: "ABSD", argLength: 1, reg: fp11, asm: "ABSD"},   // abs(arg0), float64
   183  		{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
   184  		{name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32
   185  
   186  		// shifts
   187  		{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                    // arg0 << arg1, shift amount is mod 32
   188  		{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, shift amount must be 0 through 31 inclusive
   189  		{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                    // arg0 >> arg1, unsigned, shift amount is mod 32
   190  		{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, shift amount must be 0 through 31 inclusive
   191  		{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                    // arg0 >> arg1, signed, shift amount is mod 32
   192  		{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, shift amount must be 0 through 31 inclusive
   193  
   194  		{name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"},
   195  
   196  		// comparisons
   197  		{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
   198  		{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
   199  		{name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"},                  // 1 if arg0 > 0 (signed), 0 otherwise
   200  		{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
   201  		{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
   202  		{name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"},                // 1 if arg0 > 0 (unsigned), 0 otherwise
   203  
   204  		{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
   205  		{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
   206  		{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
   207  		{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
   208  		{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
   209  		{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
   210  
   211  		// moves
   212  		{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true},    // auxint
   213  		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
   214  		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
   215  
   216  		{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
   217  
   218  		{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.
   219  		{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.
   220  		{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.
   221  		{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.
   222  		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true},   // load from arg0 + auxInt + aux.  arg1=mem.
   223  		{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.
   224  		{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.
   225  
   226  		{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.
   227  		{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.
   228  		{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.
   229  		{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.
   230  		{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.
   231  
   232  		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
   233  		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
   234  		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
   235  
   236  		// moves (no conversion)
   237  		{name: "MOVWfpgp", argLength: 1, reg: fpgp, asm: "MOVW"}, // move float32 to int32 (no conversion)
   238  		{name: "MOVWgpfp", argLength: 1, reg: gpfp, asm: "MOVW"}, // move int32 to float32 (no conversion)
   239  
   240  		// conversions
   241  		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
   242  		{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
   243  		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
   244  		{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
   245  		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0
   246  
   247  		{name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
   248  
   249  		// conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0)
   250  		// order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg)
   251  		{name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true},
   252  		{name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true},
   253  
   254  		{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
   255  		{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
   256  		{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
   257  		{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
   258  		{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
   259  		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
   260  
   261  		// function calls
   262  		{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
   263  		{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
   264  		{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
   265  		{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
   266  
   267  		// atomic ops
   268  
   269  		// load from arg0. arg1=mem.
   270  		// returns <value,memory> so they can be properly ordered with other loads.
   271  		// SYNC
   272  		// MOV(B|W)	(Rarg0), Rout
   273  		// SYNC
   274  		{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
   275  		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
   276  
   277  		// store arg1 to arg0. arg2=mem. returns memory.
   278  		// SYNC
   279  		// MOV(B|W)	Rarg1, (Rarg0)
   280  		// SYNC
   281  		{name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   282  		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   283  		{name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   284  
   285  		// atomic exchange.
   286  		// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
   287  		// SYNC
   288  		// LL	(Rarg0), Rout
   289  		// MOVW Rarg1, Rtmp
   290  		// SC	Rtmp, (Rarg0)
   291  		// BEQ	Rtmp, -3(PC)
   292  		// SYNC
   293  		{name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   294  
   295  		// atomic add.
   296  		// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
   297  		// SYNC
   298  		// LL	(Rarg0), Rout
   299  		// ADDU Rarg1, Rout, Rtmp
   300  		// SC	Rtmp, (Rarg0)
   301  		// BEQ	Rtmp, -3(PC)
   302  		// SYNC
   303  		// ADDU Rarg1, Rout
   304  		{name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   305  		{name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   306  
   307  		// atomic compare and swap.
   308  		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
   309  		// if *arg0 == arg1 {
   310  		//   *arg0 = arg2
   311  		//   return (true, memory)
   312  		// } else {
   313  		//   return (false, memory)
   314  		// }
   315  		// SYNC
   316  		// MOVW $0, Rout
   317  		// LL	(Rarg0), Rtmp
   318  		// BNE	Rtmp, Rarg1, 4(PC)
   319  		// MOVW Rarg2, Rout
   320  		// SC	Rout, (Rarg0)
   321  		// BEQ	Rout, -4(PC)
   322  		// SYNC
   323  		{name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   324  
   325  		// atomic and/or.
   326  		// *arg0 &= (|=) arg1. arg2=mem. returns memory.
   327  		// SYNC
   328  		// LL	(Rarg0), Rtmp
   329  		// AND	Rarg1, Rtmp
   330  		// SC	Rtmp, (Rarg0)
   331  		// BEQ	Rtmp, -3(PC)
   332  		// SYNC
   333  		{name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   334  		{name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   335  
   336  		// large or unaligned zeroing
   337  		// arg0 = address of memory to zero (in R1, changed as side effect)
   338  		// arg1 = address of the last element to zero
   339  		// arg2 = mem
   340  		// auxint = alignment
   341  		// returns mem
   342  		//	SUBU	$4, R1
   343  		//	MOVW	R0, 4(R1)
   344  		//	ADDU	$4, R1
   345  		//	BNE	Rarg1, R1, -2(PC)
   346  		{
   347  			name:      "LoweredZero",
   348  			aux:       "Int32",
   349  			argLength: 3,
   350  			reg: regInfo{
   351  				inputs:   []regMask{buildReg("R1"), gp},
   352  				clobbers: buildReg("R1"),
   353  			},
   354  			faultOnNilArg0: true,
   355  			addrSinkArg0:   true,
   356  			addrSinkArg1:   true,
   357  		},
   358  
   359  		// large or unaligned move
   360  		// arg0 = address of dst memory (in R2, changed as side effect)
   361  		// arg1 = address of src memory (in R1, changed as side effect)
   362  		// arg2 = address of the last element of src
   363  		// arg3 = mem
   364  		// auxint = alignment
   365  		// returns mem
   366  		//	SUBU	$4, R1
   367  		//	MOVW	4(R1), Rtmp
   368  		//	MOVW	Rtmp, (R2)
   369  		//	ADDU	$4, R1
   370  		//	ADDU	$4, R2
   371  		//	BNE	Rarg2, R1, -4(PC)
   372  		{
   373  			name:      "LoweredMove",
   374  			aux:       "Int32",
   375  			argLength: 4,
   376  			reg: regInfo{
   377  				inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
   378  				clobbers: buildReg("R1 R2"),
   379  			},
   380  			faultOnNilArg0: true,
   381  			faultOnNilArg1: true,
   382  			addrSinkArg0:   true,
   383  			addrSinkArg1:   true,
   384  			// TODO: could use addrSinkArg2 here.
   385  		},
   386  
   387  		// pseudo-ops
   388  		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
   389  
   390  		{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
   391  		{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
   392  
   393  		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   394  		// and sorts it to the very beginning of the block to prevent other
   395  		// use of R22 (mips.REGCTXT, the closure pointer)
   396  		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
   397  
   398  		// LoweredGetCallerSP returns the SP of the caller of the current function. arg0=mem.
   399  		{name: "LoweredGetCallerSP", argLength: 1, reg: gp01, rematerializeable: true},
   400  
   401  		// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
   402  		// I.e., if f calls g "calls" sys.GetCallerPC,
   403  		// the result should be the PC within f that g will return to.
   404  		// See runtime/stubs.go for a more detailed discussion.
   405  		{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
   406  
   407  		// LoweredWB invokes runtime.gcWriteBarrier. arg0=mem, auxint=# of buffer entries needed
   408  		// It saves all GP registers if necessary,
   409  		// but clobbers R31 (LR) because it's a call
   410  		// and R23 (REGTMP).
   411  		// Returns a pointer to a write barrier buffer in R25.
   412  		{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R31"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
   413  
   414  		// Do data barrier. arg0=memorys
   415  		{name: "LoweredPubBarrier", argLength: 1, asm: "SYNC", hasSideEffects: true},
   416  
   417  		// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
   418  		// the RC and CR versions are used when one of the arguments is a constant. CC is used
   419  		// when both are constant (normally both 0, as prove derives the fact that a [0] bounds
   420  		// failure means the length must have also been 0).
   421  		// AuxInt contains a report code (see PanicBounds in genericOps.go).
   422  		{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{first16, first16}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
   423  		{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first16}}, typ: "Mem", call: true},   // arg0=x, arg1=mem, returns memory.
   424  		{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first16}}, typ: "Mem", call: true},   // arg0=y, arg1=mem, returns memory.
   425  		{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true},                            // arg0=mem, returns memory.
   426  
   427  		// Same as above, but the x value is 64 bits.
   428  		{name: "LoweredPanicExtendRR", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{first4, first4, first16}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=y, arg3=mem, returns memory.
   429  		{name: "LoweredPanicExtendRC", argLength: 3, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first4, first4}}, typ: "Mem", call: true},   // arg0=x_hi, arg1=x_lo, arg2=mem, returns memory.
   430  	}
   431  
   432  	blocks := []blockData{
   433  		{name: "EQ", controls: 1},
   434  		{name: "NE", controls: 1},
   435  		{name: "LTZ", controls: 1}, // < 0
   436  		{name: "LEZ", controls: 1}, // <= 0
   437  		{name: "GTZ", controls: 1}, // > 0
   438  		{name: "GEZ", controls: 1}, // >= 0
   439  		{name: "FPT", controls: 1}, // FP flag is true
   440  		{name: "FPF", controls: 1}, // FP flag is false
   441  	}
   442  
   443  	archs = append(archs, arch{
   444  		name:            "MIPS",
   445  		pkg:             "cmd/internal/obj/mips",
   446  		genfile:         "../../mips/ssa.go",
   447  		ops:             ops,
   448  		blocks:          blocks,
   449  		regnames:        regNamesMIPS,
   450  		gpregmask:       gp,
   451  		fpregmask:       fp,
   452  		specialregmask:  hi | lo,
   453  		framepointerreg: -1, // not used
   454  		linkreg:         int8(num["R31"]),
   455  	})
   456  }
   457  

View as plain text