diff options
Diffstat (limited to 'src/cmd/compile/internal/ir/stmt.go')
-rw-r--r-- | src/cmd/compile/internal/ir/stmt.go | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ir/stmt.go b/src/cmd/compile/internal/ir/stmt.go new file mode 100644 index 0000000..80bd205 --- /dev/null +++ b/src/cmd/compile/internal/ir/stmt.go @@ -0,0 +1,411 @@ +// Copyright 2020 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. + +package ir + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/types" + "cmd/internal/src" +) + +// A Decl is a declaration of a const, type, or var. (A declared func is a Func.) +type Decl struct { + miniNode + X *Name // the thing being declared +} + +func NewDecl(pos src.XPos, op Op, x *Name) *Decl { + n := &Decl{X: x} + n.pos = pos + switch op { + default: + panic("invalid Decl op " + op.String()) + case ODCL, ODCLCONST, ODCLTYPE: + n.op = op + } + return n +} + +func (*Decl) isStmt() {} + +// A Stmt is a Node that can appear as a statement. +// This includes statement-like expressions such as f(). +// +// (It's possible it should include <-c, but that would require +// splitting ORECV out of UnaryExpr, which hasn't yet been +// necessary. Maybe instead we will introduce ExprStmt at +// some point.) +type Stmt interface { + Node + isStmt() +} + +// A miniStmt is a miniNode with extra fields common to statements. +type miniStmt struct { + miniNode + init Nodes +} + +func (*miniStmt) isStmt() {} + +func (n *miniStmt) Init() Nodes { return n.init } +func (n *miniStmt) SetInit(x Nodes) { n.init = x } +func (n *miniStmt) PtrInit() *Nodes { return &n.init } + +// An AssignListStmt is an assignment statement with +// more than one item on at least one side: Lhs = Rhs. +// If Def is true, the assignment is a :=. +type AssignListStmt struct { + miniStmt + Lhs Nodes + Def bool + Rhs Nodes +} + +func NewAssignListStmt(pos src.XPos, op Op, lhs, rhs []Node) *AssignListStmt { + n := &AssignListStmt{} + n.pos = pos + n.SetOp(op) + n.Lhs = lhs + n.Rhs = rhs + return n +} + +func (n *AssignListStmt) SetOp(op Op) { + switch op { + default: + panic(n.no("SetOp " + op.String())) + case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, OSELRECV2: + n.op = op + } +} + +// An AssignStmt is a simple assignment statement: X = Y. +// If Def is true, the assignment is a :=. +type AssignStmt struct { + miniStmt + X Node + Def bool + Y Node +} + +func NewAssignStmt(pos src.XPos, x, y Node) *AssignStmt { + n := &AssignStmt{X: x, Y: y} + n.pos = pos + n.op = OAS + return n +} + +func (n *AssignStmt) SetOp(op Op) { + switch op { + default: + panic(n.no("SetOp " + op.String())) + case OAS: + n.op = op + } +} + +// An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y. +type AssignOpStmt struct { + miniStmt + X Node + AsOp Op // OADD etc + Y Node + IncDec bool // actually ++ or -- +} + +func NewAssignOpStmt(pos src.XPos, asOp Op, x, y Node) *AssignOpStmt { + n := &AssignOpStmt{AsOp: asOp, X: x, Y: y} + n.pos = pos + n.op = OASOP + return n +} + +// A BlockStmt is a block: { List }. +type BlockStmt struct { + miniStmt + List Nodes +} + +func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt { + n := &BlockStmt{} + n.pos = pos + if !pos.IsKnown() { + n.pos = base.Pos + if len(list) > 0 { + n.pos = list[0].Pos() + } + } + n.op = OBLOCK + n.List = list + return n +} + +// A BranchStmt is a break, continue, fallthrough, or goto statement. +type BranchStmt struct { + miniStmt + Label *types.Sym // label if present +} + +func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt { + switch op { + case OBREAK, OCONTINUE, OFALL, OGOTO: + // ok + default: + panic("NewBranch " + op.String()) + } + n := &BranchStmt{Label: label} + n.pos = pos + n.op = op + return n +} + +func (n *BranchStmt) Sym() *types.Sym { return n.Label } + +// A CaseClause is a case statement in a switch or select: case List: Body. +type CaseClause struct { + miniStmt + Var *Name // declared variable for this case in type switch + List Nodes // list of expressions for switch, early select + Body Nodes +} + +func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause { + n := &CaseClause{List: list, Body: body} + n.pos = pos + n.op = OCASE + return n +} + +type CommClause struct { + miniStmt + Comm Node // communication case + Body Nodes +} + +func NewCommStmt(pos src.XPos, comm Node, body []Node) *CommClause { + n := &CommClause{Comm: comm, Body: body} + n.pos = pos + n.op = OCASE + return n +} + +// A ForStmt is a non-range for loop: for Init; Cond; Post { Body } +// Op can be OFOR or OFORUNTIL (!Cond). +type ForStmt struct { + miniStmt + Label *types.Sym + Cond Node + Late Nodes + Post Node + Body Nodes + HasBreak bool +} + +func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node) *ForStmt { + n := &ForStmt{Cond: cond, Post: post} + n.pos = pos + n.op = OFOR + if init != nil { + n.init = []Node{init} + } + n.Body = body + return n +} + +func (n *ForStmt) SetOp(op Op) { + if op != OFOR && op != OFORUNTIL { + panic(n.no("SetOp " + op.String())) + } + n.op = op +} + +// A GoDeferStmt is a go or defer statement: go Call / defer Call. +// +// The two opcodes use a single syntax because the implementations +// are very similar: both are concerned with saving Call and running it +// in a different context (a separate goroutine or a later time). +type GoDeferStmt struct { + miniStmt + Call Node +} + +func NewGoDeferStmt(pos src.XPos, op Op, call Node) *GoDeferStmt { + n := &GoDeferStmt{Call: call} + n.pos = pos + switch op { + case ODEFER, OGO: + n.op = op + default: + panic("NewGoDeferStmt " + op.String()) + } + return n +} + +// An IfStmt is a return statement: if Init; Cond { Body } else { Else }. +type IfStmt struct { + miniStmt + Cond Node + Body Nodes + Else Nodes + Likely bool // code layout hint +} + +func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt { + n := &IfStmt{Cond: cond} + n.pos = pos + n.op = OIF + n.Body = body + n.Else = els + return n +} + +// An InlineMarkStmt is a marker placed just before an inlined body. +type InlineMarkStmt struct { + miniStmt + Index int64 +} + +func NewInlineMarkStmt(pos src.XPos, index int64) *InlineMarkStmt { + n := &InlineMarkStmt{Index: index} + n.pos = pos + n.op = OINLMARK + return n +} + +func (n *InlineMarkStmt) Offset() int64 { return n.Index } +func (n *InlineMarkStmt) SetOffset(x int64) { n.Index = x } + +// A LabelStmt is a label statement (just the label, not including the statement it labels). +type LabelStmt struct { + miniStmt + Label *types.Sym // "Label:" +} + +func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt { + n := &LabelStmt{Label: label} + n.pos = pos + n.op = OLABEL + return n +} + +func (n *LabelStmt) Sym() *types.Sym { return n.Label } + +// A RangeStmt is a range loop: for Key, Value = range X { Body } +type RangeStmt struct { + miniStmt + Label *types.Sym + Def bool + X Node + Key Node + Value Node + Body Nodes + HasBreak bool + Prealloc *Name +} + +func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node) *RangeStmt { + n := &RangeStmt{X: x, Key: key, Value: value} + n.pos = pos + n.op = ORANGE + n.Body = body + return n +} + +// A ReturnStmt is a return statement. +type ReturnStmt struct { + miniStmt + origNode // for typecheckargs rewrite + Results Nodes // return list +} + +func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt { + n := &ReturnStmt{} + n.pos = pos + n.op = ORETURN + n.orig = n + n.Results = results + return n +} + +// A SelectStmt is a block: { Cases }. +type SelectStmt struct { + miniStmt + Label *types.Sym + Cases []*CommClause + HasBreak bool + + // TODO(rsc): Instead of recording here, replace with a block? + Compiled Nodes // compiled form, after walkSelect +} + +func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt { + n := &SelectStmt{Cases: cases} + n.pos = pos + n.op = OSELECT + return n +} + +// A SendStmt is a send statement: X <- Y. +type SendStmt struct { + miniStmt + Chan Node + Value Node +} + +func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt { + n := &SendStmt{Chan: ch, Value: value} + n.pos = pos + n.op = OSEND + return n +} + +// A SwitchStmt is a switch statement: switch Init; Tag { Cases }. +type SwitchStmt struct { + miniStmt + Tag Node + Cases []*CaseClause + Label *types.Sym + HasBreak bool + + // TODO(rsc): Instead of recording here, replace with a block? + Compiled Nodes // compiled form, after walkSwitch +} + +func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt { + n := &SwitchStmt{Tag: tag, Cases: cases} + n.pos = pos + n.op = OSWITCH + return n +} + +// A TailCallStmt is a tail call statement, which is used for back-end +// code generation to jump directly to another function entirely. +type TailCallStmt struct { + miniStmt + Call *CallExpr // the underlying call +} + +func NewTailCallStmt(pos src.XPos, call *CallExpr) *TailCallStmt { + n := &TailCallStmt{Call: call} + n.pos = pos + n.op = OTAILCALL + return n +} + +// A TypeSwitchGuard is the [Name :=] X.(type) in a type switch. +type TypeSwitchGuard struct { + miniNode + Tag *Ident + X Node + Used bool +} + +func NewTypeSwitchGuard(pos src.XPos, tag *Ident, x Node) *TypeSwitchGuard { + n := &TypeSwitchGuard{Tag: tag, X: x} + n.pos = pos + n.op = OTYPESW + return n +} |