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  }