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  //go:build ignore
     6  // +build ignore
     7  
     8  package main
     9  
    10  import "strings"
    11  
    12  // Notes:
    13  //  - Integer types live in the low portion of registers. Upper portions are junk.
    14  //  - Boolean types use the low-order byte of a register. 0=false, 1=true.
    15  //    Upper bytes are junk.
    16  //  - Unused portions of AuxInt are filled by sign-extending the used portion.
    17  //  - *const instructions may use a constant larger than the instruction can encode.
    18  //    In this case the assembler expands to multiple instructions and uses tmp
    19  //    register (R23).
    20  
    21  // Suffixes encode the bit width of various instructions.
    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 regNamesMIPS = []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  	//REGTMP
    58  	"R24",
    59  	"R25",
    60  	// R26 reserved by kernel
    61  	// R27 reserved by kernel
    62  	"R28",
    63  	"SP",  // aka R29
    64  	"g",   // aka R30
    65  	"R31", // REGLINK
    66  
    67  	// odd FP registers contain high parts of 64-bit FP values
    68  	"F0",
    69  	"F2",
    70  	"F4",
    71  	"F6",
    72  	"F8",
    73  	"F10",
    74  	"F12",
    75  	"F14",
    76  	"F16",
    77  	"F18",
    78  	"F20",
    79  	"F22",
    80  	"F24",
    81  	"F26",
    82  	"F28",
    83  	"F30",
    84  
    85  	"HI", // high bits of multiplication
    86  	"LO", // low bits of multiplication
    87  
    88  	// If you add registers, update asyncPreempt in runtime.
    89  
    90  	// pseudo-registers
    91  	"SB",
    92  }
    93  
    94  func init() {
    95  	// Make map from reg names to reg integers.
    96  	if len(regNamesMIPS) > 64 {
    97  		panic("too many registers")
    98  	}
    99  	num := map[string]int{}
   100  	for i, name := range regNamesMIPS {
   101  		num[name] = i
   102  	}
   103  	buildReg := func(s string) regMask {
   104  		m := regMask(0)
   105  		for _, r := range strings.Split(s, " ") {
   106  			if n, ok := num[r]; ok {
   107  				m |= regMask(1) << uint(n)
   108  				continue
   109  			}
   110  			panic("register " + r + " not found")
   111  		}
   112  		return m
   113  	}
   114  
   115  	// Common individual register masks
   116  	var (
   117  		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")
   118  		gpg        = gp | buildReg("g")
   119  		gpsp       = gp | buildReg("SP")
   120  		gpspg      = gpg | buildReg("SP")
   121  		gpspsbg    = gpspg | buildReg("SB")
   122  		fp         = buildReg("F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30")
   123  		lo         = buildReg("LO")
   124  		hi         = buildReg("HI")
   125  		callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
   126  		r1         = buildReg("R1")
   127  		r2         = buildReg("R2")
   128  		r3         = buildReg("R3")
   129  		r4         = buildReg("R4")
   130  		r5         = buildReg("R5")
   131  	)
   132  	// Common regInfo
   133  	var (
   134  		gp01      = regInfo{inputs: nil, outputs: []regMask{gp}}
   135  		gp11      = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
   136  		gp11sp    = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
   137  		gp21      = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
   138  		gp31      = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
   139  		gp2hilo   = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
   140  		gpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
   141  		gpstore   = regInfo{inputs: []regMask{gpspsbg, gpg}}
   142  		gpxchg    = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
   143  		gpcas     = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
   144  		gpstore0  = regInfo{inputs: []regMask{gpspsbg}}
   145  		fp01      = regInfo{inputs: nil, outputs: []regMask{fp}}
   146  		fp11      = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
   147  		fp21      = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
   148  		fp2flags  = regInfo{inputs: []regMask{fp, fp}}
   149  		fpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
   150  		fpstore   = regInfo{inputs: []regMask{gpspsbg, fp}}
   151  		readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
   152  	)
   153  	ops := []opData{
   154  		{name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true},                                                                           // arg0 + arg1
   155  		{name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"},                                                                         // arg0 + auxInt
   156  		{name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"},                                                                                              // arg0 - arg1
   157  		{name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"},                                                                           // arg0 - auxInt
   158  		{name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi | lo}, asm: "MUL", commutative: true}, // arg0 * arg1
   159  		{name: "MULT", argLength: 2, reg: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"},                                                  // arg0 * arg1, signed, results hi,lo
   160  		{name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"},                                              // arg0 * arg1, unsigned, results hi,lo
   161  		{name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)"},                                                                      // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   162  		{name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)"},                                                                  // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   163  
   164  		{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
   165  		{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
   166  		{name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0 - arg1
   167  		{name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0 - arg1
   168  		{name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
   169  		{name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
   170  		{name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0 / arg1
   171  		{name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0 / arg1
   172  
   173  		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0 & arg1
   174  		{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int32"},                // arg0 & auxInt
   175  		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
   176  		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int32"},                  // arg0 | auxInt
   177  		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt32"}, // arg0 ^ arg1
   178  		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int32", typ: "UInt32"}, // arg0 ^ auxInt
   179  		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^(arg0 | arg1)
   180  		{name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int32"},                // ^(arg0 | auxInt)
   181  
   182  		{name: "NEG", argLength: 1, reg: gp11},                 // -arg0
   183  		{name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"},   // -arg0, float32
   184  		{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0, float64
   185  		{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
   186  		{name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32
   187  
   188  		// shifts
   189  		{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                    // arg0 << arg1, shift amount is mod 32
   190  		{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, shift amount must be 0 through 31 inclusive
   191  		{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                    // arg0 >> arg1, unsigned, shift amount is mod 32
   192  		{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, shift amount must be 0 through 31 inclusive
   193  		{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                    // arg0 >> arg1, signed, shift amount is mod 32
   194  		{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, shift amount must be 0 through 31 inclusive
   195  
   196  		{name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"},
   197  
   198  		// comparisons
   199  		{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
   200  		{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
   201  		{name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"},                  // 1 if arg0 > 0 (signed), 0 otherwise
   202  		{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
   203  		{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
   204  		{name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"},                // 1 if arg0 > 0 (unsigned), 0 otherwise
   205  
   206  		{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
   207  		{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
   208  		{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
   209  		{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
   210  		{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
   211  		{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
   212  
   213  		// moves
   214  		{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true},    // auxint
   215  		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
   216  		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
   217  
   218  		{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
   219  
   220  		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
   221  		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   222  		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
   223  		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
   224  		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
   225  		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   226  		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   227  
   228  		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
   229  		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   230  		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   231  		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   232  		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   233  
   234  		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
   235  		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
   236  		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
   237  
   238  		// conversions
   239  		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
   240  		{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
   241  		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
   242  		{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
   243  		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0
   244  
   245  		{name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
   246  
   247  		// conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0)
   248  		// order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg)
   249  		{name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true},
   250  		{name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true},
   251  
   252  		{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
   253  		{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
   254  		{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
   255  		{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
   256  		{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
   257  		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
   258  
   259  		// function calls
   260  		{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
   261  		{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
   262  		{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
   263  		{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
   264  
   265  		// atomic ops
   266  
   267  		// load from arg0. arg1=mem.
   268  		// returns <value,memory> so they can be properly ordered with other loads.
   269  		// SYNC
   270  		// MOV(B|W)	(Rarg0), Rout
   271  		// SYNC
   272  		{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
   273  		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
   274  
   275  		// store arg1 to arg0. arg2=mem. returns memory.
   276  		// SYNC
   277  		// MOV(B|W)	Rarg1, (Rarg0)
   278  		// SYNC
   279  		{name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   280  		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   281  		{name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   282  
   283  		// atomic exchange.
   284  		// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
   285  		// SYNC
   286  		// LL	(Rarg0), Rout
   287  		// MOVW Rarg1, Rtmp
   288  		// SC	Rtmp, (Rarg0)
   289  		// BEQ	Rtmp, -3(PC)
   290  		// SYNC
   291  		{name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   292  
   293  		// atomic add.
   294  		// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
   295  		// SYNC
   296  		// LL	(Rarg0), Rout
   297  		// ADDU Rarg1, Rout, Rtmp
   298  		// SC	Rtmp, (Rarg0)
   299  		// BEQ	Rtmp, -3(PC)
   300  		// SYNC
   301  		// ADDU Rarg1, Rout
   302  		{name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   303  		{name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   304  
   305  		// atomic compare and swap.
   306  		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
   307  		// if *arg0 == arg1 {
   308  		//   *arg0 = arg2
   309  		//   return (true, memory)
   310  		// } else {
   311  		//   return (false, memory)
   312  		// }
   313  		// SYNC
   314  		// MOVW $0, Rout
   315  		// LL	(Rarg0), Rtmp
   316  		// BNE	Rtmp, Rarg1, 4(PC)
   317  		// MOVW Rarg2, Rout
   318  		// SC	Rout, (Rarg0)
   319  		// BEQ	Rout, -4(PC)
   320  		// SYNC
   321  		{name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   322  
   323  		// atomic and/or.
   324  		// *arg0 &= (|=) arg1. arg2=mem. returns memory.
   325  		// SYNC
   326  		// LL	(Rarg0), Rtmp
   327  		// AND	Rarg1, Rtmp
   328  		// SC	Rtmp, (Rarg0)
   329  		// BEQ	Rtmp, -3(PC)
   330  		// SYNC
   331  		{name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   332  		{name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   333  
   334  		// large or unaligned zeroing
   335  		// arg0 = address of memory to zero (in R1, changed as side effect)
   336  		// arg1 = address of the last element to zero
   337  		// arg2 = mem
   338  		// auxint = alignment
   339  		// returns mem
   340  		//	SUBU	$4, R1
   341  		//	MOVW	R0, 4(R1)
   342  		//	ADDU	$4, R1
   343  		//	BNE	Rarg1, R1, -2(PC)
   344  		{
   345  			name:      "LoweredZero",
   346  			aux:       "Int32",
   347  			argLength: 3,
   348  			reg: regInfo{
   349  				inputs:   []regMask{buildReg("R1"), gp},
   350  				clobbers: buildReg("R1"),
   351  			},
   352  			faultOnNilArg0: true,
   353  		},
   354  
   355  		// large or unaligned move
   356  		// arg0 = address of dst memory (in R2, changed as side effect)
   357  		// arg1 = address of src memory (in R1, changed as side effect)
   358  		// arg2 = address of the last element of src
   359  		// arg3 = mem
   360  		// auxint = alignment
   361  		// returns mem
   362  		//	SUBU	$4, R1
   363  		//	MOVW	4(R1), Rtmp
   364  		//	MOVW	Rtmp, (R2)
   365  		//	ADDU	$4, R1
   366  		//	ADDU	$4, R2
   367  		//	BNE	Rarg2, R1, -4(PC)
   368  		{
   369  			name:      "LoweredMove",
   370  			aux:       "Int32",
   371  			argLength: 4,
   372  			reg: regInfo{
   373  				inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
   374  				clobbers: buildReg("R1 R2"),
   375  			},
   376  			faultOnNilArg0: true,
   377  			faultOnNilArg1: true,
   378  		},
   379  
   380  		// pseudo-ops
   381  		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
   382  
   383  		{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
   384  		{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
   385  
   386  		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   387  		// and sorts it to the very beginning of the block to prevent other
   388  		// use of R22 (mips.REGCTXT, the closure pointer)
   389  		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
   390  
   391  		// LoweredGetCallerSP returns the SP of the caller of the current function.
   392  		{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
   393  
   394  		// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
   395  		// I.e., if f calls g "calls" getcallerpc,
   396  		// the result should be the PC within f that g will return to.
   397  		// See runtime/stubs.go for a more detailed discussion.
   398  		{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
   399  
   400  		// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
   401  		// It saves all GP registers if necessary,
   402  		// but clobbers R31 (LR) because it's a call
   403  		// and R23 (REGTMP).
   404  		{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
   405  
   406  		// There are three of these functions so that they can have three different register inputs.
   407  		// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
   408  		// default registers to match so we don't need to copy registers around unnecessarily.
   409  		{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   410  		{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   411  		{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   412  		// Extend ops are the same as Bounds ops except the indexes are 64-bit.
   413  		{name: "LoweredPanicExtendA", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r3, r4}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
   414  		{name: "LoweredPanicExtendB", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r2, r3}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
   415  		{name: "LoweredPanicExtendC", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r1, r2}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
   416  	}
   417  
   418  	blocks := []blockData{
   419  		{name: "EQ", controls: 1},
   420  		{name: "NE", controls: 1},
   421  		{name: "LTZ", controls: 1}, // < 0
   422  		{name: "LEZ", controls: 1}, // <= 0
   423  		{name: "GTZ", controls: 1}, // > 0
   424  		{name: "GEZ", controls: 1}, // >= 0
   425  		{name: "FPT", controls: 1}, // FP flag is true
   426  		{name: "FPF", controls: 1}, // FP flag is false
   427  	}
   428  
   429  	archs = append(archs, arch{
   430  		name:            "MIPS",
   431  		pkg:             "cmd/internal/obj/mips",
   432  		genfile:         "../../mips/ssa.go",
   433  		ops:             ops,
   434  		blocks:          blocks,
   435  		regnames:        regNamesMIPS,
   436  		gpregmask:       gp,
   437  		fpregmask:       fp,
   438  		specialregmask:  hi | lo,
   439  		framepointerreg: -1, // not used
   440  		linkreg:         int8(num["R31"]),
   441  	})
   442  }
   443  

View as plain text