]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ir/stmt.go
cmd/compile: use type hash from itab field instead of type field
[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/obj"
11         "cmd/internal/src"
12         "go/constant"
13 )
14
15 // A Decl is a declaration of a const, type, or var. (A declared func is a Func.)
16 type Decl struct {
17         miniNode
18         X *Name // the thing being declared
19 }
20
21 func NewDecl(pos src.XPos, op Op, x *Name) *Decl {
22         n := &Decl{X: x}
23         n.pos = pos
24         switch op {
25         default:
26                 panic("invalid Decl op " + op.String())
27         case ODCL:
28                 n.op = op
29         }
30         return n
31 }
32
33 func (*Decl) isStmt() {}
34
35 // A Stmt is a Node that can appear as a statement.
36 // This includes statement-like expressions such as f().
37 //
38 // (It's possible it should include <-c, but that would require
39 // splitting ORECV out of UnaryExpr, which hasn't yet been
40 // necessary. Maybe instead we will introduce ExprStmt at
41 // some point.)
42 type Stmt interface {
43         Node
44         isStmt()
45 }
46
47 // A miniStmt is a miniNode with extra fields common to statements.
48 type miniStmt struct {
49         miniNode
50         init Nodes
51 }
52
53 func (*miniStmt) isStmt() {}
54
55 func (n *miniStmt) Init() Nodes     { return n.init }
56 func (n *miniStmt) SetInit(x Nodes) { n.init = x }
57 func (n *miniStmt) PtrInit() *Nodes { return &n.init }
58
59 // An AssignListStmt is an assignment statement with
60 // more than one item on at least one side: Lhs = Rhs.
61 // If Def is true, the assignment is a :=.
62 type AssignListStmt struct {
63         miniStmt
64         Lhs Nodes
65         Def bool
66         Rhs Nodes
67 }
68
69 func NewAssignListStmt(pos src.XPos, op Op, lhs, rhs []Node) *AssignListStmt {
70         n := &AssignListStmt{}
71         n.pos = pos
72         n.SetOp(op)
73         n.Lhs = lhs
74         n.Rhs = rhs
75         return n
76 }
77
78 func (n *AssignListStmt) SetOp(op Op) {
79         switch op {
80         default:
81                 panic(n.no("SetOp " + op.String()))
82         case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, OSELRECV2:
83                 n.op = op
84         }
85 }
86
87 // An AssignStmt is a simple assignment statement: X = Y.
88 // If Def is true, the assignment is a :=.
89 type AssignStmt struct {
90         miniStmt
91         X   Node
92         Def bool
93         Y   Node
94 }
95
96 func NewAssignStmt(pos src.XPos, x, y Node) *AssignStmt {
97         n := &AssignStmt{X: x, Y: y}
98         n.pos = pos
99         n.op = OAS
100         return n
101 }
102
103 func (n *AssignStmt) SetOp(op Op) {
104         switch op {
105         default:
106                 panic(n.no("SetOp " + op.String()))
107         case OAS:
108                 n.op = op
109         }
110 }
111
112 // An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y.
113 type AssignOpStmt struct {
114         miniStmt
115         X      Node
116         AsOp   Op // OADD etc
117         Y      Node
118         IncDec bool // actually ++ or --
119 }
120
121 func NewAssignOpStmt(pos src.XPos, asOp Op, x, y Node) *AssignOpStmt {
122         n := &AssignOpStmt{AsOp: asOp, X: x, Y: y}
123         n.pos = pos
124         n.op = OASOP
125         return n
126 }
127
128 // A BlockStmt is a block: { List }.
129 type BlockStmt struct {
130         miniStmt
131         List Nodes
132 }
133
134 func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt {
135         n := &BlockStmt{}
136         n.pos = pos
137         if !pos.IsKnown() {
138                 n.pos = base.Pos
139                 if len(list) > 0 {
140                         n.pos = list[0].Pos()
141                 }
142         }
143         n.op = OBLOCK
144         n.List = list
145         return n
146 }
147
148 // A BranchStmt is a break, continue, fallthrough, or goto statement.
149 type BranchStmt struct {
150         miniStmt
151         Label *types.Sym // label if present
152 }
153
154 func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt {
155         switch op {
156         case OBREAK, OCONTINUE, OFALL, OGOTO:
157                 // ok
158         default:
159                 panic("NewBranch " + op.String())
160         }
161         n := &BranchStmt{Label: label}
162         n.pos = pos
163         n.op = op
164         return n
165 }
166
167 func (n *BranchStmt) SetOp(op Op) {
168         switch op {
169         default:
170                 panic(n.no("SetOp " + op.String()))
171         case OBREAK, OCONTINUE, OFALL, OGOTO:
172                 n.op = op
173         }
174 }
175
176 func (n *BranchStmt) Sym() *types.Sym { return n.Label }
177
178 // A CaseClause is a case statement in a switch or select: case List: Body.
179 type CaseClause struct {
180         miniStmt
181         Var  *Name // declared variable for this case in type switch
182         List Nodes // list of expressions for switch, early select
183
184         // RTypes is a list of RType expressions, which are copied to the
185         // corresponding OEQ nodes that are emitted when switch statements
186         // are desugared. RTypes[i] must be non-nil if the emitted
187         // comparison for List[i] will be a mixed interface/concrete
188         // comparison; see reflectdata.CompareRType for details.
189         //
190         // Because mixed interface/concrete switch cases are rare, we allow
191         // len(RTypes) < len(List). Missing entries are implicitly nil.
192         RTypes Nodes
193
194         Body Nodes
195 }
196
197 func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause {
198         n := &CaseClause{List: list, Body: body}
199         n.pos = pos
200         n.op = OCASE
201         return n
202 }
203
204 type CommClause struct {
205         miniStmt
206         Comm Node // communication case
207         Body Nodes
208 }
209
210 func NewCommStmt(pos src.XPos, comm Node, body []Node) *CommClause {
211         n := &CommClause{Comm: comm, Body: body}
212         n.pos = pos
213         n.op = OCASE
214         return n
215 }
216
217 // A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
218 type ForStmt struct {
219         miniStmt
220         Label        *types.Sym
221         Cond         Node
222         Post         Node
223         Body         Nodes
224         DistinctVars bool
225 }
226
227 func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node, distinctVars bool) *ForStmt {
228         n := &ForStmt{Cond: cond, Post: post}
229         n.pos = pos
230         n.op = OFOR
231         if init != nil {
232                 n.init = []Node{init}
233         }
234         n.Body = body
235         n.DistinctVars = distinctVars
236         return n
237 }
238
239 // A GoDeferStmt is a go or defer statement: go Call / defer Call.
240 //
241 // The two opcodes use a single syntax because the implementations
242 // are very similar: both are concerned with saving Call and running it
243 // in a different context (a separate goroutine or a later time).
244 type GoDeferStmt struct {
245         miniStmt
246         Call    Node
247         DeferAt Expr
248 }
249
250 func NewGoDeferStmt(pos src.XPos, op Op, call Node) *GoDeferStmt {
251         n := &GoDeferStmt{Call: call}
252         n.pos = pos
253         switch op {
254         case ODEFER, OGO:
255                 n.op = op
256         default:
257                 panic("NewGoDeferStmt " + op.String())
258         }
259         return n
260 }
261
262 // An IfStmt is a return statement: if Init; Cond { Body } else { Else }.
263 type IfStmt struct {
264         miniStmt
265         Cond   Node
266         Body   Nodes
267         Else   Nodes
268         Likely bool // code layout hint
269 }
270
271 func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt {
272         n := &IfStmt{Cond: cond}
273         n.pos = pos
274         n.op = OIF
275         n.Body = body
276         n.Else = els
277         return n
278 }
279
280 // A JumpTableStmt is used to implement switches. Its semantics are:
281 //
282 //      tmp := jt.Idx
283 //      if tmp == Cases[0] goto Targets[0]
284 //      if tmp == Cases[1] goto Targets[1]
285 //      ...
286 //      if tmp == Cases[n] goto Targets[n]
287 //
288 // Note that a JumpTableStmt is more like a multiway-goto than
289 // a multiway-if. In particular, the case bodies are just
290 // labels to jump to, not full Nodes lists.
291 type JumpTableStmt struct {
292         miniStmt
293
294         // Value used to index the jump table.
295         // We support only integer types that
296         // are at most the size of a uintptr.
297         Idx Node
298
299         // If Idx is equal to Cases[i], jump to Targets[i].
300         // Cases entries must be distinct and in increasing order.
301         // The length of Cases and Targets must be equal.
302         Cases   []constant.Value
303         Targets []*types.Sym
304 }
305
306 func NewJumpTableStmt(pos src.XPos, idx Node) *JumpTableStmt {
307         n := &JumpTableStmt{Idx: idx}
308         n.pos = pos
309         n.op = OJUMPTABLE
310         return n
311 }
312
313 // An InterfaceSwitchStmt is used to implement type switches.
314 // Its semantics are:
315 //
316 //      if RuntimeType implements Descriptor.Cases[0] {
317 //          Case, Itab = 0, itab<RuntimeType, Descriptor.Cases[0]>
318 //      } else if RuntimeType implements Descriptor.Cases[1] {
319 //          Case, Itab = 1, itab<RuntimeType, Descriptor.Cases[1]>
320 //      ...
321 //      } else if RuntimeType implements Descriptor.Cases[N-1] {
322 //          Case, Itab = N-1, itab<RuntimeType, Descriptor.Cases[N-1]>
323 //      } else {
324 //          Case, Itab = len(cases), nil
325 //      }
326 //
327 // RuntimeType must be a non-nil *runtime._type.
328 // Hash must be the hash field of RuntimeType (or its copy loaded from an itab).
329 // Descriptor must represent an abi.InterfaceSwitch global variable.
330 type InterfaceSwitchStmt struct {
331         miniStmt
332
333         Case        Node
334         Itab        Node
335         RuntimeType Node
336         Hash        Node
337         Descriptor  *obj.LSym
338 }
339
340 func NewInterfaceSwitchStmt(pos src.XPos, case_, itab, runtimeType, hash Node, descriptor *obj.LSym) *InterfaceSwitchStmt {
341         n := &InterfaceSwitchStmt{
342                 Case:        case_,
343                 Itab:        itab,
344                 RuntimeType: runtimeType,
345                 Hash:        hash,
346                 Descriptor:  descriptor,
347         }
348         n.pos = pos
349         n.op = OINTERFACESWITCH
350         return n
351 }
352
353 // An InlineMarkStmt is a marker placed just before an inlined body.
354 type InlineMarkStmt struct {
355         miniStmt
356         Index int64
357 }
358
359 func NewInlineMarkStmt(pos src.XPos, index int64) *InlineMarkStmt {
360         n := &InlineMarkStmt{Index: index}
361         n.pos = pos
362         n.op = OINLMARK
363         return n
364 }
365
366 func (n *InlineMarkStmt) Offset() int64     { return n.Index }
367 func (n *InlineMarkStmt) SetOffset(x int64) { n.Index = x }
368
369 // A LabelStmt is a label statement (just the label, not including the statement it labels).
370 type LabelStmt struct {
371         miniStmt
372         Label *types.Sym // "Label:"
373 }
374
375 func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt {
376         n := &LabelStmt{Label: label}
377         n.pos = pos
378         n.op = OLABEL
379         return n
380 }
381
382 func (n *LabelStmt) Sym() *types.Sym { return n.Label }
383
384 // A RangeStmt is a range loop: for Key, Value = range X { Body }
385 type RangeStmt struct {
386         miniStmt
387         Label        *types.Sym
388         Def          bool
389         X            Node
390         RType        Node `mknode:"-"` // see reflectdata/helpers.go
391         Key          Node
392         Value        Node
393         Body         Nodes
394         DistinctVars bool
395         Prealloc     *Name
396
397         // When desugaring the RangeStmt during walk, the assignments to Key
398         // and Value may require OCONVIFACE operations. If so, these fields
399         // will be copied to their respective ConvExpr fields.
400         KeyTypeWord   Node `mknode:"-"`
401         KeySrcRType   Node `mknode:"-"`
402         ValueTypeWord Node `mknode:"-"`
403         ValueSrcRType Node `mknode:"-"`
404 }
405
406 func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node, distinctVars bool) *RangeStmt {
407         n := &RangeStmt{X: x, Key: key, Value: value}
408         n.pos = pos
409         n.op = ORANGE
410         n.Body = body
411         n.DistinctVars = distinctVars
412         return n
413 }
414
415 // A ReturnStmt is a return statement.
416 type ReturnStmt struct {
417         miniStmt
418         Results Nodes // return list
419 }
420
421 func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
422         n := &ReturnStmt{}
423         n.pos = pos
424         n.op = ORETURN
425         n.Results = results
426         return n
427 }
428
429 // A SelectStmt is a block: { Cases }.
430 type SelectStmt struct {
431         miniStmt
432         Label *types.Sym
433         Cases []*CommClause
434
435         // TODO(rsc): Instead of recording here, replace with a block?
436         Compiled Nodes // compiled form, after walkSelect
437 }
438
439 func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt {
440         n := &SelectStmt{Cases: cases}
441         n.pos = pos
442         n.op = OSELECT
443         return n
444 }
445
446 // A SendStmt is a send statement: X <- Y.
447 type SendStmt struct {
448         miniStmt
449         Chan  Node
450         Value Node
451 }
452
453 func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
454         n := &SendStmt{Chan: ch, Value: value}
455         n.pos = pos
456         n.op = OSEND
457         return n
458 }
459
460 // A SwitchStmt is a switch statement: switch Init; Tag { Cases }.
461 type SwitchStmt struct {
462         miniStmt
463         Tag   Node
464         Cases []*CaseClause
465         Label *types.Sym
466
467         // TODO(rsc): Instead of recording here, replace with a block?
468         Compiled Nodes // compiled form, after walkSwitch
469 }
470
471 func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt {
472         n := &SwitchStmt{Tag: tag, Cases: cases}
473         n.pos = pos
474         n.op = OSWITCH
475         return n
476 }
477
478 // A TailCallStmt is a tail call statement, which is used for back-end
479 // code generation to jump directly to another function entirely.
480 type TailCallStmt struct {
481         miniStmt
482         Call *CallExpr // the underlying call
483 }
484
485 func NewTailCallStmt(pos src.XPos, call *CallExpr) *TailCallStmt {
486         n := &TailCallStmt{Call: call}
487         n.pos = pos
488         n.op = OTAILCALL
489         return n
490 }
491
492 // A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
493 type TypeSwitchGuard struct {
494         miniNode
495         Tag  *Ident
496         X    Node
497         Used bool
498 }
499
500 func NewTypeSwitchGuard(pos src.XPos, tag *Ident, x Node) *TypeSwitchGuard {
501         n := &TypeSwitchGuard{Tag: tag, X: x}
502         n.pos = pos
503         n.op = OTYPESW
504         return n
505 }