...

Source file src/pkg/cmd/compile/internal/ssa/gen/MIPS64Ops.go

     1	// Copyright 2016 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// +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	//  - *const instructions may use a constant larger than the instruction can encode.
    16	//    In this case the assembler expands to multiple instructions and uses tmp
    17	//    register (R23).
    18	
    19	// Suffixes encode the bit width of various instructions.
    20	// V (vlong)     = 64 bit
    21	// WU (word)     = 32 bit unsigned
    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 regNamesMIPS64 = []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		// R23 = REGTMP not used in regalloc
    58		"R24",
    59		"R25",
    60		// R26 reserved by kernel
    61		// R27 reserved by kernel
    62		// R28 = REGSB not used in regalloc
    63		"SP",  // aka R29
    64		"g",   // aka R30
    65		"R31", // aka REGLINK
    66	
    67		"F0",
    68		"F1",
    69		"F2",
    70		"F3",
    71		"F4",
    72		"F5",
    73		"F6",
    74		"F7",
    75		"F8",
    76		"F9",
    77		"F10",
    78		"F11",
    79		"F12",
    80		"F13",
    81		"F14",
    82		"F15",
    83		"F16",
    84		"F17",
    85		"F18",
    86		"F19",
    87		"F20",
    88		"F21",
    89		"F22",
    90		"F23",
    91		"F24",
    92		"F25",
    93		"F26",
    94		"F27",
    95		"F28",
    96		"F29",
    97		"F30",
    98		"F31",
    99	
   100		"HI", // high bits of multiplication
   101		"LO", // low bits of multiplication
   102	
   103		// pseudo-registers
   104		"SB",
   105	}
   106	
   107	func init() {
   108		// Make map from reg names to reg integers.
   109		if len(regNamesMIPS64) > 64 {
   110			panic("too many registers")
   111		}
   112		num := map[string]int{}
   113		for i, name := range regNamesMIPS64 {
   114			num[name] = i
   115		}
   116		buildReg := func(s string) regMask {
   117			m := regMask(0)
   118			for _, r := range strings.Split(s, " ") {
   119				if n, ok := num[r]; ok {
   120					m |= regMask(1) << uint(n)
   121					continue
   122				}
   123				panic("register " + r + " not found")
   124			}
   125			return m
   126		}
   127	
   128		// Common individual register masks
   129		var (
   130			gp         = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31")
   131			gpg        = gp | buildReg("g")
   132			gpsp       = gp | buildReg("SP")
   133			gpspg      = gpg | buildReg("SP")
   134			gpspsbg    = gpspg | buildReg("SB")
   135			fp         = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
   136			lo         = buildReg("LO")
   137			hi         = buildReg("HI")
   138			callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
   139			r1         = buildReg("R1")
   140			r2         = buildReg("R2")
   141			r3         = buildReg("R3")
   142			r4         = buildReg("R4")
   143		)
   144		// Common regInfo
   145		var (
   146			gp01     = regInfo{inputs: nil, outputs: []regMask{gp}}
   147			gp11     = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
   148			gp11sp   = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
   149			gp21     = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
   150			gp2hilo  = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
   151			gpload   = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
   152			gpstore  = regInfo{inputs: []regMask{gpspsbg, gpg}}
   153			gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
   154			gpxchg   = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
   155			gpcas    = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
   156			fp01     = regInfo{inputs: nil, outputs: []regMask{fp}}
   157			fp11     = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
   158			//fp1flags  = regInfo{inputs: []regMask{fp}}
   159			//fpgp      = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
   160			//gpfp      = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
   161			fp21      = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
   162			fp2flags  = regInfo{inputs: []regMask{fp, fp}}
   163			fpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
   164			fpstore   = regInfo{inputs: []regMask{gpspsbg, fp}}
   165			readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
   166		)
   167		ops := []opData{
   168			// binary ops
   169			{name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true},                             // arg0 + arg1
   170			{name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"},                           // arg0 + auxInt. auxInt is 32-bit, also in other *const ops.
   171			{name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"},                                                // arg0 - arg1
   172			{name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"},                             // arg0 - auxInt
   173			{name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"},     // arg0 * arg1, signed, results hi,lo
   174			{name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo
   175			{name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"},                        // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   176			{name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"},                    // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
   177	
   178			{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
   179			{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
   180			{name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0 - arg1
   181			{name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0 - arg1
   182			{name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
   183			{name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
   184			{name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0 / arg1
   185			{name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0 / arg1
   186	
   187			{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0 & arg1
   188			{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"},                // arg0 & auxInt
   189			{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
   190			{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                  // arg0 | auxInt
   191			{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1
   192			{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt
   193			{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^(arg0 | arg1)
   194			{name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"},                // ^(arg0 | auxInt)
   195	
   196			{name: "NEGV", argLength: 1, reg: gp11},                // -arg0
   197			{name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"},   // -arg0, float32
   198			{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0, float64
   199			{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
   200	
   201			// shifts
   202			{name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"},                    // arg0 << arg1, shift amount is mod 64
   203			{name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt
   204			{name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"},                    // arg0 >> arg1, unsigned, shift amount is mod 64
   205			{name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned
   206			{name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"},                    // arg0 >> arg1, signed, shift amount is mod 64
   207			{name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed
   208	
   209			// comparisons
   210			{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
   211			{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
   212			{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
   213			{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
   214	
   215			{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
   216			{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
   217			{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
   218			{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
   219			{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
   220			{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
   221	
   222			// moves
   223			{name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true},    // auxint
   224			{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
   225			{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
   226	
   227			{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
   228	
   229			{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
   230			{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   231			{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
   232			{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
   233			{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
   234			{name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
   235			{name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
   236			{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   237			{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
   238	
   239			{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.
   240			{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.
   241			{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.
   242			{name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
   243			{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.
   244			{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.
   245	
   246			{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.
   247			{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.
   248			{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.
   249			{name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of zero to arg0 + auxInt + aux.  ar12=mem.
   250	
   251			// conversions
   252			{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
   253			{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
   254			{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
   255			{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
   256			{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0, sign-extended from word
   257			{name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
   258			{name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"},   // move from arg0
   259	
   260			{name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
   261	
   262			{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
   263			{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
   264			{name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"},     // int64 -> float32
   265			{name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"},     // int64 -> float64
   266			{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
   267			{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
   268			{name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64
   269			{name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64
   270			{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
   271			{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
   272	
   273			// function calls
   274			{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
   275			{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
   276			{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
   277	
   278			// duffzero
   279			// arg0 = address of memory to zero
   280			// arg1 = mem
   281			// auxint = offset into duffzero code to start executing
   282			// returns mem
   283			// R1 aka mips.REGRT1 changed as side effect
   284			{
   285				name:      "DUFFZERO",
   286				aux:       "Int64",
   287				argLength: 2,
   288				reg: regInfo{
   289					inputs:   []regMask{gp},
   290					clobbers: buildReg("R1 R31"),
   291				},
   292				faultOnNilArg0: true,
   293			},
   294	
   295			// large or unaligned zeroing
   296			// arg0 = address of memory to zero (in R1, changed as side effect)
   297			// arg1 = address of the last element to zero
   298			// arg2 = mem
   299			// auxint = alignment
   300			// returns mem
   301			//	SUBV	$8, R1
   302			//	MOVV	R0, 8(R1)
   303			//	ADDV	$8, R1
   304			//	BNE	Rarg1, R1, -2(PC)
   305			{
   306				name:      "LoweredZero",
   307				aux:       "Int64",
   308				argLength: 3,
   309				reg: regInfo{
   310					inputs:   []regMask{buildReg("R1"), gp},
   311					clobbers: buildReg("R1"),
   312				},
   313				clobberFlags:   true,
   314				faultOnNilArg0: true,
   315			},
   316	
   317			// large or unaligned move
   318			// arg0 = address of dst memory (in R2, changed as side effect)
   319			// arg1 = address of src memory (in R1, changed as side effect)
   320			// arg2 = address of the last element of src
   321			// arg3 = mem
   322			// auxint = alignment
   323			// returns mem
   324			//	SUBV	$8, R1
   325			//	MOVV	8(R1), Rtmp
   326			//	MOVV	Rtmp, (R2)
   327			//	ADDV	$8, R1
   328			//	ADDV	$8, R2
   329			//	BNE	Rarg2, R1, -4(PC)
   330			{
   331				name:      "LoweredMove",
   332				aux:       "Int64",
   333				argLength: 4,
   334				reg: regInfo{
   335					inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
   336					clobbers: buildReg("R1 R2"),
   337				},
   338				clobberFlags:   true,
   339				faultOnNilArg0: true,
   340				faultOnNilArg1: true,
   341			},
   342	
   343			// atomic loads.
   344			// load from arg0. arg1=mem.
   345			// returns <value,memory> so they can be properly ordered with other loads.
   346			{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
   347			{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
   348			{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true},
   349	
   350			// atomic stores.
   351			// store arg1 to arg0. arg2=mem. returns memory.
   352			{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   353			{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
   354			// store zero to arg0. arg1=mem. returns memory.
   355			{name: "LoweredAtomicStorezero32", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   356			{name: "LoweredAtomicStorezero64", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
   357	
   358			// atomic exchange.
   359			// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
   360			// SYNC
   361			// LL	(Rarg0), Rout
   362			// MOVV Rarg1, Rtmp
   363			// SC	Rtmp, (Rarg0)
   364			// BEQ	Rtmp, -3(PC)
   365			// SYNC
   366			{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   367			{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   368	
   369			// atomic add.
   370			// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
   371			// SYNC
   372			// LL	(Rarg0), Rout
   373			// ADDV Rarg1, Rout, Rtmp
   374			// SC	Rtmp, (Rarg0)
   375			// BEQ	Rtmp, -3(PC)
   376			// SYNC
   377			// ADDV Rarg1, Rout
   378			{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   379			{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   380			// *arg0 += auxint. arg1=mem. returns <new content of *arg0, memory>. auxint is 32-bit.
   381			{name: "LoweredAtomicAddconst32", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   382			{name: "LoweredAtomicAddconst64", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int64", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   383	
   384			// atomic compare and swap.
   385			// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
   386			// if *arg0 == arg1 {
   387			//   *arg0 = arg2
   388			//   return (true, memory)
   389			// } else {
   390			//   return (false, memory)
   391			// }
   392			// SYNC
   393			// MOVV $0, Rout
   394			// LL	(Rarg0), Rtmp
   395			// BNE	Rtmp, Rarg1, 4(PC)
   396			// MOVV Rarg2, Rout
   397			// SC	Rout, (Rarg0)
   398			// BEQ	Rout, -4(PC)
   399			// SYNC
   400			{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   401			{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
   402	
   403			// pseudo-ops
   404			{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
   405	
   406			{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
   407			{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
   408	
   409			// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   410			// and sorts it to the very beginning of the block to prevent other
   411			// use of R22 (mips.REGCTXT, the closure pointer)
   412			{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
   413	
   414			// LoweredGetCallerSP returns the SP of the caller of the current function.
   415			{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
   416	
   417			// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
   418			// I.e., if f calls g "calls" getcallerpc,
   419			// the result should be the PC within f that g will return to.
   420			// See runtime/stubs.go for a more detailed discussion.
   421			{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
   422	
   423			// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
   424			// It saves all GP registers if necessary,
   425			// but clobbers R31 (LR) because it's a call
   426			// and R23 (REGTMP).
   427			{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
   428	
   429			// There are three of these functions so that they can have three different register inputs.
   430			// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
   431			// default registers to match so we don't need to copy registers around unnecessarily.
   432			{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).
   433			{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).
   434			{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).
   435		}
   436	
   437		blocks := []blockData{
   438			{name: "EQ"},
   439			{name: "NE"},
   440			{name: "LTZ"}, // < 0
   441			{name: "LEZ"}, // <= 0
   442			{name: "GTZ"}, // > 0
   443			{name: "GEZ"}, // >= 0
   444			{name: "FPT"}, // FP flag is true
   445			{name: "FPF"}, // FP flag is false
   446		}
   447	
   448		archs = append(archs, arch{
   449			name:            "MIPS64",
   450			pkg:             "cmd/internal/obj/mips",
   451			genfile:         "../../mips64/ssa.go",
   452			ops:             ops,
   453			blocks:          blocks,
   454			regnames:        regNamesMIPS64,
   455			gpregmask:       gp,
   456			fpregmask:       fp,
   457			specialregmask:  hi | lo,
   458			framepointerreg: -1, // not used
   459			linkreg:         int8(num["R31"]),
   460		})
   461	}
   462	

View as plain text