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