blob: e7d0d873b781ef79e43fa81d2447a139a54cdea5 [file] [log] [blame]
Dan Willemsencc753b72021-08-31 13:25:42 -07001// 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
5package ir
6
7import (
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.)
14type Decl struct {
15 miniNode
16 X *Name // the thing being declared
17}
18
19func 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
31func (*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.)
40type Stmt interface {
41 Node
42 isStmt()
43}
44
45// A miniStmt is a miniNode with extra fields common to statements.
46type miniStmt struct {
47 miniNode
48 init Nodes
49}
50
51func (*miniStmt) isStmt() {}
52
53func (n *miniStmt) Init() Nodes { return n.init }
54func (n *miniStmt) SetInit(x Nodes) { n.init = x }
55func (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 :=.
60type AssignListStmt struct {
61 miniStmt
62 Lhs Nodes
63 Def bool
64 Rhs Nodes
65}
66
67func 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
76func (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 :=.
87type AssignStmt struct {
88 miniStmt
89 X Node
90 Def bool
91 Y Node
92}
93
94func 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
101func (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.
111type AssignOpStmt struct {
112 miniStmt
113 X Node
114 AsOp Op // OADD etc
115 Y Node
116 IncDec bool // actually ++ or --
117}
118
119func 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 }.
127type BlockStmt struct {
128 miniStmt
129 List Nodes
130}
131
132func 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.
147type BranchStmt struct {
148 miniStmt
149 Label *types.Sym // label if present
150}
151
152func 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
165func (n *BranchStmt) Sym() *types.Sym { return n.Label }
166
167// A CaseClause is a case statement in a switch or select: case List: Body.
168type 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
175func 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
182type CommClause struct {
183 miniStmt
184 Comm Node // communication case
185 Body Nodes
186}
187
188func 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).
197type 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
207func 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
218func (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).
230type GoDeferStmt struct {
231 miniStmt
232 Call Node
233}
234
235func 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
Dan Willemsenbc60c3c2021-12-15 01:09:00 -0800247// An IfStmt is a return statement: if Init; Cond { Body } else { Else }.
Dan Willemsencc753b72021-08-31 13:25:42 -0700248type IfStmt struct {
249 miniStmt
250 Cond Node
251 Body Nodes
252 Else Nodes
253 Likely bool // code layout hint
254}
255
256func 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.
266type InlineMarkStmt struct {
267 miniStmt
268 Index int64
269}
270
271func 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
278func (n *InlineMarkStmt) Offset() int64 { return n.Index }
279func (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).
282type LabelStmt struct {
283 miniStmt
284 Label *types.Sym // "Label:"
285}
286
287func 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
294func (n *LabelStmt) Sym() *types.Sym { return n.Label }
295
296// A RangeStmt is a range loop: for Key, Value = range X { Body }
297type 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
309func 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.
318type ReturnStmt struct {
319 miniStmt
320 origNode // for typecheckargs rewrite
321 Results Nodes // return list
322}
323
324func 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 }.
334type 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?
Dan Willemsenbc60c3c2021-12-15 01:09:00 -0800341 Compiled Nodes // compiled form, after walkSelect
Dan Willemsencc753b72021-08-31 13:25:42 -0700342}
343
344func 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.
352type SendStmt struct {
353 miniStmt
354 Chan Node
355 Value Node
356}
357
358func 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; Expr { Cases }.
366type 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
377func 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.
386type TailCallStmt struct {
387 miniStmt
Dan Willemsenbc60c3c2021-12-15 01:09:00 -0800388 Call *CallExpr // the underlying call
Dan Willemsencc753b72021-08-31 13:25:42 -0700389}
390
Dan Willemsenbc60c3c2021-12-15 01:09:00 -0800391func NewTailCallStmt(pos src.XPos, call *CallExpr) *TailCallStmt {
392 n := &TailCallStmt{Call: call}
Dan Willemsencc753b72021-08-31 13:25:42 -0700393 n.pos = pos
394 n.op = OTAILCALL
395 return n
396}
397
398// A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
399type TypeSwitchGuard struct {
400 miniNode
401 Tag *Ident
402 X Node
403 Used bool
404}
405
406func 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}