1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
|
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// “Abstract” syntax representation.
package gc
// A Node is a single node in the syntax tree.
// Actually the syntax tree is a syntax DAG, because there is only one
// node with Op=ONAME for a given instance of a variable x.
// The same is true for Op=OTYPE and Op=OLITERAL.
type Node struct {
// Tree structure.
// Generic recursive walks should follow these fields.
Left *Node
Right *Node
Ntest *Node
Nincr *Node
Ninit *NodeList
Nbody *NodeList
Nelse *NodeList
List *NodeList
Rlist *NodeList
Op uint8
Nointerface bool
Ullman uint8 // sethi/ullman number
Addable uint8 // type of addressability - 0 is not addressable
Etype uint8 // op for OASOP, etype for OTYPE, exclam for export
Bounded bool // bounds check unnecessary
Class uint8 // PPARAM, PAUTO, PEXTERN, etc
Method uint8 // OCALLMETH name
Embedded uint8 // ODCLFIELD embedded type
Colas uint8 // OAS resulting from :=
Diag uint8 // already printed error about this
Noescape bool // func arguments do not escape
Nosplit bool // func should not execute on separate stack
Nowritebarrier bool // emit compiler error instead of write barrier
Walkdef uint8
Typecheck uint8
Local bool
Dodata uint8
Initorder uint8
Used bool
Isddd bool // is the argument variadic
Readonly bool
Implicit bool
Addrtaken bool // address taken, even if not moved to heap
Assigned bool // is the variable ever assigned to
Captured bool // is the variable captured by a closure
Byval bool // is the variable captured by value or by reference
Dupok bool // duplicate definitions ok (for func)
Wrapper bool // is method wrapper (for func)
Reslice bool // this is a reslice x = x[0:y] or x = append(x, ...)
Likely int8 // likeliness of if statement
Hasbreak bool // has break statement
Needzero bool // if it contains pointers, needs to be zeroed on function entry
Needctxt bool // function uses context register (has closure variables)
Esc uint8 // EscXXX
Funcdepth int32
// most nodes
Type *Type
Orig *Node // original form, for printing, and tracking copies of ONAMEs
// func
Nname *Node
Shortname *Node
Enter *NodeList
Exit *NodeList
Cvars *NodeList // closure params
Dcl *NodeList // autodcl for this func/closure
Inl *NodeList // copy of the body for use in inlining
Inldcl *NodeList // copy of dcl for use in inlining
Closgen int
Outerfunc *Node
// OLITERAL/OREGISTER
Val Val
// ONAME
Ntype *Node
Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement
Pack *Node // real package for import . names
Curfn *Node // function for local variables
Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn
Decldepth int // declaration loop depth, increased for every loop or label
// ONAME func param with PHEAP
Heapaddr *Node // temp holding heap address of param
Outerexpr *Node // expression copied into closure for variable
Stackparam *Node // OPARAM node referring to stack copy of param
Alloc *Node // allocation call
// ONAME closure param with PPARAMREF
Outer *Node // outer PPARAMREF in nested closure
Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF
Top int // top context (Ecall, Eproc, etc)
// ONAME substitute while inlining
Inlvar *Node
// OPACK
Pkg *Pkg
// OARRAYLIT, OMAPLIT, OSTRUCTLIT.
Initplan *InitPlan
// Escape analysis.
Escflowsrc *NodeList // flow(this, src)
Escretval *NodeList // on OCALLxxx, list of dummy return values
Escloopdepth int // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
Sym *Sym // various
InlCost int32 // unique name for OTYPE/ONAME
Vargen int32
Lineno int32
Endlineno int32
Xoffset int64
Stkdelta int64 // offset added by stack frame compaction phase.
Ostk int32
Iota int32
Walkgen uint32
Esclevel int32
Opt interface{} // for optimization passes
}
// Node ops.
const (
OXXX = iota
// names
ONAME // var, const or func name
ONONAME // unnamed arg or return value: f(int, string) (int, error) { etc }
OTYPE // type name
OPACK // import
OLITERAL // literal
// expressions
OADD // x + y
OSUB // x - y
OOR // x | y
OXOR // x ^ y
OADDSTR // s + "foo"
OADDR // &x
OANDAND // b0 && b1
OAPPEND // append
OARRAYBYTESTR // string(bytes)
OARRAYBYTESTRTMP // string(bytes) ephemeral
OARRAYRUNESTR // string(runes)
OSTRARRAYBYTE // []byte(s)
OSTRARRAYBYTETMP // []byte(s) ephemeral
OSTRARRAYRUNE // []rune(s)
OAS // x = y or x := y
OAS2 // x, y, z = xx, yy, zz
OAS2FUNC // x, y = f()
OAS2RECV // x, ok = <-c
OAS2MAPR // x, ok = m["foo"]
OAS2DOTTYPE // x, ok = I.(int)
OASOP // x += y
OCALL // function call, method call or type conversion, possibly preceded by defer or go.
OCALLFUNC // f()
OCALLMETH // t.Method()
OCALLINTER // err.Error()
OCALLPART // t.Method (without ())
OCAP // cap
OCLOSE // close
OCLOSURE // f = func() { etc }
OCMPIFACE // err1 == err2
OCMPSTR // s1 == s2
OCOMPLIT // composite literal, typechecking may convert to a more specific OXXXLIT.
OMAPLIT // M{"foo":3, "bar":4}
OSTRUCTLIT // T{x:3, y:4}
OARRAYLIT // [2]int{3, 4}
OPTRLIT // &T{x:3, y:4}
OCONV // var i int; var u uint; i = int(u)
OCONVIFACE // I(t)
OCONVNOP // type Int int; var i int; var j Int; i = int(j)
OCOPY // copy
ODCL // var x int
ODCLFUNC // func f() or func (r) f()
ODCLFIELD // struct field, interface field, or func/method argument/return value.
ODCLCONST // const pi = 3.14
ODCLTYPE // type Int int
ODELETE // delete
ODOT // t.x
ODOTPTR // p.x that is implicitly (*p).x
ODOTMETH // t.Method
ODOTINTER // err.Error
OXDOT // t.x, typechecking may convert to a more specific ODOTXXX.
ODOTTYPE // e = err.(MyErr)
ODOTTYPE2 // e, ok = err.(MyErr)
OEQ // x == y
ONE // x != y
OLT // x < y
OLE // x <= y
OGE // x >= y
OGT // x > y
OIND // *p
OINDEX // a[i]
OINDEXMAP // m[s]
OKEY // The x:3 in t{x:3, y:4}, the 1:2 in a[1:2], the 2:20 in [3]int{2:20}, etc.
OPARAM // The on-stack copy of a parameter or return value that escapes.
OLEN // len
OMAKE // make, typechecking may convert to a more specific OMAKEXXX.
OMAKECHAN // make(chan int)
OMAKEMAP // make(map[string]int)
OMAKESLICE // make([]int, 0)
OMUL // *
ODIV // x / y
OMOD // x % y
OLSH // x << u
ORSH // x >> u
OAND // x & y
OANDNOT // x &^ y
ONEW // new
ONOT // !b
OCOM // ^x
OPLUS // +x
OMINUS // -y
OOROR // b1 || b2
OPANIC // panic
OPRINT // print
OPRINTN // println
OPAREN // (x)
OSEND // c <- x
OSLICE // v[1:2], typechecking may convert to a more specific OSLICEXXX.
OSLICEARR // a[1:2]
OSLICESTR // s[1:2]
OSLICE3 // v[1:2:3], typechecking may convert to OSLICE3ARR.
OSLICE3ARR // a[1:2:3]
ORECOVER // recover
ORECV // <-c
ORUNESTR // string(i)
OSELRECV // case x = <-c:
OSELRECV2 // case x, ok = <-c:
OIOTA // iota
OREAL // real
OIMAG // imag
OCOMPLEX // complex
// statements
OBLOCK // block of code
OBREAK // break
OCASE // case, after being verified by swt.c's casebody.
OXCASE // case, before verification.
OCONTINUE // continue
ODEFER // defer
OEMPTY // no-op
OFALL // fallthrough, after being verified by swt.c's casebody.
OXFALL // fallthrough, before verification.
OFOR // for
OGOTO // goto
OIF // if
OLABEL // label:
OPROC // go
ORANGE // range
ORETURN // return
OSELECT // select
OSWITCH // switch x
OTYPESW // switch err.(type)
// types
OTCHAN // chan int
OTMAP // map[string]int
OTSTRUCT // struct{}
OTINTER // interface{}
OTFUNC // func()
OTARRAY // []int, [8]int, [N]int or [...]int
// misc
ODDD // func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}.
ODDDARG // func f(args ...int), introduced by escape analysis.
OINLCALL // intermediary representation of an inlined call.
OEFACE // itable and data words of an empty-interface value.
OITAB // itable word of an interface value.
OSPTR // base pointer of a slice or string.
OCLOSUREVAR // variable reference at beginning of closure function
OCFUNC // reference to c function pointer (not go func value)
OCHECKNIL // emit code to ensure pointer/interface not nil
OVARKILL // variable is dead
// thearch-specific registers
OREGISTER // a register, such as AX.
OINDREG // offset plus indirect of a register, such as 8(SP).
// 386/amd64-specific opcodes
OCMP // compare: ACMP.
ODEC // decrement: ADEC.
OINC // increment: AINC.
OEXTEND // extend: ACWD/ACDQ/ACQO.
OHMUL // high mul: AMUL/AIMUL for unsigned/signed (OMUL uses AIMUL for both).
OLROT // left rotate: AROL.
ORROTC // right rotate-carry: ARCR.
ORETJMP // return to other function
OEND
)
/*
* Every node has a walkgen field.
* If you want to do a traversal of a node graph that
* might contain duplicates and want to avoid
* visiting the same nodes twice, increment walkgen
* before starting. Then before processing a node, do
*
* if(n->walkgen == walkgen)
* return;
* n->walkgen = walkgen;
*
* Such a walk cannot call another such walk recursively,
* because of the use of the global walkgen.
*/
var walkgen uint32
// A NodeList is a linked list of nodes.
// TODO(rsc): Some uses of NodeList should be made into slices.
// The remaining ones probably just need a simple linked list,
// not one with concatenation support.
type NodeList struct {
N *Node
Next *NodeList
End *NodeList
}
// concat returns the concatenation of the lists a and b.
// The storage taken by both is reused for the result.
func concat(a *NodeList, b *NodeList) *NodeList {
if a == nil {
return b
}
if b == nil {
return a
}
a.End.Next = b
a.End = b.End
b.End = nil
return a
}
// list1 returns a one-element list containing n.
func list1(n *Node) *NodeList {
if n == nil {
return nil
}
if n.Op == OBLOCK && n.Ninit == nil {
// Flatten list and steal storage.
// Poison pointer to catch errant uses.
l := n.List
n.List = nil
return l
}
l := new(NodeList)
l.N = n
l.End = l
return l
}
// list returns the result of appending n to l.
func list(l *NodeList, n *Node) *NodeList {
return concat(l, list1(n))
}
// listsort sorts *l in place according to the 3-way comparison function f.
// The algorithm is mergesort, so it is guaranteed to be O(n log n).
func listsort(l **NodeList, f func(*Node, *Node) int) {
if *l == nil || (*l).Next == nil {
return
}
l1 := *l
l2 := *l
for {
l2 = l2.Next
if l2 == nil {
break
}
l2 = l2.Next
if l2 == nil {
break
}
l1 = l1.Next
}
l2 = l1.Next
l1.Next = nil
l2.End = (*l).End
(*l).End = l1
l1 = *l
listsort(&l1, f)
listsort(&l2, f)
if f(l1.N, l2.N) < 0 {
*l = l1
} else {
*l = l2
l2 = l1
l1 = *l
}
// now l1 == *l; and l1 < l2
var le *NodeList
for (l1 != nil) && (l2 != nil) {
for (l1.Next != nil) && f(l1.Next.N, l2.N) < 0 {
l1 = l1.Next
}
// l1 is last one from l1 that is < l2
le = l1.Next // le is the rest of l1, first one that is >= l2
if le != nil {
le.End = (*l).End
}
(*l).End = l1 // cut *l at l1
*l = concat(*l, l2) // glue l2 to *l's tail
l1 = l2 // l1 is the first element of *l that is < the new l2
l2 = le // ... because l2 now is the old tail of l1
}
*l = concat(*l, l2) // any remainder
}
// count returns the length of the list l.
func count(l *NodeList) int {
n := int64(0)
for ; l != nil; l = l.Next {
n++
}
if int64(int(n)) != n { // Overflow.
Yyerror("too many elements in list")
}
return int(n)
}
|