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  		gp2hilo   = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
   134  		gpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
   135  		gpstore   = regInfo{inputs: []regMask{gpspsbg, gpg}}
   136  		gpxchg    = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
   137  		gpcas     = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
   138  		gpstore0  = regInfo{inputs: []regMask{gpspsbg}}
   139  		fpgp      = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
   140  		gpfp      = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
   141  		fp01      = regInfo{inputs: nil, outputs: []regMask{fp}}
   142  		fp11      = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
   143  		fp21      = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
   144  		fp2flags  = regInfo{inputs: []regMask{fp, fp}}
   145  		fpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
   146  		fpstore   = regInfo{inputs: []regMask{gpspsbg, fp}}
   147  		readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
   148  	)
   149  	ops := []opData{
   150  		{name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true},                                                                           // arg0 + arg1
   151  		{name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"},                                                                         // arg0 + auxInt
   152  		{name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"},                                                                                              // arg0 - arg1
   153  		{name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"},                                                                           // arg0 - auxInt
   154  		{name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi | lo}, asm: "MUL", commutative: true}, // arg0 * arg1
   155  		{name: "MULT", argLength: 2, reg: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"},                                                  // arg0 * arg1, signed, results hi,lo
   156  		{name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"},                                              // arg0 * arg1, unsigned, results hi,lo
   157  		{name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)"},                                                                      // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   158  		{name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)"},                                                                  // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   159  
   160  		{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
   161  		{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
   162  		{name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0 - arg1
   163  		{name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0 - arg1
   164  		{name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
   165  		{name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
   166  		{name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0 / arg1
   167  		{name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0 / arg1
   168  
   169  		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0 & arg1
   170  		{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int32"},                // arg0 & auxInt
   171  		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
   172  		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int32"},                  // arg0 | auxInt
   173  		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt32"}, // arg0 ^ arg1
   174  		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int32", typ: "UInt32"}, // arg0 ^ auxInt
   175  		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^(arg0 | arg1)
   176  		{name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int32"},                // ^(arg0 | auxInt)
   177  
   178  		{name: "NEG", argLength: 1, reg: gp11},                 // -arg0
   179  		{name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"},   // -arg0, float32
   180  		{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0, float64
   181  		{name: "ABSD", argLength: 1, reg: fp11, asm: "ABSD"},   // abs(arg0), float64
   182  		{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
   183  		{name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32
   184  
   185  		// shifts
   186  		{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                    // arg0 << arg1, shift amount is mod 32
   187  		{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, shift amount must be 0 through 31 inclusive
   188  		{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                    // arg0 >> arg1, unsigned, shift amount is mod 32
   189  		{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, shift amount must be 0 through 31 inclusive
   190  		{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                    // arg0 >> arg1, signed, shift amount is mod 32
   191  		{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, shift amount must be 0 through 31 inclusive
   192  
   193  		{name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"},
   194  
   195  		// comparisons
   196  		{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
   197  		{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
   198  		{name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"},                  // 1 if arg0 > 0 (signed), 0 otherwise
   199  		{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
   200  		{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
   201  		{name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"},                // 1 if arg0 > 0 (unsigned), 0 otherwise
   202  
   203  		{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
   204  		{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
   205  		{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
   206  		{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
   207  		{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
   208  		{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
   209  
   210  		// moves
   211  		{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true},    // auxint
   212  		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
   213  		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
   214  
   215  		{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
   216  
   217  		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
   218  		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   219  		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
   220  		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
   221  		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
   222  		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   223  		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   224  
   225  		{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.
   226  		{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.
   227  		{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.
   228  		{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.
   229  		{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.
   230  
   231  		{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.
   232  		{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.
   233  		{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.
   234  
   235  		// moves (no conversion)
   236  		{name: "MOVWfpgp", argLength: 1, reg: fpgp, asm: "MOVW"}, // move float32 to int32 (no conversion)
   237  		{name: "MOVWgpfp", argLength: 1, reg: gpfp, asm: "MOVW"}, // move int32 to float32 (no conversion)
   238  
   239  		// conversions
   240  		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
   241  		{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
   242  		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
   243  		{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
   244  		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0
   245  
   246  		{name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
   247  
   248  		// conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0)
   249  		// order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg)
   250  		{name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true},
   251  		{name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true},
   252  
   253  		{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
   254  		{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
   255  		{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
   256  		{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
   257  		{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
   258  		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
   259  
   260  		// function calls
   261  		{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
   262  		{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
   263  		{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
   264  		{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
   265  
   266  		// atomic ops
   267  
   268  		// load from arg0. arg1=mem.
   269  		// returns <value,memory> so they can be properly ordered with other loads.
   270  		// SYNC
   271  		// MOV(B|W)	(Rarg0), Rout
   272  		// SYNC
   273  		{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
   274  		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
   275  
   276  		// store arg1 to arg0. arg2=mem. returns memory.
   277  		// SYNC
   278  		// MOV(B|W)	Rarg1, (Rarg0)
   279  		// SYNC
   280  		{name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   281  		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   282  		{name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   283  
   284  		// atomic exchange.
   285  		// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
   286  		// SYNC
   287  		// LL	(Rarg0), Rout
   288  		// MOVW Rarg1, Rtmp
   289  		// SC	Rtmp, (Rarg0)
   290  		// BEQ	Rtmp, -3(PC)
   291  		// SYNC
   292  		{name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   293  
   294  		// atomic add.
   295  		// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
   296  		// SYNC
   297  		// LL	(Rarg0), Rout
   298  		// ADDU Rarg1, Rout, Rtmp
   299  		// SC	Rtmp, (Rarg0)
   300  		// BEQ	Rtmp, -3(PC)
   301  		// SYNC
   302  		// ADDU Rarg1, Rout
   303  		{name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   304  		{name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   305  
   306  		// atomic compare and swap.
   307  		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
   308  		// if *arg0 == arg1 {
   309  		//   *arg0 = arg2
   310  		//   return (true, memory)
   311  		// } else {
   312  		//   return (false, memory)
   313  		// }
   314  		// SYNC
   315  		// MOVW $0, Rout
   316  		// LL	(Rarg0), Rtmp
   317  		// BNE	Rtmp, Rarg1, 4(PC)
   318  		// MOVW Rarg2, Rout
   319  		// SC	Rout, (Rarg0)
   320  		// BEQ	Rout, -4(PC)
   321  		// SYNC
   322  		{name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   323  
   324  		// atomic and/or.
   325  		// *arg0 &= (|=) arg1. arg2=mem. returns memory.
   326  		// SYNC
   327  		// LL	(Rarg0), Rtmp
   328  		// AND	Rarg1, Rtmp
   329  		// SC	Rtmp, (Rarg0)
   330  		// BEQ	Rtmp, -3(PC)
   331  		// SYNC
   332  		{name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   333  		{name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
   334  
   335  		// large or unaligned zeroing
   336  		// arg0 = address of memory to zero (in R1, changed as side effect)
   337  		// arg1 = address of the last element to zero
   338  		// arg2 = mem
   339  		// auxint = alignment
   340  		// returns mem
   341  		//	SUBU	$4, R1
   342  		//	MOVW	R0, 4(R1)
   343  		//	ADDU	$4, R1
   344  		//	BNE	Rarg1, R1, -2(PC)
   345  		{
   346  			name:      "LoweredZero",
   347  			aux:       "Int32",
   348  			argLength: 3,
   349  			reg: regInfo{
   350  				inputs:   []regMask{buildReg("R1"), gp},
   351  				clobbers: buildReg("R1"),
   352  			},
   353  			faultOnNilArg0: true,
   354  		},
   355  
   356  		// large or unaligned move
   357  		// arg0 = address of dst memory (in R2, changed as side effect)
   358  		// arg1 = address of src memory (in R1, changed as side effect)
   359  		// arg2 = address of the last element of src
   360  		// arg3 = mem
   361  		// auxint = alignment
   362  		// returns mem
   363  		//	SUBU	$4, R1
   364  		//	MOVW	4(R1), Rtmp
   365  		//	MOVW	Rtmp, (R2)
   366  		//	ADDU	$4, R1
   367  		//	ADDU	$4, R2
   368  		//	BNE	Rarg2, R1, -4(PC)
   369  		{
   370  			name:      "LoweredMove",
   371  			aux:       "Int32",
   372  			argLength: 4,
   373  			reg: regInfo{
   374  				inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
   375  				clobbers: buildReg("R1 R2"),
   376  			},
   377  			faultOnNilArg0: true,
   378  			faultOnNilArg1: true,
   379  		},
   380  
   381  		// pseudo-ops
   382  		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
   383  
   384  		{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
   385  		{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
   386  
   387  		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   388  		// and sorts it to the very beginning of the block to prevent other
   389  		// use of R22 (mips.REGCTXT, the closure pointer)
   390  		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
   391  
   392  		// LoweredGetCallerSP returns the SP of the caller of the current function. arg0=mem.
   393  		{name: "LoweredGetCallerSP", argLength: 1, reg: gp01, rematerializeable: true},
   394  
   395  		// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
   396  		// I.e., if f calls g "calls" sys.GetCallerPC,
   397  		// the result should be the PC within f that g will return to.
   398  		// See runtime/stubs.go for a more detailed discussion.
   399  		{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
   400  
   401  		// LoweredWB invokes runtime.gcWriteBarrier. arg0=mem, auxint=# of buffer entries needed
   402  		// It saves all GP registers if necessary,
   403  		// but clobbers R31 (LR) because it's a call
   404  		// and R23 (REGTMP).
   405  		// Returns a pointer to a write barrier buffer in R25.
   406  		{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R31"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
   407  
   408  		// Do data barrier. arg0=memorys
   409  		{name: "LoweredPubBarrier", argLength: 1, asm: "SYNC", hasSideEffects: true},
   410  
   411  		// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
   412  		// the RC and CR versions are used when one of the arguments is a constant. CC is used
   413  		// when both are constant (normally both 0, as prove derives the fact that a [0] bounds
   414  		// failure means the length must have also been 0).
   415  		// AuxInt contains a report code (see PanicBounds in genericOps.go).
   416  		{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{first16, first16}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
   417  		{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first16}}, typ: "Mem", call: true},   // arg0=x, arg1=mem, returns memory.
   418  		{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first16}}, typ: "Mem", call: true},   // arg0=y, arg1=mem, returns memory.
   419  		{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true},                            // arg0=mem, returns memory.
   420  
   421  		// Same as above, but the x value is 64 bits.
   422  		{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.
   423  		{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.
   424  	}
   425  
   426  	blocks := []blockData{
   427  		{name: "EQ", controls: 1},
   428  		{name: "NE", controls: 1},
   429  		{name: "LTZ", controls: 1}, // < 0
   430  		{name: "LEZ", controls: 1}, // <= 0
   431  		{name: "GTZ", controls: 1}, // > 0
   432  		{name: "GEZ", controls: 1}, // >= 0
   433  		{name: "FPT", controls: 1}, // FP flag is true
   434  		{name: "FPF", controls: 1}, // FP flag is false
   435  	}
   436  
   437  	archs = append(archs, arch{
   438  		name:            "MIPS",
   439  		pkg:             "cmd/internal/obj/mips",
   440  		genfile:         "../../mips/ssa.go",
   441  		ops:             ops,
   442  		blocks:          blocks,
   443  		regnames:        regNamesMIPS,
   444  		gpregmask:       gp,
   445  		fpregmask:       fp,
   446  		specialregmask:  hi | lo,
   447  		framepointerreg: -1, // not used
   448  		linkreg:         int8(num["R31"]),
   449  	})
   450  }
   451  

View as plain text