...

Source file src/pkg/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	// +build ignore
     6	
     7	package main
     8	
     9	import "strings"
    10	
    11	// Notes:
    12	//  - Integer types live in the low portion of registers. Upper portions are junk.
    13	//  - Boolean types use the low-order byte of a register. 0=false, 1=true.
    14	//    Upper bytes are junk.
    15	//  - Unused portions of AuxInt are filled by sign-extending the used portion.
    16	//  - *const instructions may use a constant larger than the instruction can encode.
    17	//    In this case the assembler expands to multiple instructions and uses tmp
    18	//    register (R23).
    19	
    20	// Suffixes encode the bit width of various instructions.
    21	// W (word)      = 32 bit
    22	// H (half word) = 16 bit
    23	// HU            = 16 bit unsigned
    24	// B (byte)      = 8 bit
    25	// BU            = 8 bit unsigned
    26	// F (float)     = 32 bit float
    27	// D (double)    = 64 bit float
    28	
    29	// Note: registers not used in regalloc are not included in this list,
    30	// so that regmask stays within int64
    31	// Be careful when hand coding regmasks.
    32	var regNamesMIPS = []string{
    33		"R0", // constant 0
    34		"R1",
    35		"R2",
    36		"R3",
    37		"R4",
    38		"R5",
    39		"R6",
    40		"R7",
    41		"R8",
    42		"R9",
    43		"R10",
    44		"R11",
    45		"R12",
    46		"R13",
    47		"R14",
    48		"R15",
    49		"R16",
    50		"R17",
    51		"R18",
    52		"R19",
    53		"R20",
    54		"R21",
    55		"R22",
    56		//REGTMP
    57		"R24",
    58		"R25",
    59		// R26 reserved by kernel
    60		// R27 reserved by kernel
    61		"R28",
    62		"SP",  // aka R29
    63		"g",   // aka R30
    64		"R31", // REGLINK
    65	
    66		// odd FP registers contain high parts of 64-bit FP values
    67		"F0",
    68		"F2",
    69		"F4",
    70		"F6",
    71		"F8",
    72		"F10",
    73		"F12",
    74		"F14",
    75		"F16",
    76		"F18",
    77		"F20",
    78		"F22",
    79		"F24",
    80		"F26",
    81		"F28",
    82		"F30",
    83	
    84		"HI", // high bits of multiplication
    85		"LO", // low bits of multiplication
    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			r1         = buildReg("R1")
   124			r2         = buildReg("R2")
   125			r3         = buildReg("R3")
   126			r4         = buildReg("R4")
   127			r5         = buildReg("R5")
   128		)
   129		// Common regInfo
   130		var (
   131			gp01      = regInfo{inputs: nil, outputs: []regMask{gp}}
   132			gp11      = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
   133			gp11sp    = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
   134			gp21      = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
   135			gp31      = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
   136			gp2hilo   = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
   137			gpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
   138			gpstore   = regInfo{inputs: []regMask{gpspsbg, gpg}}
   139			gpxchg    = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
   140			gpcas     = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
   141			gpstore0  = regInfo{inputs: []regMask{gpspsbg}}
   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: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"},                                                  // arg0 * arg1, signed, results hi,lo
   157			{name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"},                                              // arg0 * arg1, unsigned, results hi,lo
   158			{name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)"},                                                                      // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   159			{name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)"},                                                                  // arg0 / arg1, signed, results hi=arg0%arg1,lo=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: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
   183	
   184			// shifts
   185			{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                    // arg0 << arg1, shift amount is mod 32
   186			{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt
   187			{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                    // arg0 >> arg1, unsigned, shift amount is mod 32
   188			{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned
   189			{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                    // arg0 >> arg1, signed, shift amount is mod 32
   190			{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed
   191	
   192			{name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"},
   193	
   194			// comparisons
   195			{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
   196			{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
   197			{name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"},                  // 1 if arg0 > 0 (signed), 0 otherwise
   198			{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
   199			{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
   200			{name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"},                // 1 if arg0 > 0 (unsigned), 0 otherwise
   201	
   202			{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
   203			{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
   204			{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
   205			{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
   206			{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
   207			{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
   208	
   209			// moves
   210			{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true},    // auxint
   211			{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
   212			{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
   213	
   214			{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
   215	
   216			{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
   217			{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   218			{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
   219			{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
   220			{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
   221			{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   222			{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   223	
   224			{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.
   225			{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.
   226			{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.
   227			{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.
   228			{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.
   229	
   230			{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.
   231			{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.
   232			{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.
   233	
   234			// conversions
   235			{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
   236			{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
   237			{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
   238			{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
   239			{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0
   240	
   241			{name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
   242	
   243			// conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0)
   244			// order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg)
   245			{name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true},
   246			{name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true},
   247	
   248			{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
   249			{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
   250			{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
   251			{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
   252			{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
   253			{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
   254	
   255			// function calls
   256			{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                           // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
   257			{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
   258			{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
   259	
   260			// atomic ops
   261	
   262			// load from arg0. arg1=mem.
   263			// returns <value,memory> so they can be properly ordered with other loads.
   264			// SYNC
   265			// MOVW	(Rarg0), Rout
   266			// SYNC
   267			{name: "LoweredAtomicLoad", argLength: 2, reg: gpload, faultOnNilArg0: true},
   268	
   269			// store arg1 to arg0. arg2=mem. returns memory.
   270			// SYNC
   271			// MOVW	Rarg1, (Rarg0)
   272			// SYNC
   273			{name: "LoweredAtomicStore", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   274			{name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   275	
   276			// atomic exchange.
   277			// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
   278			// SYNC
   279			// LL	(Rarg0), Rout
   280			// MOVW Rarg1, Rtmp
   281			// SC	Rtmp, (Rarg0)
   282			// BEQ	Rtmp, -3(PC)
   283			// SYNC
   284			{name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   285	
   286			// atomic add.
   287			// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
   288			// SYNC
   289			// LL	(Rarg0), Rout
   290			// ADDU Rarg1, Rout, Rtmp
   291			// SC	Rtmp, (Rarg0)
   292			// BEQ	Rtmp, -3(PC)
   293			// SYNC
   294			// ADDU Rarg1, Rout
   295			{name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   296			{name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   297	
   298			// atomic compare and swap.
   299			// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
   300			// if *arg0 == arg1 {
   301			//   *arg0 = arg2
   302			//   return (true, memory)
   303			// } else {
   304			//   return (false, memory)
   305			// }
   306			// SYNC
   307			// MOVW $0, Rout
   308			// LL	(Rarg0), Rtmp
   309			// BNE	Rtmp, Rarg1, 4(PC)
   310			// MOVW Rarg2, Rout
   311			// SC	Rout, (Rarg0)
   312			// BEQ	Rout, -4(PC)
   313			// SYNC
   314			{name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   315	
   316			// atomic and/or.
   317			// *arg0 &= (|=) arg1. arg2=mem. returns memory.
   318			// SYNC
   319			// LL	(Rarg0), Rtmp
   320			// AND	Rarg1, Rtmp
   321			// SC	Rtmp, (Rarg0)
   322			// BEQ	Rtmp, -3(PC)
   323			// SYNC
   324			{name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
   325			{name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
   326	
   327			// large or unaligned zeroing
   328			// arg0 = address of memory to zero (in R1, changed as side effect)
   329			// arg1 = address of the last element to zero
   330			// arg2 = mem
   331			// auxint = alignment
   332			// returns mem
   333			//	SUBU	$4, R1
   334			//	MOVW	R0, 4(R1)
   335			//	ADDU	$4, R1
   336			//	BNE	Rarg1, R1, -2(PC)
   337			{
   338				name:      "LoweredZero",
   339				aux:       "Int32",
   340				argLength: 3,
   341				reg: regInfo{
   342					inputs:   []regMask{buildReg("R1"), gp},
   343					clobbers: buildReg("R1"),
   344				},
   345				faultOnNilArg0: true,
   346			},
   347	
   348			// large or unaligned move
   349			// arg0 = address of dst memory (in R2, changed as side effect)
   350			// arg1 = address of src memory (in R1, changed as side effect)
   351			// arg2 = address of the last element of src
   352			// arg3 = mem
   353			// auxint = alignment
   354			// returns mem
   355			//	SUBU	$4, R1
   356			//	MOVW	4(R1), Rtmp
   357			//	MOVW	Rtmp, (R2)
   358			//	ADDU	$4, R1
   359			//	ADDU	$4, R2
   360			//	BNE	Rarg2, R1, -4(PC)
   361			{
   362				name:      "LoweredMove",
   363				aux:       "Int32",
   364				argLength: 4,
   365				reg: regInfo{
   366					inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
   367					clobbers: buildReg("R1 R2"),
   368				},
   369				faultOnNilArg0: true,
   370				faultOnNilArg1: true,
   371			},
   372	
   373			// pseudo-ops
   374			{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
   375	
   376			{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
   377			{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
   378	
   379			// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   380			// and sorts it to the very beginning of the block to prevent other
   381			// use of R22 (mips.REGCTXT, the closure pointer)
   382			{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
   383	
   384			// LoweredGetCallerSP returns the SP of the caller of the current function.
   385			{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
   386	
   387			// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
   388			// I.e., if f calls g "calls" getcallerpc,
   389			// the result should be the PC within f that g will return to.
   390			// See runtime/stubs.go for a more detailed discussion.
   391			{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
   392	
   393			// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
   394			// It saves all GP registers if necessary,
   395			// but clobbers R31 (LR) because it's a call
   396			// and R23 (REGTMP).
   397			{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
   398	
   399			// There are three of these functions so that they can have three different register inputs.
   400			// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
   401			// default registers to match so we don't need to copy registers around unnecessarily.
   402			{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   403			{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   404			{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
   405			// Extend ops are the same as Bounds ops except the indexes are 64-bit.
   406			{name: "LoweredPanicExtendA", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r3, r4}}, typ: "Mem"}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
   407			{name: "LoweredPanicExtendB", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r2, r3}}, typ: "Mem"}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
   408			{name: "LoweredPanicExtendC", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r1, r2}}, typ: "Mem"}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
   409		}
   410	
   411		blocks := []blockData{
   412			{name: "EQ"},
   413			{name: "NE"},
   414			{name: "LTZ"}, // < 0
   415			{name: "LEZ"}, // <= 0
   416			{name: "GTZ"}, // > 0
   417			{name: "GEZ"}, // >= 0
   418			{name: "FPT"}, // FP flag is true
   419			{name: "FPF"}, // FP flag is false
   420		}
   421	
   422		archs = append(archs, arch{
   423			name:            "MIPS",
   424			pkg:             "cmd/internal/obj/mips",
   425			genfile:         "../../mips/ssa.go",
   426			ops:             ops,
   427			blocks:          blocks,
   428			regnames:        regNamesMIPS,
   429			gpregmask:       gp,
   430			fpregmask:       fp,
   431			specialregmask:  hi | lo,
   432			framepointerreg: -1, // not used
   433			linkreg:         int8(num["R31"]),
   434		})
   435	}
   436	

View as plain text