github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/ir/node.go (about) 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 ir 8 9 import ( 10 "fmt" 11 "github.com/bir3/gocompiler/src/go/constant" 12 "sort" 13 14 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 15 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 16 "github.com/bir3/gocompiler/src/cmd/internal/src" 17 ) 18 19 // A Node is the abstract interface to an IR node. 20 type Node interface { 21 // Formatting 22 Format(s fmt.State, verb rune) 23 24 // Source position. 25 Pos() src.XPos 26 SetPos(x src.XPos) 27 28 // For making copies. For Copy and SepCopy. 29 copy() Node 30 31 doChildren(func(Node) bool) bool 32 editChildren(func(Node) Node) 33 editChildrenWithHidden(func(Node) Node) 34 35 // Abstract graph structure, for generic traversals. 36 Op() Op 37 Init() Nodes 38 39 // Fields specific to certain Ops only. 40 Type() *types.Type 41 SetType(t *types.Type) 42 Name() *Name 43 Sym() *types.Sym 44 Val() constant.Value 45 SetVal(v constant.Value) 46 47 // Storage for analysis passes. 48 Esc() uint16 49 SetEsc(x uint16) 50 51 // Typecheck values: 52 // 0 means the node is not typechecked 53 // 1 means the node is completely typechecked 54 // 2 means typechecking of the node is in progress 55 // 3 means the node has its type from types2, but may need transformation 56 Typecheck() uint8 57 SetTypecheck(x uint8) 58 NonNil() bool 59 MarkNonNil() 60 } 61 62 // Line returns n's position as a string. If n has been inlined, 63 // it uses the outermost position where n has been inlined. 64 func Line(n Node) string { 65 return base.FmtPos(n.Pos()) 66 } 67 68 func IsSynthetic(n Node) bool { 69 name := n.Sym().Name 70 return name[0] == '.' || name[0] == '~' 71 } 72 73 // IsAutoTmp indicates if n was created by the compiler as a temporary, 74 // based on the setting of the .AutoTemp flag in n's Name. 75 func IsAutoTmp(n Node) bool { 76 if n == nil || n.Op() != ONAME { 77 return false 78 } 79 return n.Name().AutoTemp() 80 } 81 82 // MayBeShared reports whether n may occur in multiple places in the AST. 83 // Extra care must be taken when mutating such a node. 84 func MayBeShared(n Node) bool { 85 switch n.Op() { 86 case ONAME, OLITERAL, ONIL, OTYPE: 87 return true 88 } 89 return false 90 } 91 92 type InitNode interface { 93 Node 94 PtrInit() *Nodes 95 SetInit(x Nodes) 96 } 97 98 func TakeInit(n Node) Nodes { 99 init := n.Init() 100 if len(init) != 0 { 101 n.(InitNode).SetInit(nil) 102 } 103 return init 104 } 105 106 //go:generate stringer -type=Op -trimprefix=O node.go 107 108 type Op uint8 109 110 // Node ops. 111 const ( 112 OXXX Op = iota 113 114 // names 115 ONAME // var or func name 116 // Unnamed arg or return value: f(int, string) (int, error) { etc } 117 // Also used for a qualified package identifier that hasn't been resolved yet. 118 ONONAME 119 OTYPE // type name 120 OLITERAL // literal 121 ONIL // nil 122 123 // expressions 124 OADD // X + Y 125 OSUB // X - Y 126 OOR // X | Y 127 OXOR // X ^ Y 128 OADDSTR // +{List} (string addition, list elements are strings) 129 OADDR // &X 130 OANDAND // X && Y 131 OAPPEND // append(Args); after walk, X may contain elem type descriptor 132 OBYTES2STR // Type(X) (Type is string, X is a []byte) 133 OBYTES2STRTMP // Type(X) (Type is string, X is a []byte, ephemeral) 134 ORUNES2STR // Type(X) (Type is string, X is a []rune) 135 OSTR2BYTES // Type(X) (Type is []byte, X is a string) 136 OSTR2BYTESTMP // Type(X) (Type is []byte, X is a string, ephemeral) 137 OSTR2RUNES // Type(X) (Type is []rune, X is a string) 138 OSLICE2ARR // Type(X) (Type is [N]T, X is a []T) 139 OSLICE2ARRPTR // Type(X) (Type is *[N]T, X is a []T) 140 // X = Y or (if Def=true) X := Y 141 // If Def, then Init includes a DCL node for X. 142 OAS 143 // Lhs = Rhs (x, y, z = a, b, c) or (if Def=true) Lhs := Rhs 144 // If Def, then Init includes DCL nodes for Lhs 145 OAS2 146 OAS2DOTTYPE // Lhs = Rhs (x, ok = I.(int)) 147 OAS2FUNC // Lhs = Rhs (x, y = f()) 148 OAS2MAPR // Lhs = Rhs (x, ok = m["foo"]) 149 OAS2RECV // Lhs = Rhs (x, ok = <-c) 150 OASOP // X AsOp= Y (x += y) 151 OCALL // X(Args) (function call, method call or type conversion) 152 153 // OCALLFUNC, OCALLMETH, and OCALLINTER have the same structure. 154 // Prior to walk, they are: X(Args), where Args is all regular arguments. 155 // After walk, if any argument whose evaluation might requires temporary variable, 156 // that temporary variable will be pushed to Init, Args will contains an updated 157 // set of arguments. 158 OCALLFUNC // X(Args) (function call f(args)) 159 OCALLMETH // X(Args) (direct method call x.Method(args)) 160 OCALLINTER // X(Args) (interface method call x.Method(args)) 161 OCAP // cap(X) 162 OCLOSE // close(X) 163 OCLOSURE // func Type { Func.Closure.Body } (func literal) 164 OCOMPLIT // Type{List} (composite literal, not yet lowered to specific form) 165 OMAPLIT // Type{List} (composite literal, Type is map) 166 OSTRUCTLIT // Type{List} (composite literal, Type is struct) 167 OARRAYLIT // Type{List} (composite literal, Type is array) 168 OSLICELIT // Type{List} (composite literal, Type is slice), Len is slice length. 169 OPTRLIT // &X (X is composite literal) 170 OCONV // Type(X) (type conversion) 171 OCONVIFACE // Type(X) (type conversion, to interface) 172 OCONVIDATA // Builds a data word to store X in an interface. Equivalent to IDATA(CONVIFACE(X)). Is an ir.ConvExpr. 173 OCONVNOP // Type(X) (type conversion, no effect) 174 OCOPY // copy(X, Y) 175 ODCL // var X (declares X of type X.Type) 176 177 // Used during parsing but don't last. 178 ODCLFUNC // func f() or func (r) f() 179 ODCLCONST // const pi = 3.14 180 ODCLTYPE // type Int int or type Int = int 181 182 ODELETE // delete(Args) 183 ODOT // X.Sel (X is of struct type) 184 ODOTPTR // X.Sel (X is of pointer to struct type) 185 ODOTMETH // X.Sel (X is non-interface, Sel is method name) 186 ODOTINTER // X.Sel (X is interface, Sel is method name) 187 OXDOT // X.Sel (before rewrite to one of the preceding) 188 ODOTTYPE // X.Ntype or X.Type (.Ntype during parsing, .Type once resolved); after walk, Itab contains address of interface type descriptor and Itab.X contains address of concrete type descriptor 189 ODOTTYPE2 // X.Ntype or X.Type (.Ntype during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, Itab contains address of interface type descriptor 190 OEQ // X == Y 191 ONE // X != Y 192 OLT // X < Y 193 OLE // X <= Y 194 OGE // X >= Y 195 OGT // X > Y 196 ODEREF // *X 197 OINDEX // X[Index] (index of array or slice) 198 OINDEXMAP // X[Index] (index of map) 199 OKEY // Key:Value (key:value in struct/array/map literal) 200 OSTRUCTKEY // Field:Value (key:value in struct literal, after type checking) 201 OLEN // len(X) 202 OMAKE // make(Args) (before type checking converts to one of the following) 203 OMAKECHAN // make(Type[, Len]) (type is chan) 204 OMAKEMAP // make(Type[, Len]) (type is map) 205 OMAKESLICE // make(Type[, Len[, Cap]]) (type is slice) 206 OMAKESLICECOPY // makeslicecopy(Type, Len, Cap) (type is slice; Len is length and Cap is the copied from slice) 207 // OMAKESLICECOPY is created by the order pass and corresponds to: 208 // s = make(Type, Len); copy(s, Cap) 209 // 210 // Bounded can be set on the node when Len == len(Cap) is known at compile time. 211 // 212 // This node is created so the walk pass can optimize this pattern which would 213 // otherwise be hard to detect after the order pass. 214 OMUL // X * Y 215 ODIV // X / Y 216 OMOD // X % Y 217 OLSH // X << Y 218 ORSH // X >> Y 219 OAND // X & Y 220 OANDNOT // X &^ Y 221 ONEW // new(X); corresponds to calls to new in source code 222 ONOT // !X 223 OBITNOT // ^X 224 OPLUS // +X 225 ONEG // -X 226 OOROR // X || Y 227 OPANIC // panic(X) 228 OPRINT // print(List) 229 OPRINTN // println(List) 230 OPAREN // (X) 231 OSEND // Chan <- Value 232 OSLICE // X[Low : High] (X is untypechecked or slice) 233 OSLICEARR // X[Low : High] (X is pointer to array) 234 OSLICESTR // X[Low : High] (X is string) 235 OSLICE3 // X[Low : High : Max] (X is untypedchecked or slice) 236 OSLICE3ARR // X[Low : High : Max] (X is pointer to array) 237 OSLICEHEADER // sliceheader{Ptr, Len, Cap} (Ptr is unsafe.Pointer, Len is length, Cap is capacity) 238 OSTRINGHEADER // stringheader{Ptr, Len} (Ptr is unsafe.Pointer, Len is length) 239 ORECOVER // recover() 240 ORECOVERFP // recover(Args) w/ explicit FP argument 241 ORECV // <-X 242 ORUNESTR // Type(X) (Type is string, X is rune) 243 OSELRECV2 // like OAS2: Lhs = Rhs where len(Lhs)=2, len(Rhs)=1, Rhs[0].Op = ORECV (appears as .Var of OCASE) 244 OREAL // real(X) 245 OIMAG // imag(X) 246 OCOMPLEX // complex(X, Y) 247 OALIGNOF // unsafe.Alignof(X) 248 OOFFSETOF // unsafe.Offsetof(X) 249 OSIZEOF // unsafe.Sizeof(X) 250 OUNSAFEADD // unsafe.Add(X, Y) 251 OUNSAFESLICE // unsafe.Slice(X, Y) 252 OUNSAFESLICEDATA // unsafe.SliceData(X) 253 OUNSAFESTRING // unsafe.String(X, Y) 254 OUNSAFESTRINGDATA // unsafe.StringData(X) 255 OMETHEXPR // X(Args) (method expression T.Method(args), first argument is the method receiver) 256 OMETHVALUE // X.Sel (method expression t.Method, not called) 257 258 // statements 259 OBLOCK // { List } (block of code) 260 OBREAK // break [Label] 261 // OCASE: case List: Body (List==nil means default) 262 // For OTYPESW, List is a OTYPE node for the specified type (or OLITERAL 263 // for nil) or an ODYNAMICTYPE indicating a runtime type for generics. 264 // If a type-switch variable is specified, Var is an 265 // ONAME for the version of the type-switch variable with the specified 266 // type. 267 OCASE 268 OCONTINUE // continue [Label] 269 ODEFER // defer Call 270 OFALL // fallthrough 271 OFOR // for Init; Cond; Post { Body } 272 OGOTO // goto Label 273 OIF // if Init; Cond { Then } else { Else } 274 OLABEL // Label: 275 OGO // go Call 276 ORANGE // for Key, Value = range X { Body } 277 ORETURN // return Results 278 OSELECT // select { Cases } 279 OSWITCH // switch Init; Expr { Cases } 280 // OTYPESW: X := Y.(type) (appears as .Tag of OSWITCH) 281 // X is nil if there is no type-switch variable 282 OTYPESW 283 OFUNCINST // instantiation of a generic function 284 285 // misc 286 // intermediate representation of an inlined call. Uses Init (assignments 287 // for the captured variables, parameters, retvars, & INLMARK op), 288 // Body (body of the inlined function), and ReturnVars (list of 289 // return values) 290 OINLCALL // intermediary representation of an inlined call. 291 OEFACE // itable and data words of an empty-interface value. 292 OITAB // itable word of an interface value. 293 OIDATA // data word of an interface value in X 294 OSPTR // base pointer of a slice or string. Bounded==1 means known non-nil. 295 OCFUNC // reference to c function pointer (not go func value) 296 OCHECKNIL // emit code to ensure pointer/interface not nil 297 ORESULT // result of a function call; Xoffset is stack offset 298 OINLMARK // start of an inlined body, with file/line of caller. Xoffset is an index into the inline tree. 299 OLINKSYMOFFSET // offset within a name 300 OJUMPTABLE // A jump table structure for implementing dense expression switches 301 302 // opcodes for generics 303 ODYNAMICDOTTYPE // x = i.(T) where T is a type parameter (or derived from a type parameter) 304 ODYNAMICDOTTYPE2 // x, ok = i.(T) where T is a type parameter (or derived from a type parameter) 305 ODYNAMICTYPE // a type node for type switches (represents a dynamic target type for a type switch) 306 307 // arch-specific opcodes 308 OTAILCALL // tail call to another function 309 OGETG // runtime.getg() (read g pointer) 310 OGETCALLERPC // runtime.getcallerpc() (continuation PC in caller frame) 311 OGETCALLERSP // runtime.getcallersp() (stack pointer in caller frame) 312 313 OEND 314 ) 315 316 // IsCmp reports whether op is a comparison operation (==, !=, <, <=, 317 // >, or >=). 318 func (op Op) IsCmp() bool { 319 switch op { 320 case OEQ, ONE, OLT, OLE, OGT, OGE: 321 return true 322 } 323 return false 324 } 325 326 // Nodes is a pointer to a slice of *Node. 327 // For fields that are not used in most nodes, this is used instead of 328 // a slice to save space. 329 type Nodes []Node 330 331 // Append appends entries to Nodes. 332 func (n *Nodes) Append(a ...Node) { 333 if len(a) == 0 { 334 return 335 } 336 *n = append(*n, a...) 337 } 338 339 // Prepend prepends entries to Nodes. 340 // If a slice is passed in, this will take ownership of it. 341 func (n *Nodes) Prepend(a ...Node) { 342 if len(a) == 0 { 343 return 344 } 345 *n = append(a, *n...) 346 } 347 348 // Take clears n, returning its former contents. 349 func (n *Nodes) Take() []Node { 350 ret := *n 351 *n = nil 352 return ret 353 } 354 355 // Copy returns a copy of the content of the slice. 356 func (n Nodes) Copy() Nodes { 357 if n == nil { 358 return nil 359 } 360 c := make(Nodes, len(n)) 361 copy(c, n) 362 return c 363 } 364 365 // NameQueue is a FIFO queue of *Name. The zero value of NameQueue is 366 // a ready-to-use empty queue. 367 type NameQueue struct { 368 ring []*Name 369 head, tail int 370 } 371 372 // Empty reports whether q contains no Names. 373 func (q *NameQueue) Empty() bool { 374 return q.head == q.tail 375 } 376 377 // PushRight appends n to the right of the queue. 378 func (q *NameQueue) PushRight(n *Name) { 379 if len(q.ring) == 0 { 380 q.ring = make([]*Name, 16) 381 } else if q.head+len(q.ring) == q.tail { 382 // Grow the ring. 383 nring := make([]*Name, len(q.ring)*2) 384 // Copy the old elements. 385 part := q.ring[q.head%len(q.ring):] 386 if q.tail-q.head <= len(part) { 387 part = part[:q.tail-q.head] 388 copy(nring, part) 389 } else { 390 pos := copy(nring, part) 391 copy(nring[pos:], q.ring[:q.tail%len(q.ring)]) 392 } 393 q.ring, q.head, q.tail = nring, 0, q.tail-q.head 394 } 395 396 q.ring[q.tail%len(q.ring)] = n 397 q.tail++ 398 } 399 400 // PopLeft pops a Name from the left of the queue. It panics if q is 401 // empty. 402 func (q *NameQueue) PopLeft() *Name { 403 if q.Empty() { 404 panic("dequeue empty") 405 } 406 n := q.ring[q.head%len(q.ring)] 407 q.head++ 408 return n 409 } 410 411 // NameSet is a set of Names. 412 type NameSet map[*Name]struct{} 413 414 // Has reports whether s contains n. 415 func (s NameSet) Has(n *Name) bool { 416 _, isPresent := s[n] 417 return isPresent 418 } 419 420 // Add adds n to s. 421 func (s *NameSet) Add(n *Name) { 422 if *s == nil { 423 *s = make(map[*Name]struct{}) 424 } 425 (*s)[n] = struct{}{} 426 } 427 428 // Sorted returns s sorted according to less. 429 func (s NameSet) Sorted(less func(*Name, *Name) bool) []*Name { 430 var res []*Name 431 for n := range s { 432 res = append(res, n) 433 } 434 sort.Slice(res, func(i, j int) bool { return less(res[i], res[j]) }) 435 return res 436 } 437 438 type PragmaFlag uint16 439 440 const ( 441 // Func pragmas. 442 Nointerface PragmaFlag = 1 << iota 443 Noescape // func parameters don't escape 444 Norace // func must not have race detector annotations 445 Nosplit // func should not execute on separate stack 446 Noinline // func should not be inlined 447 NoCheckPtr // func should not be instrumented by checkptr 448 CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all 449 UintptrKeepAlive // pointers converted to uintptr must be kept alive 450 UintptrEscapes // pointers converted to uintptr escape 451 452 // Runtime-only func pragmas. 453 // See ../../../../runtime/HACKING.md for detailed descriptions. 454 Systemstack // func must run on system stack 455 Nowritebarrier // emit compiler error instead of write barrier 456 Nowritebarrierrec // error on write barrier in this or recursive callees 457 Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees 458 459 // Go command pragmas 460 GoBuildPragma 461 462 RegisterParams // TODO(register args) remove after register abi is working 463 464 ) 465 466 func AsNode(n types.Object) Node { 467 if n == nil { 468 return nil 469 } 470 return n.(Node) 471 } 472 473 var BlankNode Node 474 475 func IsConst(n Node, ct constant.Kind) bool { 476 return ConstType(n) == ct 477 } 478 479 // IsNil reports whether n represents the universal untyped zero value "nil". 480 func IsNil(n Node) bool { 481 // Check n.Orig because constant propagation may produce typed nil constants, 482 // which don't exist in the Go spec. 483 return n != nil && Orig(n).Op() == ONIL 484 } 485 486 func IsBlank(n Node) bool { 487 if n == nil { 488 return false 489 } 490 return n.Sym().IsBlank() 491 } 492 493 // IsMethod reports whether n is a method. 494 // n must be a function or a method. 495 func IsMethod(n Node) bool { 496 return n.Type().Recv() != nil 497 } 498 499 func HasNamedResults(fn *Func) bool { 500 typ := fn.Type() 501 return typ.NumResults() > 0 && types.OrigSym(typ.Results().Field(0).Sym) != nil 502 } 503 504 // HasUniquePos reports whether n has a unique position that can be 505 // used for reporting error messages. 506 // 507 // It's primarily used to distinguish references to named objects, 508 // whose Pos will point back to their declaration position rather than 509 // their usage position. 510 func HasUniquePos(n Node) bool { 511 switch n.Op() { 512 case ONAME: 513 return false 514 case OLITERAL, ONIL, OTYPE: 515 if n.Sym() != nil { 516 return false 517 } 518 } 519 520 if !n.Pos().IsKnown() { 521 if base.Flag.K != 0 { 522 base.Warn("setlineno: unknown position (line 0)") 523 } 524 return false 525 } 526 527 return true 528 } 529 530 func SetPos(n Node) src.XPos { 531 lno := base.Pos 532 if n != nil && HasUniquePos(n) { 533 base.Pos = n.Pos() 534 } 535 return lno 536 } 537 538 // The result of InitExpr MUST be assigned back to n, e.g. 539 // 540 // n.X = InitExpr(init, n.X) 541 func InitExpr(init []Node, expr Node) Node { 542 if len(init) == 0 { 543 return expr 544 } 545 546 n, ok := expr.(InitNode) 547 if !ok || MayBeShared(n) { 548 // Introduce OCONVNOP to hold init list. 549 n = NewConvExpr(base.Pos, OCONVNOP, nil, expr) 550 n.SetType(expr.Type()) 551 n.SetTypecheck(1) 552 } 553 554 n.PtrInit().Prepend(init...) 555 return n 556 } 557 558 // what's the outer value that a write to n affects? 559 // outer value means containing struct or array. 560 func OuterValue(n Node) Node { 561 for { 562 switch nn := n; nn.Op() { 563 case OXDOT: 564 base.FatalfAt(n.Pos(), "OXDOT in OuterValue: %v", n) 565 case ODOT: 566 nn := nn.(*SelectorExpr) 567 n = nn.X 568 continue 569 case OPAREN: 570 nn := nn.(*ParenExpr) 571 n = nn.X 572 continue 573 case OCONVNOP: 574 nn := nn.(*ConvExpr) 575 n = nn.X 576 continue 577 case OINDEX: 578 nn := nn.(*IndexExpr) 579 if nn.X.Type() == nil { 580 base.Fatalf("OuterValue needs type for %v", nn.X) 581 } 582 if nn.X.Type().IsArray() { 583 n = nn.X 584 continue 585 } 586 } 587 588 return n 589 } 590 } 591 592 const ( 593 EscUnknown = iota 594 EscNone // Does not escape to heap, result, or parameters. 595 EscHeap // Reachable from the heap 596 EscNever // By construction will not escape. 597 )