Source file src/cmd/compile/internal/ir/stmt.go

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

View as plain text