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