github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/ir/stmt.go (about) 1 // Copyright 2020 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 package ir 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 10 "github.com/bir3/gocompiler/src/cmd/internal/src" 11 "github.com/bir3/gocompiler/src/go/constant" 12 ) 13 14 // A Decl is a declaration of a const, type, or var. (A declared func is a Func.) 15 type Decl struct { 16 miniNode 17 X *Name // the thing being declared 18 } 19 20 func NewDecl(pos src.XPos, op Op, x *Name) *Decl { 21 n := &Decl{X: x} 22 n.pos = pos 23 switch op { 24 default: 25 panic("invalid Decl op " + op.String()) 26 case ODCL, ODCLCONST, ODCLTYPE: 27 n.op = op 28 } 29 return n 30 } 31 32 func (*Decl) isStmt() {} 33 34 // A Stmt is a Node that can appear as a statement. 35 // This includes statement-like expressions such as f(). 36 // 37 // (It's possible it should include <-c, but that would require 38 // splitting ORECV out of UnaryExpr, which hasn't yet been 39 // necessary. Maybe instead we will introduce ExprStmt at 40 // some point.) 41 type Stmt interface { 42 Node 43 isStmt() 44 } 45 46 // A miniStmt is a miniNode with extra fields common to statements. 47 type miniStmt struct { 48 miniNode 49 init Nodes 50 } 51 52 func (*miniStmt) isStmt() {} 53 54 func (n *miniStmt) Init() Nodes { return n.init } 55 func (n *miniStmt) SetInit(x Nodes) { n.init = x } 56 func (n *miniStmt) PtrInit() *Nodes { return &n.init } 57 58 // An AssignListStmt is an assignment statement with 59 // more than one item on at least one side: Lhs = Rhs. 60 // If Def is true, the assignment is a :=. 61 type AssignListStmt struct { 62 miniStmt 63 Lhs Nodes 64 Def bool 65 Rhs Nodes 66 } 67 68 func NewAssignListStmt(pos src.XPos, op Op, lhs, rhs []Node) *AssignListStmt { 69 n := &AssignListStmt{} 70 n.pos = pos 71 n.SetOp(op) 72 n.Lhs = lhs 73 n.Rhs = rhs 74 return n 75 } 76 77 func (n *AssignListStmt) SetOp(op Op) { 78 switch op { 79 default: 80 panic(n.no("SetOp " + op.String())) 81 case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, OSELRECV2: 82 n.op = op 83 } 84 } 85 86 // An AssignStmt is a simple assignment statement: X = Y. 87 // If Def is true, the assignment is a :=. 88 type AssignStmt struct { 89 miniStmt 90 X Node 91 Def bool 92 Y Node 93 } 94 95 func NewAssignStmt(pos src.XPos, x, y Node) *AssignStmt { 96 n := &AssignStmt{X: x, Y: y} 97 n.pos = pos 98 n.op = OAS 99 return n 100 } 101 102 func (n *AssignStmt) SetOp(op Op) { 103 switch op { 104 default: 105 panic(n.no("SetOp " + op.String())) 106 case OAS: 107 n.op = op 108 } 109 } 110 111 // An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y. 112 type AssignOpStmt struct { 113 miniStmt 114 X Node 115 AsOp Op // OADD etc 116 Y Node 117 IncDec bool // actually ++ or -- 118 } 119 120 func NewAssignOpStmt(pos src.XPos, asOp Op, x, y Node) *AssignOpStmt { 121 n := &AssignOpStmt{AsOp: asOp, X: x, Y: y} 122 n.pos = pos 123 n.op = OASOP 124 return n 125 } 126 127 // A BlockStmt is a block: { List }. 128 type BlockStmt struct { 129 miniStmt 130 List Nodes 131 } 132 133 func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt { 134 n := &BlockStmt{} 135 n.pos = pos 136 if !pos.IsKnown() { 137 n.pos = base.Pos 138 if len(list) > 0 { 139 n.pos = list[0].Pos() 140 } 141 } 142 n.op = OBLOCK 143 n.List = list 144 return n 145 } 146 147 // A BranchStmt is a break, continue, fallthrough, or goto statement. 148 type BranchStmt struct { 149 miniStmt 150 Label *types.Sym // label if present 151 } 152 153 func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt { 154 switch op { 155 case OBREAK, OCONTINUE, OFALL, OGOTO: 156 // ok 157 default: 158 panic("NewBranch " + op.String()) 159 } 160 n := &BranchStmt{Label: label} 161 n.pos = pos 162 n.op = op 163 return n 164 } 165 166 func (n *BranchStmt) Sym() *types.Sym { return n.Label } 167 168 // A CaseClause is a case statement in a switch or select: case List: Body. 169 type CaseClause struct { 170 miniStmt 171 Var *Name // declared variable for this case in type switch 172 List Nodes // list of expressions for switch, early select 173 174 // RTypes is a list of RType expressions, which are copied to the 175 // corresponding OEQ nodes that are emitted when switch statements 176 // are desugared. RTypes[i] must be non-nil if the emitted 177 // comparison for List[i] will be a mixed interface/concrete 178 // comparison; see reflectdata.CompareRType for details. 179 // 180 // Because mixed interface/concrete switch cases are rare, we allow 181 // len(RTypes) < len(List). Missing entries are implicitly nil. 182 RTypes Nodes 183 184 Body Nodes 185 } 186 187 func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause { 188 n := &CaseClause{List: list, Body: body} 189 n.pos = pos 190 n.op = OCASE 191 return n 192 } 193 194 type CommClause struct { 195 miniStmt 196 Comm Node // communication case 197 Body Nodes 198 } 199 200 func NewCommStmt(pos src.XPos, comm Node, body []Node) *CommClause { 201 n := &CommClause{Comm: comm, Body: body} 202 n.pos = pos 203 n.op = OCASE 204 return n 205 } 206 207 // A ForStmt is a non-range for loop: for Init; Cond; Post { Body } 208 type ForStmt struct { 209 miniStmt 210 Label *types.Sym 211 Cond Node 212 Post Node 213 Body Nodes 214 HasBreak bool 215 } 216 217 func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node) *ForStmt { 218 n := &ForStmt{Cond: cond, Post: post} 219 n.pos = pos 220 n.op = OFOR 221 if init != nil { 222 n.init = []Node{init} 223 } 224 n.Body = body 225 return n 226 } 227 228 // A GoDeferStmt is a go or defer statement: go Call / defer Call. 229 // 230 // The two opcodes use a single syntax because the implementations 231 // are very similar: both are concerned with saving Call and running it 232 // in a different context (a separate goroutine or a later time). 233 type GoDeferStmt struct { 234 miniStmt 235 Call Node 236 } 237 238 func NewGoDeferStmt(pos src.XPos, op Op, call Node) *GoDeferStmt { 239 n := &GoDeferStmt{Call: call} 240 n.pos = pos 241 switch op { 242 case ODEFER, OGO: 243 n.op = op 244 default: 245 panic("NewGoDeferStmt " + op.String()) 246 } 247 return n 248 } 249 250 // An IfStmt is a return statement: if Init; Cond { Body } else { Else }. 251 type IfStmt struct { 252 miniStmt 253 Cond Node 254 Body Nodes 255 Else Nodes 256 Likely bool // code layout hint 257 } 258 259 func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt { 260 n := &IfStmt{Cond: cond} 261 n.pos = pos 262 n.op = OIF 263 n.Body = body 264 n.Else = els 265 return n 266 } 267 268 // A JumpTableStmt is used to implement switches. Its semantics are: 269 // 270 // tmp := jt.Idx 271 // if tmp == Cases[0] goto Targets[0] 272 // if tmp == Cases[1] goto Targets[1] 273 // ... 274 // if tmp == Cases[n] goto Targets[n] 275 // 276 // Note that a JumpTableStmt is more like a multiway-goto than 277 // a multiway-if. In particular, the case bodies are just 278 // labels to jump to, not not full Nodes lists. 279 type JumpTableStmt struct { 280 miniStmt 281 282 // Value used to index the jump table. 283 // We support only integer types that 284 // are at most the size of a uintptr. 285 Idx Node 286 287 // If Idx is equal to Cases[i], jump to Targets[i]. 288 // Cases entries must be distinct and in increasing order. 289 // The length of Cases and Targets must be equal. 290 Cases []constant.Value 291 Targets []*types.Sym 292 } 293 294 func NewJumpTableStmt(pos src.XPos, idx Node) *JumpTableStmt { 295 n := &JumpTableStmt{Idx: idx} 296 n.pos = pos 297 n.op = OJUMPTABLE 298 return n 299 } 300 301 // An InlineMarkStmt is a marker placed just before an inlined body. 302 type InlineMarkStmt struct { 303 miniStmt 304 Index int64 305 } 306 307 func NewInlineMarkStmt(pos src.XPos, index int64) *InlineMarkStmt { 308 n := &InlineMarkStmt{Index: index} 309 n.pos = pos 310 n.op = OINLMARK 311 return n 312 } 313 314 func (n *InlineMarkStmt) Offset() int64 { return n.Index } 315 func (n *InlineMarkStmt) SetOffset(x int64) { n.Index = x } 316 317 // A LabelStmt is a label statement (just the label, not including the statement it labels). 318 type LabelStmt struct { 319 miniStmt 320 Label *types.Sym // "Label:" 321 } 322 323 func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt { 324 n := &LabelStmt{Label: label} 325 n.pos = pos 326 n.op = OLABEL 327 return n 328 } 329 330 func (n *LabelStmt) Sym() *types.Sym { return n.Label } 331 332 // A RangeStmt is a range loop: for Key, Value = range X { Body } 333 type RangeStmt struct { 334 miniStmt 335 Label *types.Sym 336 Def bool 337 X Node 338 RType Node `mknode:"-"` // see reflectdata/helpers.go 339 Key Node 340 Value Node 341 Body Nodes 342 HasBreak bool 343 Prealloc *Name 344 345 // When desugaring the RangeStmt during walk, the assignments to Key 346 // and Value may require OCONVIFACE operations. If so, these fields 347 // will be copied to their respective ConvExpr fields. 348 KeyTypeWord Node `mknode:"-"` 349 KeySrcRType Node `mknode:"-"` 350 ValueTypeWord Node `mknode:"-"` 351 ValueSrcRType Node `mknode:"-"` 352 } 353 354 func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node) *RangeStmt { 355 n := &RangeStmt{X: x, Key: key, Value: value} 356 n.pos = pos 357 n.op = ORANGE 358 n.Body = body 359 return n 360 } 361 362 // A ReturnStmt is a return statement. 363 type ReturnStmt struct { 364 miniStmt 365 origNode // for typecheckargs rewrite 366 Results Nodes // return list 367 } 368 369 func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt { 370 n := &ReturnStmt{} 371 n.pos = pos 372 n.op = ORETURN 373 n.orig = n 374 n.Results = results 375 return n 376 } 377 378 // A SelectStmt is a block: { Cases }. 379 type SelectStmt struct { 380 miniStmt 381 Label *types.Sym 382 Cases []*CommClause 383 HasBreak bool 384 385 // TODO(rsc): Instead of recording here, replace with a block? 386 Compiled Nodes // compiled form, after walkSelect 387 } 388 389 func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt { 390 n := &SelectStmt{Cases: cases} 391 n.pos = pos 392 n.op = OSELECT 393 return n 394 } 395 396 // A SendStmt is a send statement: X <- Y. 397 type SendStmt struct { 398 miniStmt 399 Chan Node 400 Value Node 401 } 402 403 func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt { 404 n := &SendStmt{Chan: ch, Value: value} 405 n.pos = pos 406 n.op = OSEND 407 return n 408 } 409 410 // A SwitchStmt is a switch statement: switch Init; Tag { Cases }. 411 type SwitchStmt struct { 412 miniStmt 413 Tag Node 414 Cases []*CaseClause 415 Label *types.Sym 416 HasBreak bool 417 418 // TODO(rsc): Instead of recording here, replace with a block? 419 Compiled Nodes // compiled form, after walkSwitch 420 } 421 422 func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt { 423 n := &SwitchStmt{Tag: tag, Cases: cases} 424 n.pos = pos 425 n.op = OSWITCH 426 return n 427 } 428 429 // A TailCallStmt is a tail call statement, which is used for back-end 430 // code generation to jump directly to another function entirely. 431 type TailCallStmt struct { 432 miniStmt 433 Call *CallExpr // the underlying call 434 } 435 436 func NewTailCallStmt(pos src.XPos, call *CallExpr) *TailCallStmt { 437 n := &TailCallStmt{Call: call} 438 n.pos = pos 439 n.op = OTAILCALL 440 return n 441 } 442 443 // A TypeSwitchGuard is the [Name :=] X.(type) in a type switch. 444 type TypeSwitchGuard struct { 445 miniNode 446 Tag *Ident 447 X Node 448 Used bool 449 } 450 451 func NewTypeSwitchGuard(pos src.XPos, tag *Ident, x Node) *TypeSwitchGuard { 452 n := &TypeSwitchGuard{Tag: tag, X: x} 453 n.pos = pos 454 n.op = OTYPESW 455 return n 456 }