1
2
3
4
5 package ssa
6
7
8
9 import (
10 "fmt"
11 "go/ast"
12 "go/token"
13 "go/types"
14
15 "golang.org/x/tools/internal/typeparams"
16 )
17
18
19
20
21
22
23
24
25
26
27
28
29 func emitAlloc(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc {
30 v := &Alloc{Comment: comment}
31 v.setType(types.NewPointer(typ))
32 v.setPos(pos)
33 f.emit(v)
34 return v
35 }
36
37
38
39 func emitNew(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc {
40 alloc := emitAlloc(f, typ, pos, comment)
41 alloc.Heap = true
42 return alloc
43 }
44
45
46
47
48
49
50 func emitLocal(f *Function, t types.Type, pos token.Pos, comment string) *Alloc {
51 local := emitAlloc(f, t, pos, comment)
52 f.Locals = append(f.Locals, local)
53 return local
54 }
55
56
57
58
59 func emitLocalVar(f *Function, v *types.Var) *Alloc {
60 alloc := emitLocal(f, f.typ(v.Type()), v.Pos(), v.Name())
61 f.vars[v] = alloc
62 return alloc
63 }
64
65
66
67 func emitLoad(f *Function, addr Value) *UnOp {
68 v := &UnOp{Op: token.MUL, X: addr}
69 v.setType(typeparams.MustDeref(addr.Type()))
70 f.emit(v)
71 return v
72 }
73
74
75
76 func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) {
77 if !f.debugInfo() {
78 return
79 }
80 if v == nil || e == nil {
81 panic("nil")
82 }
83 var obj types.Object
84 e = unparen(e)
85 if id, ok := e.(*ast.Ident); ok {
86 if isBlankIdent(id) {
87 return
88 }
89 obj = f.objectOf(id)
90 switch obj.(type) {
91 case *types.Nil, *types.Const, *types.Builtin:
92 return
93 }
94 }
95 f.emit(&DebugRef{
96 X: v,
97 Expr: e,
98 IsAddr: isAddr,
99 object: obj,
100 })
101 }
102
103
104
105
106
107 func emitArith(f *Function, op token.Token, x, y Value, t types.Type, pos token.Pos) Value {
108 switch op {
109 case token.SHL, token.SHR:
110 x = emitConv(f, x, t)
111
112
113
114
115
116 if isUntyped(y.Type().Underlying()) {
117
118
119
120
121 y = emitConv(f, y, types.Typ[types.Uint])
122 }
123
124 case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
125 x = emitConv(f, x, t)
126 y = emitConv(f, y, t)
127
128 default:
129 panic("illegal op in emitArith: " + op.String())
130
131 }
132 v := &BinOp{
133 Op: op,
134 X: x,
135 Y: y,
136 }
137 v.setPos(pos)
138 v.setType(t)
139 return f.emit(v)
140 }
141
142
143
144 func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value {
145 xt := x.Type().Underlying()
146 yt := y.Type().Underlying()
147
148
149
150
151
152
153
154
155 if x == vTrue && op == token.EQL {
156 if yt, ok := yt.(*types.Basic); ok && yt.Info()&types.IsBoolean != 0 {
157 return y
158 }
159 }
160
161 if types.Identical(xt, yt) {
162
163 } else if isNonTypeParamInterface(x.Type()) {
164 y = emitConv(f, y, x.Type())
165 } else if isNonTypeParamInterface(y.Type()) {
166 x = emitConv(f, x, y.Type())
167 } else if _, ok := x.(*Const); ok {
168 x = emitConv(f, x, y.Type())
169 } else if _, ok := y.(*Const); ok {
170 y = emitConv(f, y, x.Type())
171 } else {
172
173 }
174
175 v := &BinOp{
176 Op: op,
177 X: x,
178 Y: y,
179 }
180 v.setPos(pos)
181 v.setType(tBool)
182 return f.emit(v)
183 }
184
185
186
187
188 func isValuePreserving(ut_src, ut_dst types.Type) bool {
189
190 if types.IdenticalIgnoreTags(ut_dst, ut_src) {
191 return true
192 }
193
194 switch ut_dst.(type) {
195 case *types.Chan:
196
197 _, ok := ut_src.(*types.Chan)
198 return ok
199
200 case *types.Pointer:
201
202 _, ok := ut_src.(*types.Pointer)
203 return ok
204 }
205 return false
206 }
207
208
209
210
211
212 func emitConv(f *Function, val Value, typ types.Type) Value {
213 t_src := val.Type()
214
215
216 if types.Identical(t_src, typ) {
217 return val
218 }
219 ut_dst := typ.Underlying()
220 ut_src := t_src.Underlying()
221
222
223 if isNonTypeParamInterface(typ) {
224
225 if isValuePreserving(ut_src, ut_dst) {
226 c := &ChangeType{X: val}
227 c.setType(typ)
228 return f.emit(c)
229 }
230
231
232 if isNonTypeParamInterface(t_src) {
233 c := &ChangeInterface{X: val}
234 c.setType(typ)
235 return f.emit(c)
236 }
237
238
239 if ut_src == tUntypedNil {
240 return zeroConst(typ)
241 }
242
243
244 if t, ok := ut_src.(*types.Basic); ok && t.Info()&types.IsUntyped != 0 {
245 val = emitConv(f, val, types.Default(ut_src))
246 }
247
248
249
250 t := val.Type()
251 if f.typeparams.Len() == 0 || !f.Prog.isParameterized(t) {
252 addRuntimeType(f.Prog, t)
253 }
254
255 mi := &MakeInterface{X: val}
256 mi.setType(typ)
257 return f.emit(mi)
258 }
259
260
261
262
263
264 dst_terms := typeSetOf(ut_dst)
265 src_terms := typeSetOf(ut_src)
266
267
268
269
270 type conversionCase uint8
271 const (
272 changeType conversionCase = 1 << iota
273 sliceToArray
274 sliceToArrayPtr
275 sliceTo0Array
276 sliceTo0ArrayPtr
277 convert
278 )
279
280
281 classify := func(us, ud types.Type) conversionCase {
282
283 if isValuePreserving(us, ud) {
284 return changeType
285 }
286
287
288 if slice, ok := us.(*types.Slice); ok {
289 var arr *types.Array
290 var ptr bool
291
292 switch d := ud.(type) {
293 case *types.Array:
294 arr = d
295 case *types.Pointer:
296 arr, _ = d.Elem().Underlying().(*types.Array)
297 ptr = true
298 }
299 if arr != nil && types.Identical(slice.Elem(), arr.Elem()) {
300 if arr.Len() == 0 {
301 if ptr {
302 return sliceTo0ArrayPtr
303 } else {
304 return sliceTo0Array
305 }
306 }
307 if ptr {
308 return sliceToArrayPtr
309 } else {
310 return sliceToArray
311 }
312 }
313 }
314
315
316
317 if !isBasic(us) && !isBasic(ud) {
318 panic(fmt.Sprintf("in %s: cannot convert term %s (%s [within %s]) to type %s [within %s]", f, val, val.Type(), us, typ, ud))
319 }
320 return convert
321 }
322
323 var classifications conversionCase
324 for _, s := range src_terms {
325 us := s.Type().Underlying()
326 for _, d := range dst_terms {
327 ud := d.Type().Underlying()
328 classifications |= classify(us, ud)
329 }
330 }
331 if classifications == 0 {
332 panic(fmt.Sprintf("in %s: cannot convert %s (%s) to %s", f, val, val.Type(), typ))
333 }
334
335
336 if c, ok := val.(*Const); ok {
337
338 if isBasic(ut_dst) {
339
340
341
342
343
344 return NewConst(c.Value, typ)
345 }
346
347 const mayPanic = sliceToArray | sliceToArrayPtr
348 if c.Value == nil && classifications&mayPanic == 0 {
349 return NewConst(nil, typ)
350 }
351
352
353
354 }
355
356 switch classifications {
357 case changeType:
358 c := &ChangeType{X: val}
359 c.setType(typ)
360 return f.emit(c)
361
362 case sliceToArrayPtr, sliceTo0ArrayPtr:
363 c := &SliceToArrayPointer{X: val}
364 c.setType(typ)
365 return f.emit(c)
366
367 case sliceToArray:
368 ptype := types.NewPointer(typ)
369 p := &SliceToArrayPointer{X: val}
370 p.setType(ptype)
371 x := f.emit(p)
372 unOp := &UnOp{Op: token.MUL, X: x}
373 unOp.setType(typ)
374 return f.emit(unOp)
375
376 case sliceTo0Array:
377 return zeroConst(typ)
378
379 case convert:
380 c := &Convert{X: val}
381 c.setType(typ)
382 return f.emit(c)
383
384 default:
385 c := &MultiConvert{X: val, from: src_terms, to: dst_terms}
386 c.setType(typ)
387 return f.emit(c)
388 }
389 }
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405 func emitTypeCoercion(f *Function, v Value, typ types.Type) Value {
406 if types.Identical(v.Type(), typ) {
407 return v
408 }
409
410 c := &ChangeType{
411 X: v,
412 }
413 c.setType(typ)
414 f.emit(c)
415 return c
416 }
417
418
419
420 func emitStore(f *Function, addr, val Value, pos token.Pos) *Store {
421 typ := typeparams.MustDeref(addr.Type())
422 s := &Store{
423 Addr: addr,
424 Val: emitConv(f, val, typ),
425 pos: pos,
426 }
427 f.emit(s)
428 return s
429 }
430
431
432
433 func emitJump(f *Function, target *BasicBlock) {
434 b := f.currentBlock
435 b.emit(new(Jump))
436 addEdge(b, target)
437 f.currentBlock = nil
438 }
439
440
441
442
443 func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock) {
444 b := f.currentBlock
445 b.emit(&If{Cond: cond})
446 addEdge(b, tblock)
447 addEdge(b, fblock)
448 f.currentBlock = nil
449 }
450
451
452
453 func emitExtract(f *Function, tuple Value, index int) Value {
454 e := &Extract{Tuple: tuple, Index: index}
455 e.setType(tuple.Type().(*types.Tuple).At(index).Type())
456 return f.emit(e)
457 }
458
459
460
461 func emitTypeAssert(f *Function, x Value, t types.Type, pos token.Pos) Value {
462 a := &TypeAssert{X: x, AssertedType: t}
463 a.setPos(pos)
464 a.setType(t)
465 return f.emit(a)
466 }
467
468
469
470 func emitTypeTest(f *Function, x Value, t types.Type, pos token.Pos) Value {
471 a := &TypeAssert{
472 X: x,
473 AssertedType: t,
474 CommaOk: true,
475 }
476 a.setPos(pos)
477 a.setType(types.NewTuple(
478 newVar("value", t),
479 varOk,
480 ))
481 return f.emit(a)
482 }
483
484
485
486
487
488
489 func emitTailCall(f *Function, call *Call) {
490 tresults := f.Signature.Results()
491 nr := tresults.Len()
492 if nr == 1 {
493 call.typ = tresults.At(0).Type()
494 } else {
495 call.typ = tresults
496 }
497 tuple := f.emit(call)
498 var ret Return
499 switch nr {
500 case 0:
501
502 case 1:
503 ret.Results = []Value{tuple}
504 default:
505 for i := 0; i < nr; i++ {
506 v := emitExtract(f, tuple, i)
507
508
509
510
511 ret.Results = append(ret.Results, v)
512 }
513 }
514 f.emit(&ret)
515 f.currentBlock = nil
516 }
517
518
519
520
521
522
523
524
525 func emitImplicitSelections(f *Function, v Value, indices []int, pos token.Pos) Value {
526 for _, index := range indices {
527 if isPointerCore(v.Type()) {
528 fld := fieldOf(typeparams.MustDeref(v.Type()), index)
529 instr := &FieldAddr{
530 X: v,
531 Field: index,
532 }
533 instr.setPos(pos)
534 instr.setType(types.NewPointer(fld.Type()))
535 v = f.emit(instr)
536
537 if isPointerCore(fld.Type()) {
538 v = emitLoad(f, v)
539 }
540 } else {
541 fld := fieldOf(v.Type(), index)
542 instr := &Field{
543 X: v,
544 Field: index,
545 }
546 instr.setPos(pos)
547 instr.setType(fld.Type())
548 v = f.emit(instr)
549 }
550 }
551 return v
552 }
553
554
555
556
557
558
559
560 func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value {
561 if isPointerCore(v.Type()) {
562 fld := fieldOf(typeparams.MustDeref(v.Type()), index)
563 instr := &FieldAddr{
564 X: v,
565 Field: index,
566 }
567 instr.setPos(id.Pos())
568 instr.setType(types.NewPointer(fld.Type()))
569 v = f.emit(instr)
570
571 if !wantAddr {
572 v = emitLoad(f, v)
573 }
574 } else {
575 fld := fieldOf(v.Type(), index)
576 instr := &Field{
577 X: v,
578 Field: index,
579 }
580 instr.setPos(id.Pos())
581 instr.setType(fld.Type())
582 v = f.emit(instr)
583 }
584 emitDebugRef(f, id, v, wantAddr)
585 return v
586 }
587
588
589
590
591
592
593
594
595
596 func createRecoverBlock(f *Function) {
597 if f.Recover != nil {
598 return
599 }
600 saved := f.currentBlock
601
602 f.Recover = f.newBasicBlock("recover")
603 f.currentBlock = f.Recover
604
605 var results []Value
606 if f.namedResults != nil {
607
608 for _, r := range f.namedResults {
609 results = append(results, emitLoad(f, r))
610 }
611 } else {
612 R := f.Signature.Results()
613 for i, n := 0, R.Len(); i < n; i++ {
614 T := R.At(i).Type()
615
616
617 results = append(results, zeroConst(T))
618 }
619 }
620 f.emit(&Return{Results: results})
621
622 f.currentBlock = saved
623 }
624
View as plain text