Home | History | Annotate | Download | only in gen
      1 // Copyright 2015 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 // Generic opcodes typically specify a width. The inputs and outputs
     10 // of that op are the given number of bits wide. There is no notion of
     11 // "sign", so Add32 can be used both for signed and unsigned 32-bit
     12 // addition.
     13 
     14 // Signed/unsigned is explicit with the extension ops
     15 // (SignExt*/ZeroExt*) and implicit as the arg to some opcodes
     16 // (e.g. the second argument to shifts is unsigned). If not mentioned,
     17 // all args take signed inputs, or don't care whether their inputs
     18 // are signed or unsigned.
     19 
     20 // Unused portions of AuxInt are filled by sign-extending the used portion.
     21 // Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful.
     22 var genericOps = []opData{
     23 	// 2-input arithmetic
     24 	// Types must be consistent with Go typing. Add, for example, must take two values
     25 	// of the same type and produces that same type.
     26 	{name: "Add8", argLength: 2, commutative: true}, // arg0 + arg1
     27 	{name: "Add16", argLength: 2, commutative: true},
     28 	{name: "Add32", argLength: 2, commutative: true},
     29 	{name: "Add64", argLength: 2, commutative: true},
     30 	{name: "AddPtr", argLength: 2}, // For address calculations.  arg0 is a pointer and arg1 is an int.
     31 	{name: "Add32F", argLength: 2},
     32 	{name: "Add64F", argLength: 2},
     33 
     34 	{name: "Sub8", argLength: 2}, // arg0 - arg1
     35 	{name: "Sub16", argLength: 2},
     36 	{name: "Sub32", argLength: 2},
     37 	{name: "Sub64", argLength: 2},
     38 	{name: "SubPtr", argLength: 2},
     39 	{name: "Sub32F", argLength: 2},
     40 	{name: "Sub64F", argLength: 2},
     41 
     42 	{name: "Mul8", argLength: 2, commutative: true}, // arg0 * arg1
     43 	{name: "Mul16", argLength: 2, commutative: true},
     44 	{name: "Mul32", argLength: 2, commutative: true},
     45 	{name: "Mul64", argLength: 2, commutative: true},
     46 	{name: "Mul32F", argLength: 2},
     47 	{name: "Mul64F", argLength: 2},
     48 
     49 	{name: "Div32F", argLength: 2}, // arg0 / arg1
     50 	{name: "Div64F", argLength: 2},
     51 
     52 	{name: "Hmul8", argLength: 2},  // (arg0 * arg1) >> width, signed
     53 	{name: "Hmul8u", argLength: 2}, // (arg0 * arg1) >> width, unsigned
     54 	{name: "Hmul16", argLength: 2},
     55 	{name: "Hmul16u", argLength: 2},
     56 	{name: "Hmul32", argLength: 2},
     57 	{name: "Hmul32u", argLength: 2},
     58 	{name: "Hmul64", argLength: 2},
     59 	{name: "Hmul64u", argLength: 2},
     60 
     61 	{name: "Mul32uhilo", argLength: 2, typ: "(UInt32,UInt32)"}, // arg0 * arg1, returns (hi, lo)
     62 	{name: "Mul64uhilo", argLength: 2, typ: "(UInt64,UInt64)"}, // arg0 * arg1, returns (hi, lo)
     63 
     64 	// Weird special instruction for strength reduction of divides.
     65 	{name: "Avg64u", argLength: 2}, // (uint64(arg0) + uint64(arg1)) / 2, correct to all 64 bits.
     66 
     67 	{name: "Div8", argLength: 2},  // arg0 / arg1, signed
     68 	{name: "Div8u", argLength: 2}, // arg0 / arg1, unsigned
     69 	{name: "Div16", argLength: 2},
     70 	{name: "Div16u", argLength: 2},
     71 	{name: "Div32", argLength: 2},
     72 	{name: "Div32u", argLength: 2},
     73 	{name: "Div64", argLength: 2},
     74 	{name: "Div64u", argLength: 2},
     75 	{name: "Div128u", argLength: 3}, // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r)
     76 
     77 	{name: "Mod8", argLength: 2},  // arg0 % arg1, signed
     78 	{name: "Mod8u", argLength: 2}, // arg0 % arg1, unsigned
     79 	{name: "Mod16", argLength: 2},
     80 	{name: "Mod16u", argLength: 2},
     81 	{name: "Mod32", argLength: 2},
     82 	{name: "Mod32u", argLength: 2},
     83 	{name: "Mod64", argLength: 2},
     84 	{name: "Mod64u", argLength: 2},
     85 
     86 	{name: "And8", argLength: 2, commutative: true}, // arg0 & arg1
     87 	{name: "And16", argLength: 2, commutative: true},
     88 	{name: "And32", argLength: 2, commutative: true},
     89 	{name: "And64", argLength: 2, commutative: true},
     90 
     91 	{name: "Or8", argLength: 2, commutative: true}, // arg0 | arg1
     92 	{name: "Or16", argLength: 2, commutative: true},
     93 	{name: "Or32", argLength: 2, commutative: true},
     94 	{name: "Or64", argLength: 2, commutative: true},
     95 
     96 	{name: "Xor8", argLength: 2, commutative: true}, // arg0 ^ arg1
     97 	{name: "Xor16", argLength: 2, commutative: true},
     98 	{name: "Xor32", argLength: 2, commutative: true},
     99 	{name: "Xor64", argLength: 2, commutative: true},
    100 
    101 	// For shifts, AxB means the shifted value has A bits and the shift amount has B bits.
    102 	// Shift amounts are considered unsigned.
    103 	{name: "Lsh8x8", argLength: 2}, // arg0 << arg1
    104 	{name: "Lsh8x16", argLength: 2},
    105 	{name: "Lsh8x32", argLength: 2},
    106 	{name: "Lsh8x64", argLength: 2},
    107 	{name: "Lsh16x8", argLength: 2},
    108 	{name: "Lsh16x16", argLength: 2},
    109 	{name: "Lsh16x32", argLength: 2},
    110 	{name: "Lsh16x64", argLength: 2},
    111 	{name: "Lsh32x8", argLength: 2},
    112 	{name: "Lsh32x16", argLength: 2},
    113 	{name: "Lsh32x32", argLength: 2},
    114 	{name: "Lsh32x64", argLength: 2},
    115 	{name: "Lsh64x8", argLength: 2},
    116 	{name: "Lsh64x16", argLength: 2},
    117 	{name: "Lsh64x32", argLength: 2},
    118 	{name: "Lsh64x64", argLength: 2},
    119 
    120 	{name: "Rsh8x8", argLength: 2}, // arg0 >> arg1, signed
    121 	{name: "Rsh8x16", argLength: 2},
    122 	{name: "Rsh8x32", argLength: 2},
    123 	{name: "Rsh8x64", argLength: 2},
    124 	{name: "Rsh16x8", argLength: 2},
    125 	{name: "Rsh16x16", argLength: 2},
    126 	{name: "Rsh16x32", argLength: 2},
    127 	{name: "Rsh16x64", argLength: 2},
    128 	{name: "Rsh32x8", argLength: 2},
    129 	{name: "Rsh32x16", argLength: 2},
    130 	{name: "Rsh32x32", argLength: 2},
    131 	{name: "Rsh32x64", argLength: 2},
    132 	{name: "Rsh64x8", argLength: 2},
    133 	{name: "Rsh64x16", argLength: 2},
    134 	{name: "Rsh64x32", argLength: 2},
    135 	{name: "Rsh64x64", argLength: 2},
    136 
    137 	{name: "Rsh8Ux8", argLength: 2}, // arg0 >> arg1, unsigned
    138 	{name: "Rsh8Ux16", argLength: 2},
    139 	{name: "Rsh8Ux32", argLength: 2},
    140 	{name: "Rsh8Ux64", argLength: 2},
    141 	{name: "Rsh16Ux8", argLength: 2},
    142 	{name: "Rsh16Ux16", argLength: 2},
    143 	{name: "Rsh16Ux32", argLength: 2},
    144 	{name: "Rsh16Ux64", argLength: 2},
    145 	{name: "Rsh32Ux8", argLength: 2},
    146 	{name: "Rsh32Ux16", argLength: 2},
    147 	{name: "Rsh32Ux32", argLength: 2},
    148 	{name: "Rsh32Ux64", argLength: 2},
    149 	{name: "Rsh64Ux8", argLength: 2},
    150 	{name: "Rsh64Ux16", argLength: 2},
    151 	{name: "Rsh64Ux32", argLength: 2},
    152 	{name: "Rsh64Ux64", argLength: 2},
    153 
    154 	// (Left) rotates replace pattern matches in the front end
    155 	// of (arg0 << arg1) ^ (arg0 >> (A-arg1))
    156 	// where A is the bit width of arg0 and result.
    157 	// Note that because rotates are pattern-matched from
    158 	// shifts, that a rotate of arg1=A+k (k > 0) bits originated from
    159 	//    (arg0 << A+k) ^ (arg0 >> -k) =
    160 	//    0 ^ arg0>>huge_unsigned =
    161 	//    0 ^ 0 = 0
    162 	// which is not the same as a rotation by A+k
    163 	//
    164 	// However, in the specific case of k = 0, the result of
    165 	// the shift idiom is the same as the result for the
    166 	// rotate idiom, i.e., result=arg0.
    167 	// This is different from shifts, where
    168 	// arg0 << A is defined to be zero.
    169 	//
    170 	// Because of this, and also because the primary use case
    171 	// for rotates is hashing and crypto code with constant
    172 	// distance, rotate instructions are only substituted
    173 	// when arg1 is a constant between 1 and A-1, inclusive.
    174 	{name: "Lrot8", argLength: 1, aux: "Int64"},
    175 	{name: "Lrot16", argLength: 1, aux: "Int64"},
    176 	{name: "Lrot32", argLength: 1, aux: "Int64"},
    177 	{name: "Lrot64", argLength: 1, aux: "Int64"},
    178 
    179 	// 2-input comparisons
    180 	{name: "Eq8", argLength: 2, commutative: true, typ: "Bool"}, // arg0 == arg1
    181 	{name: "Eq16", argLength: 2, commutative: true, typ: "Bool"},
    182 	{name: "Eq32", argLength: 2, commutative: true, typ: "Bool"},
    183 	{name: "Eq64", argLength: 2, commutative: true, typ: "Bool"},
    184 	{name: "EqPtr", argLength: 2, commutative: true, typ: "Bool"},
    185 	{name: "EqInter", argLength: 2, typ: "Bool"}, // arg0 or arg1 is nil; other cases handled by frontend
    186 	{name: "EqSlice", argLength: 2, typ: "Bool"}, // arg0 or arg1 is nil; other cases handled by frontend
    187 	{name: "Eq32F", argLength: 2, typ: "Bool"},
    188 	{name: "Eq64F", argLength: 2, typ: "Bool"},
    189 
    190 	{name: "Neq8", argLength: 2, commutative: true, typ: "Bool"}, // arg0 != arg1
    191 	{name: "Neq16", argLength: 2, commutative: true, typ: "Bool"},
    192 	{name: "Neq32", argLength: 2, commutative: true, typ: "Bool"},
    193 	{name: "Neq64", argLength: 2, commutative: true, typ: "Bool"},
    194 	{name: "NeqPtr", argLength: 2, commutative: true, typ: "Bool"},
    195 	{name: "NeqInter", argLength: 2, typ: "Bool"}, // arg0 or arg1 is nil; other cases handled by frontend
    196 	{name: "NeqSlice", argLength: 2, typ: "Bool"}, // arg0 or arg1 is nil; other cases handled by frontend
    197 	{name: "Neq32F", argLength: 2, typ: "Bool"},
    198 	{name: "Neq64F", argLength: 2},
    199 
    200 	{name: "Less8", argLength: 2, typ: "Bool"},  // arg0 < arg1, signed
    201 	{name: "Less8U", argLength: 2, typ: "Bool"}, // arg0 < arg1, unsigned
    202 	{name: "Less16", argLength: 2, typ: "Bool"},
    203 	{name: "Less16U", argLength: 2, typ: "Bool"},
    204 	{name: "Less32", argLength: 2, typ: "Bool"},
    205 	{name: "Less32U", argLength: 2, typ: "Bool"},
    206 	{name: "Less64", argLength: 2, typ: "Bool"},
    207 	{name: "Less64U", argLength: 2, typ: "Bool"},
    208 	{name: "Less32F", argLength: 2, typ: "Bool"},
    209 	{name: "Less64F", argLength: 2, typ: "Bool"},
    210 
    211 	{name: "Leq8", argLength: 2, typ: "Bool"},  // arg0 <= arg1, signed
    212 	{name: "Leq8U", argLength: 2, typ: "Bool"}, // arg0 <= arg1, unsigned
    213 	{name: "Leq16", argLength: 2, typ: "Bool"},
    214 	{name: "Leq16U", argLength: 2, typ: "Bool"},
    215 	{name: "Leq32", argLength: 2, typ: "Bool"},
    216 	{name: "Leq32U", argLength: 2, typ: "Bool"},
    217 	{name: "Leq64", argLength: 2, typ: "Bool"},
    218 	{name: "Leq64U", argLength: 2, typ: "Bool"},
    219 	{name: "Leq32F", argLength: 2, typ: "Bool"},
    220 	{name: "Leq64F", argLength: 2, typ: "Bool"},
    221 
    222 	{name: "Greater8", argLength: 2, typ: "Bool"},  // arg0 > arg1, signed
    223 	{name: "Greater8U", argLength: 2, typ: "Bool"}, // arg0 > arg1, unsigned
    224 	{name: "Greater16", argLength: 2, typ: "Bool"},
    225 	{name: "Greater16U", argLength: 2, typ: "Bool"},
    226 	{name: "Greater32", argLength: 2, typ: "Bool"},
    227 	{name: "Greater32U", argLength: 2, typ: "Bool"},
    228 	{name: "Greater64", argLength: 2, typ: "Bool"},
    229 	{name: "Greater64U", argLength: 2, typ: "Bool"},
    230 	{name: "Greater32F", argLength: 2, typ: "Bool"},
    231 	{name: "Greater64F", argLength: 2, typ: "Bool"},
    232 
    233 	{name: "Geq8", argLength: 2, typ: "Bool"},  // arg0 <= arg1, signed
    234 	{name: "Geq8U", argLength: 2, typ: "Bool"}, // arg0 <= arg1, unsigned
    235 	{name: "Geq16", argLength: 2, typ: "Bool"},
    236 	{name: "Geq16U", argLength: 2, typ: "Bool"},
    237 	{name: "Geq32", argLength: 2, typ: "Bool"},
    238 	{name: "Geq32U", argLength: 2, typ: "Bool"},
    239 	{name: "Geq64", argLength: 2, typ: "Bool"},
    240 	{name: "Geq64U", argLength: 2, typ: "Bool"},
    241 	{name: "Geq32F", argLength: 2, typ: "Bool"},
    242 	{name: "Geq64F", argLength: 2, typ: "Bool"},
    243 
    244 	// boolean ops
    245 	{name: "AndB", argLength: 2, typ: "Bool"}, // arg0 && arg1 (not shortcircuited)
    246 	{name: "OrB", argLength: 2, typ: "Bool"},  // arg0 || arg1 (not shortcircuited)
    247 	{name: "EqB", argLength: 2, typ: "Bool"},  // arg0 == arg1
    248 	{name: "NeqB", argLength: 2, typ: "Bool"}, // arg0 != arg1
    249 	{name: "Not", argLength: 1, typ: "Bool"},  // !arg0, boolean
    250 
    251 	// 1-input ops
    252 	{name: "Neg8", argLength: 1}, // -arg0
    253 	{name: "Neg16", argLength: 1},
    254 	{name: "Neg32", argLength: 1},
    255 	{name: "Neg64", argLength: 1},
    256 	{name: "Neg32F", argLength: 1},
    257 	{name: "Neg64F", argLength: 1},
    258 
    259 	{name: "Com8", argLength: 1}, // ^arg0
    260 	{name: "Com16", argLength: 1},
    261 	{name: "Com32", argLength: 1},
    262 	{name: "Com64", argLength: 1},
    263 
    264 	{name: "Ctz32", argLength: 1}, // Count trailing (low  order) zeroes (returns 0-32)
    265 	{name: "Ctz64", argLength: 1}, // Count trailing zeroes (returns 0-64)
    266 
    267 	{name: "Bswap32", argLength: 1}, // Swap bytes
    268 	{name: "Bswap64", argLength: 1}, // Swap bytes
    269 
    270 	{name: "Sqrt", argLength: 1}, // sqrt(arg0), float64 only
    271 
    272 	// Data movement, max argument length for Phi is indefinite so just pick
    273 	// a really large number
    274 	{name: "Phi", argLength: -1}, // select an argument based on which predecessor block we came from
    275 	{name: "Copy", argLength: 1}, // output = arg0
    276 	// Convert converts between pointers and integers.
    277 	// We have a special op for this so as to not confuse GC
    278 	// (particularly stack maps).  It takes a memory arg so it
    279 	// gets correctly ordered with respect to GC safepoints.
    280 	// arg0=ptr/int arg1=mem, output=int/ptr
    281 	{name: "Convert", argLength: 2},
    282 
    283 	// constants. Constant values are stored in the aux or
    284 	// auxint fields.
    285 	{name: "ConstBool", aux: "Bool"},     // auxint is 0 for false and 1 for true
    286 	{name: "ConstString", aux: "String"}, // value is aux.(string)
    287 	{name: "ConstNil", typ: "BytePtr"},   // nil pointer
    288 	{name: "Const8", aux: "Int8"},        // auxint is sign-extended 8 bits
    289 	{name: "Const16", aux: "Int16"},      // auxint is sign-extended 16 bits
    290 	{name: "Const32", aux: "Int32"},      // auxint is sign-extended 32 bits
    291 	{name: "Const64", aux: "Int64"},      // value is auxint
    292 	{name: "Const32F", aux: "Float32"},   // value is math.Float64frombits(uint64(auxint)) and is exactly prepresentable as float 32
    293 	{name: "Const64F", aux: "Float64"},   // value is math.Float64frombits(uint64(auxint))
    294 	{name: "ConstInterface"},             // nil interface
    295 	{name: "ConstSlice"},                 // nil slice
    296 
    297 	// Constant-like things
    298 	{name: "InitMem"},            // memory input to the function.
    299 	{name: "Arg", aux: "SymOff"}, // argument to the function.  aux=GCNode of arg, off = offset in that arg.
    300 
    301 	// The address of a variable.  arg0 is the base pointer (SB or SP, depending
    302 	// on whether it is a global or stack variable).  The Aux field identifies the
    303 	// variable. It will be either an *ExternSymbol (with arg0=SB), *ArgSymbol (arg0=SP),
    304 	// or *AutoSymbol (arg0=SP).
    305 	{name: "Addr", argLength: 1, aux: "Sym"}, // Address of a variable.  Arg0=SP or SB.  Aux identifies the variable.
    306 
    307 	{name: "SP"},                 // stack pointer
    308 	{name: "SB", typ: "Uintptr"}, // static base pointer (a.k.a. globals pointer)
    309 	{name: "Func", aux: "Sym"},   // entry address of a function
    310 	{name: "Invalid"},            // unused value
    311 
    312 	// Memory operations
    313 	{name: "Load", argLength: 2},                                  // Load from arg0.  arg1=memory
    314 	{name: "Store", argLength: 3, typ: "Mem", aux: "Int64"},       // Store arg1 to arg0.  arg2=memory, auxint=size.  Returns memory.
    315 	{name: "Move", argLength: 3, typ: "Mem", aux: "SizeAndAlign"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size+alignment.  Returns memory.
    316 	{name: "Zero", argLength: 2, typ: "Mem", aux: "SizeAndAlign"}, // arg0=destptr, arg1=mem, auxint=size+alignment. Returns memory.
    317 
    318 	// Memory operations with write barriers.
    319 	// Expand to runtime calls. Write barrier will be removed if write on stack.
    320 	{name: "StoreWB", argLength: 3, typ: "Mem", aux: "Int64"},                  // Store arg1 to arg0. arg2=memory, auxint=size.  Returns memory.
    321 	{name: "MoveWB", argLength: 3, typ: "Mem", aux: "SymSizeAndAlign"},         // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size+alignment, aux=symbol-of-type (for typedmemmove).  Returns memory.
    322 	{name: "MoveWBVolatile", argLength: 3, typ: "Mem", aux: "SymSizeAndAlign"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size+alignment, aux=symbol-of-type (for typedmemmove).  Returns memory. Src is volatile, i.e. needs to move to a temp space before calling typedmemmove.
    323 	{name: "ZeroWB", argLength: 2, typ: "Mem", aux: "SymSizeAndAlign"},         // arg0=destptr, arg1=mem, auxint=size+alignment, aux=symbol-of-type. Returns memory.
    324 
    325 	// Function calls. Arguments to the call have already been written to the stack.
    326 	// Return values appear on the stack. The method receiver, if any, is treated
    327 	// as a phantom first argument.
    328 	{name: "ClosureCall", argLength: 3, aux: "Int64", call: true}, // arg0=code pointer, arg1=context ptr, arg2=memory.  auxint=arg size.  Returns memory.
    329 	{name: "StaticCall", argLength: 1, aux: "SymOff", call: true}, // call function aux.(*gc.Sym), arg0=memory.  auxint=arg size.  Returns memory.
    330 	{name: "DeferCall", argLength: 1, aux: "Int64", call: true},   // defer call.  arg0=memory, auxint=arg size.  Returns memory.
    331 	{name: "GoCall", argLength: 1, aux: "Int64", call: true},      // go call.  arg0=memory, auxint=arg size.  Returns memory.
    332 	{name: "InterCall", argLength: 2, aux: "Int64", call: true},   // interface call.  arg0=code pointer, arg1=memory, auxint=arg size.  Returns memory.
    333 
    334 	// Conversions: signed extensions, zero (unsigned) extensions, truncations
    335 	{name: "SignExt8to16", argLength: 1, typ: "Int16"},
    336 	{name: "SignExt8to32", argLength: 1, typ: "Int32"},
    337 	{name: "SignExt8to64", argLength: 1, typ: "Int64"},
    338 	{name: "SignExt16to32", argLength: 1, typ: "Int32"},
    339 	{name: "SignExt16to64", argLength: 1, typ: "Int64"},
    340 	{name: "SignExt32to64", argLength: 1, typ: "Int64"},
    341 	{name: "ZeroExt8to16", argLength: 1, typ: "UInt16"},
    342 	{name: "ZeroExt8to32", argLength: 1, typ: "UInt32"},
    343 	{name: "ZeroExt8to64", argLength: 1, typ: "UInt64"},
    344 	{name: "ZeroExt16to32", argLength: 1, typ: "UInt32"},
    345 	{name: "ZeroExt16to64", argLength: 1, typ: "UInt64"},
    346 	{name: "ZeroExt32to64", argLength: 1, typ: "UInt64"},
    347 	{name: "Trunc16to8", argLength: 1},
    348 	{name: "Trunc32to8", argLength: 1},
    349 	{name: "Trunc32to16", argLength: 1},
    350 	{name: "Trunc64to8", argLength: 1},
    351 	{name: "Trunc64to16", argLength: 1},
    352 	{name: "Trunc64to32", argLength: 1},
    353 
    354 	{name: "Cvt32to32F", argLength: 1},
    355 	{name: "Cvt32to64F", argLength: 1},
    356 	{name: "Cvt64to32F", argLength: 1},
    357 	{name: "Cvt64to64F", argLength: 1},
    358 	{name: "Cvt32Fto32", argLength: 1},
    359 	{name: "Cvt32Fto64", argLength: 1},
    360 	{name: "Cvt64Fto32", argLength: 1},
    361 	{name: "Cvt64Fto64", argLength: 1},
    362 	{name: "Cvt32Fto64F", argLength: 1},
    363 	{name: "Cvt64Fto32F", argLength: 1},
    364 
    365 	// Automatically inserted safety checks
    366 	{name: "IsNonNil", argLength: 1, typ: "Bool"},        // arg0 != nil
    367 	{name: "IsInBounds", argLength: 2, typ: "Bool"},      // 0 <= arg0 < arg1. arg1 is guaranteed >= 0.
    368 	{name: "IsSliceInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 <= arg1. arg1 is guaranteed >= 0.
    369 	{name: "NilCheck", argLength: 2, typ: "Void"},        // arg0=ptr, arg1=mem. Panics if arg0 is nil. Returns void.
    370 
    371 	// Pseudo-ops
    372 	{name: "GetG", argLength: 1}, // runtime.getg() (read g pointer). arg0=mem
    373 	{name: "GetClosurePtr"},      // get closure pointer from dedicated register
    374 
    375 	// Indexing operations
    376 	{name: "PtrIndex", argLength: 2},             // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
    377 	{name: "OffPtr", argLength: 1, aux: "Int64"}, // arg0 + auxint (arg0 and result are pointers)
    378 
    379 	// Slices
    380 	{name: "SliceMake", argLength: 3},                // arg0=ptr, arg1=len, arg2=cap
    381 	{name: "SlicePtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
    382 	{name: "SliceLen", argLength: 1},                 // len(arg0)
    383 	{name: "SliceCap", argLength: 1},                 // cap(arg0)
    384 
    385 	// Complex (part/whole)
    386 	{name: "ComplexMake", argLength: 2}, // arg0=real, arg1=imag
    387 	{name: "ComplexReal", argLength: 1}, // real(arg0)
    388 	{name: "ComplexImag", argLength: 1}, // imag(arg0)
    389 
    390 	// Strings
    391 	{name: "StringMake", argLength: 2},                // arg0=ptr, arg1=len
    392 	{name: "StringPtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
    393 	{name: "StringLen", argLength: 1, typ: "Int"},     // len(arg0)
    394 
    395 	// Interfaces
    396 	{name: "IMake", argLength: 2},                // arg0=itab, arg1=data
    397 	{name: "ITab", argLength: 1, typ: "BytePtr"}, // arg0=interface, returns itable field
    398 	{name: "IData", argLength: 1},                // arg0=interface, returns data field
    399 
    400 	// Structs
    401 	{name: "StructMake0"},                              // Returns struct with 0 fields.
    402 	{name: "StructMake1", argLength: 1},                // arg0=field0.  Returns struct.
    403 	{name: "StructMake2", argLength: 2},                // arg0,arg1=field0,field1.  Returns struct.
    404 	{name: "StructMake3", argLength: 3},                // arg0..2=field0..2.  Returns struct.
    405 	{name: "StructMake4", argLength: 4},                // arg0..3=field0..3.  Returns struct.
    406 	{name: "StructSelect", argLength: 1, aux: "Int64"}, // arg0=struct, auxint=field index.  Returns the auxint'th field.
    407 
    408 	// Arrays
    409 	{name: "ArrayMake0"},                              // Returns array with 0 elements
    410 	{name: "ArrayMake1", argLength: 1},                // Returns array with 1 element
    411 	{name: "ArraySelect", argLength: 1, aux: "Int64"}, // arg0=array, auxint=index. Returns a[i].
    412 
    413 	// Spill&restore ops for the register allocator. These are
    414 	// semantically identical to OpCopy; they do not take/return
    415 	// stores like regular memory ops do. We can get away without memory
    416 	// args because we know there is no aliasing of spill slots on the stack.
    417 	{name: "StoreReg", argLength: 1},
    418 	{name: "LoadReg", argLength: 1},
    419 
    420 	// Used during ssa construction. Like Copy, but the arg has not been specified yet.
    421 	{name: "FwdRef", aux: "Sym"},
    422 
    423 	// Unknown value. Used for Values whose values don't matter because they are dead code.
    424 	{name: "Unknown"},
    425 
    426 	{name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized.  arg0=mem, returns mem
    427 	{name: "VarKill", argLength: 1, aux: "Sym"},            // aux is a *gc.Node of a variable that is known to be dead.  arg0=mem, returns mem
    428 	{name: "VarLive", argLength: 1, aux: "Sym"},            // aux is a *gc.Node of a variable that must be kept live.  arg0=mem, returns mem
    429 	{name: "KeepAlive", argLength: 2, typ: "Mem"},          // arg[0] is a value that must be kept alive until this mark.  arg[1]=mem, returns mem
    430 
    431 	// Ops for breaking 64-bit operations on 32-bit architectures
    432 	{name: "Int64Make", argLength: 2, typ: "UInt64"}, // arg0=hi, arg1=lo
    433 	{name: "Int64Hi", argLength: 1, typ: "UInt32"},   // high 32-bit of arg0
    434 	{name: "Int64Lo", argLength: 1, typ: "UInt32"},   // low 32-bit of arg0
    435 
    436 	{name: "Add32carry", argLength: 2, commutative: true, typ: "(UInt32,Flags)"}, // arg0 + arg1, returns (value, carry)
    437 	{name: "Add32withcarry", argLength: 3, commutative: true},                    // arg0 + arg1 + arg2, arg2=carry (0 or 1)
    438 
    439 	{name: "Sub32carry", argLength: 2, typ: "(UInt32,Flags)"}, // arg0 - arg1, returns (value, carry)
    440 	{name: "Sub32withcarry", argLength: 3},                    // arg0 - arg1 - arg2, arg2=carry (0 or 1)
    441 
    442 	{name: "Signmask", argLength: 1, typ: "Int32"},  // 0 if arg0 >= 0, -1 if arg0 < 0
    443 	{name: "Zeromask", argLength: 1, typ: "UInt32"}, // 0 if arg0 == 0, 0xffffffff if arg0 != 0
    444 	{name: "Slicemask", argLength: 1},               // 0 if arg0 == 0, -1 if arg0 > 0, undef if arg0<0. Type is native int size.
    445 
    446 	{name: "Cvt32Uto32F", argLength: 1}, // uint32 -> float32, only used on 32-bit arch
    447 	{name: "Cvt32Uto64F", argLength: 1}, // uint32 -> float64, only used on 32-bit arch
    448 	{name: "Cvt32Fto32U", argLength: 1}, // float32 -> uint32, only used on 32-bit arch
    449 	{name: "Cvt64Fto32U", argLength: 1}, // float64 -> uint32, only used on 32-bit arch
    450 	{name: "Cvt64Uto32F", argLength: 1}, // uint64 -> float32, only used on archs that has the instruction
    451 	{name: "Cvt64Uto64F", argLength: 1}, // uint64 -> float64, only used on archs that has the instruction
    452 	{name: "Cvt32Fto64U", argLength: 1}, // float32 -> uint64, only used on archs that has the instruction
    453 	{name: "Cvt64Fto64U", argLength: 1}, // float64 -> uint64, only used on archs that has the instruction
    454 
    455 	// pseudo-ops for breaking Tuple
    456 	{name: "Select0", argLength: 1}, // the first component of a tuple
    457 	{name: "Select1", argLength: 1}, // the second component of a tuple
    458 
    459 	// Atomic operations used for semantically inlining runtime/internal/atomic.
    460 	// Atomic loads return a new memory so that the loads are properly ordered
    461 	// with respect to other loads and stores.
    462 	// TODO: use for sync/atomic at some point.
    463 	{name: "AtomicLoad32", argLength: 2, typ: "(UInt32,Mem)"},         // Load from arg0.  arg1=memory.  Returns loaded value and new memory.
    464 	{name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"},         // Load from arg0.  arg1=memory.  Returns loaded value and new memory.
    465 	{name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"},       // Load from arg0.  arg1=memory.  Returns loaded value and new memory.
    466 	{name: "AtomicStore32", argLength: 3, typ: "Mem"},                 // Store arg1 to *arg0.  arg2=memory.  Returns memory.
    467 	{name: "AtomicStore64", argLength: 3, typ: "Mem"},                 // Store arg1 to *arg0.  arg2=memory.  Returns memory.
    468 	{name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem"},            // Store arg1 to *arg0.  arg2=memory.  Returns memory.
    469 	{name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)"},     // Store arg1 to *arg0.  arg2=memory.  Returns old contents of *arg0 and new memory.
    470 	{name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)"},     // Store arg1 to *arg0.  arg2=memory.  Returns old contents of *arg0 and new memory.
    471 	{name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)"},          // Do *arg0 += arg1.  arg2=memory.  Returns sum and new memory.
    472 	{name: "AtomicAdd64", argLength: 3, typ: "(UInt64,Mem)"},          // Do *arg0 += arg1.  arg2=memory.  Returns sum and new memory.
    473 	{name: "AtomicCompareAndSwap32", argLength: 4, typ: "(Bool,Mem)"}, // if *arg0==arg1, then set *arg0=arg2.  Returns true iff store happens and new memory.
    474 	{name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)"}, // if *arg0==arg1, then set *arg0=arg2.  Returns true iff store happens and new memory.
    475 	{name: "AtomicAnd8", argLength: 3, typ: "Mem"},                    // *arg0 &= arg1.  arg2=memory.  Returns memory.
    476 	{name: "AtomicOr8", argLength: 3, typ: "Mem"},                     // *arg0 |= arg1.  arg2=memory.  Returns memory.
    477 }
    478 
    479 //     kind           control    successors       implicit exit
    480 //   ----------------------------------------------------------
    481 //     Exit        return mem                []             yes
    482 //      Ret        return mem                []             yes
    483 //   RetJmp        return mem                []             yes
    484 //    Plain               nil            [next]
    485 //       If   a boolean Value      [then, else]
    486 //     Call               mem            [next]             yes  (control opcode should be OpCall or OpStaticCall)
    487 //    Check              void            [next]             yes  (control opcode should be Op{Lowered}NilCheck)
    488 //    First               nil    [always,never]
    489 
    490 var genericBlocks = []blockData{
    491 	{name: "Plain"},  // a single successor
    492 	{name: "If"},     // 2 successors, if control goto Succs[0] else goto Succs[1]
    493 	{name: "Defer"},  // 2 successors, Succs[0]=defer queued, Succs[1]=defer recovered. control is call op (of memory type)
    494 	{name: "Ret"},    // no successors, control value is memory result
    495 	{name: "RetJmp"}, // no successors, jumps to b.Aux.(*gc.Sym)
    496 	{name: "Exit"},   // no successors, control value generates a panic
    497 
    498 	// transient block state used for dead code removal
    499 	{name: "First"}, // 2 successors, always takes the first one (second is dead)
    500 }
    501 
    502 func init() {
    503 	archs = append(archs, arch{
    504 		name:    "generic",
    505 		ops:     genericOps,
    506 		blocks:  genericBlocks,
    507 		generic: true,
    508 	})
    509 }
    510