]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ir/stmt.go
b3d6b0fbd5c4d71dd12ed6db747ced7e8da38f72
[gostls13.git] / 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         "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:
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) SetOp(op Op) {
167         switch op {
168         default:
169                 panic(n.no("SetOp " + op.String()))
170         case OBREAK, OCONTINUE, OFALL, OGOTO:
171                 n.op = op
172         }
173 }
174
175 func (n *BranchStmt) Sym() *types.Sym { return n.Label }
176
177 // A CaseClause is a case statement in a switch or select: case List: Body.
178 type CaseClause struct {
179         miniStmt
180         Var  *Name // declared variable for this case in type switch
181         List Nodes // list of expressions for switch, early select
182
183         // RTypes is a list of RType expressions, which are copied to the
184         // corresponding OEQ nodes that are emitted when switch statements
185         // are desugared. RTypes[i] must be non-nil if the emitted
186         // comparison for List[i] will be a mixed interface/concrete
187         // comparison; see reflectdata.CompareRType for details.
188         //
189         // Because mixed interface/concrete switch cases are rare, we allow
190         // len(RTypes) < len(List). Missing entries are implicitly nil.
191         RTypes Nodes
192
193         Body Nodes
194 }
195
196 func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause {
197         n := &CaseClause{List: list, Body: body}
198         n.pos = pos
199         n.op = OCASE
200         return n
201 }
202
203 type CommClause struct {
204         miniStmt
205         Comm Node // communication case
206         Body Nodes
207 }
208
209 func NewCommStmt(pos src.XPos, comm Node, body []Node) *CommClause {
210         n := &CommClause{Comm: comm, Body: body}
211         n.pos = pos
212         n.op = OCASE
213         return n
214 }
215
216 // A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
217 type ForStmt struct {
218         miniStmt
219         Label        *types.Sym
220         Cond         Node
221         Post         Node
222         Body         Nodes
223         DistinctVars bool
224 }
225
226 func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node, distinctVars bool) *ForStmt {
227         n := &ForStmt{Cond: cond, Post: post}
228         n.pos = pos
229         n.op = OFOR
230         if init != nil {
231                 n.init = []Node{init}
232         }
233         n.Body = body
234         n.DistinctVars = distinctVars
235         return n
236 }
237
238 // A GoDeferStmt is a go or defer statement: go Call / defer Call.
239 //
240 // The two opcodes use a single syntax because the implementations
241 // are very similar: both are concerned with saving Call and running it
242 // in a different context (a separate goroutine or a later time).
243 type GoDeferStmt struct {
244         miniStmt
245         Call    Node
246         DeferAt Expr
247 }
248
249 func NewGoDeferStmt(pos src.XPos, op Op, call Node) *GoDeferStmt {
250         n := &GoDeferStmt{Call: call}
251         n.pos = pos
252         switch op {
253         case ODEFER, OGO:
254                 n.op = op
255         default:
256                 panic("NewGoDeferStmt " + op.String())
257         }
258         return n
259 }
260
261 // An IfStmt is a return statement: if Init; Cond { Body } else { Else }.
262 type IfStmt struct {
263         miniStmt
264         Cond   Node
265         Body   Nodes
266         Else   Nodes
267         Likely bool // code layout hint
268 }
269
270 func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt {
271         n := &IfStmt{Cond: cond}
272         n.pos = pos
273         n.op = OIF
274         n.Body = body
275         n.Else = els
276         return n
277 }
278
279 // A JumpTableStmt is used to implement switches. Its semantics are:
280 //
281 //      tmp := jt.Idx
282 //      if tmp == Cases[0] goto Targets[0]
283 //      if tmp == Cases[1] goto Targets[1]
284 //      ...
285 //      if tmp == Cases[n] goto Targets[n]
286 //
287 // Note that a JumpTableStmt is more like a multiway-goto than
288 // a multiway-if. In particular, the case bodies are just
289 // labels to jump to, not full Nodes lists.
290 type JumpTableStmt struct {
291         miniStmt
292
293         // Value used to index the jump table.
294         // We support only integer types that
295         // are at most the size of a uintptr.
296         Idx Node
297
298         // If Idx is equal to Cases[i], jump to Targets[i].
299         // Cases entries must be distinct and in increasing order.
300         // The length of Cases and Targets must be equal.
301         Cases   []constant.Value
302         Targets []*types.Sym
303 }
304
305 func NewJumpTableStmt(pos src.XPos, idx Node) *JumpTableStmt {
306         n := &JumpTableStmt{Idx: idx}
307         n.pos = pos
308         n.op = OJUMPTABLE
309         return n
310 }
311
312 // An InlineMarkStmt is a marker placed just before an inlined body.
313 type InlineMarkStmt struct {
314         miniStmt
315         Index int64
316 }
317
318 func NewInlineMarkStmt(pos src.XPos, index int64) *InlineMarkStmt {
319         n := &InlineMarkStmt{Index: index}
320         n.pos = pos
321         n.op = OINLMARK
322         return n
323 }
324
325 func (n *InlineMarkStmt) Offset() int64     { return n.Index }
326 func (n *InlineMarkStmt) SetOffset(x int64) { n.Index = x }
327
328 // A LabelStmt is a label statement (just the label, not including the statement it labels).
329 type LabelStmt struct {
330         miniStmt
331         Label *types.Sym // "Label:"
332 }
333
334 func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt {
335         n := &LabelStmt{Label: label}
336         n.pos = pos
337         n.op = OLABEL
338         return n
339 }
340
341 func (n *LabelStmt) Sym() *types.Sym { return n.Label }
342
343 // A RangeStmt is a range loop: for Key, Value = range X { Body }
344 type RangeStmt struct {
345         miniStmt
346         Label        *types.Sym
347         Def          bool
348         X            Node
349         RType        Node `mknode:"-"` // see reflectdata/helpers.go
350         Key          Node
351         Value        Node
352         Body         Nodes
353         DistinctVars bool
354         Prealloc     *Name
355
356         // When desugaring the RangeStmt during walk, the assignments to Key
357         // and Value may require OCONVIFACE operations. If so, these fields
358         // will be copied to their respective ConvExpr fields.
359         KeyTypeWord   Node `mknode:"-"`
360         KeySrcRType   Node `mknode:"-"`
361         ValueTypeWord Node `mknode:"-"`
362         ValueSrcRType Node `mknode:"-"`
363 }
364
365 func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node, distinctVars bool) *RangeStmt {
366         n := &RangeStmt{X: x, Key: key, Value: value}
367         n.pos = pos
368         n.op = ORANGE
369         n.Body = body
370         n.DistinctVars = distinctVars
371         return n
372 }
373
374 // A ReturnStmt is a return statement.
375 type ReturnStmt struct {
376         miniStmt
377         Results Nodes // return list
378 }
379
380 func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
381         n := &ReturnStmt{}
382         n.pos = pos
383         n.op = ORETURN
384         n.Results = results
385         return n
386 }
387
388 // A SelectStmt is a block: { Cases }.
389 type SelectStmt struct {
390         miniStmt
391         Label *types.Sym
392         Cases []*CommClause
393
394         // TODO(rsc): Instead of recording here, replace with a block?
395         Compiled Nodes // compiled form, after walkSelect
396 }
397
398 func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt {
399         n := &SelectStmt{Cases: cases}
400         n.pos = pos
401         n.op = OSELECT
402         return n
403 }
404
405 // A SendStmt is a send statement: X <- Y.
406 type SendStmt struct {
407         miniStmt
408         Chan  Node
409         Value Node
410 }
411
412 func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
413         n := &SendStmt{Chan: ch, Value: value}
414         n.pos = pos
415         n.op = OSEND
416         return n
417 }
418
419 // A SwitchStmt is a switch statement: switch Init; Tag { Cases }.
420 type SwitchStmt struct {
421         miniStmt
422         Tag   Node
423         Cases []*CaseClause
424         Label *types.Sym
425
426         // TODO(rsc): Instead of recording here, replace with a block?
427         Compiled Nodes // compiled form, after walkSwitch
428 }
429
430 func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt {
431         n := &SwitchStmt{Tag: tag, Cases: cases}
432         n.pos = pos
433         n.op = OSWITCH
434         return n
435 }
436
437 // A TailCallStmt is a tail call statement, which is used for back-end
438 // code generation to jump directly to another function entirely.
439 type TailCallStmt struct {
440         miniStmt
441         Call *CallExpr // the underlying call
442 }
443
444 func NewTailCallStmt(pos src.XPos, call *CallExpr) *TailCallStmt {
445         n := &TailCallStmt{Call: call}
446         n.pos = pos
447         n.op = OTAILCALL
448         return n
449 }
450
451 // A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
452 type TypeSwitchGuard struct {
453         miniNode
454         Tag  *Ident
455         X    Node
456         Used bool
457 }
458
459 func NewTypeSwitchGuard(pos src.XPos, tag *Ident, x Node) *TypeSwitchGuard {
460         n := &TypeSwitchGuard{Tag: tag, X: x}
461         n.pos = pos
462         n.op = OTYPESW
463         return n
464 }