]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssa/gen/genericOps.go
[dev.ssa] Merge branch 'master' into dev.ssa
[gostls13.git] / src / cmd / compile / internal / ssa / gen / genericOps.go
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         // Weird special instruction for strength reduction of divides.
62         {name: "Avg64u", argLength: 2}, // (uint64(arg0) + uint64(arg1)) / 2, correct to all 64 bits.
63
64         {name: "Div8", argLength: 2},  // arg0 / arg1, signed
65         {name: "Div8u", argLength: 2}, // arg0 / arg1, unsigned
66         {name: "Div16", argLength: 2},
67         {name: "Div16u", argLength: 2},
68         {name: "Div32", argLength: 2},
69         {name: "Div32u", argLength: 2},
70         {name: "Div64", argLength: 2},
71         {name: "Div64u", argLength: 2},
72
73         {name: "Mod8", argLength: 2},  // arg0 % arg1, signed
74         {name: "Mod8u", argLength: 2}, // arg0 % arg1, unsigned
75         {name: "Mod16", argLength: 2},
76         {name: "Mod16u", argLength: 2},
77         {name: "Mod32", argLength: 2},
78         {name: "Mod32u", argLength: 2},
79         {name: "Mod64", argLength: 2},
80         {name: "Mod64u", argLength: 2},
81
82         {name: "And8", argLength: 2, commutative: true}, // arg0 & arg1
83         {name: "And16", argLength: 2, commutative: true},
84         {name: "And32", argLength: 2, commutative: true},
85         {name: "And64", argLength: 2, commutative: true},
86
87         {name: "Or8", argLength: 2, commutative: true}, // arg0 | arg1
88         {name: "Or16", argLength: 2, commutative: true},
89         {name: "Or32", argLength: 2, commutative: true},
90         {name: "Or64", argLength: 2, commutative: true},
91
92         {name: "Xor8", argLength: 2, commutative: true}, // arg0 ^ arg1
93         {name: "Xor16", argLength: 2, commutative: true},
94         {name: "Xor32", argLength: 2, commutative: true},
95         {name: "Xor64", argLength: 2, commutative: true},
96
97         // For shifts, AxB means the shifted value has A bits and the shift amount has B bits.
98         // Shift amounts are considered unsigned.
99         {name: "Lsh8x8", argLength: 2}, // arg0 << arg1
100         {name: "Lsh8x16", argLength: 2},
101         {name: "Lsh8x32", argLength: 2},
102         {name: "Lsh8x64", argLength: 2},
103         {name: "Lsh16x8", argLength: 2},
104         {name: "Lsh16x16", argLength: 2},
105         {name: "Lsh16x32", argLength: 2},
106         {name: "Lsh16x64", argLength: 2},
107         {name: "Lsh32x8", argLength: 2},
108         {name: "Lsh32x16", argLength: 2},
109         {name: "Lsh32x32", argLength: 2},
110         {name: "Lsh32x64", argLength: 2},
111         {name: "Lsh64x8", argLength: 2},
112         {name: "Lsh64x16", argLength: 2},
113         {name: "Lsh64x32", argLength: 2},
114         {name: "Lsh64x64", argLength: 2},
115
116         {name: "Rsh8x8", argLength: 2}, // arg0 >> arg1, signed
117         {name: "Rsh8x16", argLength: 2},
118         {name: "Rsh8x32", argLength: 2},
119         {name: "Rsh8x64", argLength: 2},
120         {name: "Rsh16x8", argLength: 2},
121         {name: "Rsh16x16", argLength: 2},
122         {name: "Rsh16x32", argLength: 2},
123         {name: "Rsh16x64", argLength: 2},
124         {name: "Rsh32x8", argLength: 2},
125         {name: "Rsh32x16", argLength: 2},
126         {name: "Rsh32x32", argLength: 2},
127         {name: "Rsh32x64", argLength: 2},
128         {name: "Rsh64x8", argLength: 2},
129         {name: "Rsh64x16", argLength: 2},
130         {name: "Rsh64x32", argLength: 2},
131         {name: "Rsh64x64", argLength: 2},
132
133         {name: "Rsh8Ux8", argLength: 2}, // arg0 >> arg1, unsigned
134         {name: "Rsh8Ux16", argLength: 2},
135         {name: "Rsh8Ux32", argLength: 2},
136         {name: "Rsh8Ux64", argLength: 2},
137         {name: "Rsh16Ux8", argLength: 2},
138         {name: "Rsh16Ux16", argLength: 2},
139         {name: "Rsh16Ux32", argLength: 2},
140         {name: "Rsh16Ux64", argLength: 2},
141         {name: "Rsh32Ux8", argLength: 2},
142         {name: "Rsh32Ux16", argLength: 2},
143         {name: "Rsh32Ux32", argLength: 2},
144         {name: "Rsh32Ux64", argLength: 2},
145         {name: "Rsh64Ux8", argLength: 2},
146         {name: "Rsh64Ux16", argLength: 2},
147         {name: "Rsh64Ux32", argLength: 2},
148         {name: "Rsh64Ux64", argLength: 2},
149
150         // (Left) rotates replace pattern matches in the front end
151         // of (arg0 << arg1) ^ (arg0 >> (A-arg1))
152         // where A is the bit width of arg0 and result.
153         // Note that because rotates are pattern-matched from
154         // shifts, that a rotate of arg1=A+k (k > 0) bits originated from
155         //    (arg0 << A+k) ^ (arg0 >> -k) =
156         //    0 ^ arg0>>huge_unsigned =
157         //    0 ^ 0 = 0
158         // which is not the same as a rotation by A+k
159         //
160         // However, in the specific case of k = 0, the result of
161         // the shift idiom is the same as the result for the
162         // rotate idiom, i.e., result=arg0.
163         // This is different from shifts, where
164         // arg0 << A is defined to be zero.
165         //
166         // Because of this, and also because the primary use case
167         // for rotates is hashing and crypto code with constant
168         // distance, rotate instructions are only substituted
169         // when arg1 is a constant between 1 and A-1, inclusive.
170         {name: "Lrot8", argLength: 1, aux: "Int64"},
171         {name: "Lrot16", argLength: 1, aux: "Int64"},
172         {name: "Lrot32", argLength: 1, aux: "Int64"},
173         {name: "Lrot64", argLength: 1, aux: "Int64"},
174
175         // 2-input comparisons
176         {name: "Eq8", argLength: 2, commutative: true}, // arg0 == arg1
177         {name: "Eq16", argLength: 2, commutative: true},
178         {name: "Eq32", argLength: 2, commutative: true},
179         {name: "Eq64", argLength: 2, commutative: true},
180         {name: "EqPtr", argLength: 2, commutative: true},
181         {name: "EqInter", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
182         {name: "EqSlice", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
183         {name: "Eq32F", argLength: 2},
184         {name: "Eq64F", argLength: 2},
185
186         {name: "Neq8", argLength: 2, commutative: true}, // arg0 != arg1
187         {name: "Neq16", argLength: 2, commutative: true},
188         {name: "Neq32", argLength: 2, commutative: true},
189         {name: "Neq64", argLength: 2, commutative: true},
190         {name: "NeqPtr", argLength: 2, commutative: true},
191         {name: "NeqInter", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
192         {name: "NeqSlice", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
193         {name: "Neq32F", argLength: 2},
194         {name: "Neq64F", argLength: 2},
195
196         {name: "Less8", argLength: 2},  // arg0 < arg1, signed
197         {name: "Less8U", argLength: 2}, // arg0 < arg1, unsigned
198         {name: "Less16", argLength: 2},
199         {name: "Less16U", argLength: 2},
200         {name: "Less32", argLength: 2},
201         {name: "Less32U", argLength: 2},
202         {name: "Less64", argLength: 2},
203         {name: "Less64U", argLength: 2},
204         {name: "Less32F", argLength: 2},
205         {name: "Less64F", argLength: 2},
206
207         {name: "Leq8", argLength: 2},  // arg0 <= arg1, signed
208         {name: "Leq8U", argLength: 2}, // arg0 <= arg1, unsigned
209         {name: "Leq16", argLength: 2},
210         {name: "Leq16U", argLength: 2},
211         {name: "Leq32", argLength: 2},
212         {name: "Leq32U", argLength: 2},
213         {name: "Leq64", argLength: 2},
214         {name: "Leq64U", argLength: 2},
215         {name: "Leq32F", argLength: 2},
216         {name: "Leq64F", argLength: 2},
217
218         {name: "Greater8", argLength: 2},  // arg0 > arg1, signed
219         {name: "Greater8U", argLength: 2}, // arg0 > arg1, unsigned
220         {name: "Greater16", argLength: 2},
221         {name: "Greater16U", argLength: 2},
222         {name: "Greater32", argLength: 2},
223         {name: "Greater32U", argLength: 2},
224         {name: "Greater64", argLength: 2},
225         {name: "Greater64U", argLength: 2},
226         {name: "Greater32F", argLength: 2},
227         {name: "Greater64F", argLength: 2},
228
229         {name: "Geq8", argLength: 2},  // arg0 <= arg1, signed
230         {name: "Geq8U", argLength: 2}, // arg0 <= arg1, unsigned
231         {name: "Geq16", argLength: 2},
232         {name: "Geq16U", argLength: 2},
233         {name: "Geq32", argLength: 2},
234         {name: "Geq32U", argLength: 2},
235         {name: "Geq64", argLength: 2},
236         {name: "Geq64U", argLength: 2},
237         {name: "Geq32F", argLength: 2},
238         {name: "Geq64F", argLength: 2},
239
240         // boolean ops
241         {name: "AndB", argLength: 2}, // arg0 && arg1 (not shortcircuited)
242         {name: "OrB", argLength: 2},  // arg0 || arg1 (not shortcircuited)
243         {name: "EqB", argLength: 2},  // arg0 == arg1
244         {name: "NeqB", argLength: 2}, // arg0 != arg1
245         {name: "Not", argLength: 1},  // !arg0, boolean
246
247         // 1-input ops
248         {name: "Neg8", argLength: 1}, // -arg0
249         {name: "Neg16", argLength: 1},
250         {name: "Neg32", argLength: 1},
251         {name: "Neg64", argLength: 1},
252         {name: "Neg32F", argLength: 1},
253         {name: "Neg64F", argLength: 1},
254
255         {name: "Com8", argLength: 1}, // ^arg0
256         {name: "Com16", argLength: 1},
257         {name: "Com32", argLength: 1},
258         {name: "Com64", argLength: 1},
259
260         {name: "Ctz16", argLength: 1}, // Count trailing (low  order) zeroes (returns 0-16)
261         {name: "Ctz32", argLength: 1}, // Count trailing zeroes (returns 0-32)
262         {name: "Ctz64", argLength: 1}, // Count trailing zeroes (returns 0-64)
263
264         {name: "Clz16", argLength: 1}, // Count leading (high order) zeroes (returns 0-16)
265         {name: "Clz32", argLength: 1}, // Count leading zeroes (returns 0-32)
266         {name: "Clz64", argLength: 1}, // Count leading zeroes (returns 0-64)
267
268         {name: "Bswap32", argLength: 1}, // Swap bytes
269         {name: "Bswap64", argLength: 1}, // Swap bytes
270
271         {name: "Sqrt", argLength: 1}, // sqrt(arg0), float64 only
272
273         // Data movement, max argument length for Phi is indefinite so just pick
274         // a really large number
275         {name: "Phi", argLength: -1}, // select an argument based on which predecessor block we came from
276         {name: "Copy", argLength: 1}, // output = arg0
277         // Convert converts between pointers and integers.
278         // We have a special op for this so as to not confuse GC
279         // (particularly stack maps).  It takes a memory arg so it
280         // gets correctly ordered with respect to GC safepoints.
281         // arg0=ptr/int arg1=mem, output=int/ptr
282         {name: "Convert", argLength: 2},
283
284         // constants. Constant values are stored in the aux or
285         // auxint fields.
286         {name: "ConstBool", aux: "Bool"},     // auxint is 0 for false and 1 for true
287         {name: "ConstString", aux: "String"}, // value is aux.(string)
288         {name: "ConstNil", typ: "BytePtr"},   // nil pointer
289         {name: "Const8", aux: "Int8"},        // auxint is sign-extended 8 bits
290         {name: "Const16", aux: "Int16"},      // auxint is sign-extended 16 bits
291         {name: "Const32", aux: "Int32"},      // auxint is sign-extended 32 bits
292         {name: "Const64", aux: "Int64"},      // value is auxint
293         {name: "Const32F", aux: "Float32"},   // value is math.Float64frombits(uint64(auxint)) and is exactly prepresentable as float 32
294         {name: "Const64F", aux: "Float64"},   // value is math.Float64frombits(uint64(auxint))
295         {name: "ConstInterface"},             // nil interface
296         {name: "ConstSlice"},                 // nil slice
297
298         // Constant-like things
299         {name: "InitMem"},            // memory input to the function.
300         {name: "Arg", aux: "SymOff"}, // argument to the function.  aux=GCNode of arg, off = offset in that arg.
301
302         // The address of a variable.  arg0 is the base pointer (SB or SP, depending
303         // on whether it is a global or stack variable).  The Aux field identifies the
304         // variable. It will be either an *ExternSymbol (with arg0=SB), *ArgSymbol (arg0=SP),
305         // or *AutoSymbol (arg0=SP).
306         {name: "Addr", argLength: 1, aux: "Sym"}, // Address of a variable.  Arg0=SP or SB.  Aux identifies the variable.
307
308         {name: "SP"},                 // stack pointer
309         {name: "SB", typ: "Uintptr"}, // static base pointer (a.k.a. globals pointer)
310         {name: "Func", aux: "Sym"},   // entry address of a function
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, aux: "Int64"},              // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size.  Returns memory.
316         {name: "Zero", argLength: 2, aux: "Int64"},              // arg0=destptr, arg1=mem, auxint=size. Returns memory.
317
318         // Function calls. Arguments to the call have already been written to the stack.
319         // Return values appear on the stack. The method receiver, if any, is treated
320         // as a phantom first argument.
321         {name: "ClosureCall", argLength: 3, aux: "Int64"}, // arg0=code pointer, arg1=context ptr, arg2=memory.  auxint=arg size.  Returns memory.
322         {name: "StaticCall", argLength: 1, aux: "SymOff"}, // call function aux.(*gc.Sym), arg0=memory.  auxint=arg size.  Returns memory.
323         {name: "DeferCall", argLength: 1, aux: "Int64"},   // defer call.  arg0=memory, auxint=arg size.  Returns memory.
324         {name: "GoCall", argLength: 1, aux: "Int64"},      // go call.  arg0=memory, auxint=arg size.  Returns memory.
325         {name: "InterCall", argLength: 2, aux: "Int64"},   // interface call.  arg0=code pointer, arg1=memory, auxint=arg size.  Returns memory.
326
327         // Conversions: signed extensions, zero (unsigned) extensions, truncations
328         {name: "SignExt8to16", argLength: 1, typ: "Int16"},
329         {name: "SignExt8to32", argLength: 1, typ: "Int32"},
330         {name: "SignExt8to64", argLength: 1},
331         {name: "SignExt16to32", argLength: 1, typ: "Int32"},
332         {name: "SignExt16to64", argLength: 1},
333         {name: "SignExt32to64", argLength: 1},
334         {name: "ZeroExt8to16", argLength: 1, typ: "UInt16"},
335         {name: "ZeroExt8to32", argLength: 1, typ: "UInt32"},
336         {name: "ZeroExt8to64", argLength: 1},
337         {name: "ZeroExt16to32", argLength: 1, typ: "UInt32"},
338         {name: "ZeroExt16to64", argLength: 1},
339         {name: "ZeroExt32to64", argLength: 1},
340         {name: "Trunc16to8", argLength: 1},
341         {name: "Trunc32to8", argLength: 1},
342         {name: "Trunc32to16", argLength: 1},
343         {name: "Trunc64to8", argLength: 1},
344         {name: "Trunc64to16", argLength: 1},
345         {name: "Trunc64to32", argLength: 1},
346
347         {name: "Cvt32to32F", argLength: 1},
348         {name: "Cvt32to64F", argLength: 1},
349         {name: "Cvt64to32F", argLength: 1},
350         {name: "Cvt64to64F", argLength: 1},
351         {name: "Cvt32Fto32", argLength: 1},
352         {name: "Cvt32Fto64", argLength: 1},
353         {name: "Cvt64Fto32", argLength: 1},
354         {name: "Cvt64Fto64", argLength: 1},
355         {name: "Cvt32Fto64F", argLength: 1},
356         {name: "Cvt64Fto32F", argLength: 1},
357
358         // Automatically inserted safety checks
359         {name: "IsNonNil", argLength: 1, typ: "Bool"},        // arg0 != nil
360         {name: "IsInBounds", argLength: 2, typ: "Bool"},      // 0 <= arg0 < arg1. arg1 is guaranteed >= 0.
361         {name: "IsSliceInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 <= arg1. arg1 is guaranteed >= 0.
362         {name: "NilCheck", argLength: 2, typ: "Void"},        // arg0=ptr, arg1=mem. Panics if arg0 is nil, returns void.
363
364         // Pseudo-ops
365         {name: "GetG", argLength: 1}, // runtime.getg() (read g pointer). arg0=mem
366         {name: "GetClosurePtr"},      // get closure pointer from dedicated register
367
368         // Indexing operations
369         {name: "ArrayIndex", aux: "Int64", argLength: 1}, // arg0=array, auxint=index. Returns a[i]
370         {name: "PtrIndex", argLength: 2},                 // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
371         {name: "OffPtr", argLength: 1, aux: "Int64"},     // arg0 + auxint (arg0 and result are pointers)
372
373         // Slices
374         {name: "SliceMake", argLength: 3},                // arg0=ptr, arg1=len, arg2=cap
375         {name: "SlicePtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
376         {name: "SliceLen", argLength: 1},                 // len(arg0)
377         {name: "SliceCap", argLength: 1},                 // cap(arg0)
378
379         // Complex (part/whole)
380         {name: "ComplexMake", argLength: 2}, // arg0=real, arg1=imag
381         {name: "ComplexReal", argLength: 1}, // real(arg0)
382         {name: "ComplexImag", argLength: 1}, // imag(arg0)
383
384         // Strings
385         {name: "StringMake", argLength: 2},                // arg0=ptr, arg1=len
386         {name: "StringPtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
387         {name: "StringLen", argLength: 1, typ: "Int"},     // len(arg0)
388
389         // Interfaces
390         {name: "IMake", argLength: 2},                // arg0=itab, arg1=data
391         {name: "ITab", argLength: 1, typ: "BytePtr"}, // arg0=interface, returns itable field
392         {name: "IData", argLength: 1},                // arg0=interface, returns data field
393
394         // Structs
395         {name: "StructMake0"},                              // Returns struct with 0 fields.
396         {name: "StructMake1", argLength: 1},                // arg0=field0.  Returns struct.
397         {name: "StructMake2", argLength: 2},                // arg0,arg1=field0,field1.  Returns struct.
398         {name: "StructMake3", argLength: 3},                // arg0..2=field0..2.  Returns struct.
399         {name: "StructMake4", argLength: 4},                // arg0..3=field0..3.  Returns struct.
400         {name: "StructSelect", argLength: 1, aux: "Int64"}, // arg0=struct, auxint=field index.  Returns the auxint'th field.
401
402         // Spill&restore ops for the register allocator. These are
403         // semantically identical to OpCopy; they do not take/return
404         // stores like regular memory ops do. We can get away without memory
405         // args because we know there is no aliasing of spill slots on the stack.
406         {name: "StoreReg", argLength: 1},
407         {name: "LoadReg", argLength: 1},
408
409         // Used during ssa construction. Like Copy, but the arg has not been specified yet.
410         {name: "FwdRef", aux: "Sym"},
411
412         // Unknown value. Used for Values whose values don't matter because they are dead code.
413         {name: "Unknown"},
414
415         {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
416         {name: "VarKill", argLength: 1, aux: "Sym"},            // aux is a *gc.Node of a variable that is known to be dead.  arg0=mem, returns mem
417         {name: "VarLive", argLength: 1, aux: "Sym"},            // aux is a *gc.Node of a variable that must be kept live.  arg0=mem, returns mem
418         {name: "KeepAlive", argLength: 2, typ: "Mem"},          // arg[0] is a value that must be kept alive until this mark.  arg[1]=mem, returns mem
419 }
420
421 //     kind           control    successors       implicit exit
422 //   ----------------------------------------------------------
423 //     Exit        return mem                []             yes
424 //      Ret        return mem                []             yes
425 //   RetJmp        return mem                []             yes
426 //    Plain               nil            [next]
427 //       If   a boolean Value      [then, else]
428 //     Call               mem            [next]             yes  (control opcode should be OpCall or OpStaticCall)
429 //    Check              void            [next]             yes  (control opcode should be Op{Lowered}NilCheck)
430 //    First               nil    [always,never]
431
432 var genericBlocks = []blockData{
433         {name: "Plain"},  // a single successor
434         {name: "If"},     // 2 successors, if control goto Succs[0] else goto Succs[1]
435         {name: "Call"},   // 1 successor, control is call op (of memory type)
436         {name: "Defer"},  // 2 successors, Succs[0]=defer queued, Succs[1]=defer recovered. control is call op (of memory type)
437         {name: "Check"},  // 1 successor, control is nilcheck op (of void type)
438         {name: "Ret"},    // no successors, control value is memory result
439         {name: "RetJmp"}, // no successors, jumps to b.Aux.(*gc.Sym)
440         {name: "Exit"},   // no successors, control value generates a panic
441
442         // transient block state used for dead code removal
443         {name: "First"}, // 2 successors, always takes the first one (second is dead)
444 }
445
446 func init() {
447         archs = append(archs, arch{
448                 name:    "generic",
449                 ops:     genericOps,
450                 blocks:  genericBlocks,
451                 generic: true,
452         })
453 }