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.
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/types"
15 // A Decl is a declaration of a const, type, or var. (A declared func is a Func.)
18 X *Name // the thing being declared
21 func NewDecl(pos src.XPos, op Op, x *Name) *Decl {
26 panic("invalid Decl op " + op.String())
33 func (*Decl) isStmt() {}
35 // A Stmt is a Node that can appear as a statement.
36 // This includes statement-like expressions such as f().
38 // (It's possible it should include <-c, but that would require
39 // splitting ORECV out of UnaryExpr, which hasn't yet been
40 // necessary. Maybe instead we will introduce ExprStmt at
47 // A miniStmt is a miniNode with extra fields common to statements.
48 type miniStmt struct {
53 func (*miniStmt) isStmt() {}
55 func (n *miniStmt) Init() Nodes { return n.init }
56 func (n *miniStmt) SetInit(x Nodes) { n.init = x }
57 func (n *miniStmt) PtrInit() *Nodes { return &n.init }
59 // An AssignListStmt is an assignment statement with
60 // more than one item on at least one side: Lhs = Rhs.
61 // If Def is true, the assignment is a :=.
62 type AssignListStmt struct {
69 func NewAssignListStmt(pos src.XPos, op Op, lhs, rhs []Node) *AssignListStmt {
70 n := &AssignListStmt{}
78 func (n *AssignListStmt) SetOp(op Op) {
81 panic(n.no("SetOp " + op.String()))
82 case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, OSELRECV2:
87 // An AssignStmt is a simple assignment statement: X = Y.
88 // If Def is true, the assignment is a :=.
89 type AssignStmt struct {
96 func NewAssignStmt(pos src.XPos, x, y Node) *AssignStmt {
97 n := &AssignStmt{X: x, Y: y}
103 func (n *AssignStmt) SetOp(op Op) {
106 panic(n.no("SetOp " + op.String()))
112 // An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y.
113 type AssignOpStmt struct {
118 IncDec bool // actually ++ or --
121 func NewAssignOpStmt(pos src.XPos, asOp Op, x, y Node) *AssignOpStmt {
122 n := &AssignOpStmt{AsOp: asOp, X: x, Y: y}
128 // A BlockStmt is a block: { List }.
129 type BlockStmt struct {
134 func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt {
140 n.pos = list[0].Pos()
148 // A BranchStmt is a break, continue, fallthrough, or goto statement.
149 type BranchStmt struct {
151 Label *types.Sym // label if present
154 func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt {
156 case OBREAK, OCONTINUE, OFALL, OGOTO:
159 panic("NewBranch " + op.String())
161 n := &BranchStmt{Label: label}
167 func (n *BranchStmt) SetOp(op Op) {
170 panic(n.no("SetOp " + op.String()))
171 case OBREAK, OCONTINUE, OFALL, OGOTO:
176 func (n *BranchStmt) Sym() *types.Sym { return n.Label }
178 // A CaseClause is a case statement in a switch or select: case List: Body.
179 type CaseClause struct {
181 Var *Name // declared variable for this case in type switch
182 List Nodes // list of expressions for switch, early select
184 // RTypes is a list of RType expressions, which are copied to the
185 // corresponding OEQ nodes that are emitted when switch statements
186 // are desugared. RTypes[i] must be non-nil if the emitted
187 // comparison for List[i] will be a mixed interface/concrete
188 // comparison; see reflectdata.CompareRType for details.
190 // Because mixed interface/concrete switch cases are rare, we allow
191 // len(RTypes) < len(List). Missing entries are implicitly nil.
197 func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause {
198 n := &CaseClause{List: list, Body: body}
204 type CommClause struct {
206 Comm Node // communication case
210 func NewCommStmt(pos src.XPos, comm Node, body []Node) *CommClause {
211 n := &CommClause{Comm: comm, Body: body}
217 // A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
218 type ForStmt struct {
227 func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node, distinctVars bool) *ForStmt {
228 n := &ForStmt{Cond: cond, Post: post}
232 n.init = []Node{init}
235 n.DistinctVars = distinctVars
239 // A GoDeferStmt is a go or defer statement: go Call / defer Call.
241 // The two opcodes use a single syntax because the implementations
242 // are very similar: both are concerned with saving Call and running it
243 // in a different context (a separate goroutine or a later time).
244 type GoDeferStmt struct {
250 func NewGoDeferStmt(pos src.XPos, op Op, call Node) *GoDeferStmt {
251 n := &GoDeferStmt{Call: call}
257 panic("NewGoDeferStmt " + op.String())
262 // An IfStmt is a return statement: if Init; Cond { Body } else { Else }.
268 Likely bool // code layout hint
271 func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt {
272 n := &IfStmt{Cond: cond}
280 // A JumpTableStmt is used to implement switches. Its semantics are:
283 // if tmp == Cases[0] goto Targets[0]
284 // if tmp == Cases[1] goto Targets[1]
286 // if tmp == Cases[n] goto Targets[n]
288 // Note that a JumpTableStmt is more like a multiway-goto than
289 // a multiway-if. In particular, the case bodies are just
290 // labels to jump to, not full Nodes lists.
291 type JumpTableStmt struct {
294 // Value used to index the jump table.
295 // We support only integer types that
296 // are at most the size of a uintptr.
299 // If Idx is equal to Cases[i], jump to Targets[i].
300 // Cases entries must be distinct and in increasing order.
301 // The length of Cases and Targets must be equal.
302 Cases []constant.Value
306 func NewJumpTableStmt(pos src.XPos, idx Node) *JumpTableStmt {
307 n := &JumpTableStmt{Idx: idx}
313 // An InterfaceSwitchStmt is used to implement type switches.
314 // Its semantics are:
316 // if RuntimeType implements Descriptor.Cases[0] {
317 // Case, Itab = 0, itab<RuntimeType, Descriptor.Cases[0]>
318 // } else if RuntimeType implements Descriptor.Cases[1] {
319 // Case, Itab = 1, itab<RuntimeType, Descriptor.Cases[1]>
321 // } else if RuntimeType implements Descriptor.Cases[N-1] {
322 // Case, Itab = N-1, itab<RuntimeType, Descriptor.Cases[N-1]>
324 // Case, Itab = len(cases), nil
326 // RuntimeType must be a non-nil *runtime._type.
327 // Descriptor must represent an abi.InterfaceSwitch global variable.
328 type InterfaceSwitchStmt struct {
337 func NewInterfaceSwitchStmt(pos src.XPos, case_, itab, runtimeType Node, descriptor *obj.LSym) *InterfaceSwitchStmt {
338 n := &InterfaceSwitchStmt{
341 RuntimeType: runtimeType,
342 Descriptor: descriptor,
345 n.op = OINTERFACESWITCH
349 // An InlineMarkStmt is a marker placed just before an inlined body.
350 type InlineMarkStmt struct {
355 func NewInlineMarkStmt(pos src.XPos, index int64) *InlineMarkStmt {
356 n := &InlineMarkStmt{Index: index}
362 func (n *InlineMarkStmt) Offset() int64 { return n.Index }
363 func (n *InlineMarkStmt) SetOffset(x int64) { n.Index = x }
365 // A LabelStmt is a label statement (just the label, not including the statement it labels).
366 type LabelStmt struct {
368 Label *types.Sym // "Label:"
371 func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt {
372 n := &LabelStmt{Label: label}
378 func (n *LabelStmt) Sym() *types.Sym { return n.Label }
380 // A RangeStmt is a range loop: for Key, Value = range X { Body }
381 type RangeStmt struct {
386 RType Node `mknode:"-"` // see reflectdata/helpers.go
393 // When desugaring the RangeStmt during walk, the assignments to Key
394 // and Value may require OCONVIFACE operations. If so, these fields
395 // will be copied to their respective ConvExpr fields.
396 KeyTypeWord Node `mknode:"-"`
397 KeySrcRType Node `mknode:"-"`
398 ValueTypeWord Node `mknode:"-"`
399 ValueSrcRType Node `mknode:"-"`
402 func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node, distinctVars bool) *RangeStmt {
403 n := &RangeStmt{X: x, Key: key, Value: value}
407 n.DistinctVars = distinctVars
411 // A ReturnStmt is a return statement.
412 type ReturnStmt struct {
414 Results Nodes // return list
417 func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
425 // A SelectStmt is a block: { Cases }.
426 type SelectStmt struct {
431 // TODO(rsc): Instead of recording here, replace with a block?
432 Compiled Nodes // compiled form, after walkSelect
435 func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt {
436 n := &SelectStmt{Cases: cases}
442 // A SendStmt is a send statement: X <- Y.
443 type SendStmt struct {
449 func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
450 n := &SendStmt{Chan: ch, Value: value}
456 // A SwitchStmt is a switch statement: switch Init; Tag { Cases }.
457 type SwitchStmt struct {
463 // TODO(rsc): Instead of recording here, replace with a block?
464 Compiled Nodes // compiled form, after walkSwitch
467 func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt {
468 n := &SwitchStmt{Tag: tag, Cases: cases}
474 // A TailCallStmt is a tail call statement, which is used for back-end
475 // code generation to jump directly to another function entirely.
476 type TailCallStmt struct {
478 Call *CallExpr // the underlying call
481 func NewTailCallStmt(pos src.XPos, call *CallExpr) *TailCallStmt {
482 n := &TailCallStmt{Call: call}
488 // A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
489 type TypeSwitchGuard struct {
496 func NewTypeSwitchGuard(pos src.XPos, tag *Ident, x Node) *TypeSwitchGuard {
497 n := &TypeSwitchGuard{Tag: tag, X: x}