2020-11-28 00:43:50 -05:00
|
|
|
// 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 (
|
2020-12-21 01:20:20 -05:00
|
|
|
"cmd/compile/internal/base"
|
2020-11-28 00:43:50 -05:00
|
|
|
"cmd/compile/internal/types"
|
|
|
|
|
"cmd/internal/src"
|
|
|
|
|
)
|
|
|
|
|
|
2020-11-29 21:23:47 -05:00
|
|
|
// A Decl is a declaration of a const, type, or var. (A declared func is a Func.)
|
|
|
|
|
type Decl struct {
|
|
|
|
|
miniNode
|
|
|
|
|
X Node // the thing being declared
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewDecl(pos src.XPos, op Op, x Node) *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
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 11:37:54 -05:00
|
|
|
func (*Decl) isStmt() {}
|
|
|
|
|
|
|
|
|
|
// A Stmt is a Node that can appear as a statement.
|
2020-12-07 15:26:24 -05:00
|
|
|
// 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.)
|
2020-12-04 11:37:54 -05:00
|
|
|
type Stmt interface {
|
|
|
|
|
Node
|
|
|
|
|
isStmt()
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-28 00:43:50 -05:00
|
|
|
// A miniStmt is a miniNode with extra fields common to statements.
|
|
|
|
|
type miniStmt struct {
|
|
|
|
|
miniNode
|
|
|
|
|
init Nodes
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 11:37:54 -05:00
|
|
|
func (*miniStmt) isStmt() {}
|
|
|
|
|
|
2020-11-28 00:43:50 -05:00
|
|
|
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 }
|
|
|
|
|
func (n *miniStmt) HasCall() bool { return n.bits&miniHasCall != 0 }
|
|
|
|
|
func (n *miniStmt) SetHasCall(b bool) { n.bits.set(miniHasCall, b) }
|
|
|
|
|
|
2020-11-29 21:23:47 -05:00
|
|
|
// 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
|
2020-12-11 12:55:14 -05:00
|
|
|
Lhs Nodes
|
|
|
|
|
Def bool
|
|
|
|
|
Rhs Nodes
|
2020-11-29 21:23:47 -05:00
|
|
|
}
|
|
|
|
|
|
2020-12-07 09:14:44 -05:00
|
|
|
func NewAssignListStmt(pos src.XPos, op Op, lhs, rhs []Node) *AssignListStmt {
|
2020-11-29 21:23:47 -05:00
|
|
|
n := &AssignListStmt{}
|
|
|
|
|
n.pos = pos
|
2020-12-07 09:14:44 -05:00
|
|
|
n.SetOp(op)
|
2020-11-29 21:23:47 -05:00
|
|
|
n.Lhs.Set(lhs)
|
|
|
|
|
n.Rhs.Set(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
|
2020-12-11 12:55:14 -05:00
|
|
|
X Node
|
|
|
|
|
Def bool
|
|
|
|
|
Y Node
|
2020-11-29 21:23:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()))
|
2020-12-07 10:51:44 +07:00
|
|
|
case OAS:
|
2020-11-29 21:23:47 -05:00
|
|
|
n.op = op
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y.
|
|
|
|
|
type AssignOpStmt struct {
|
|
|
|
|
miniStmt
|
|
|
|
|
typ *types.Type
|
|
|
|
|
X Node
|
|
|
|
|
AsOp Op // OADD etc
|
|
|
|
|
Y Node
|
|
|
|
|
IncDec bool // actually ++ or --
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-10 18:45:35 -05:00
|
|
|
func NewAssignOpStmt(pos src.XPos, asOp Op, x, y Node) *AssignOpStmt {
|
|
|
|
|
n := &AssignOpStmt{AsOp: asOp, X: x, Y: y}
|
2020-11-29 21:23:47 -05:00
|
|
|
n.pos = pos
|
|
|
|
|
n.op = OASOP
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (n *AssignOpStmt) Type() *types.Type { return n.typ }
|
|
|
|
|
func (n *AssignOpStmt) SetType(x *types.Type) { n.typ = x }
|
|
|
|
|
|
|
|
|
|
// A BlockStmt is a block: { List }.
|
|
|
|
|
type BlockStmt struct {
|
|
|
|
|
miniStmt
|
2020-12-23 00:02:08 -05:00
|
|
|
List Nodes
|
2020-11-29 21:23:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt {
|
|
|
|
|
n := &BlockStmt{}
|
|
|
|
|
n.pos = pos
|
2020-12-21 01:20:20 -05:00
|
|
|
if !pos.IsKnown() {
|
|
|
|
|
n.pos = base.Pos
|
|
|
|
|
if len(list) > 0 {
|
|
|
|
|
n.pos = list[0].Pos()
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-29 21:23:47 -05:00
|
|
|
n.op = OBLOCK
|
2020-12-23 00:02:08 -05:00
|
|
|
n.List.Set(list)
|
2020-11-29 21:23:47 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-28 00:43:50 -05:00
|
|
|
// A BranchStmt is a break, continue, fallthrough, or goto statement.
|
2020-11-29 21:23:47 -05:00
|
|
|
//
|
|
|
|
|
// For back-end code generation, Op may also be RETJMP (return+jump),
|
|
|
|
|
// in which case the label names another function entirely.
|
2020-11-28 00:43:50 -05:00
|
|
|
type BranchStmt struct {
|
|
|
|
|
miniStmt
|
|
|
|
|
Label *types.Sym // label if present
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt {
|
|
|
|
|
switch op {
|
2020-11-29 21:23:47 -05:00
|
|
|
case OBREAK, OCONTINUE, OFALL, OGOTO, ORETJMP:
|
2020-11-28 00:43:50 -05:00
|
|
|
// ok
|
|
|
|
|
default:
|
|
|
|
|
panic("NewBranch " + op.String())
|
|
|
|
|
}
|
|
|
|
|
n := &BranchStmt{Label: label}
|
|
|
|
|
n.pos = pos
|
|
|
|
|
n.op = op
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 00:02:08 -05:00
|
|
|
func (n *BranchStmt) Sym() *types.Sym { return n.Label }
|
2020-11-28 00:43:50 -05:00
|
|
|
|
2020-11-29 21:23:47 -05:00
|
|
|
// A CaseStmt is a case statement in a switch or select: case List: Body.
|
|
|
|
|
type CaseStmt struct {
|
|
|
|
|
miniStmt
|
2020-12-23 00:02:08 -05:00
|
|
|
Vars Nodes // declared variable for this case in type switch
|
|
|
|
|
List Nodes // list of expressions for switch, early select
|
|
|
|
|
Comm Node // communication case (Exprs[0]) after select is type-checked
|
|
|
|
|
Body Nodes
|
2020-11-29 21:23:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewCaseStmt(pos src.XPos, list, body []Node) *CaseStmt {
|
|
|
|
|
n := &CaseStmt{}
|
|
|
|
|
n.pos = pos
|
|
|
|
|
n.op = OCASE
|
2020-12-23 00:02:08 -05:00
|
|
|
n.List.Set(list)
|
|
|
|
|
n.Body.Set(body)
|
2020-11-29 21:23:47 -05:00
|
|
|
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
|
2020-12-23 00:02:08 -05:00
|
|
|
Label *types.Sym
|
|
|
|
|
Cond Node
|
|
|
|
|
Late Nodes
|
|
|
|
|
Post Node
|
|
|
|
|
Body Nodes
|
|
|
|
|
HasBreak bool
|
2020-11-29 21:23:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
n.init.Set(init)
|
2020-12-23 00:02:08 -05:00
|
|
|
n.Body.Set(body)
|
2020-11-29 21:23:47 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (n *ForStmt) SetOp(op Op) {
|
|
|
|
|
if op != OFOR && op != OFORUNTIL {
|
|
|
|
|
panic(n.no("SetOp " + op.String()))
|
|
|
|
|
}
|
|
|
|
|
n.op = op
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-07 09:14:44 -05:00
|
|
|
// A GoDeferStmt is a go or defer statement: go Call / defer Call.
|
|
|
|
|
//
|
|
|
|
|
// The two opcodes use a signle 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 {
|
2020-11-29 21:23:47 -05:00
|
|
|
miniStmt
|
|
|
|
|
Call Node
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-07 09:14:44 -05:00
|
|
|
func NewGoDeferStmt(pos src.XPos, op Op, call Node) *GoDeferStmt {
|
|
|
|
|
n := &GoDeferStmt{Call: call}
|
2020-11-29 21:23:47 -05:00
|
|
|
n.pos = pos
|
2020-12-07 09:14:44 -05:00
|
|
|
switch op {
|
|
|
|
|
case ODEFER, OGO:
|
|
|
|
|
n.op = op
|
|
|
|
|
default:
|
|
|
|
|
panic("NewGoDeferStmt " + op.String())
|
|
|
|
|
}
|
2020-11-29 21:23:47 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A IfStmt is a return statement: if Init; Cond { Then } else { Else }.
|
|
|
|
|
type IfStmt struct {
|
|
|
|
|
miniStmt
|
2020-12-23 00:02:08 -05:00
|
|
|
Cond Node
|
|
|
|
|
Body Nodes
|
|
|
|
|
Else Nodes
|
|
|
|
|
Likely bool // code layout hint
|
2020-11-29 21:23:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt {
|
|
|
|
|
n := &IfStmt{Cond: cond}
|
|
|
|
|
n.pos = pos
|
|
|
|
|
n.op = OIF
|
2020-12-23 00:02:08 -05:00
|
|
|
n.Body.Set(body)
|
2020-11-29 21:23:47 -05:00
|
|
|
n.Else.Set(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
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 18:43:18 -05:00
|
|
|
func (n *InlineMarkStmt) Offset() int64 { return n.Index }
|
|
|
|
|
func (n *InlineMarkStmt) SetOffset(x int64) { n.Index = x }
|
2020-11-29 21:23:47 -05:00
|
|
|
|
2020-11-28 00:43:50 -05:00
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 00:02:08 -05:00
|
|
|
func (n *LabelStmt) Sym() *types.Sym { return n.Label }
|
2020-11-29 21:23:47 -05:00
|
|
|
|
|
|
|
|
// A RangeStmt is a range loop: for Vars = range X { Stmts }
|
|
|
|
|
// Op can be OFOR or OFORUNTIL (!Cond).
|
|
|
|
|
type RangeStmt struct {
|
|
|
|
|
miniStmt
|
2020-12-23 00:02:08 -05:00
|
|
|
Label *types.Sym
|
|
|
|
|
Vars Nodes // TODO(rsc): Replace with Key, Value Node
|
|
|
|
|
Def bool
|
|
|
|
|
X Node
|
|
|
|
|
Body Nodes
|
|
|
|
|
HasBreak bool
|
|
|
|
|
typ *types.Type // TODO(rsc): Remove - use X.Type() instead
|
|
|
|
|
Prealloc *Name
|
2020-11-29 21:23:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewRangeStmt(pos src.XPos, vars []Node, x Node, body []Node) *RangeStmt {
|
|
|
|
|
n := &RangeStmt{X: x}
|
|
|
|
|
n.pos = pos
|
|
|
|
|
n.op = ORANGE
|
|
|
|
|
n.Vars.Set(vars)
|
2020-12-23 00:02:08 -05:00
|
|
|
n.Body.Set(body)
|
2020-11-29 21:23:47 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 18:43:18 -05:00
|
|
|
func (n *RangeStmt) Type() *types.Type { return n.typ }
|
|
|
|
|
func (n *RangeStmt) SetType(x *types.Type) { n.typ = x }
|
2020-11-29 21:23:47 -05:00
|
|
|
|
|
|
|
|
// A ReturnStmt is a return statement.
|
|
|
|
|
type ReturnStmt struct {
|
|
|
|
|
miniStmt
|
|
|
|
|
orig Node // 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.Set(results)
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 00:02:08 -05:00
|
|
|
func (n *ReturnStmt) Orig() Node { return n.orig }
|
|
|
|
|
func (n *ReturnStmt) SetOrig(x Node) { n.orig = x }
|
2020-11-29 21:23:47 -05:00
|
|
|
|
|
|
|
|
// A SelectStmt is a block: { Cases }.
|
|
|
|
|
type SelectStmt struct {
|
|
|
|
|
miniStmt
|
2020-12-23 00:02:08 -05:00
|
|
|
Label *types.Sym
|
|
|
|
|
Cases Nodes
|
|
|
|
|
HasBreak bool
|
2020-11-29 21:23:47 -05:00
|
|
|
|
|
|
|
|
// TODO(rsc): Instead of recording here, replace with a block?
|
|
|
|
|
Compiled Nodes // compiled form, after walkswitch
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewSelectStmt(pos src.XPos, cases []Node) *SelectStmt {
|
|
|
|
|
n := &SelectStmt{}
|
|
|
|
|
n.pos = pos
|
|
|
|
|
n.op = OSELECT
|
|
|
|
|
n.Cases.Set(cases)
|
|
|
|
|
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; Expr { Cases }.
|
|
|
|
|
type SwitchStmt struct {
|
|
|
|
|
miniStmt
|
2020-12-23 00:02:08 -05:00
|
|
|
Tag Node
|
|
|
|
|
Cases Nodes // list of *CaseStmt
|
|
|
|
|
Label *types.Sym
|
|
|
|
|
HasBreak bool
|
2020-11-29 21:23:47 -05:00
|
|
|
|
|
|
|
|
// TODO(rsc): Instead of recording here, replace with a block?
|
|
|
|
|
Compiled Nodes // compiled form, after walkswitch
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewSwitchStmt(pos src.XPos, tag Node, cases []Node) *SwitchStmt {
|
|
|
|
|
n := &SwitchStmt{Tag: tag}
|
|
|
|
|
n.pos = pos
|
|
|
|
|
n.op = OSWITCH
|
|
|
|
|
n.Cases.Set(cases)
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
|
|
|
|
|
type TypeSwitchGuard struct {
|
|
|
|
|
miniNode
|
2020-12-07 21:56:58 -08:00
|
|
|
Tag *Ident
|
|
|
|
|
X Node
|
|
|
|
|
Used bool
|
2020-11-29 21:23:47 -05:00
|
|
|
}
|
|
|
|
|
|
2020-12-07 21:56:58 -08:00
|
|
|
func NewTypeSwitchGuard(pos src.XPos, tag *Ident, x Node) *TypeSwitchGuard {
|
|
|
|
|
n := &TypeSwitchGuard{Tag: tag, X: x}
|
2020-11-29 21:23:47 -05:00
|
|
|
n.pos = pos
|
|
|
|
|
n.op = OTYPESW
|
|
|
|
|
return n
|
|
|
|
|
}
|