ssa_builder.mx raw
1 package main
2
3 func asType(t Type) Type { return t }
4
5 // CreatePackage builds the SSA Package from type-checked syntax files.
6 func (prog *SSAProgram) CreatePackage(pkg *TCPackage, files []*File, info *Info) *SSAPackage {
7 p := &SSAPackage{
8 Prog: prog,
9 Pkg: pkg,
10 Members: map[string]SSAMember{},
11 }
12 prog.packages[pkg] = p
13 prog.imported[pkg.Path()] = p
14
15 pb := &ssaPkgBuilder{pkg: p, info: info, prog: prog}
16
17 for _, f := range files {
18 pb.registerImportsAndTypes(f)
19 }
20 for _, f := range files {
21 pb.registerFile(f)
22 }
23 for _, f := range files {
24 pb.buildFile(f)
25 }
26 return p
27 }
28
29 // ssaPkgBuilder builds one SSAPackage.
30 type ssaPkgBuilder struct {
31 pkg *SSAPackage
32 info *Info
33 prog *SSAProgram
34 }
35
36 func (pb *ssaPkgBuilder) registerImportsAndTypes(f *File) {
37 for _, d := range f.DeclList {
38 switch d := d.(type) {
39 case *ImportDecl:
40 pb.registerImport(d)
41 case *TypeDecl:
42 pb.registerType(d)
43 }
44 }
45 }
46
47 func (pb *ssaPkgBuilder) registerFile(f *File) {
48 for _, d := range f.DeclList {
49 switch d := d.(type) {
50 case *FuncDecl:
51 pb.registerFunc(d)
52 case *VarDecl:
53 pb.registerVar(d)
54 case *ConstDecl:
55 pb.registerConst(d)
56 }
57 }
58 }
59
60 func (pb *ssaPkgBuilder) registerImport(d *ImportDecl) {
61 if d.Path == nil {
62 return
63 }
64 path := d.Path.Value
65 if len(path) >= 2 && path[0] == '"' {
66 path = path[1 : len(path)-1]
67 }
68 localName := ""
69 if d.LocalPkgName != nil {
70 localName = d.LocalPkgName.Value
71 }
72 if localName == "" {
73 for i := len(path) - 1; i >= 0; i-- {
74 if path[i] == '/' {
75 localName = path[i+1:]
76 break
77 }
78 }
79 if localName == "" {
80 localName = path
81 }
82 }
83 if localName == "." || localName == "_" {
84 return
85 }
86 existing := pb.pkg.Pkg.Scope().Lookup(localName)
87 if existing != nil {
88 return
89 }
90 impPkg := pb.prog.ImportedPackage(path)
91 if impPkg != nil && impPkg.Pkg != nil {
92 pn := NewPkgName(nil, localName, impPkg.Pkg)
93 pb.pkg.Pkg.Scope().Insert(pn)
94 } else {
95 ensureImportRegistry()
96 regPkg := importRegistry[path]
97 if regPkg != nil {
98 pn := NewPkgName(nil, localName, regPkg)
99 pb.pkg.Pkg.Scope().Insert(pn)
100 }
101 }
102 }
103
104 func pkgResolveTypeAST(pkg *SSAPackage, e Expr) Type {
105 if e == nil {
106 return nil
107 }
108 switch e := e.(type) {
109 case *Name:
110 if _, obj := Universe.LookupParent(e.Value); obj != nil {
111 if tn, ok := obj.(*TypeName); ok {
112 return tn.Type()
113 }
114 }
115 if pkg != nil {
116 obj := pkg.Pkg.Scope().Lookup(e.Value)
117 if tn, ok := obj.(*TypeName); ok {
118 return tn.Type()
119 }
120 }
121 case *Operation:
122 if e.Y == nil && e.Op == Mul {
123 base := pkgResolveTypeAST(pkg, e.X)
124 if base != nil {
125 return NewPointer(base)
126 }
127 }
128 case *SliceType:
129 elem := pkgResolveTypeAST(pkg, e.Elem)
130 if elem != nil {
131 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
132 return Typ[TCString]
133 }
134 return NewSlice(elem)
135 }
136 case *MapType:
137 key := pkgResolveTypeAST(pkg, e.Key)
138 val := pkgResolveTypeAST(pkg, e.Value)
139 if key != nil && val != nil {
140 return NewTCMap(key, val)
141 }
142 case *FuncType:
143 return pkgResolveSigAST(pkg, e)
144 case *SelectorExpr:
145 if x, ok := e.X.(*Name); ok {
146 var pn *PkgName
147 if okv, okok := pkg.Pkg.Scope().Lookup(x.Value).(*PkgName); okok {
148 pn = okv
149 }
150 if pn != nil && pn.Imported() != nil {
151 sel := pn.Imported().Scope().Lookup(e.Sel.Value)
152 if tn, ok2 := sel.(*TypeName); ok2 {
153 return tn.Type()
154 }
155 }
156 }
157 case *InterfaceType:
158 return NewTCInterface(nil, nil)
159 case *DotsType:
160 elem := pkgResolveTypeAST(pkg, e.Elem)
161 if elem != nil {
162 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
163 return Typ[TCString]
164 }
165 return NewSlice(elem)
166 }
167 }
168 return nil
169 }
170
171 func pkgResolveSigAST(pkg *SSAPackage, ft *FuncType) *Signature {
172 if ft == nil {
173 return nil
174 }
175 var params []*TCVar
176 for _, p := range ft.ParamList {
177 typ := pkgResolveTypeAST(pkg, p.Type)
178 pname := ""
179 if p.Name != nil {
180 pname = p.Name.Value
181 }
182 params = append(params, NewTCVar(nil, pname, typ))
183 }
184 var results []*TCVar
185 for _, r := range ft.ResultList {
186 typ := pkgResolveTypeAST(pkg, r.Type)
187 rname := ""
188 if r.Name != nil {
189 rname = r.Name.Value
190 }
191 results = append(results, NewTCVar(nil, rname, typ))
192 }
193 variadic := false
194 if len(ft.ParamList) > 0 {
195 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
196 variadic = true
197 }
198 }
199 var pTuple, rTuple *Tuple
200 if len(params) > 0 {
201 pTuple = NewTuple(params...)
202 }
203 if len(results) > 0 {
204 rTuple = NewTuple(results...)
205 }
206 return NewSignature(nil, pTuple, rTuple, variadic)
207 }
208
209 func (pb *ssaPkgBuilder) registerFunc(d *FuncDecl) {
210 if len(d.TParamList) > 0 {
211 return
212 }
213 if d.Recv != nil {
214 pb.registerMethod(d)
215 return
216 }
217 if d.Name.Value == "init" {
218 writeStr(2, "compile error: init() is not allowed; use main() for package initialization\n")
219 return
220 }
221 var obj *TCFunc
222 if o := pb.pkg.Pkg.Scope().Lookup(d.Name.Value); o != nil {
223 if okv, okok := o.(*TCFunc); okok {
224 obj = okv
225 }
226 }
227 var sig *Signature
228 if obj != nil {
229 if okv, okok := obj.Type().(*Signature); okok {
230 sig = okv
231 }
232 }
233 if sig == nil && d.Type != nil {
234 sig = pkgResolveSigAST(pb.pkg, d.Type)
235 }
236 fn := &SSAFunction{
237 name: d.Name.Value,
238 object: obj,
239 Signature: sig,
240 pos: 0,
241 Pkg: pb.pkg,
242 Prog: pb.prog,
243 }
244 if compileExportMap != nil {
245 if ename, ok := compileExportMap[d.Name.Value]; ok {
246 fn.externalSymbol = ename
247 fn.isExternC = true
248 }
249 }
250 if d.Body == nil && isNoContextExtern(pb.pkg.Pkg.Path(), d.Name.Value) {
251 fn.isExternC = true
252 }
253 pb.pkg.Members[fn.name] = fn
254 }
255
256 func checkInitBody(body *BlockStmt) string {
257 for _, s := range body.List {
258 if err := checkInitStmt(s); err != "" {
259 return err
260 }
261 }
262 return ""
263 }
264
265 func checkInitStmt(s Stmt) string {
266 switch s := s.(type) {
267 case *SelectStmt:
268 return "select{} not allowed in init()"
269 case *BlockStmt:
270 for _, sub := range s.List {
271 if err := checkInitStmt(sub); err != "" {
272 return err
273 }
274 }
275 case *IfStmt:
276 if s.Then != nil {
277 if err := checkInitStmt(s.Then); err != "" {
278 return err
279 }
280 }
281 if s.Else != nil {
282 if err := checkInitStmt(s.Else); err != "" {
283 return err
284 }
285 }
286 case *ForStmt:
287 if s.Body != nil {
288 if err := checkInitStmt(s.Body); err != "" {
289 return err
290 }
291 }
292 case *SwitchStmt:
293 for _, cc := range s.Body {
294 for _, sub := range cc.Body {
295 if err := checkInitStmt(sub); err != "" {
296 return err
297 }
298 }
299 }
300 case *ExprStmt:
301 if err := checkInitExpr(s.X); err != "" {
302 return err
303 }
304 }
305 return ""
306 }
307
308 func checkInitExpr(x Expr) string {
309 if x == nil {
310 return ""
311 }
312 if c, ok := x.(*CallExpr); ok {
313 if n, ok2 := c.Fun.(*Name); ok2 && n.Value == "spawn" {
314 return "spawn() not allowed in init()"
315 }
316 }
317 return ""
318 }
319
320 func isNoContextExtern(pkg, name string) bool {
321 if pkg == "internal/runtime/syscall" && name == "Syscall6" {
322 return true
323 }
324 if pkg == "syscall" {
325 switch name {
326 case "runtime_entersyscall", "runtime_exitsyscall",
327 "Exit", "Getpagesize", "gettimeofday",
328 "runtime_BeforeExec", "runtime_AfterExec",
329 "runtime_BeforeFork", "runtime_AfterFork", "runtime_AfterForkInChild":
330 return true
331 }
332 }
333 if pkg == "os" {
334 switch name {
335 case "putchar", "getchar", "buffered", "gosched", "runtime_args":
336 return true
337 }
338 }
339 return false
340 }
341
342 func (pb *ssaPkgBuilder) registerMethod(d *FuncDecl) {
343 recvTypeName := ssaRecvTypeName(d.Recv)
344 if recvTypeName == "" {
345 return
346 }
347 mangledName := recvTypeName | "." | d.Name.Value
348 var obj *TCFunc
349 obj = pb.findMethod(recvTypeName, d.Name.Value)
350 var sig *Signature
351 if obj != nil {
352 if okv, okok := obj.Type().(*Signature); okok {
353 sig = okv
354 }
355 }
356 if sig == nil && d.Type != nil {
357 sig = pkgResolveSigAST(pb.pkg, d.Type)
358 }
359 fn := &SSAFunction{
360 name: mangledName,
361 object: obj,
362 Signature: sig,
363 pos: 0,
364 Pkg: pb.pkg,
365 Prog: pb.prog,
366 }
367 pb.pkg.Members[mangledName] = fn
368 }
369
370 func ssaRecvTypeName(recv *Field) string {
371 if recv == nil {
372 return ""
373 }
374 switch t := recv.Type.(type) {
375 case *Name:
376 return t.Value
377 case *Operation:
378 if t.Y == nil && t.Op == Mul {
379 if n, ok := t.X.(*Name); ok {
380 return n.Value
381 }
382 }
383 }
384 return ""
385 }
386
387 func (pb *ssaPkgBuilder) findMethod(typeName string, methodName string) *TCFunc {
388 obj := pb.pkg.Pkg.Scope().Lookup(typeName)
389 if obj == nil {
390 return nil
391 }
392 tn, ok := obj.(*TypeName)
393 if !ok {
394 return nil
395 }
396 named, ok := tn.Type().(*Named)
397 if !ok {
398 return nil
399 }
400 for i := 0; i < named.NumMethods(); i++ {
401 m := named.Method(i)
402 if m.Name() == methodName {
403 return m
404 }
405 }
406 return nil
407 }
408
409 func (pb *ssaPkgBuilder) registerVar(d *VarDecl) {
410 if d.Values != nil {
411 for _, name := range d.NameList {
412 writeStr(2, "compile error: package-level var " | name.Value | " has initializer; assign in main() instead\n")
413 }
414 return
415 }
416 for _, name := range d.NameList {
417 var obj *TCVar
418 if o := pb.pkg.Pkg.Scope().Lookup(name.Value); o != nil {
419 if okv, okok := o.(*TCVar); okok {
420 obj = okv
421 }
422 }
423 var typ Type
424 if obj != nil {
425 typ = obj.Type()
426 }
427 if typ == nil && d.Type != nil {
428 typ = pkgResolveTypeAST(pb.pkg, d.Type)
429 }
430 g := &SSAGlobal{
431 name: name.Value,
432 object: obj,
433 typ: NewPointer(typ),
434 pos: 0,
435 pkg: pb.pkg,
436 }
437 pb.pkg.Members[name.Value] = g
438 }
439 }
440
441 func (pb *ssaPkgBuilder) registerType(d *TypeDecl) {
442 var obj *TypeName
443 if o := pb.pkg.Pkg.Scope().Lookup(d.Name.Value); o != nil {
444 if okv, okok := o.(*TypeName); okok {
445 obj = okv
446 }
447 }
448 if obj == nil {
449 underlying := pkgResolveTypeAST(pb.pkg, d.Type)
450 if underlying == nil {
451 underlying = &TCStruct{}
452 }
453 named := NewNamed(NewTypeName(pb.pkg.Pkg, d.Name.Value, nil), underlying)
454 named.obj.typ = named
455 pb.pkg.Pkg.Scope().Insert(named.obj)
456 obj = named.obj
457 }
458 t := &SSAType_{object: obj, pkg: pb.pkg}
459 pb.pkg.Members[d.Name.Value] = t
460 }
461
462 func (pb *ssaPkgBuilder) registerConst(d *ConstDecl) {
463 for _, name := range d.NameList {
464 var obj *TCConst
465 if o := pb.pkg.Pkg.Scope().Lookup(name.Value); o != nil {
466 if okv, okok := o.(*TCConst); okok {
467 obj = okv
468 }
469 }
470 if obj == nil {
471 continue
472 }
473 c := &SSANamedConst{
474 object: obj,
475 Value: &SSAConst{typ: obj.Type(), val: localizeConstVal(obj.Val(), obj.Type())},
476 pkg: pb.pkg,
477 }
478 pb.pkg.Members[name.Value] = c
479 }
480 }
481
482 func (pb *ssaPkgBuilder) buildFile(f *File) {
483 for _, d := range f.DeclList {
484 if fd, ok := d.(*FuncDecl); ok {
485 pb.buildFunc(fd)
486 }
487 }
488 }
489
490 func (pb *ssaPkgBuilder) buildFunc(d *FuncDecl) {
491 if len(d.TParamList) > 0 {
492 return
493 }
494 if d.Body == nil {
495 return
496 }
497 name := d.Name.Value
498 if d.Recv != nil {
499 rtn := ssaRecvTypeName(d.Recv)
500 if rtn != "" {
501 name = rtn | "." | d.Name.Value
502 }
503 }
504 var fn *SSAFunction
505 if okv, okok := pb.pkg.Members[name].(*SSAFunction); okok {
506 fn = okv
507 }
508 if fn == nil {
509 return
510 }
511 fb := newSSAFuncBuilder(fn, pb.info)
512 fb.buildBody(d)
513 }
514
515 // ssaFuncBuilder builds one SSAFunction body.
516 type ssaFuncBuilder struct {
517 fn *SSAFunction
518 info *Info
519 parent *ssaFuncBuilder
520 currentBlock *SSABasicBlock
521 vars map[Object]*SSAAlloc
522 localTypes map[string]Type
523 localConsts map[string]*SSAConst
524 freeVarPtrs map[string]*SSAFreeVar
525 namedResults []*SSAAlloc
526 paramAllocas []*SSAAlloc
527 tailBlock *SSABasicBlock
528 counter int32
529
530 loops []ssaLoopState
531 pendingLabel string
532 labels map[string]*SSABasicBlock
533 deferred int32
534 typeSubst map[string]Type
535 srcScope *Scope
536 }
537
538 type ssaLoopState struct {
539 label string
540 body *SSABasicBlock
541 post *SSABasicBlock
542 done *SSABasicBlock
543 }
544
545 func newSSAFuncBuilder(fn *SSAFunction, info *Info) *ssaFuncBuilder {
546 return &ssaFuncBuilder{
547 fn: fn,
548 info: info,
549 vars: map[Object]*SSAAlloc{},
550 localTypes: map[string]Type{},
551 }
552 }
553
554 func (fb *ssaFuncBuilder) newBlock(comment string) *SSABasicBlock {
555 return NewSSABasicBlock(fb.fn, comment)
556 }
557
558 func (fb *ssaFuncBuilder) labelBlock(name string) *SSABasicBlock {
559 if fb.labels == nil {
560 fb.labels = map[string]*SSABasicBlock{}
561 }
562 if b := fb.labels[name]; b != nil {
563 return b
564 }
565 b := fb.newBlock("label." + name)
566 fb.labels[name] = b
567 return b
568 }
569
570 func (fb *ssaFuncBuilder) emit(instr SSAInstruction) {
571 if fb.currentBlock == nil {
572 return
573 }
574 instr.setBlock(fb.currentBlock)
575 fb.currentBlock.Instrs = append(fb.currentBlock.Instrs, instr)
576 }
577
578 func (fb *ssaFuncBuilder) nextName() string {
579 fb.counter++
580 return "t" | ssaItoa(fb.counter)
581 }
582
583 func (fb *ssaFuncBuilder) buildBody(d *FuncDecl) {
584 entry := fb.newBlock("entry")
585 fb.currentBlock = entry
586
587 sig := fb.fn.Signature
588 if sig == nil {
589 return
590 }
591 params := sig.Params()
592 if d.Recv != nil {
593 recv := sig.Recv()
594 if recv != nil {
595 recvName := recv.Name()
596 if recvName == "" && d.Recv.Name != nil {
597 recvName = d.Recv.Name.Value
598 }
599 p := &SSAParameter{
600 name: recvName,
601 typ: recv.Type(),
602 pos: 0,
603 parent: fb.fn,
604 }
605 fb.fn.Params = append(fb.fn.Params, p)
606 if recvName != "" && recvName != "_" {
607 recvObj := NewTCVar(fb.fn.Pkg.Pkg, recvName, recv.Type())
608 p.object = recvObj
609 alloc := fb.emitAlloc(recv.Type(), 0)
610 fb.vars[recvObj] = alloc
611 fb.paramAllocas = append(fb.paramAllocas, alloc)
612 fb.emitStore(alloc, p)
613 }
614 }
615 }
616 if params != nil {
617 for i := 0; i < params.Len(); i++ {
618 pvar := params.At(i)
619 p := &SSAParameter{
620 name: pvar.Name(),
621 typ: pvar.Type(),
622 pos: fb.fn.pos,
623 parent: fb.fn,
624 }
625 fb.fn.Params = append(fb.fn.Params, p)
626 if pvar.Name() != "" && pvar.Name() != "_" {
627 obj := NewTCVar(fb.fn.Pkg.Pkg, pvar.Name(), pvar.Type())
628 alloc := fb.emitAlloc(pvar.Type(), p.pos)
629 fb.vars[obj] = alloc
630 fb.paramAllocas = append(fb.paramAllocas, alloc)
631 fb.emitStore(alloc, p)
632 }
633 }
634 }
635
636 if sig.Results() != nil {
637 for i := 0; i < sig.Results().Len(); i++ {
638 r := sig.Results().At(i)
639 if r.Name() != "" && r.Name() != "_" {
640 alloc := fb.emitAlloc(r.Type(), fb.fn.pos)
641 fb.namedResults = append(fb.namedResults, alloc)
642 fb.fn.Locals = append(fb.fn.Locals, alloc)
643 fb.vars[r] = alloc
644 }
645 }
646 }
647
648 if len(fb.paramAllocas) > 0 {
649 fb.tailBlock = fb.newBlock("tailcall")
650 fb.emit(&SSAJump{Comment: "enter.body"})
651 fb.currentBlock.Succs = append(fb.currentBlock.Succs, fb.tailBlock)
652 fb.tailBlock.Preds = append(fb.tailBlock.Preds, fb.currentBlock)
653 fb.currentBlock = fb.tailBlock
654 }
655
656 if d.Body != nil {
657 fb.buildBlock(d.Body)
658 }
659
660 if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
661 if len(fb.namedResults) > 0 {
662 var vals []SSAValue
663 for _, nr := range fb.namedResults {
664 elemType := nr.SSAType()
665 if p, ok := elemType.(*Pointer); ok {
666 elemType = p.Elem()
667 }
668 vals = append(vals, fb.emitLoad(nr, elemType))
669 }
670 fb.emitReturn(vals, 0)
671 } else {
672 fb.emitReturn(nil, 0)
673 }
674 }
675 fb.fn.NamedResults = fb.namedResults
676 }
677
678 func (fb *ssaFuncBuilder) emitAlloc(typ Type, pos int32) *SSAAlloc {
679 a := &SSAAlloc{Heap: false}
680 a.typ = NewPointer(typ)
681 a.pos = pos
682 a.name = fb.nextName()
683 fb.emit(a)
684 fb.fn.Locals = append(fb.fn.Locals, a)
685 return a
686 }
687
688 func (fb *ssaFuncBuilder) emitStore(addr SSAValue, val SSAValue) {
689 fb.emit(&SSAStore{Addr: addr, Val: val})
690 }
691
692 func (fb *ssaFuncBuilder) emitLoad(addr SSAValue, typ Type) SSAValue {
693 u := &SSAUnOp{Op: OpMul, X: addr}
694 u.typ = typ
695 u.name = fb.nextName()
696 fb.emit(u)
697 return u
698 }
699
700 func (fb *ssaFuncBuilder) emitReturn(vals []SSAValue, pos int32) {
701 fb.emit(&SSAReturn{Results: vals, pos: pos})
702 fb.currentBlock = nil
703 }
704
705 func (fb *ssaFuncBuilder) blockTerminated(b *SSABasicBlock) bool {
706 if len(b.Instrs) == 0 {
707 return false
708 }
709 switch b.Instrs[len(b.Instrs)-1].(type) {
710 case *SSAReturn, *SSAJump, *SSAIf, *SSAPanic:
711 return true
712 }
713 return false
714 }
715
716 // Statement builders.
717
718 func (fb *ssaFuncBuilder) buildBlock(b *BlockStmt) {
719 if b == nil {
720 return
721 }
722 for _, s := range b.List {
723 fb.buildStmt(s)
724 }
725 }
726
727 func (fb *ssaFuncBuilder) buildStmt(s Stmt) {
728 if s == nil {
729 return
730 }
731 if ls, ok := s.(*LabeledStmt); ok {
732 if ls.Label != nil {
733 fb.pendingLabel = ls.Label.Value
734 lblBlock := fb.labelBlock(ls.Label.Value)
735 if fb.currentBlock != nil {
736 fb.emit(&SSAJump{Comment: "goto.label." + ls.Label.Value})
737 fb.currentBlock.Succs = append(fb.currentBlock.Succs, lblBlock)
738 lblBlock.Preds = append(lblBlock.Preds, fb.currentBlock)
739 }
740 fb.currentBlock = lblBlock
741 }
742 fb.buildStmt(ls.Stmt)
743 fb.pendingLabel = ""
744 return
745 }
746 if fb.currentBlock == nil {
747 return
748 }
749 switch s := s.(type) {
750 case *EmptyStmt:
751 // nothing
752 case *ExprStmt:
753 fb.buildExpr(s.X)
754 case *AssignStmt:
755 fb.buildAssign(s)
756 case *BlockStmt:
757 fb.buildBlock(s)
758 case *DeclStmt:
759 for _, d := range s.DeclList {
760 fb.buildLocalDecl(d)
761 }
762 case *IfStmt:
763 fb.buildIf(s)
764 case *ForStmt:
765 fb.buildFor(s)
766 case *SwitchStmt:
767 fb.buildSwitch(s)
768 case *SelectStmt:
769 fb.buildSelect(s)
770 case *ReturnStmt:
771 fb.buildReturn(s)
772 case *BranchStmt:
773 fb.buildBranch(s)
774 case *SendStmt:
775 ch := fb.buildExpr(s.Chan)
776 val := fb.buildExpr(s.Value)
777 if ch != nil && val != nil {
778 fb.emit(&SSASend{Chan: ch, X: val})
779 }
780 case *CallStmt:
781 var call *CallExpr
782 if okv, okok := s.Call.(*CallExpr); okok {
783 call = okv
784 }
785 switch s.Tok {
786 case Go:
787 if call != nil {
788 fb.buildGoStmt(call)
789 }
790 case Defer:
791 if call != nil {
792 fb.buildDeferStmt(call)
793 }
794 default:
795 fb.buildExpr(s.Call)
796 }
797 }
798 }
799
800 func (fb *ssaFuncBuilder) buildAssign(s *AssignStmt) {
801 if s.Rhs == nil {
802 lv := fb.buildExpr(s.Lhs)
803 if lv == nil {
804 return
805 }
806 one := &SSAConst{typ: lv.SSAType(), val: constInt{1}}
807 op := OpAdd
808 if s.Op == Sub {
809 op = OpSub
810 }
811 bin := &SSABinOp{Op: op, X: lv, Y: one}
812 bin.typ = lv.SSAType()
813 bin.name = fb.nextName()
814 fb.emit(bin)
815 fb.buildStore(s.Lhs, bin)
816 return
817 }
818 if s.Op == Def {
819 fb.buildShortVarDecl(s)
820 return
821 }
822 if s.Op != 0 {
823 lv := fb.buildExpr(s.Lhs)
824 rv := fb.buildExpr(s.Rhs)
825 if lv == nil || rv == nil {
826 return
827 }
828 op := compoundOp(s.Op)
829 bin := &SSABinOp{Op: op, X: lv, Y: rv}
830 bin.typ = lv.SSAType()
831 bin.name = fb.nextName()
832 fb.emit(bin)
833 fb.buildStore(s.Lhs, bin)
834 return
835 }
836 lhsList, lhsIsList := s.Lhs.(*ListExpr)
837 rhsList, rhsIsList := s.Rhs.(*ListExpr)
838 if lhsIsList && rhsIsList && len(lhsList.ElemList) == len(rhsList.ElemList) {
839 vals := []SSAValue{:len(rhsList.ElemList)}
840 for i, re := range rhsList.ElemList {
841 vals[i] = fb.buildExpr(re)
842 }
843 for i, le := range lhsList.ElemList {
844 if vals[i] != nil {
845 fb.buildStore(le, vals[i])
846 }
847 }
848 return
849 }
850 if lhsIsList && len(lhsList.ElemList) == 2 {
851 if ae, ok := s.Rhs.(*AssertExpr); ok {
852 x := fb.buildExpr(ae.X)
853 assertedType := fb.resolveType(ae.Type)
854 if x != nil && assertedType != nil {
855 ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
856 ta.typ = NewTuple(
857 NewTCVar(nil, "val", assertedType),
858 NewTCVar(nil, "ok", Typ[Bool]),
859 )
860 ta.name = fb.nextName()
861 fb.emit(ta)
862 for i, le := range lhsList.ElemList {
863 if n, ok := le.(*Name); ok && n.Value == "_" {
864 continue
865 }
866 ext := &SSAExtract{Tuple: ta, Index: i}
867 ext.typ = ssaTupleElemType(ta.typ, i)
868 ext.name = fb.nextName()
869 fb.emit(ext)
870 fb.buildStore(le, ext)
871 }
872 return
873 }
874 }
875 if ie, ok := s.Rhs.(*IndexExpr); ok {
876 x := fb.buildExpr(ie.X)
877 idx := fb.buildExpr(ie.Index)
878 if x != nil && idx != nil {
879 if mt, ok2 := safeUnderlying(x.SSAType()).(*TCMap); ok2 {
880 idx = fb.coerceToInterface(idx, mt.Key())
881 l := &SSALookup{X: x, Index: idx, CommaOk: true}
882 l.typ = NewTuple(
883 NewTCVar(nil, "v", mt.Elem()),
884 NewTCVar(nil, "ok", Typ[Bool]),
885 )
886 l.name = fb.nextName()
887 fb.emit(l)
888 for i, le := range lhsList.ElemList {
889 if n, ok := le.(*Name); ok && n.Value == "_" {
890 continue
891 }
892 ext := &SSAExtract{Tuple: l, Index: i}
893 ext.typ = ssaTupleElemType(l.typ, i)
894 ext.name = fb.nextName()
895 fb.emit(ext)
896 fb.buildStore(le, ext)
897 }
898 return
899 }
900 }
901 }
902 }
903 rhs := fb.buildExpr(s.Rhs)
904 if rhs == nil {
905 return
906 }
907 fb.buildStore(s.Lhs, rhs)
908 }
909
910 func (fb *ssaFuncBuilder) coerceToInterface(val SSAValue, targetType Type) SSAValue {
911 if targetType == nil || val == nil || val.SSAType() == nil {
912 return val
913 }
914 if _, isIface := safeUnderlying(targetType).(*TCInterface); isIface {
915 if _, alreadyIface := safeUnderlying(val.SSAType()).(*TCInterface); !alreadyIface {
916 mi := &SSAMakeInterface{X: val}
917 mi.typ = targetType
918 mi.name = fb.nextName()
919 fb.emit(mi)
920 return mi
921 }
922 }
923 return val
924 }
925
926 func (fb *ssaFuncBuilder) buildStore(lhs Expr, val SSAValue) {
927 if lhs == nil {
928 panic("buildStore: nil lhs")
929 }
930 switch lhs := lhs.(type) {
931 case *Name:
932 if lhs == nil {
933 panic("buildStore: nil *Name after type switch")
934 }
935 if lhs.Value == "_" {
936 return
937 }
938 obj := fb.lookupObject(lhs.Value)
939 if obj == nil {
940 return
941 }
942 if alloc, ok := fb.vars[obj]; ok {
943 val = fb.coerceToInterface(val, obj.Type())
944 fb.emitStore(alloc, val)
945 } else if fv, ok := fb.freeVarPtrs[lhs.Value]; ok {
946 val = fb.coerceToInterface(val, obj.Type())
947 fb.emitStore(fv, val)
948 } else if g, ok := fb.fn.Pkg.Members[lhs.Value].(*SSAGlobal); ok {
949 if p, ok2 := g.SSAType().(*Pointer); ok2 && p.Elem() != nil {
950 val = fb.coerceToInterface(val, p.Elem())
951 }
952 fb.emitStore(g, val)
953 }
954 case *Operation:
955 if lhs.Y == nil && lhs.Op == Mul {
956 ptr := fb.buildExpr(lhs.X)
957 if ptr != nil {
958 if p, ok2 := ptr.SSAType().(*Pointer); ok2 && p.Elem() != nil {
959 val = fb.coerceToInterface(val, p.Elem())
960 }
961 fb.emitStore(ptr, val)
962 }
963 }
964 case *SelectorExpr:
965 addr := fb.buildSelectorAddr(lhs)
966 if addr == nil {
967 return
968 }
969 if p, ok2 := addr.SSAType().(*Pointer); ok2 && p.Elem() != nil {
970 val = fb.coerceToInterface(val, p.Elem())
971 }
972 fb.emitStore(addr, val)
973 case *IndexExpr:
974 base := fb.buildExpr(lhs.X)
975 idx := fb.buildExpr(lhs.Index)
976 if base == nil || idx == nil {
977 return
978 }
979 if m, isMap := safeUnderlying(base.SSAType()).(*TCMap); isMap {
980 idx = fb.coerceToInterface(idx, m.Key())
981 val = fb.coerceToInterface(val, m.Elem())
982 fb.emit(&SSAMapUpdate{Map: base, Key: idx, Value: val})
983 return
984 }
985 // For array LHS assignment, resolve the address of the base directly
986 // so SSAIndexAddr GEPs into the original, not a stack copy.
987 var baseAddr SSAValue
988 if n, ok := lhs.X.(*Name); ok {
989 obj := fb.lookupObject(n.Value)
990 if obj != nil {
991 if alloc, ok2 := fb.vars[obj]; ok2 {
992 baseAddr = alloc
993 } else if g, ok2 := fb.fn.Pkg.Members[n.Value].(*SSAGlobal); ok2 {
994 baseAddr = g
995 }
996 }
997 } else if sel, ok := lhs.X.(*SelectorExpr); ok {
998 baseAddr = fb.buildSelectorAddr(sel)
999 }
1000 if baseAddr != nil {
1001 if _, isArr := safeUnderlying(base.SSAType()).(*Array); isArr {
1002 ia := &SSAIndexAddr{X: baseAddr, Index: idx}
1003 ia.typ = NewPointer(ssaElemType(base.SSAType()))
1004 ia.name = fb.nextName()
1005 fb.emit(ia)
1006 if p, ok2 := ia.SSAType().(*Pointer); ok2 && p.Elem() != nil {
1007 val = fb.coerceToInterface(val, p.Elem())
1008 }
1009 fb.emitStore(ia, val)
1010 return
1011 }
1012 }
1013 ia := &SSAIndexAddr{X: base, Index: idx}
1014 ia.typ = NewPointer(ssaElemType(base.SSAType()))
1015 ia.name = fb.nextName()
1016 fb.emit(ia)
1017 if p, ok2 := ia.SSAType().(*Pointer); ok2 && p.Elem() != nil {
1018 val = fb.coerceToInterface(val, p.Elem())
1019 }
1020 fb.emitStore(ia, val)
1021 case *ListExpr:
1022 for i, e := range lhs.ElemList {
1023 ext := &SSAExtract{Tuple: val, Index: i}
1024 ext.typ = ssaTupleElemType(val.SSAType(), i)
1025 ext.name = fb.nextName()
1026 fb.emit(ext)
1027 fb.buildStore(e, ext)
1028 }
1029 }
1030 }
1031
1032 func (fb *ssaFuncBuilder) buildShortVarDecl(s *AssignStmt) {
1033 names := ssaExprNames(s.Lhs)
1034 if len(names) == 2 {
1035 if ae, ok := s.Rhs.(*AssertExpr); ok {
1036 x := fb.buildExpr(ae.X)
1037 assertedType := fb.resolveType(ae.Type)
1038 if x != nil && assertedType != nil {
1039 ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
1040 ta.typ = NewTuple(
1041 NewTCVar(nil, "val", assertedType),
1042 NewTCVar(nil, "ok", Typ[Bool]),
1043 )
1044 ta.name = fb.nextName()
1045 fb.emit(ta)
1046 for i, name := range names {
1047 if name.Value == "_" {
1048 continue
1049 }
1050 ext := &SSAExtract{Tuple: ta, Index: i}
1051 ext.typ = ssaTupleElemType(ta.typ, i)
1052 ext.name = fb.nextName()
1053 fb.emit(ext)
1054 fb.removeVar(name.Value)
1055 obj := NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1056 alloc := fb.emitAlloc(ext.typ, 0)
1057 fb.vars[obj] = alloc
1058 fb.emitStore(alloc, ext)
1059 }
1060 return
1061 }
1062 }
1063 if ie, ok := s.Rhs.(*IndexExpr); ok {
1064 x := fb.buildExpr(ie.X)
1065 idx := fb.buildExpr(ie.Index)
1066 if x != nil && idx != nil {
1067 if mt, ok2 := safeUnderlying(x.SSAType()).(*TCMap); ok2 {
1068 idx = fb.coerceToInterface(idx, mt.Key())
1069 l := &SSALookup{X: x, Index: idx, CommaOk: true}
1070 l.typ = NewTuple(
1071 NewTCVar(nil, "v", mt.Elem()),
1072 NewTCVar(nil, "ok", Typ[Bool]),
1073 )
1074 l.name = fb.nextName()
1075 fb.emit(l)
1076 for i, name := range names {
1077 if name.Value == "_" {
1078 continue
1079 }
1080 ext := &SSAExtract{Tuple: l, Index: i}
1081 ext.typ = ssaTupleElemType(l.typ, i)
1082 ext.name = fb.nextName()
1083 fb.emit(ext)
1084 fb.removeVar(name.Value)
1085 var obj Object
1086 if fb.info != nil {
1087 obj = fb.info.Defs[name]
1088 }
1089 if obj == nil {
1090 obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1091 }
1092 alloc := fb.emitAlloc(ext.typ, 0)
1093 fb.vars[obj] = alloc
1094 fb.emitStore(alloc, ext)
1095 }
1096 return
1097 }
1098 }
1099 }
1100 }
1101 if rhsList, ok := s.Rhs.(*ListExpr); ok && len(rhsList.ElemList) == len(names) {
1102 vals := []SSAValue{:len(rhsList.ElemList)}
1103 for i, re := range rhsList.ElemList {
1104 vals[i] = fb.buildExpr(re)
1105 }
1106 for i, name := range names {
1107 if name.Value == "_" {
1108 continue
1109 }
1110 var typ Type
1111 if vals[i] != nil {
1112 typ = vals[i].SSAType()
1113 }
1114 fb.removeVar(name.Value)
1115 var obj Object
1116 if fb.info != nil {
1117 obj = fb.info.Defs[name]
1118 }
1119 if obj == nil {
1120 obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1121 }
1122 alloc := fb.emitAlloc(typ, 0)
1123 fb.vars[obj] = alloc
1124 if vals[i] != nil {
1125 fb.emitStore(alloc, vals[i])
1126 }
1127 }
1128 return
1129 }
1130
1131 rhs := fb.buildExpr(s.Rhs)
1132
1133 isTuple := false
1134 var tup *Tuple
1135 if rhs != nil {
1136 tup, isTuple = rhs.SSAType().(*Tuple)
1137 }
1138 for i, name := range names {
1139 if name.Value == "_" {
1140 continue
1141 }
1142 var typ Type
1143 if rhs != nil {
1144 if isTuple && i < tup.Len() {
1145 typ = tup.At(i).Type()
1146 } else if i == 0 {
1147 typ = rhs.SSAType()
1148 }
1149 }
1150 if typ == nil {
1151 typ = Typ[Int32]
1152 }
1153 fb.removeVar(name.Value)
1154 var obj Object
1155 if fb.info != nil {
1156 obj = fb.info.Defs[name]
1157 }
1158 if obj == nil {
1159 obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1160 }
1161 alloc := fb.emitAlloc(typ, 0)
1162 fb.vars[obj] = alloc
1163 var initVal SSAValue
1164 if rhs != nil {
1165 if isTuple {
1166 ext := &SSAExtract{Tuple: rhs, Index: i}
1167 ext.typ = typ
1168 ext.name = fb.nextName()
1169 fb.emit(ext)
1170 initVal = ext
1171 } else if i == 0 {
1172 initVal = rhs
1173 }
1174 }
1175 if initVal != nil {
1176 fb.emitStore(alloc, initVal)
1177 }
1178 }
1179 }
1180
1181 func (fb *ssaFuncBuilder) buildLocalDecl(d Decl) {
1182 switch d := d.(type) {
1183 case *VarDecl:
1184 var typ Type
1185 if fb.info != nil && len(d.NameList) > 0 {
1186 if obj := fb.info.Defs[d.NameList[0]]; obj != nil {
1187 typ = obj.Type()
1188 }
1189 }
1190 if typ == nil && d.Type != nil {
1191 typ = fb.resolveType(d.Type)
1192 }
1193 initVal := fb.buildExpr(d.Values)
1194 for _, name := range d.NameList {
1195 if name.Value == "_" {
1196 continue
1197 }
1198 fb.removeVar(name.Value)
1199 var obj Object
1200 if fb.info != nil {
1201 obj = fb.info.Defs[name]
1202 }
1203 if obj == nil {
1204 obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1205 }
1206 alloc := fb.emitAlloc(obj.Type(), 0)
1207 fb.vars[obj] = alloc
1208 fb.fn.Locals = append(fb.fn.Locals, alloc)
1209 if initVal != nil {
1210 initVal = fb.coerceToInterface(initVal, obj.Type())
1211 fb.emitStore(alloc, initVal)
1212 } else {
1213 fb.emitStore(alloc, &SSAConst{typ: obj.Type(), val: nil})
1214 }
1215 }
1216 case *ConstDecl:
1217 if d.Values != nil && len(d.NameList) > 0 {
1218 if fb.localConsts == nil {
1219 fb.localConsts = map[string]*SSAConst{}
1220 }
1221 if list, ok := d.Values.(*ListExpr); ok {
1222 for i, name := range d.NameList {
1223 if i < len(list.ElemList) {
1224 if v := fb.buildExpr(list.ElemList[i]); v != nil {
1225 if c := ssaExtractConst(v); c != nil {
1226 fb.localConsts[name.Value] = c
1227 }
1228 }
1229 }
1230 }
1231 } else if len(d.NameList) == 1 {
1232 if v := fb.buildExpr(d.Values); v != nil {
1233 if c := ssaExtractConst(v); c != nil {
1234 fb.localConsts[d.NameList[0].Value] = c
1235 }
1236 }
1237 }
1238 }
1239 case *TypeDecl:
1240 if d.Name != nil {
1241 resolved := fb.resolveTypeAST(d.Type)
1242 if resolved != nil {
1243 fb.localTypes[d.Name.Value] = resolved
1244 }
1245 }
1246 }
1247 }
1248
1249 func (fb *ssaFuncBuilder) buildIf(s *IfStmt) {
1250 var savedVars map[Object]*SSAAlloc
1251 if s.Init != nil {
1252 savedVars = fb.saveVars()
1253 fb.buildStmt(s.Init)
1254 }
1255 if fb.currentBlock == nil {
1256 if savedVars != nil {
1257 fb.vars = savedVars
1258 }
1259 return
1260 }
1261 cond := fb.buildExpr(s.Cond)
1262 if cond == nil {
1263 if savedVars != nil {
1264 fb.vars = savedVars
1265 }
1266 return
1267 }
1268
1269 thenBlock := fb.newBlock("if.then")
1270 var elseBlock *SSABasicBlock
1271 doneBlock := fb.newBlock("if.done")
1272
1273 if s.Else != nil {
1274 elseBlock = fb.newBlock("if.else")
1275 } else {
1276 elseBlock = doneBlock
1277 }
1278
1279 fb.emit(&SSAIf{Cond: cond})
1280 fb.currentBlock.Succs = append(fb.currentBlock.Succs, thenBlock, elseBlock)
1281 thenBlock.Preds = append(thenBlock.Preds, fb.currentBlock)
1282 elseBlock.Preds = append(elseBlock.Preds, fb.currentBlock)
1283
1284 fb.currentBlock = thenBlock
1285 fb.buildBlock(s.Then)
1286 if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1287 fb.emit(&SSAJump{Comment: "if.done"})
1288 fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1289 doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1290 }
1291
1292 if s.Else != nil {
1293 fb.currentBlock = elseBlock
1294 fb.buildStmt(s.Else)
1295 if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1296 fb.emit(&SSAJump{Comment: "if.done"})
1297 fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1298 doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1299 }
1300 }
1301
1302 fb.currentBlock = doneBlock
1303 if savedVars != nil {
1304 fb.vars = savedVars
1305 }
1306 }
1307
1308 func (fb *ssaFuncBuilder) buildFor(s *ForStmt) {
1309 var savedVars map[Object]*SSAAlloc
1310 if s.Init != nil {
1311 if rc, ok := s.Init.(*RangeClause); ok {
1312 fb.buildRangeLoop(s, rc)
1313 return
1314 }
1315 savedVars = fb.saveVars()
1316 fb.buildStmt(s.Init)
1317 }
1318
1319 condBlock := fb.newBlock("for.cond")
1320 bodyBlock := fb.newBlock("for.body")
1321 postBlock := fb.newBlock("for.post")
1322 doneBlock := fb.newBlock("for.done")
1323
1324 fb.emit(&SSAJump{Comment: "for.cond"})
1325 fb.currentBlock.Succs = append(fb.currentBlock.Succs, condBlock)
1326 condBlock.Preds = append(condBlock.Preds, fb.currentBlock)
1327
1328 fb.loops = append(fb.loops, ssaLoopState{label: fb.pendingLabel, body: bodyBlock, post: postBlock, done: doneBlock})
1329 fb.pendingLabel = ""
1330
1331 fb.currentBlock = condBlock
1332 if s.Cond != nil {
1333 cond := fb.buildExpr(s.Cond)
1334 if cond != nil {
1335 fb.emit(&SSAIf{Cond: cond})
1336 fb.currentBlock.Succs = append(fb.currentBlock.Succs, bodyBlock, doneBlock)
1337 bodyBlock.Preds = append(bodyBlock.Preds, condBlock)
1338 doneBlock.Preds = append(doneBlock.Preds, condBlock)
1339 }
1340 } else {
1341 fb.emit(&SSAJump{Comment: "for.body"})
1342 fb.currentBlock.Succs = append(fb.currentBlock.Succs, bodyBlock)
1343 bodyBlock.Preds = append(bodyBlock.Preds, condBlock)
1344 }
1345
1346 fb.currentBlock = bodyBlock
1347 fb.buildBlock(s.Body)
1348 if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1349 fb.emit(&SSAJump{Comment: "for.post"})
1350 fb.currentBlock.Succs = append(fb.currentBlock.Succs, postBlock)
1351 postBlock.Preds = append(postBlock.Preds, fb.currentBlock)
1352 }
1353
1354 fb.currentBlock = postBlock
1355 if s.Post != nil {
1356 fb.buildStmt(s.Post)
1357 }
1358 if fb.currentBlock != nil {
1359 fb.emit(&SSAJump{Comment: "for.cond"})
1360 fb.currentBlock.Succs = append(fb.currentBlock.Succs, condBlock)
1361 condBlock.Preds = append(condBlock.Preds, fb.currentBlock)
1362 }
1363
1364 fb.loops = fb.loops[:len(fb.loops)-1]
1365 fb.currentBlock = doneBlock
1366 if savedVars != nil {
1367 fb.vars = savedVars
1368 }
1369 }
1370
1371 func (fb *ssaFuncBuilder) buildRangeLoop(s *ForStmt, rc *RangeClause) {
1372 savedVars := fb.saveVars()
1373 iterExpr := fb.buildExpr(rc.X)
1374 if iterExpr == nil {
1375 return
1376 }
1377
1378 r := &SSARange{X: iterExpr}
1379 r.typ = Typ[Invalid]
1380 r.name = fb.nextName()
1381 fb.emit(r)
1382
1383 bodyBlock := fb.newBlock("range.body")
1384 doneBlock := fb.newBlock("range.done")
1385
1386 condBlock := fb.newBlock("range.cond")
1387
1388 fb.loops = append(fb.loops, ssaLoopState{label: fb.pendingLabel, body: bodyBlock, post: condBlock, done: doneBlock})
1389 fb.pendingLabel = ""
1390 fb.emit(&SSAJump{Comment: "range.cond"})
1391 fb.currentBlock.Succs = append(fb.currentBlock.Succs, condBlock)
1392 condBlock.Preds = append(condBlock.Preds, fb.currentBlock)
1393
1394 fb.currentBlock = condBlock
1395 iterSSAType := iterExpr.SSAType()
1396 if iterSSAType == nil {
1397 tv := rc.X.GetTypeInfo()
1398 if tv.Type != nil {
1399 iterSSAType = tv.Type
1400 }
1401 }
1402 nxt := &SSANext{Iter: r, IsString: ssaIsStringType(iterSSAType)}
1403 keyTyp := asType(Typ[Int32])
1404 valTyp := asType(Typ[Invalid])
1405 iterT := iterSSAType
1406 iterU := safeUnderlying(iterT)
1407 if sl, ok := iterU.(*Slice); ok {
1408 valTyp = sl.Elem()
1409 } else if sl, ok := iterT.(*Slice); ok {
1410 valTyp = sl.Elem()
1411 } else if mt, ok := iterU.(*TCMap); ok {
1412 keyTyp = mt.Key()
1413 valTyp = mt.Elem()
1414 } else if mt, ok := iterT.(*TCMap); ok {
1415 keyTyp = mt.Key()
1416 valTyp = mt.Elem()
1417 } else if ar, ok := iterU.(*Array); ok {
1418 valTyp = ar.Elem()
1419 } else if ar, ok := iterT.(*Array); ok {
1420 valTyp = ar.Elem()
1421 } else if p, ok := iterU.(*Pointer); ok && p.Elem() != nil {
1422 if ar, ok2 := safeUnderlying(p.Elem()).(*Array); ok2 {
1423 valTyp = ar.Elem()
1424 }
1425 }
1426 if valTyp == asType(Typ[Invalid]) && ssaIsStringType(iterSSAType) {
1427 valTyp = asType(Typ[Uint8])
1428 }
1429 nxt.typ = NewTuple(
1430 NewTCVar(nil, "ok", Typ[Bool]),
1431 NewTCVar(nil, "k", keyTyp),
1432 NewTCVar(nil, "v", valTyp),
1433 )
1434 nxt.name = fb.nextName()
1435 fb.emit(nxt)
1436
1437 okExt := &SSAExtract{Tuple: nxt, Index: 0}
1438 okExt.typ = Typ[Bool]
1439 okExt.name = fb.nextName()
1440 fb.emit(okExt)
1441
1442 fb.emit(&SSAIf{Cond: okExt})
1443 fb.currentBlock.Succs = append(fb.currentBlock.Succs, bodyBlock, doneBlock)
1444 bodyBlock.Preds = append(bodyBlock.Preds, condBlock)
1445 doneBlock.Preds = append(doneBlock.Preds, condBlock)
1446
1447 fb.currentBlock = bodyBlock
1448 if rc.Lhs != nil && rc.Def {
1449 names := ssaExprNames(rc.Lhs)
1450 for i, name := range names {
1451 if name.Value == "_" {
1452 continue
1453 }
1454 ext := &SSAExtract{Tuple: nxt, Index: i + 1}
1455 ext.typ = ssaTupleElemType(nxt.typ, i+1)
1456 ext.name = fb.nextName()
1457 fb.emit(ext)
1458 var obj Object
1459 if fb.info != nil {
1460 obj = fb.info.Defs[name]
1461 }
1462 if obj == nil {
1463 obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1464 }
1465 fb.removeVar(name.Value)
1466 alloc := fb.emitAlloc(ext.typ, 0)
1467 fb.vars[obj] = alloc
1468 fb.emitStore(alloc, ext)
1469 }
1470 } else if rc.Lhs != nil && !rc.Def {
1471 names := ssaExprNames(rc.Lhs)
1472 for i, name := range names {
1473 if name.Value == "_" {
1474 continue
1475 }
1476 ext := &SSAExtract{Tuple: nxt, Index: i + 1}
1477 ext.typ = ssaTupleElemType(nxt.typ, i+1)
1478 ext.name = fb.nextName()
1479 fb.emit(ext)
1480 fb.buildStore(name, ext)
1481 }
1482 }
1483 fb.buildBlock(s.Body)
1484 if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1485 fb.emit(&SSAJump{Comment: "range.cond"})
1486 fb.currentBlock.Succs = append(fb.currentBlock.Succs, condBlock)
1487 condBlock.Preds = append(condBlock.Preds, fb.currentBlock)
1488 }
1489
1490 fb.loops = fb.loops[:len(fb.loops)-1]
1491 fb.currentBlock = doneBlock
1492 fb.vars = savedVars
1493 }
1494
1495 func (fb *ssaFuncBuilder) buildSwitch(s *SwitchStmt) {
1496 var savedVars map[Object]*SSAAlloc
1497 if s.Init != nil {
1498 savedVars = fb.saveVars()
1499 fb.buildStmt(s.Init)
1500 }
1501 if fb.currentBlock == nil {
1502 if savedVars != nil {
1503 fb.vars = savedVars
1504 }
1505 return
1506 }
1507
1508 doneBlock := fb.newBlock("switch.done")
1509 savedLoops := fb.loops
1510 fb.loops = append(fb.loops, ssaLoopState{label: fb.pendingLabel, done: doneBlock})
1511 fb.pendingLabel = ""
1512
1513 if s.Tag != nil {
1514 if tsg, ok := s.Tag.(*TypeSwitchGuard); ok {
1515 fb.buildTypeSwitch(s, tsg, doneBlock)
1516 fb.loops = savedLoops
1517 fb.currentBlock = doneBlock
1518 if savedVars != nil {
1519 fb.vars = savedVars
1520 }
1521 return
1522 }
1523 }
1524
1525 var tag SSAValue
1526 if s.Tag != nil {
1527 tag = fb.buildExpr(s.Tag)
1528 }
1529
1530 for _, clause := range s.Body {
1531 caseBlock := fb.newBlock("switch.case")
1532 nextBlock := fb.newBlock("switch.next")
1533
1534 if clause.Cases != nil && tag != nil {
1535 var cond SSAValue
1536 caseExprs := []Expr{clause.Cases}
1537 if list, ok := clause.Cases.(*ListExpr); ok {
1538 caseExprs = list.ElemList
1539 }
1540 for _, ce := range caseExprs {
1541 caseVal := fb.buildExpr(ce)
1542 cmp := &SSABinOp{Op: OpEql, X: tag, Y: caseVal}
1543 cmp.typ = Typ[Bool]
1544 cmp.name = fb.nextName()
1545 fb.emit(cmp)
1546 if cond == nil {
1547 cond = cmp
1548 } else {
1549 orOp := &SSABinOp{Op: OpLor, X: cond, Y: cmp}
1550 orOp.typ = Typ[Bool]
1551 orOp.name = fb.nextName()
1552 fb.emit(orOp)
1553 cond = orOp
1554 }
1555 }
1556 fb.emit(&SSAIf{Cond: cond})
1557 fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock, nextBlock)
1558 caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1559 nextBlock.Preds = append(nextBlock.Preds, fb.currentBlock)
1560 } else if clause.Cases != nil && tag == nil {
1561 cond := fb.buildExpr(clause.Cases)
1562 fb.emit(&SSAIf{Cond: cond})
1563 fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock, nextBlock)
1564 caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1565 nextBlock.Preds = append(nextBlock.Preds, fb.currentBlock)
1566 } else {
1567 fb.emit(&SSAJump{Comment: "switch.case"})
1568 fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock)
1569 caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1570 }
1571
1572 fb.currentBlock = caseBlock
1573 caseSaved := fb.saveVars()
1574 for _, stmt := range clause.Body {
1575 fb.buildStmt(stmt)
1576 if fb.currentBlock == nil {
1577 break
1578 }
1579 }
1580 if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1581 fb.emit(&SSAJump{Comment: "switch.done"})
1582 fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1583 doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1584 }
1585 fb.vars = caseSaved
1586 fb.currentBlock = nextBlock
1587 }
1588
1589 if fb.currentBlock != nil {
1590 fb.emit(&SSAJump{Comment: "switch.done"})
1591 fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1592 doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1593 }
1594
1595 fb.loops = savedLoops
1596 fb.currentBlock = doneBlock
1597 if savedVars != nil {
1598 fb.vars = savedVars
1599 }
1600 }
1601
1602 func (fb *ssaFuncBuilder) buildTypeSwitch(s *SwitchStmt, tsg *TypeSwitchGuard, doneBlock *SSABasicBlock) {
1603 x := fb.buildExpr(tsg.X)
1604 var savedObj Object
1605 var savedAlloc *SSAAlloc
1606 if tsg.Lhs != nil {
1607 for obj, alloc := range fb.vars {
1608 if obj.Name() == tsg.Lhs.Value {
1609 savedObj = obj
1610 savedAlloc = alloc
1611 break
1612 }
1613 }
1614 }
1615 for _, clause := range s.Body {
1616 caseBlock := fb.newBlock("typeswitch.case")
1617 nextBlock := fb.newBlock("typeswitch.next")
1618
1619 if clause.Cases != nil {
1620 caseExprs := []Expr{clause.Cases}
1621 if list, ok := clause.Cases.(*ListExpr); ok {
1622 caseExprs = list.ElemList
1623 }
1624
1625 var cond SSAValue
1626 var firstTA *SSATypeAssert
1627 var firstType Type
1628 for _, ce := range caseExprs {
1629 if n, isName := ce.(*Name); isName && n.Value == "nil" {
1630 nilType := x.SSAType()
1631 if nilType == nil {
1632 nilType = NewTCInterface(nil, nil)
1633 }
1634 nilCheck := &SSABinOp{Op: OpEql, X: x, Y: &SSAConst{typ: nilType, val: nil}}
1635 nilCheck.typ = Typ[Bool]
1636 nilCheck.name = fb.nextName()
1637 fb.emit(nilCheck)
1638 if cond == nil {
1639 cond = nilCheck
1640 } else {
1641 orOp := &SSABinOp{Op: OpLor, X: cond, Y: nilCheck}
1642 orOp.typ = Typ[Bool]
1643 orOp.name = fb.nextName()
1644 fb.emit(orOp)
1645 cond = orOp
1646 }
1647 continue
1648 }
1649 var assertedType Type
1650 if fb.info != nil {
1651 tv := fb.info.Types[ce]
1652 assertedType = tv.Type
1653 }
1654 if assertedType == nil {
1655 assertedType = fb.resolveType(ce)
1656 }
1657 if assertedType == nil {
1658 assertedType = Typ[Invalid]
1659 }
1660 ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
1661 ta.typ = NewTuple(
1662 NewTCVar(nil, "val", assertedType),
1663 NewTCVar(nil, "ok", Typ[Bool]),
1664 )
1665 ta.name = fb.nextName()
1666 fb.emit(ta)
1667 okExt := &SSAExtract{Tuple: ta, Index: 1}
1668 okExt.typ = Typ[Bool]
1669 okExt.name = fb.nextName()
1670 fb.emit(okExt)
1671 if firstTA == nil {
1672 firstTA = ta
1673 firstType = assertedType
1674 }
1675 if cond == nil {
1676 cond = okExt
1677 } else {
1678 orOp := &SSABinOp{Op: OpLor, X: cond, Y: okExt}
1679 orOp.typ = Typ[Bool]
1680 orOp.name = fb.nextName()
1681 fb.emit(orOp)
1682 cond = orOp
1683 }
1684 }
1685 fb.emit(&SSAIf{Cond: cond})
1686 fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock, nextBlock)
1687 caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1688 nextBlock.Preds = append(nextBlock.Preds, fb.currentBlock)
1689
1690 fb.currentBlock = caseBlock
1691 if tsg.Lhs != nil {
1692 var guardVal SSAValue
1693 var guardType Type
1694 if firstTA != nil {
1695 ext := &SSAExtract{Tuple: firstTA, Index: 0}
1696 ext.typ = firstType
1697 ext.name = fb.nextName()
1698 fb.emit(ext)
1699 guardVal = ext
1700 guardType = firstType
1701 } else {
1702 guardType = x.SSAType()
1703 if guardType == nil {
1704 guardType = NewTCInterface(nil, nil)
1705 }
1706 guardVal = &SSAConst{typ: guardType, val: nil}
1707 }
1708 for old := range fb.vars {
1709 if old.Name() == tsg.Lhs.Value {
1710 delete(fb.vars, old)
1711 break
1712 }
1713 }
1714 obj := NewTCVar(fb.fn.Pkg.Pkg, tsg.Lhs.Value, guardType)
1715 alloc := fb.emitAlloc(guardType, 0)
1716 fb.vars[obj] = alloc
1717 fb.emitStore(alloc, guardVal)
1718 }
1719 } else {
1720 fb.emit(&SSAJump{Comment: "typeswitch.case"})
1721 fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock)
1722 caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1723 fb.currentBlock = caseBlock
1724 }
1725
1726 caseSaved := fb.saveVars()
1727 for _, stmt := range clause.Body {
1728 fb.buildStmt(stmt)
1729 if fb.currentBlock == nil {
1730 break
1731 }
1732 }
1733 if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1734 fb.emit(&SSAJump{Comment: "switch.done"})
1735 fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1736 doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1737 }
1738 fb.vars = caseSaved
1739 fb.currentBlock = nextBlock
1740 }
1741 if fb.currentBlock != nil {
1742 fb.emit(&SSAJump{Comment: "switch.done"})
1743 fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1744 doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1745 }
1746 if savedObj != nil && savedAlloc != nil {
1747 for old := range fb.vars {
1748 if old.Name() == tsg.Lhs.Value {
1749 delete(fb.vars, old)
1750 break
1751 }
1752 }
1753 fb.vars[savedObj] = savedAlloc
1754 }
1755 }
1756
1757 func (fb *ssaFuncBuilder) buildSelect(s *SelectStmt) {
1758 doneBlock := fb.newBlock("select.done")
1759
1760 var states []*SSASelectState
1761 caseBlocks := [](*SSABasicBlock){:0:len(s.Body)}
1762 for i, clause := range s.Body {
1763 cb := fb.newBlock("select.case")
1764 caseBlocks = append(caseBlocks, cb)
1765 state := &SSASelectState{}
1766 if clause.Comm != nil {
1767 switch comm := clause.Comm.(type) {
1768 case *SendStmt:
1769 state.Dir = SelectDirSend
1770 state.Chan = fb.buildExpr(comm.Chan)
1771 state.Send = fb.buildExpr(comm.Value)
1772 case *AssignStmt:
1773 var chanExpr Expr
1774 if op, ok2 := comm.Rhs.(*Operation); ok2 && op.Y == nil && op.Op == Recv {
1775 chanExpr = op.X
1776 }
1777 if chanExpr != nil {
1778 state.Dir = SelectDirRecv
1779 state.Chan = fb.buildExpr(chanExpr)
1780 }
1781 case *ExprStmt:
1782 if op, ok2 := comm.X.(*Operation); ok2 && op.Y == nil && op.Op == Recv {
1783 state.Dir = SelectDirRecv
1784 state.Chan = fb.buildExpr(op.X)
1785 }
1786 }
1787 }
1788 states = append(states, state)
1789 _ = i
1790 }
1791
1792 sel := &SSASelect{States: states, Blocking: true}
1793 sel.typ = NewTuple(
1794 NewTCVar(nil, "index", Typ[Int32]),
1795 NewTCVar(nil, "recvOk", Typ[Bool]),
1796 )
1797 sel.name = fb.nextName()
1798 fb.emit(sel)
1799
1800 for i, clause := range s.Body {
1801 fb.currentBlock = caseBlocks[i]
1802 var selectCommVars []Object
1803 savedVars := map[Object]*SSAAlloc{}
1804 if clause.Comm != nil {
1805 if assign, ok := clause.Comm.(*AssignStmt); ok {
1806 if op, ok2 := assign.Rhs.(*Operation); ok2 && op.Y == nil && op.Op == Recv {
1807 chanVal := states[i].Chan
1808 var elemType Type
1809 if chanVal != nil {
1810 ct := chanVal.SSAType()
1811 if p, ok3 := safeUnderlying(ct).(*Pointer); ok3 {
1812 ct = p.Elem()
1813 }
1814 if ch, ok3 := safeUnderlying(ct).(*TCChan); ok3 {
1815 elemType = ch.Elem()
1816 }
1817 }
1818 if elemType == nil {
1819 elemType = Typ[Int32]
1820 }
1821 alloc := fb.emitAlloc(elemType, 0)
1822 if assign.Lhs != nil {
1823 if name, ok3 := assign.Lhs.(*Name); ok3 {
1824 for existObj := range fb.vars {
1825 if existObj.Name() == name.Value {
1826 savedVars[existObj] = fb.vars[existObj]
1827 delete(fb.vars, existObj)
1828 }
1829 }
1830 obj := NewTCVar(nil, name.Value, elemType)
1831 fb.vars[obj] = alloc
1832 selectCommVars = append(selectCommVars, obj)
1833 }
1834 }
1835 }
1836 }
1837 }
1838 for _, stmt := range clause.Body {
1839 fb.buildStmt(stmt)
1840 if fb.currentBlock == nil {
1841 break
1842 }
1843 }
1844 for _, obj := range selectCommVars {
1845 delete(fb.vars, obj)
1846 }
1847 for obj, val := range savedVars {
1848 fb.vars[obj] = val
1849 }
1850 if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1851 fb.emit(&SSAJump{Comment: "select.done"})
1852 fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1853 doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1854 }
1855 }
1856
1857 fb.currentBlock = doneBlock
1858 }
1859
1860 func (fb *ssaFuncBuilder) isSelfTailCall(e Expr) (*CallExpr, bool) {
1861 call, ok := e.(*CallExpr)
1862 if !ok || fb.tailBlock == nil || fb.deferred > 0 {
1863 return nil, false
1864 }
1865 name, ok := call.Fun.(*Name)
1866 if !ok {
1867 return nil, false
1868 }
1869 obj := fb.lookupObject(name.Value)
1870 if obj == nil {
1871 return nil, false
1872 }
1873 tc, ok := obj.(*TCFunc)
1874 if !ok || tc == nil {
1875 return nil, false
1876 }
1877 var fn *SSAFunction
1878 if okv, okok := fb.fn.Pkg.Members[name.Value].(*SSAFunction); okok {
1879 fn = okv
1880 }
1881 if fn != fb.fn {
1882 return nil, false
1883 }
1884 return call, true
1885 }
1886
1887 func (fb *ssaFuncBuilder) buildReturn(s *ReturnStmt) {
1888 if s.Results != nil {
1889 if call, ok := fb.isSelfTailCall(s.Results); ok {
1890 args := fb.buildArgs(call.ArgList)
1891 if len(args) == len(fb.paramAllocas) {
1892 for i, arg := range args {
1893 fb.emitStore(fb.paramAllocas[i], arg)
1894 }
1895 fb.emit(&SSAJump{Comment: "tailcall"})
1896 fb.currentBlock.Succs = append(fb.currentBlock.Succs, fb.tailBlock)
1897 fb.tailBlock.Preds = append(fb.tailBlock.Preds, fb.currentBlock)
1898 fb.currentBlock = nil
1899 return
1900 }
1901 }
1902 }
1903 var vals []SSAValue
1904 if s.Results != nil {
1905 if list, ok := s.Results.(*ListExpr); ok {
1906 for i, el := range list.ElemList {
1907 v := fb.buildExpr(el)
1908 if v != nil {
1909 vals = append(vals, v)
1910 } else if fb.fn.Signature != nil && fb.fn.Signature.Results() != nil && i < fb.fn.Signature.Results().Len() {
1911 vals = append(vals, &SSAConst{typ: fb.fn.Signature.Results().At(i).Type(), val: nil})
1912 }
1913 }
1914 } else {
1915 v := fb.buildExpr(s.Results)
1916 if v != nil {
1917 if v.SSAType() == nil {
1918 vals = append(vals, v)
1919 } else if tup, ok := v.SSAType().(*Tuple); ok && tup.Len() > 1 {
1920 for i := 0; i < tup.Len(); i++ {
1921 ext := &SSAExtract{Tuple: v, Index: i}
1922 ext.typ = tup.At(i).Type()
1923 ext.name = fb.nextName()
1924 fb.emit(ext)
1925 vals = append(vals, ext)
1926 }
1927 } else {
1928 vals = append(vals, v)
1929 }
1930 }
1931 }
1932 } else if len(fb.namedResults) > 0 {
1933 for _, nr := range fb.namedResults {
1934 elemType := nr.SSAType()
1935 if p, ok := elemType.(*Pointer); ok {
1936 elemType = p.Elem()
1937 }
1938 vals = append(vals, fb.emitLoad(nr, elemType))
1939 }
1940 }
1941 if fb.fn.Signature != nil && fb.fn.Signature.Results() != nil {
1942 for i, v := range vals {
1943 if i < fb.fn.Signature.Results().Len() {
1944 retType := fb.fn.Signature.Results().At(i).Type()
1945 vals[i] = fb.coerceToInterface(v, retType)
1946 }
1947 }
1948 }
1949 fb.emitReturn(vals, 0)
1950 }
1951
1952 func (fb *ssaFuncBuilder) buildBranch(s *BranchStmt) {
1953 if fb.currentBlock == nil {
1954 return
1955 }
1956 switch s.Tok {
1957 case Break:
1958 if len(fb.loops) > 0 {
1959 var doneBlock *SSABasicBlock
1960 if s.Label != nil {
1961 for i := len(fb.loops) - 1; i >= 0; i-- {
1962 if fb.loops[i].label == s.Label.Value {
1963 doneBlock = fb.loops[i].done
1964 break
1965 }
1966 }
1967 }
1968 if doneBlock == nil {
1969 doneBlock = fb.loops[len(fb.loops)-1].done
1970 }
1971 fb.emit(&SSAJump{Comment: "break"})
1972 fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1973 doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1974 fb.currentBlock = nil
1975 }
1976 case Continue:
1977 for i := len(fb.loops) - 1; i >= 0; i-- {
1978 postBlock := fb.loops[i].post
1979 if postBlock == nil {
1980 postBlock = fb.loops[i].body
1981 }
1982 if postBlock == nil {
1983 continue
1984 }
1985 fb.emit(&SSAJump{Comment: "continue"})
1986 fb.currentBlock.Succs = append(fb.currentBlock.Succs, postBlock)
1987 postBlock.Preds = append(postBlock.Preds, fb.currentBlock)
1988 fb.currentBlock = nil
1989 break
1990 }
1991 case Goto:
1992 if s.Label != nil {
1993 target := fb.labelBlock(s.Label.Value)
1994 fb.emit(&SSAJump{Comment: "goto." + s.Label.Value})
1995 fb.currentBlock.Succs = append(fb.currentBlock.Succs, target)
1996 target.Preds = append(target.Preds, fb.currentBlock)
1997 fb.currentBlock = nil
1998 }
1999 case Return:
2000 fb.emitReturn(nil, 0)
2001 }
2002 }
2003
2004 func (fb *ssaFuncBuilder) buildGoStmt(call *CallExpr) {
2005 fn := fb.buildExpr(call.Fun)
2006 if fn == nil {
2007 return
2008 }
2009 args := fb.buildArgs(call.ArgList)
2010 g := &SSAGo{Call: SSACallCommon{Value: fn, Args: args}}
2011 fb.emit(g)
2012 }
2013
2014 func (fb *ssaFuncBuilder) buildDeferStmt(call *CallExpr) {
2015 fn := fb.buildExpr(call.Fun)
2016 if fn == nil {
2017 return
2018 }
2019 args := fb.buildArgs(call.ArgList)
2020 d := &SSADefer{Call: SSACallCommon{Value: fn, Args: args}}
2021 fb.emit(d)
2022 fb.deferred++
2023 }
2024
2025 // Expression builders.
2026
2027 func (fb *ssaFuncBuilder) buildExpr(e Expr) SSAValue {
2028 if e == nil || fb.currentBlock == nil {
2029 return nil
2030 }
2031 switch e := e.(type) {
2032 case *Name:
2033 return fb.buildIdent(e)
2034 case *BasicLit:
2035 return fb.buildLit(e)
2036 case *Operation:
2037 return fb.buildOperation(e)
2038 case *CallExpr:
2039 return fb.buildCall(e)
2040 case *SelectorExpr:
2041 return fb.buildSelector(e)
2042 case *IndexExpr:
2043 return fb.buildIndex(e)
2044 case *SliceExpr:
2045 return fb.buildSlice(e)
2046 case *AssertExpr:
2047 return fb.buildAssert(e)
2048 case *CompositeLit:
2049 return fb.buildCompositeLit(e)
2050 case *FuncLit:
2051 return fb.buildFuncLit(e)
2052 case *ParenExpr:
2053 return fb.buildExpr(e.X)
2054 case *ListExpr:
2055 var last SSAValue
2056 for _, el := range e.ElemList {
2057 last = fb.buildExpr(el)
2058 }
2059 return last
2060 case *KeyValueExpr:
2061 return fb.buildExpr(e.Value)
2062 }
2063 return nil
2064 }
2065
2066 func (fb *ssaFuncBuilder) buildIdent(e *Name) SSAValue {
2067 if e.Value == "_" || e.Value == "nil" {
2068 return &SSAConst{typ: nil, val: nil}
2069 }
2070 if fb.localConsts != nil {
2071 if c, ok := fb.localConsts[e.Value]; ok {
2072 return c
2073 }
2074 }
2075 obj := fb.lookupObject(e.Value)
2076 if obj == nil && fb.info != nil {
2077 obj = fb.info.Uses[e]
2078 }
2079 if obj == nil {
2080 if fb.fn.Pkg != nil {
2081 if fn, ok := fb.fn.Pkg.Members[e.Value].(*SSAFunction); ok {
2082 return fn
2083 }
2084 if g, ok := fb.fn.Pkg.Members[e.Value].(*SSAGlobal); ok {
2085 return fb.emitLoad(g, g.typ)
2086 }
2087 }
2088 return fb.builtinValue(e.Value)
2089 }
2090 switch obj := obj.(type) {
2091 case *TCVar:
2092 if alloc, ok := fb.vars[obj]; ok {
2093 return fb.emitLoad(alloc, obj.Type())
2094 }
2095 if fv, ok := fb.freeVarPtrs[e.Value]; ok {
2096 return fb.emitLoad(fv, obj.Type())
2097 }
2098 if fb.parent != nil {
2099 p := fb.parent
2100 for p != nil {
2101 if _, ok := p.vars[obj]; ok {
2102 fb.ensureFreeVarChain(e.Value, obj.Type())
2103 fv := fb.getOrCreateFreeVar(e.Value, obj.Type())
2104 return fb.emitLoad(fv, obj.Type())
2105 }
2106 if p.freeVarPtrs != nil {
2107 if _, ok := p.freeVarPtrs[e.Value]; ok {
2108 fb.ensureFreeVarChain(e.Value, obj.Type())
2109 fv := fb.getOrCreateFreeVar(e.Value, obj.Type())
2110 return fb.emitLoad(fv, obj.Type())
2111 }
2112 }
2113 p = p.parent
2114 }
2115 }
2116 if g, ok := fb.fn.Pkg.Members[e.Value].(*SSAGlobal); ok {
2117 return fb.emitLoad(g, obj.Type())
2118 }
2119 return &SSAConst{typ: obj.Type(), val: nil}
2120 case *TCConst:
2121 return &SSAConst{typ: obj.Type(), val: localizeConstVal(obj.Val(), obj.Type())}
2122 case *TCFunc:
2123 var fn *SSAFunction
2124 if okv, okok := fb.fn.Pkg.Members[e.Value].(*SSAFunction); okok {
2125 fn = okv
2126 }
2127 if fn != nil {
2128 return fn
2129 }
2130 return &SSAConst{typ: obj.Type(), val: nil}
2131 case *TypeName:
2132 return nil
2133 case *Builtin:
2134 return &SSABuiltin{id: obj.ID(), name: obj.Name()}
2135 }
2136 return nil
2137 }
2138
2139 func (fb *ssaFuncBuilder) builtinValue(name string) SSAValue {
2140 id, ok := ssaBuiltinID(name)
2141 if !ok {
2142 return nil
2143 }
2144 return &SSABuiltin{id: id, name: name}
2145 }
2146
2147 func (fb *ssaFuncBuilder) buildLit(e *BasicLit) SSAValue {
2148 cv := evalBasicLitLocal(e)
2149 if cv == nil {
2150 return nil
2151 }
2152 switch e.Kind {
2153 case IntLit:
2154 return &SSAConst{typ: Typ[UntypedInt], val: cv}
2155 case FloatLit:
2156 return &SSAConst{typ: Typ[UntypedFloat], val: cv}
2157 case StringLit:
2158 return &SSAConst{typ: Typ[UntypedString], val: cv}
2159 case RuneLit:
2160 return &SSAConst{typ: Typ[UntypedRune], val: cv}
2161 }
2162 return nil
2163 }
2164
2165 func (fb *ssaFuncBuilder) buildOperation(e *Operation) SSAValue {
2166 if e.Y == nil {
2167 if e.Op == Add {
2168 return fb.buildExpr(e.X)
2169 }
2170 op := syntaxOpToSSAOp(e.Op, true)
2171 if op == OpAnd {
2172 if name, ok := e.X.(*Name); ok {
2173 obj := fb.lookupObject(name.Value)
2174 if obj != nil {
2175 if alloc, ok2 := fb.vars[obj]; ok2 {
2176 return alloc
2177 }
2178 if g, ok2 := fb.fn.Pkg.Members[name.Value].(*SSAGlobal); ok2 {
2179 return g
2180 }
2181 }
2182 }
2183 if ie, ok := e.X.(*IndexExpr); ok {
2184 base := fb.buildExpr(ie.X)
2185 idx := fb.buildExpr(ie.Index)
2186 if base == nil || idx == nil {
2187 return nil
2188 }
2189 ia := &SSAIndexAddr{X: base, Index: idx}
2190 ia.typ = NewPointer(ssaElemType(base.SSAType()))
2191 ia.name = fb.nextName()
2192 fb.emit(ia)
2193 return ia
2194 }
2195 if sel, ok := e.X.(*SelectorExpr); ok {
2196 addr := fb.buildSelectorAddr(sel)
2197 if addr != nil {
2198 return addr
2199 }
2200 }
2201 x := fb.buildExpr(e.X)
2202 if x == nil {
2203 return nil
2204 }
2205 a := &SSAAlloc{Heap: true}
2206 a.typ = NewPointer(x.SSAType())
2207 a.name = fb.nextName()
2208 fb.emit(a)
2209 fb.emitStore(a, x)
2210 return a
2211 }
2212 x := fb.buildExpr(e.X)
2213 if x == nil {
2214 return nil
2215 }
2216 if op == OpArrow {
2217 u := &SSAUnOp{Op: OpArrow, X: x}
2218 u.typ = ssaChanElemType(x.SSAType())
2219 u.name = fb.nextName()
2220 fb.emit(u)
2221 return u
2222 }
2223 u := &SSAUnOp{Op: op, X: x}
2224 if op == OpMul {
2225 if p, ok := x.SSAType().(*Pointer); ok {
2226 u.typ = p.Elem()
2227 } else {
2228 u.typ = x.SSAType()
2229 }
2230 } else {
2231 u.typ = x.SSAType()
2232 }
2233 u.name = fb.nextName()
2234 fb.emit(u)
2235 return u
2236 }
2237 op := syntaxOpToSSAOp(e.Op, false)
2238 if op == OpLand || op == OpLor {
2239 x := fb.buildExpr(e.X)
2240 if x == nil {
2241 return nil
2242 }
2243 rhsBlock := fb.newBlock("sc.rhs")
2244 mergeBlock := fb.newBlock("sc.merge")
2245 entryBlock := fb.currentBlock
2246 fb.emit(&SSAIf{Cond: x})
2247 if op == OpLand {
2248 fb.currentBlock.Succs = append(fb.currentBlock.Succs, rhsBlock, mergeBlock)
2249 } else {
2250 fb.currentBlock.Succs = append(fb.currentBlock.Succs, mergeBlock, rhsBlock)
2251 }
2252 rhsBlock.Preds = append(rhsBlock.Preds, entryBlock)
2253 mergeBlock.Preds = append(mergeBlock.Preds, entryBlock)
2254 fb.currentBlock = rhsBlock
2255 y := fb.buildExpr(e.Y)
2256 if y == nil {
2257 y = &SSAConst{typ: Typ[Bool], val: constBool{false}}
2258 }
2259 fb.emit(&SSAJump{Comment: "sc.merge"})
2260 fb.currentBlock.Succs = append(fb.currentBlock.Succs, mergeBlock)
2261 mergeBlock.Preds = append(mergeBlock.Preds, fb.currentBlock)
2262 fb.currentBlock = mergeBlock
2263 var shortVal SSAValue
2264 if op == OpLand {
2265 shortVal = &SSAConst{typ: Typ[Bool], val: constBool{false}}
2266 } else {
2267 shortVal = &SSAConst{typ: Typ[Bool], val: constBool{true}}
2268 }
2269 phi := &SSAPhi{Edges: []SSAValue{shortVal, y}, Comment: "sc"}
2270 phi.typ = Typ[Bool]
2271 phi.name = fb.nextName()
2272 fb.emit(phi)
2273 return phi
2274 }
2275 x := fb.buildExpr(e.X)
2276 y := fb.buildExpr(e.Y)
2277 if x == nil || y == nil {
2278 return nil
2279 }
2280 if xc, ok := x.(*SSAConst); ok {
2281 if yc, ok2 := y.(*SSAConst); ok2 {
2282 if xc.val != nil && yc.val != nil {
2283 folded := evalBinaryLocal(e.Op, xc.val, yc.val)
2284 if folded != nil {
2285 ct := xc.typ
2286 if ct == nil {
2287 ct = yc.typ
2288 }
2289 if _, isBool := folded.(constBool); isBool {
2290 ct = Typ[Bool]
2291 }
2292 return &SSAConst{typ: ct, val: folded}
2293 }
2294 }
2295 }
2296 }
2297 b := &SSABinOp{Op: op, X: x, Y: y}
2298 b.name = fb.nextName()
2299 switch op {
2300 case OpEql, OpNeq, OpLss, OpLeq, OpGtr, OpGeq:
2301 b.typ = Typ[Bool]
2302 default:
2303 xT := x.SSAType()
2304 yT := y.SSAType()
2305 xUntyped := false
2306 if xB, ok := safeUnderlying(xT).(*Basic); ok && xB.Info()&IsUntyped != 0 {
2307 xUntyped = true
2308 }
2309 if xT != nil && !xUntyped {
2310 b.typ = xT
2311 } else if yT != nil {
2312 b.typ = yT
2313 } else {
2314 b.typ = xT
2315 }
2316 }
2317 fb.emit(b)
2318 return b
2319 }
2320
2321 func (fb *ssaFuncBuilder) buildCall(e *CallExpr) SSAValue {
2322 if ie, ok := e.Fun.(*IndexExpr); ok {
2323 if result := fb.tryGenericCallFromIndex(ie, e.ArgList, e.HasDots); result != nil {
2324 return result
2325 }
2326 }
2327 if name, ok := e.Fun.(*Name); ok {
2328 obj := fb.lookupObject(name.Value)
2329 if tn, ok2 := obj.(*TypeName); ok2 {
2330 if _, isTP := tn.Type().(*TypeParam); !isTP {
2331 args := fb.buildArgs(e.ArgList)
2332 if len(args) == 1 && args[0] != nil {
2333 if _, isIface := safeUnderlying(tn.Type()).(*TCInterface); isIface {
2334 mi := &SSAMakeInterface{X: args[0]}
2335 mi.typ = tn.Type()
2336 mi.name = fb.nextName()
2337 fb.emit(mi)
2338 return mi
2339 }
2340 conv := &SSAConvert{X: args[0]}
2341 conv.typ = tn.Type()
2342 conv.name = fb.nextName()
2343 fb.emit(conv)
2344 return conv
2345 }
2346 return nil
2347 }
2348 }
2349 if tcFn, ok2 := obj.(*TCFunc); ok2 {
2350 isGeneric := false
2351 if genericFuncDecls != nil {
2352 pkgPath := fb.fn.Pkg.Pkg.Path()
2353 if _, gok := genericFuncDecls[pkgPath|"."|name.Value]; gok {
2354 isGeneric = true
2355 }
2356 if !isGeneric && fb.srcScope != nil && genericPkgScopes != nil {
2357 for gPkg, gScope := range genericPkgScopes {
2358 if gScope == fb.srcScope {
2359 if _, gok2 := genericFuncDecls[gPkg|"."|name.Value]; gok2 {
2360 isGeneric = true
2361 break
2362 }
2363 }
2364 }
2365 }
2366 }
2367 if !isGeneric {
2368 fnPkg := fb.fn.Pkg
2369 if fb.srcScope != nil && tcFn.Pkg() != nil && tcFn.Pkg() != fb.fn.Pkg.Pkg {
2370 fnPkg = fb.ensureImportedSSAPackage(tcFn.Pkg())
2371 }
2372 var ssaFn *SSAFunction
2373 if okv, okok := fnPkg.Members[name.Value].(*SSAFunction); okok {
2374 ssaFn = okv
2375 }
2376 if ssaFn == nil {
2377 ssaFn = &SSAFunction{
2378 name: name.Value,
2379 object: tcFn,
2380 Pkg: fnPkg,
2381 Prog: fb.fn.Prog,
2382 }
2383 if tcFn.Type() != nil {
2384 if okv, okok := tcFn.Type().(*Signature); okok {
2385 ssaFn.Signature = okv
2386 }
2387 }
2388 }
2389 args := fb.buildArgs(e.ArgList)
2390 if ssaFn.Signature != nil {
2391 if ssaFn.Signature.Variadic() && !e.HasDots {
2392 args = fb.wrapVariadicArgs(args, ssaFn.Signature)
2393 }
2394 args = fb.coerceArgsToInterface(args, ssaFn.Signature)
2395 }
2396 var retType Type
2397 if ssaFn.Signature != nil {
2398 if ssaFn.Signature.Results() != nil && ssaFn.Signature.Results().Len() == 1 {
2399 retType = ssaFn.Signature.Results().At(0).Type()
2400 } else if ssaFn.Signature.Results() != nil && ssaFn.Signature.Results().Len() > 1 {
2401 retType = ssaFn.Signature.Results()
2402 }
2403 }
2404 call := &SSACall{Call: SSACallCommon{Value: ssaFn, Args: args}}
2405 call.typ = retType
2406 call.name = fb.nextName()
2407 fb.emit(call)
2408 if retType == nil {
2409 return nil
2410 }
2411 return call
2412 }
2413 }
2414 if result := fb.tryGenericLocalCall(name.Value, e.ArgList, e.HasDots); result != nil {
2415 return result
2416 }
2417 }
2418 if convType := fb.resolveTypeAST(e.Fun); convType != nil {
2419 args := fb.buildArgs(e.ArgList)
2420 if len(args) == 1 && args[0] != nil {
2421 if _, isIface := safeUnderlying(convType).(*TCInterface); isIface {
2422 mi := &SSAMakeInterface{X: args[0]}
2423 mi.typ = convType
2424 mi.name = fb.nextName()
2425 fb.emit(mi)
2426 return mi
2427 }
2428 conv := &SSAConvert{X: args[0]}
2429 conv.typ = convType
2430 conv.name = fb.nextName()
2431 fb.emit(conv)
2432 return conv
2433 }
2434 return nil
2435 }
2436 if sel, ok := e.Fun.(*SelectorExpr); ok {
2437 if name, ok2 := sel.X.(*Name); ok2 {
2438 obj := fb.lookupObject(name.Value)
2439 if pn, ok3 := obj.(*PkgName); ok3 {
2440 return fb.buildPkgCall(pn, sel.Sel.Value, e.ArgList, e.HasDots)
2441 }
2442 }
2443 recv := fb.buildExpr(sel.X)
2444 if recv != nil && recv.SSAType() != nil {
2445 if fn, fixedRecv := fb.resolveMethodCallWithRecv(sel, recv); fn != nil {
2446 args := fb.buildArgs(e.ArgList)
2447 if fn.Signature != nil {
2448 if fn.Signature.Variadic() && !e.HasDots {
2449 args = fb.wrapVariadicArgs(args, fn.Signature)
2450 }
2451 args = fb.coerceArgsToInterface(args, fn.Signature)
2452 }
2453 allArgs := []SSAValue{:0:len(args) + 1}
2454 allArgs = append(allArgs, fixedRecv)
2455 for _, ma := range args {
2456 allArgs = append(allArgs, ma)
2457 }
2458 var retType Type
2459 if fn.Signature != nil {
2460 if fn.Signature.Results() != nil && fn.Signature.Results().Len() == 1 {
2461 retType = fn.Signature.Results().At(0).Type()
2462 } else if fn.Signature.Results() != nil && fn.Signature.Results().Len() > 1 {
2463 retType = fn.Signature.Results()
2464 }
2465 }
2466 call := &SSACall{Call: SSACallCommon{Value: fn, Args: allArgs}}
2467 call.typ = retType
2468 call.name = fb.nextName()
2469 fb.emit(call)
2470 return call
2471 }
2472 if inv := fb.buildIfaceMethodCall(sel, recv, e.ArgList); inv != nil {
2473 return inv
2474 }
2475 println("MCALL-FAIL:", sel.Sel.Value, recv.SSAType().String())
2476 }
2477 }
2478 fn := fb.buildExpr(e.Fun)
2479 args := fb.buildArgs(e.ArgList)
2480
2481 if fn == nil {
2482 return nil
2483 }
2484 if bi, ok := fn.(*SSABuiltin); ok {
2485 return fb.buildBuiltinCall(e, bi, args)
2486 }
2487
2488 var retType Type
2489 if fn.SSAType() != nil {
2490 if sig, ok := safeUnderlying(fn.SSAType()).(*Signature); ok {
2491 if sig.Results() != nil && sig.Results().Len() == 1 {
2492 retType = sig.Results().At(0).Type()
2493 } else if sig.Results() != nil && sig.Results().Len() > 1 {
2494 retType = sig.Results()
2495 }
2496 }
2497 } else if ssaFn, ok := fn.(*SSAFunction); ok && ssaFn.Signature != nil {
2498 sig := ssaFn.Signature
2499 if sig.Results() != nil && sig.Results().Len() == 1 {
2500 retType = sig.Results().At(0).Type()
2501 } else if sig.Results() != nil && sig.Results().Len() > 1 {
2502 retType = sig.Results()
2503 }
2504 }
2505
2506 if fn.SSAType() != nil {
2507 if sig, ok := safeUnderlying(fn.SSAType()).(*Signature); ok {
2508 if sig.Variadic() && !e.HasDots {
2509 args = fb.wrapVariadicArgs(args, sig)
2510 }
2511 args = fb.coerceArgsToInterface(args, sig)
2512 }
2513 }
2514
2515 call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
2516 call.typ = retType
2517 call.name = fb.nextName()
2518 fb.emit(call)
2519
2520 if retType == nil {
2521 return nil
2522 }
2523 return call
2524 }
2525
2526 func (fb *ssaFuncBuilder) coerceArgsToInterface(args []SSAValue, sig *Signature) []SSAValue {
2527 if sig.Params() == nil {
2528 return args
2529 }
2530 for i := 0; i < len(args) && i < sig.Params().Len(); i++ {
2531 paramType := sig.Params().At(i).Type()
2532 if paramType == nil || args[i] == nil || args[i].SSAType() == nil {
2533 continue
2534 }
2535 _, isIface := safeUnderlying(paramType).(*TCInterface)
2536 if !isIface {
2537 continue
2538 }
2539 _, argIsIface := safeUnderlying(args[i].SSAType()).(*TCInterface)
2540 if argIsIface {
2541 continue
2542 }
2543 mi := &SSAMakeInterface{X: args[i], IType: paramType}
2544 mi.typ = paramType
2545 mi.name = fb.nextName()
2546 fb.emit(mi)
2547 args[i] = mi
2548 }
2549 return args
2550 }
2551
2552 func (fb *ssaFuncBuilder) wrapVariadicArgs(args []SSAValue, sig *Signature) []SSAValue {
2553 if sig.Params() == nil {
2554 return args
2555 }
2556 nFixed := sig.Params().Len() - 1
2557 if nFixed < 0 {
2558 nFixed = 0
2559 }
2560 if nFixed > len(args) {
2561 nFixed = len(args)
2562 }
2563 nVariadic := len(args) - nFixed
2564 if nVariadic <= 0 {
2565 nilSlice := NewSSAConst(constNil{}, sig.Params().At(sig.Params().Len()-1).Type())
2566 result := []SSAValue{:nFixed:nFixed}
2567 copy(result, args[:nFixed])
2568 return append(result, nilSlice)
2569 }
2570 sliceType := sig.Params().At(sig.Params().Len() - 1).Type()
2571 var elemType Type
2572 if sl, ok := safeUnderlying(sliceType).(*Slice); ok {
2573 elemType = sl.Elem()
2574 }
2575 // HasDots lost because closures can't write to captured named returns.
2576 // Detect spread: if exactly 1 variadic arg whose type matches the
2577 // variadic param's slice type, pass it through. This covers both
2578 // concrete T and interface{} variadics (e.g. fmt.Print -> fmt.Fprint).
2579 if nVariadic == 1 && elemType != nil {
2580 argT := args[nFixed].SSAType()
2581 if argT != nil && Identical(argT, sliceType) {
2582 return args
2583 }
2584 }
2585 lenVal := NewSSAConst(constInt{int64(nVariadic)}, Typ[Int32])
2586 ms := &SSAMakeSlice{Len: lenVal, Cap: lenVal}
2587 ms.typ = sliceType
2588 ms.name = fb.nextName()
2589 fb.emit(ms)
2590 for i := 0; i < nVariadic; i++ {
2591 idx := NewSSAConst(constInt{int64(i)}, Typ[Int32])
2592 ia := &SSAIndexAddr{X: ms, Index: idx}
2593 ia.typ = NewPointer(elemType)
2594 ia.name = fb.nextName()
2595 fb.emit(ia)
2596 v := args[nFixed+i]
2597 if elemType != nil {
2598 v = fb.coerceToInterface(v, elemType)
2599 }
2600 fb.emitStore(ia, v)
2601 }
2602 result := []SSAValue{:nFixed:nFixed}
2603 copy(result, args[:nFixed])
2604 return append(result, ms)
2605 }
2606
2607 func (fb *ssaFuncBuilder) buildArgs(argList []Expr) []SSAValue {
2608 args := []SSAValue{:0:len(argList)}
2609 for _, a := range argList {
2610 v := fb.buildExpr(a)
2611 if v != nil {
2612 args = append(args, v)
2613 }
2614 }
2615 return args
2616 }
2617
2618 func (fb *ssaFuncBuilder) buildBuiltinCall(e *CallExpr, b *SSABuiltin, args []SSAValue) SSAValue {
2619 switch b.id {
2620 case BuiltinLen, BuiltinCap:
2621 if b.id == BuiltinLen && len(args) == 1 {
2622 if c, ok := args[0].(*SSAConst); ok && c.val != nil {
2623 if s, ok2 := c.val.(constStr); ok2 {
2624 return &SSAConst{typ: Typ[Int32], val: constInt{int64(len(s.s))}}
2625 }
2626 }
2627 }
2628 call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2629 call.typ = Typ[Int32]
2630 call.name = fb.nextName()
2631 fb.emit(call)
2632 return call
2633 case BuiltinAppend:
2634 if len(args) > 1 {
2635 if sl, ok := safeUnderlying(args[0].SSAType()).(*Slice); ok {
2636 if _, isIface := safeUnderlying(sl.Elem()).(*TCInterface); isIface {
2637 for i := 1; i < len(args); i++ {
2638 if e.HasDots && i == 1 {
2639 continue
2640 }
2641 if args[i] == nil || args[i].SSAType() == nil {
2642 continue
2643 }
2644 if _, argIface := safeUnderlying(args[i].SSAType()).(*TCInterface); argIface {
2645 continue
2646 }
2647 mi := &SSAMakeInterface{X: args[i], IType: sl.Elem()}
2648 mi.typ = sl.Elem()
2649 mi.name = fb.nextName()
2650 fb.emit(mi)
2651 args[i] = mi
2652 }
2653 }
2654 }
2655 }
2656 call := &SSACall{Call: SSACallCommon{Value: b, Args: args, HasDots: e.HasDots}}
2657 if len(args) > 0 {
2658 call.typ = args[0].SSAType()
2659 }
2660 call.name = fb.nextName()
2661 fb.emit(call)
2662 return call
2663 case BuiltinMake:
2664 if len(e.ArgList) == 0 {
2665 return nil
2666 }
2667 typ := fb.resolveType(e.ArgList[0])
2668 return fb.emitMake(typ, args)
2669 case BuiltinNew:
2670 if len(e.ArgList) == 0 {
2671 return nil
2672 }
2673 typ := fb.resolveType(e.ArgList[0])
2674 a := &SSAAlloc{Heap: true}
2675 a.typ = NewPointer(typ)
2676 a.name = fb.nextName()
2677 fb.emit(a)
2678 return a
2679 case BuiltinPanic:
2680 if len(args) > 0 {
2681 fb.emit(&SSAPanic{X: args[0]})
2682 fb.currentBlock = nil
2683 }
2684 return nil
2685 case BuiltinClose, BuiltinDelete, BuiltinClear, BuiltinPrint, BuiltinPrintln:
2686 call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2687 call.name = fb.nextName()
2688 fb.emit(call)
2689 return nil
2690 case BuiltinCopy:
2691 call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2692 call.typ = Typ[Int32]
2693 call.name = fb.nextName()
2694 fb.emit(call)
2695 return call
2696 case BuiltinRecover:
2697 call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2698 call.typ = NewTCInterface(nil, nil)
2699 call.name = fb.nextName()
2700 fb.emit(call)
2701 return call
2702 case BuiltinMin, BuiltinMax:
2703 call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2704 if len(args) > 0 && args[0] != nil {
2705 call.typ = args[0].SSAType()
2706 } else {
2707 call.typ = Typ[Int32]
2708 }
2709 call.name = fb.nextName()
2710 fb.emit(call)
2711 return call
2712 }
2713 call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2714 call.name = fb.nextName()
2715 fb.emit(call)
2716 return call
2717 }
2718
2719 func (fb *ssaFuncBuilder) emitMake(typ Type, sizeArgs []SSAValue) SSAValue {
2720 if typ == nil {
2721 return nil
2722 }
2723 switch u := safeUnderlying(typ).(type) {
2724 case *Basic:
2725 if u.kind == TCString {
2726 ms := &SSAMakeSlice{}
2727 ms.typ = typ
2728 ms.name = fb.nextName()
2729 if len(sizeArgs) > 0 {
2730 ms.Len = sizeArgs[0]
2731 }
2732 if len(sizeArgs) > 1 {
2733 ms.Cap = sizeArgs[1]
2734 }
2735 fb.emit(ms)
2736 return ms
2737 }
2738 case *Slice:
2739 ms := &SSAMakeSlice{}
2740 ms.typ = typ
2741 ms.name = fb.nextName()
2742 if len(sizeArgs) > 0 {
2743 ms.Len = sizeArgs[0]
2744 }
2745 if len(sizeArgs) > 1 {
2746 ms.Cap = sizeArgs[1]
2747 }
2748 fb.emit(ms)
2749 return ms
2750 case *TCMap:
2751 mm := &SSAMakeMap{}
2752 mm.typ = typ
2753 mm.name = fb.nextName()
2754 if len(sizeArgs) > 0 {
2755 mm.Reserve = sizeArgs[0]
2756 }
2757 fb.emit(mm)
2758 return mm
2759 case *TCChan:
2760 mc := &SSAMakeChan{}
2761 mc.typ = typ
2762 mc.name = fb.nextName()
2763 if len(sizeArgs) > 0 {
2764 mc.Size = sizeArgs[0]
2765 }
2766 fb.emit(mc)
2767 return mc
2768 }
2769 return nil
2770 }
2771
2772 func (fb *ssaFuncBuilder) buildSelector(e *SelectorExpr) SSAValue {
2773 if name, ok := e.X.(*Name); ok {
2774 obj := fb.lookupObject(name.Value)
2775 if pn, ok2 := obj.(*PkgName); ok2 {
2776 return fb.buildPkgMember(pn, e.Sel.Value)
2777 }
2778 }
2779 fa := fb.buildSelectorAddr(e)
2780 if fa != nil {
2781 elemType := fa.SSAType()
2782 if p, ok := safeUnderlying(elemType).(*Pointer); ok {
2783 elemType = p.Elem()
2784 }
2785 return fb.emitLoad(fa, elemType)
2786 }
2787 recv := fb.buildExpr(e.X)
2788 if recv == nil {
2789 return nil
2790 }
2791 return fb.buildMethodValue(e, recv)
2792 }
2793
2794 func (fb *ssaFuncBuilder) buildMethodValue(sel *SelectorExpr, recv SSAValue) SSAValue {
2795 fn, fixedRecv := fb.resolveMethodCallWithRecv(sel, recv)
2796 if fn == nil || fn.Signature == nil {
2797 return nil
2798 }
2799 methodSig := fn.Signature
2800 var wrapperParams *Tuple
2801 if methodSig.Params() != nil && methodSig.Params().Len() > 0 {
2802 vars := []*TCVar{:0:methodSig.Params().Len()}
2803 for i := 0; i < methodSig.Params().Len(); i++ {
2804 vars = append(vars, methodSig.Params().At(i))
2805 }
2806 wrapperParams = NewTuple(vars...)
2807 }
2808 wrapperSig := NewSignature(nil, wrapperParams, methodSig.Results(), methodSig.Variadic())
2809 name := fb.fn.name | "__mval" | ssaItoa(len(fb.fn.AnonFuncs)+1)
2810 wrapper := &SSAFunction{
2811 name: name,
2812 Signature: wrapperSig,
2813 Pkg: fb.fn.Pkg,
2814 Prog: fb.fn.Prog,
2815 parent: fb.fn,
2816 }
2817 fb.fn.AnonFuncs = append(fb.fn.AnonFuncs, wrapper)
2818 recvType := fixedRecv.SSAType()
2819 if _, isAlloc := fixedRecv.(*SSAAlloc); !isAlloc {
2820 if _, isPtr := safeUnderlying(recvType).(*Pointer); !isPtr {
2821 alloc := &SSAAlloc{}
2822 alloc.typ = NewPointer(recvType)
2823 alloc.name = fb.nextName()
2824 alloc.Heap = true
2825 fb.emit(alloc)
2826 storeOp := &SSAStore{Addr: alloc, Val: fixedRecv}
2827 fb.emit(storeOp)
2828 fixedRecv = alloc
2829 }
2830 }
2831 fv := &SSAFreeVar{name: "recv", typ: recvType, parent: wrapper}
2832 wrapper.FreeVars = append(wrapper.FreeVars, fv)
2833 if wrapperParams != nil {
2834 for i := 0; i < wrapperParams.Len(); i++ {
2835 v := wrapperParams.At(i)
2836 p := &SSAParameter{name: v.Name(), typ: v.Type(), parent: wrapper}
2837 wrapper.Params = append(wrapper.Params, p)
2838 }
2839 }
2840 entry := NewSSABasicBlock(wrapper, "entry")
2841 args := []SSAValue{:0:1 + len(wrapper.Params)}
2842 args = append(args, fv)
2843 for _, p := range wrapper.Params {
2844 args = append(args, p)
2845 }
2846 var retType Type
2847 if methodSig.Results() != nil && methodSig.Results().Len() == 1 {
2848 retType = methodSig.Results().At(0).Type()
2849 } else if methodSig.Results() != nil && methodSig.Results().Len() > 1 {
2850 retType = methodSig.Results()
2851 }
2852 call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
2853 call.typ = retType
2854 call.name = "t1"
2855 call.setBlock(entry)
2856 entry.Instrs = append(entry.Instrs, call)
2857 ret := &SSAReturn{}
2858 if retType != nil {
2859 ret.Results = []SSAValue{call}
2860 }
2861 ret.setBlock(entry)
2862 entry.Instrs = append(entry.Instrs, ret)
2863 mc := &SSAMakeClosure{Fn: wrapper, Bindings: []SSAValue{fixedRecv}}
2864 mc.typ = wrapperSig
2865 mc.name = fb.nextName()
2866 fb.emit(mc)
2867 return mc
2868 }
2869
2870 func (fb *ssaFuncBuilder) ensureImportedSSAPackage(imported *TCPackage) *SSAPackage {
2871 impPkg := fb.fn.Prog.ImportedPackage(imported.Path())
2872 if impPkg == nil {
2873 impPkg = &SSAPackage{
2874 Prog: fb.fn.Prog,
2875 Pkg: imported,
2876 Members: map[string]SSAMember{},
2877 }
2878 fb.fn.Prog.imported[imported.Path()] = impPkg
2879 fb.fn.Prog.packages[imported] = impPkg
2880 }
2881 return impPkg
2882 }
2883
2884 func (fb *ssaFuncBuilder) buildPkgMember(pn *PkgName, memberName string) SSAValue {
2885 imported := pn.Imported()
2886 if imported == nil {
2887 return nil
2888 }
2889 obj := imported.Scope().Lookup(memberName)
2890 if obj == nil {
2891 return nil
2892 }
2893 switch obj := obj.(type) {
2894 case *TCConst:
2895 return &SSAConst{typ: obj.Type(), val: localizeConstVal(obj.Val(), obj.Type())}
2896 case *TCVar:
2897 impPkg := fb.ensureImportedSSAPackage(imported)
2898 g, ok := impPkg.Members[memberName].(*SSAGlobal)
2899 if !ok {
2900 g = &SSAGlobal{
2901 name: memberName,
2902 typ: NewPointer(obj.Type()),
2903 pkg: impPkg,
2904 }
2905 impPkg.Members[memberName] = g
2906 }
2907 return fb.emitLoad(g, obj.Type())
2908 case *TCFunc:
2909 impPkg := fb.ensureImportedSSAPackage(imported)
2910 fn := impPkg.Func(memberName)
2911 if fn != nil {
2912 return fn
2913 }
2914 sig := obj.Signature()
2915 if sig != nil {
2916 fn = &SSAFunction{
2917 name: memberName,
2918 object: obj,
2919 Signature: sig,
2920 Pkg: impPkg,
2921 Prog: fb.fn.Prog,
2922 }
2923 impPkg.Members[memberName] = fn
2924 return fn
2925 }
2926 return nil
2927 }
2928 return nil
2929 }
2930
2931 func (fb *ssaFuncBuilder) buildSelectorAddr(e *SelectorExpr) SSAValue {
2932 var addr SSAValue
2933 var structType Type
2934 if inner, ok := e.X.(*SelectorExpr); ok {
2935 addr = fb.buildSelectorAddr(inner)
2936 if addr == nil {
2937 return nil
2938 }
2939 structType = addr.SSAType()
2940 if p, ok := safeUnderlying(structType).(*Pointer); ok {
2941 structType = p.Elem()
2942 }
2943 if p, ok := safeUnderlying(structType).(*Pointer); ok {
2944 ld := &SSAUnOp{Op: OpMul, X: addr}
2945 ld.typ = structType
2946 ld.name = fb.nextName()
2947 fb.emit(ld)
2948 addr = ld
2949 structType = p.Elem()
2950 }
2951 } else if ie, ok := e.X.(*IndexExpr); ok {
2952 x := fb.buildExpr(ie.X)
2953 idx := fb.buildExpr(ie.Index)
2954 if x == nil || idx == nil {
2955 return nil
2956 }
2957 ia := &SSAIndexAddr{X: x, Index: idx}
2958 elemT := ssaElemType(x.SSAType())
2959 ia.typ = NewPointer(elemT)
2960 ia.name = fb.nextName()
2961 fb.emit(ia)
2962 addr = ia
2963 structType = elemT
2964 if _, isPtr := safeUnderlying(elemT).(*Pointer); isPtr {
2965 ld := fb.emitLoad(ia, elemT)
2966 addr = ld
2967 structType = elemT
2968 }
2969 } else {
2970 x := fb.buildExpr(e.X)
2971 if x == nil || x.SSAType() == nil {
2972 if name, ok := e.X.(*Name); ok {
2973 obj := fb.lookupObject(name.Value)
2974 if pn, ok := obj.(*PkgName); ok {
2975 return fb.buildPkgMemberAddr(pn, e.Sel.Value)
2976 }
2977 }
2978 return nil
2979 }
2980 baseType := x.SSAType()
2981 addr = x
2982 if _, ok := safeUnderlying(baseType).(*Pointer); !ok {
2983 if name, ok := e.X.(*Name); ok {
2984 obj := fb.lookupObject(name.Value)
2985 if obj != nil {
2986 if alloc, ok2 := fb.vars[obj]; ok2 {
2987 addr = alloc
2988 baseType = NewPointer(baseType)
2989 } else if fb.freeVarPtrs != nil {
2990 if fv, ok2 := fb.freeVarPtrs[name.Value]; ok2 {
2991 addr = fv
2992 baseType = NewPointer(baseType)
2993 }
2994 }
2995 }
2996 }
2997 }
2998 structType = baseType
2999 if p, ok := safeUnderlying(structType).(*Pointer); ok {
3000 structType = p.Elem()
3001 }
3002 }
3003 fieldIdx := fb.fieldIndex(structType, e.Sel.Value)
3004 if fieldIdx >= 0 {
3005 fa := &SSAFieldAddr{X: addr, Field: fieldIdx}
3006 fa.typ = NewPointer(fb.fieldType(structType, fieldIdx))
3007 fa.name = fb.nextName()
3008 fb.emit(fa)
3009 return fa
3010 }
3011 path := fb.findEmbeddedFieldPath(structType, e.Sel.Value)
3012 if len(path) >= 2 {
3013 cur := addr
3014 curType := structType
3015 for pi, idx := range path {
3016 fa := &SSAFieldAddr{X: cur, Field: idx}
3017 fa.typ = NewPointer(fb.fieldType(curType, idx))
3018 fa.name = fb.nextName()
3019 fb.emit(fa)
3020 curType = fb.fieldType(curType, idx)
3021 if pi < len(path)-1 {
3022 if p, ok := safeUnderlying(curType).(*Pointer); ok {
3023 ld := &SSAUnOp{Op: OpMul, X: fa}
3024 ld.typ = curType
3025 ld.name = fb.nextName()
3026 fb.emit(ld)
3027 cur = ld
3028 curType = p.Elem()
3029 continue
3030 }
3031 }
3032 cur = fa
3033 }
3034 return cur
3035 }
3036 return nil
3037 }
3038
3039 func (fb *ssaFuncBuilder) buildIndex(e *IndexExpr) SSAValue {
3040 x := fb.buildExpr(e.X)
3041 idx := fb.buildExpr(e.Index)
3042 if x == nil || idx == nil {
3043 return nil
3044 }
3045 if x.SSAType() == nil {
3046 return nil
3047 }
3048 switch t := safeUnderlying(x.SSAType()).(type) {
3049 case *TCMap:
3050 idx = fb.coerceToInterface(idx, t.Key())
3051 l := &SSALookup{X: x, Index: idx}
3052 l.typ = t.Elem()
3053 l.name = fb.nextName()
3054 fb.emit(l)
3055 return l
3056 default:
3057 elemType := ssaElemType(x.SSAType())
3058 if p, ok := safeUnderlying(x.SSAType()).(*Pointer); ok && p.Elem() != nil {
3059 if arr, ok2 := safeUnderlying(p.Elem()).(*Array); ok2 {
3060 elemType = arr.Elem()
3061 }
3062 }
3063 ia := &SSAIndexAddr{X: x, Index: idx}
3064 ia.typ = NewPointer(elemType)
3065 ia.name = fb.nextName()
3066 fb.emit(ia)
3067 return fb.emitLoad(ia, elemType)
3068 }
3069 }
3070
3071 func (fb *ssaFuncBuilder) buildSlice(e *SliceExpr) SSAValue {
3072 x := fb.buildExpr(e.X)
3073 if x == nil {
3074 return nil
3075 }
3076 sl := &SSASlice{X: x}
3077 if len(e.Index) > 0 && e.Index[0] != nil {
3078 sl.Low = fb.buildExpr(e.Index[0])
3079 }
3080 if len(e.Index) > 1 && e.Index[1] != nil {
3081 sl.High = fb.buildExpr(e.Index[1])
3082 }
3083 if len(e.Index) > 2 && e.Index[2] != nil {
3084 sl.Max = fb.buildExpr(e.Index[2])
3085 }
3086 sl.typ = ssaSliceOf(x.SSAType())
3087 sl.name = fb.nextName()
3088 fb.emit(sl)
3089 return sl
3090 }
3091
3092 func (fb *ssaFuncBuilder) buildAssert(e *AssertExpr) SSAValue {
3093 x := fb.buildExpr(e.X)
3094 assertedType := fb.resolveType(e.Type)
3095 if x == nil {
3096 return nil
3097 }
3098 ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: false}
3099 ta.typ = assertedType
3100 ta.name = fb.nextName()
3101 fb.emit(ta)
3102 return ta
3103 }
3104
3105 func (fb *ssaFuncBuilder) buildCompositeLit(e *CompositeLit) SSAValue {
3106 var typ Type
3107 if e.Type != nil {
3108 typ = fb.resolveType(e.Type)
3109 }
3110 if typ == nil {
3111 return nil
3112 }
3113
3114 if sl, ok := safeUnderlying(typ).(*Slice); ok {
3115 return fb.buildSliceLit(e, typ, sl)
3116 }
3117
3118 if mt, isMap := safeUnderlying(typ).(*TCMap); isMap {
3119 mm := &SSAMakeMap{}
3120 mm.typ = typ
3121 mm.name = fb.nextName()
3122 fb.emit(mm)
3123 for _, el := range e.ElemList {
3124 if kv, ok := el.(*KeyValueExpr); ok {
3125 k := fb.buildExpr(kv.Key)
3126 v := fb.buildExpr(kv.Value)
3127 if k != nil && v != nil {
3128 k = fb.coerceToInterface(k, mt.Key())
3129 v = fb.coerceToInterface(v, mt.Elem())
3130 fb.emit(&SSAMapUpdate{Map: mm, Key: k, Value: v})
3131 }
3132 }
3133 }
3134 return mm
3135 }
3136
3137 if ar, isArr := safeUnderlying(typ).(*Array); isArr {
3138 return fb.buildArrayLit(e, typ, ar)
3139 }
3140
3141 alloc := fb.emitAlloc(typ, 0)
3142 posIdx := 0
3143 for _, el := range e.ElemList {
3144 if kv, ok := el.(*KeyValueExpr); ok {
3145 if _, ok2 := safeUnderlying(typ).(*TCStruct); ok2 {
3146 idx := fb.fieldIndex(typ, kv.Key.(*Name).Value)
3147 if idx >= 0 {
3148 fa := &SSAFieldAddr{X: alloc, Field: idx}
3149 ft := fb.fieldType(typ, idx)
3150 fa.typ = NewPointer(ft)
3151 fa.name = fb.nextName()
3152 fb.emit(fa)
3153 v := fb.buildExpr(kv.Value)
3154 if v != nil {
3155 v = fb.coerceToInterface(v, ft)
3156 fb.emitStore(fa, v)
3157 }
3158 }
3159 }
3160 } else {
3161 v := fb.buildExpr(el)
3162 if v != nil {
3163 if _, ok2 := safeUnderlying(typ).(*TCStruct); ok2 {
3164 ft := fb.fieldType(typ, posIdx)
3165 fa := &SSAFieldAddr{X: alloc, Field: posIdx}
3166 fa.typ = NewPointer(ft)
3167 fa.name = fb.nextName()
3168 fb.emit(fa)
3169 v = fb.coerceToInterface(v, ft)
3170 fb.emitStore(fa, v)
3171 }
3172 }
3173 posIdx++
3174 }
3175 }
3176 return fb.emitLoad(alloc, typ)
3177 }
3178
3179 func (fb *ssaFuncBuilder) buildArrayLit(e *CompositeLit, typ Type, ar *Array) SSAValue {
3180 if ar.Len() < 0 {
3181 ar = NewArray(ar.Elem(), int64(len(e.ElemList)))
3182 typ = ar
3183 }
3184 alloc := fb.emitAlloc(typ, 0)
3185 elemTyp := ar.Elem()
3186 for i, el := range e.ElemList {
3187 var expr Expr
3188 if kv, ok := el.(*KeyValueExpr); ok {
3189 expr = kv.Value
3190 } else {
3191 expr = el
3192 }
3193 var v SSAValue
3194 if cl, ok := expr.(*CompositeLit); ok && cl.Type == nil {
3195 v = fb.buildCompositeLitWithType(cl, elemTyp)
3196 } else {
3197 v = fb.buildExpr(expr)
3198 }
3199 if v == nil {
3200 continue
3201 }
3202 idx := &SSAConst{typ: Typ[Int32], val: constInt{int64(i)}}
3203 ia := &SSAIndexAddr{X: alloc, Index: idx}
3204 ia.typ = NewPointer(elemTyp)
3205 ia.name = fb.nextName()
3206 fb.emit(ia)
3207 v = fb.coerceToInterface(v, elemTyp)
3208 fb.emitStore(ia, v)
3209 }
3210 return fb.emitLoad(alloc, typ)
3211 }
3212
3213 func (fb *ssaFuncBuilder) buildCompositeLitWithType(e *CompositeLit, typ Type) SSAValue {
3214 if sl, ok := safeUnderlying(typ).(*Slice); ok {
3215 return fb.buildSliceLit(e, typ, sl)
3216 }
3217 if ar, isArr := safeUnderlying(typ).(*Array); isArr {
3218 return fb.buildArrayLit(e, typ, ar)
3219 }
3220 alloc := fb.emitAlloc(typ, 0)
3221 posIdx := 0
3222 for _, el := range e.ElemList {
3223 if kv, ok := el.(*KeyValueExpr); ok {
3224 if _, ok2 := safeUnderlying(typ).(*TCStruct); ok2 {
3225 idx := fb.fieldIndex(typ, kv.Key.(*Name).Value)
3226 if idx >= 0 {
3227 ft := fb.fieldType(typ, idx)
3228 fa := &SSAFieldAddr{X: alloc, Field: idx}
3229 fa.typ = NewPointer(ft)
3230 fa.name = fb.nextName()
3231 fb.emit(fa)
3232 v := fb.buildExpr(kv.Value)
3233 if v != nil {
3234 v = fb.coerceToInterface(v, ft)
3235 fb.emitStore(fa, v)
3236 }
3237 }
3238 }
3239 } else {
3240 v := fb.buildExpr(el)
3241 if v != nil {
3242 if _, ok2 := safeUnderlying(typ).(*TCStruct); ok2 {
3243 ft := fb.fieldType(typ, posIdx)
3244 fa := &SSAFieldAddr{X: alloc, Field: posIdx}
3245 fa.typ = NewPointer(ft)
3246 fa.name = fb.nextName()
3247 fb.emit(fa)
3248 v = fb.coerceToInterface(v, ft)
3249 fb.emitStore(fa, v)
3250 }
3251 }
3252 posIdx++
3253 }
3254 }
3255 return fb.emitLoad(alloc, typ)
3256 }
3257
3258 func (fb *ssaFuncBuilder) buildSliceLit(e *CompositeLit, typ Type, sl *Slice) SSAValue {
3259 n := len(e.ElemList)
3260 nVal := &SSAConst{typ: Typ[Int32], val: constInt{int64(n)}}
3261 ms := &SSAMakeSlice{}
3262 ms.typ = typ
3263 ms.name = fb.nextName()
3264 ms.Len = nVal
3265 ms.Cap = nVal
3266 fb.emit(ms)
3267
3268 for i, el := range e.ElemList {
3269 var v SSAValue
3270 if kv, ok := el.(*KeyValueExpr); ok {
3271 v = fb.buildExpr(kv.Value)
3272 } else {
3273 v = fb.buildExpr(el)
3274 }
3275 if v == nil {
3276 continue
3277 }
3278 idx := &SSAConst{typ: Typ[Int32], val: constInt{int64(i)}}
3279 ia := &SSAIndexAddr{X: ms, Index: idx}
3280 ia.typ = NewPointer(sl.Elem())
3281 ia.name = fb.nextName()
3282 fb.emit(ia)
3283 v = fb.coerceToInterface(v, sl.Elem())
3284 fb.emitStore(ia, v)
3285 }
3286 return ms
3287 }
3288
3289 func (fb *ssaFuncBuilder) buildFuncLit(e *FuncLit) SSAValue {
3290 var sig *Signature
3291 if fb.info != nil {
3292 if tv, ok := fb.info.Types[e]; ok {
3293 if okv, okok := tv.Type.(*Signature); okok {
3294 sig = okv
3295 }
3296 }
3297 }
3298 if sig == nil && e.Type != nil {
3299 sig = tcResolveFuncInline(e.Type, fb.fn.Pkg.Pkg.Scope())
3300 }
3301 name := fb.fn.name | "__anon" | ssaItoa(len(fb.fn.AnonFuncs)+1)
3302 anon := &SSAFunction{
3303 name: name,
3304 Signature: sig,
3305 pos: 0,
3306 Pkg: fb.fn.Pkg,
3307 Prog: fb.fn.Prog,
3308 parent: fb.fn,
3309 }
3310 fb.fn.AnonFuncs = append(fb.fn.AnonFuncs, anon)
3311
3312 ab := newSSAFuncBuilder(anon, fb.info)
3313 ab.parent = fb
3314 ab.srcScope = fb.srcScope
3315 ab.typeSubst = fb.typeSubst
3316 d := &FuncDecl{
3317 Name: &Name{Value: name},
3318 Type: e.Type,
3319 Body: e.Body,
3320 }
3321 ab.buildBody(d)
3322
3323 if len(anon.FreeVars) == 0 {
3324 return anon
3325 }
3326 bindings := []SSAValue{:0:len(anon.FreeVars)}
3327 for _, fv := range anon.FreeVars {
3328 obj := fb.lookupObject(fv.name)
3329 if obj != nil {
3330 if alloc, ok := fb.vars[obj]; ok {
3331 alloc.Heap = true
3332 bindings = append(bindings, alloc)
3333 } else if pfv, ok := fb.freeVarPtrs[fv.name]; ok {
3334 bindings = append(bindings, pfv)
3335 } else {
3336 bindings = append(bindings, &SSAConst{typ: NewPointer(fv.typ), val: nil})
3337 }
3338 } else {
3339 bindings = append(bindings, &SSAConst{typ: NewPointer(fv.typ), val: nil})
3340 }
3341 }
3342 mc := &SSAMakeClosure{Fn: anon, Bindings: bindings}
3343 mc.typ = sig
3344 mc.name = fb.nextName()
3345 fb.emit(mc)
3346 return mc
3347 }
3348
3349 func ssaExtractConst(v SSAValue) *SSAConst {
3350 if c, ok := v.(*SSAConst); ok {
3351 return c
3352 }
3353 if conv, ok := v.(*SSAConvert); ok {
3354 if c, ok2 := conv.X.(*SSAConst); ok2 {
3355 return &SSAConst{typ: conv.SSAType(), val: c.val}
3356 }
3357 }
3358 return nil
3359 }
3360
3361 func (fb *ssaFuncBuilder) saveVars() map[Object]*SSAAlloc {
3362 saved := map[Object]*SSAAlloc{}
3363 for k, v := range fb.vars {
3364 saved[k] = v
3365 }
3366 return saved
3367 }
3368
3369 func (fb *ssaFuncBuilder) removeVar(name string) {
3370 for o := range fb.vars {
3371 if o.Name() == name {
3372 delete(fb.vars, o)
3373 return
3374 }
3375 }
3376 }
3377
3378
3379 func (fb *ssaFuncBuilder) buildPkgMemberAddr(pn *PkgName, memberName string) SSAValue {
3380 imported := pn.Imported()
3381 if imported == nil {
3382 return nil
3383 }
3384 obj := imported.Scope().Lookup(memberName)
3385 if obj == nil {
3386 return nil
3387 }
3388 switch obj := obj.(type) {
3389 case *TCConst:
3390 return nil
3391 case *TCVar:
3392 impPkg := fb.ensureImportedSSAPackage(imported)
3393 g, ok := impPkg.Members[memberName].(*SSAGlobal)
3394 if !ok {
3395 g = &SSAGlobal{
3396 name: memberName,
3397 typ: NewPointer(obj.Type()),
3398 pkg: impPkg,
3399 }
3400 impPkg.Members[memberName] = g
3401 }
3402 return g
3403 }
3404 return nil
3405 }
3406
3407 func (fb *ssaFuncBuilder) buildPkgCall(pn *PkgName, funcName string, argList []Expr, hasDots bool) SSAValue {
3408 imported := pn.Imported()
3409 if imported == nil {
3410 return nil
3411 }
3412 if imported.Path() == "unsafe" && funcName == "Slice" {
3413 return fb.buildUnsafeSlice(argList)
3414 }
3415 if imported.Path() == "unsafe" && (funcName == "SliceData" || funcName == "StringData") {
3416 arg := fb.buildExpr(argList[0])
3417 extract := &SSAExtract{Tuple: arg, Index: 0}
3418 extract.typ = Typ[UnsafePointer]
3419 extract.name = fb.nextName()
3420 extract.setBlock(fb.currentBlock)
3421 fb.currentBlock.Instrs = append(fb.currentBlock.Instrs, extract)
3422 return extract
3423 }
3424 if result := fb.tryGenericPkgCall(pn, funcName, argList, hasDots); result != nil {
3425 return result
3426 }
3427 obj := imported.Scope().Lookup(funcName)
3428 if obj == nil {
3429 return nil
3430 }
3431 fn, ok := obj.(*TCFunc)
3432 if !ok {
3433 if v, ok2 := obj.(*TCVar); ok2 && v.Type() != nil {
3434 if sig, ok3 := safeUnderlying(v.Type()).(*Signature); ok3 {
3435 impPkg := fb.ensureImportedSSAPackage(imported)
3436 gv, ok4 := impPkg.Members[funcName].(*SSAGlobal)
3437 if !ok4 {
3438 gv = &SSAGlobal{name: funcName, typ: NewPointer(v.Type()), pkg: impPkg}
3439 impPkg.Members[funcName] = gv
3440 }
3441 load := fb.emitLoad(gv, v.Type())
3442 args := fb.buildArgs(argList)
3443 if sig.Variadic() && !hasDots {
3444 args = fb.wrapVariadicArgs(args, sig)
3445 }
3446 args = fb.coerceArgsToInterface(args, sig)
3447 var retType Type
3448 if sig.Results() != nil && sig.Results().Len() == 1 {
3449 retType = sig.Results().At(0).Type()
3450 } else if sig.Results() != nil && sig.Results().Len() > 1 {
3451 retType = sig.Results()
3452 }
3453 call := &SSACall{Call: SSACallCommon{Value: load, Args: args}}
3454 call.typ = retType
3455 call.name = fb.nextName()
3456 fb.emit(call)
3457 if retType == nil {
3458 return nil
3459 }
3460 return call
3461 }
3462 }
3463 return nil
3464 }
3465 impPkg := fb.ensureImportedSSAPackage(imported)
3466 ssaFn := impPkg.Func(funcName)
3467 if ssaFn == nil {
3468 ssaFn = &SSAFunction{
3469 name: funcName,
3470 object: fn,
3471 Signature: fn.Type().(*Signature),
3472 Pkg: impPkg,
3473 Prog: fb.fn.Prog,
3474 }
3475 if isNoContextExtern(imported.Path(), funcName) {
3476 ssaFn.isExternC = true
3477 }
3478 impPkg.Members[funcName] = ssaFn
3479 }
3480 args := fb.buildArgs(argList)
3481 var retType Type
3482 if ssaFn.Signature != nil {
3483 if ssaFn.Signature.Variadic() && !hasDots {
3484 args = fb.wrapVariadicArgs(args, ssaFn.Signature)
3485 }
3486 args = fb.coerceArgsToInterface(args, ssaFn.Signature)
3487 if ssaFn.Signature.Results() != nil && ssaFn.Signature.Results().Len() == 1 {
3488 retType = ssaFn.Signature.Results().At(0).Type()
3489 } else if ssaFn.Signature.Results() != nil && ssaFn.Signature.Results().Len() > 1 {
3490 retType = ssaFn.Signature.Results()
3491 }
3492 }
3493 call := &SSACall{Call: SSACallCommon{Value: ssaFn, Args: args}}
3494 call.typ = retType
3495 call.name = fb.nextName()
3496 fb.emit(call)
3497 if retType == nil {
3498 return nil
3499 }
3500 return call
3501 }
3502
3503 func (fb *ssaFuncBuilder) buildUnsafeSlice(argList []Expr) SSAValue {
3504 if len(argList) < 2 {
3505 return nil
3506 }
3507 ptrVal := fb.buildExpr(argList[0])
3508 lenVal := fb.buildExpr(argList[1])
3509 if ptrVal == nil || lenVal == nil {
3510 return nil
3511 }
3512 var elemType Type
3513 if pt, ok := safeUnderlying(ptrVal.SSAType()).(*Pointer); ok {
3514 elemType = pt.Elem()
3515 }
3516 if elemType == nil {
3517 elemType = Typ[Uint8]
3518 }
3519 ms := &SSAMakeSlice{Len: lenVal, Cap: lenVal, Data: ptrVal}
3520 if b, ok := elemType.(*Basic); ok && b.kind == Uint8 {
3521 ms.typ = Typ[TCString]
3522 } else {
3523 ms.typ = NewSlice(elemType)
3524 }
3525 ms.name = fb.nextName()
3526 fb.emit(ms)
3527 return ms
3528 }
3529
3530 // Helpers.
3531
3532 func (fb *ssaFuncBuilder) lookupObject(name string) Object {
3533 for obj := range fb.vars {
3534 if obj.Name() == name {
3535 return obj
3536 }
3537 }
3538 p := fb.parent
3539 for p != nil {
3540 for obj := range p.vars {
3541 if obj.Name() == name {
3542 return obj
3543 }
3544 }
3545 p = p.parent
3546 }
3547 if fb.srcScope != nil {
3548 if _, obj := fb.srcScope.LookupParent(name); obj != nil {
3549 return obj
3550 }
3551 }
3552 if fb.fn.Pkg != nil {
3553 if _, obj := fb.fn.Pkg.Pkg.Scope().LookupParent(name); obj != nil {
3554 return obj
3555 }
3556 }
3557 if fb.info != nil {
3558 return nil
3559 }
3560 return nil
3561 }
3562
3563 func (fb *ssaFuncBuilder) evalConstArrayLen(e Expr) int64 {
3564 switch e := e.(type) {
3565 case *BasicLit:
3566 return ssaParseInt64(e.Value)
3567 case *Name:
3568 if fb.localConsts != nil {
3569 if c, ok := fb.localConsts[e.Value]; ok {
3570 if ci, ok2 := c.val.(constInt); ok2 {
3571 return ci.v
3572 }
3573 }
3574 }
3575 obj := fb.lookupObject(e.Value)
3576 if c, ok := obj.(*TCConst); ok && c.val != nil {
3577 if ci, ok2 := c.val.(constInt); ok2 {
3578 return ci.v
3579 }
3580 }
3581 if constValMap != nil {
3582 if v, ok := constValMap[e.Value]; ok {
3583 return v
3584 }
3585 }
3586 case *Operation:
3587 if e.Y == nil {
3588 x := fb.evalConstArrayLen(e.X)
3589 if x < 0 {
3590 return -1
3591 }
3592 if e.Op == Sub {
3593 return -x
3594 }
3595 return x
3596 }
3597 x := fb.evalConstArrayLen(e.X)
3598 y := fb.evalConstArrayLen(e.Y)
3599 if x < 0 || y < 0 {
3600 return -1
3601 }
3602 switch e.Op {
3603 case Add:
3604 return x + y
3605 case Sub:
3606 return x - y
3607 case Mul:
3608 return x * y
3609 case Div:
3610 if y == 0 {
3611 return -1
3612 }
3613 return x / y
3614 case Shl:
3615 return x << uint32(y)
3616 case Shr:
3617 return x >> uint32(y)
3618 case And:
3619 return x & y
3620 case Or:
3621 return x | y
3622 }
3623 case *ParenExpr:
3624 return fb.evalConstArrayLen(e.X)
3625 }
3626 return -1
3627 }
3628
3629 func (fb *ssaFuncBuilder) getOrCreateFreeVar(name string, typ Type) SSAValue {
3630 for _, fv := range fb.fn.FreeVars {
3631 if fv.name == name {
3632 return fv
3633 }
3634 }
3635 fv := &SSAFreeVar{
3636 name: name,
3637 typ: typ,
3638 parent: fb.fn,
3639 }
3640 fb.fn.FreeVars = append(fb.fn.FreeVars, fv)
3641 if fb.freeVarPtrs == nil {
3642 fb.freeVarPtrs = map[string]*SSAFreeVar{}
3643 }
3644 fb.freeVarPtrs[name] = fv
3645 return fv
3646 }
3647
3648 func (fb *ssaFuncBuilder) ensureFreeVarChain(name string, typ Type) {
3649 var chain []*ssaFuncBuilder
3650 p := fb.parent
3651 for p != nil {
3652 hasVar := false
3653 if _, ok := p.vars[fb.lookupObject(name)]; ok {
3654 hasVar = true
3655 }
3656 if p.freeVarPtrs != nil {
3657 if _, ok := p.freeVarPtrs[name]; ok {
3658 hasVar = true
3659 }
3660 }
3661 if hasVar {
3662 break
3663 }
3664 chain = append(chain, p)
3665 p = p.parent
3666 }
3667 for i := len(chain) - 1; i >= 0; i-- {
3668 chain[i].getOrCreateFreeVar(name, typ)
3669 }
3670 }
3671
3672 func (fb *ssaFuncBuilder) lookupVar(name string) *TCVar {
3673 obj := fb.lookupObject(name)
3674 var v *TCVar
3675 if okv, okok := obj.(*TCVar); okok {
3676 v = okv
3677 }
3678 return v
3679 }
3680
3681 func (fb *ssaFuncBuilder) resolveMethodCallWithRecv(sel *SelectorExpr, recv SSAValue) (*SSAFunction, SSAValue) {
3682 typ := recv.SSAType()
3683 isPtr := false
3684 if p, ok := safeUnderlying(typ).(*Pointer); ok {
3685 typ = p.Elem()
3686 isPtr = true
3687 }
3688 if _, ok := safeUnderlying(typ).(*TCInterface); ok {
3689 return nil, nil
3690 }
3691 named, ok := typ.(*Named)
3692 if !ok {
3693 return nil, nil
3694 }
3695 typeName := ""
3696 if named.Obj() != nil {
3697 typeName = named.Obj().Name()
3698 }
3699 if typeName == "" {
3700 return nil, nil
3701 }
3702 mangledName := typeName | "." | sel.Sel.Value
3703 isExternal := named.Obj() != nil && named.Obj().Pkg() != nil && named.Obj().Pkg().Path() != fb.fn.Pkg.Pkg.Path()
3704 var fn *SSAFunction
3705 if !isExternal {
3706 if okv, okok := fb.fn.Pkg.Members[mangledName].(*SSAFunction); okok {
3707 fn = okv
3708 }
3709 }
3710 if fn == nil {
3711 extKey := mangledName
3712 if isExternal {
3713 extKey = named.Obj().Pkg().Path() | "." | mangledName
3714 }
3715 for i := 0; i < named.NumMethods(); i++ {
3716 m := named.Method(i)
3717 if m.Name() == sel.Sel.Value {
3718 fn = fb.fn.Pkg.ExternalFunc(extKey, m.Signature())
3719 if isExternal {
3720 fn.externalSymbol = extKey
3721 }
3722 break
3723 }
3724 }
3725 }
3726 if fn != nil {
3727 if fn.Signature != nil && fn.Signature.Recv() != nil {
3728 recvParam := fn.Signature.Recv()
3729 _, recvIsPtr := safeUnderlying(recvParam.Type()).(*Pointer)
3730 if recvIsPtr && !isPtr {
3731 if nameExpr, ok2 := sel.X.(*Name); ok2 {
3732 obj := fb.lookupObject(nameExpr.Value)
3733 if obj != nil {
3734 if alloc, ok3 := fb.vars[obj]; ok3 {
3735 recv = alloc
3736 }
3737 }
3738 } else if innerSel, ok2 := sel.X.(*SelectorExpr); ok2 {
3739 addr := fb.buildSelectorAddr(innerSel)
3740 if addr != nil {
3741 recv = addr
3742 }
3743 }
3744 }
3745 }
3746 return fn, recv
3747 }
3748 st, ok2 := safeUnderlying(named).(*TCStruct)
3749 if !ok2 || st == nil {
3750 return nil, nil
3751 }
3752 if !isPtr {
3753 fixed := false
3754 if innerSel, ok3 := sel.X.(*SelectorExpr); ok3 {
3755 addr := fb.buildSelectorAddr(innerSel)
3756 if addr != nil {
3757 recv = addr
3758 fixed = true
3759 }
3760 }
3761 if !fixed {
3762 if nameExpr, ok3 := sel.X.(*Name); ok3 {
3763 obj := fb.lookupObject(nameExpr.Value)
3764 if obj != nil {
3765 if a, ok4 := fb.vars[obj]; ok4 {
3766 recv = a
3767 fixed = true
3768 }
3769 }
3770 }
3771 }
3772 if !fixed {
3773 alloc := &SSAAlloc{}
3774 alloc.typ = NewPointer(recv.SSAType())
3775 alloc.name = fb.nextName()
3776 fb.emit(alloc)
3777 storeOp := &SSAStore{Addr: alloc, Val: recv}
3778 fb.emit(storeOp)
3779 recv = alloc
3780 }
3781 }
3782 return fb.resolveEmbeddedMethod(st, recv, sel.Sel.Value, 4)
3783 }
3784
3785 func (fb *ssaFuncBuilder) resolveEmbeddedMethod(st *TCStruct, recv SSAValue, methodName string, maxDepth int) (*SSAFunction, SSAValue) {
3786 if maxDepth <= 0 || st == nil {
3787 return nil, nil
3788 }
3789 for i := 0; i < st.NumFields(); i++ {
3790 f := st.Field(i)
3791 if !f.Anonymous() {
3792 continue
3793 }
3794 embedType := f.Type()
3795 embedNamed, ok3 := embedType.(*Named)
3796 if !ok3 {
3797 if p, ok4 := embedType.(*Pointer); ok4 {
3798 embedNamed, ok3 = p.Elem().(*Named)
3799 }
3800 }
3801 if !ok3 || embedNamed.Obj() == nil {
3802 continue
3803 }
3804 embedName := embedNamed.Obj().Name()
3805 embedMangledName := embedName | "." | methodName
3806 var embedFn *SSAFunction
3807 if okv, okok := fb.fn.Pkg.Members[embedMangledName].(*SSAFunction); okok {
3808 embedFn = okv
3809 }
3810 if embedFn != nil {
3811 fieldAddr := &SSAFieldAddr{X: recv, Field: i}
3812 fieldAddr.typ = NewPointer(embedType)
3813 fieldAddr.name = fb.nextName()
3814 fb.emit(fieldAddr)
3815 var embedRecv SSAValue = fieldAddr
3816 if _, isEmbedPtr := safeUnderlying(embedType).(*Pointer); isEmbedPtr {
3817 ld := &SSAUnOp{Op: OpMul, X: fieldAddr}
3818 ld.typ = embedType
3819 ld.name = fb.nextName()
3820 fb.emit(ld)
3821 embedRecv = ld
3822 }
3823 return embedFn, embedRecv
3824 }
3825 embedSt, ok5 := safeUnderlying(embedNamed).(*TCStruct)
3826 if !ok5 || embedSt == nil {
3827 continue
3828 }
3829 fieldAddr := &SSAFieldAddr{X: recv, Field: i}
3830 fieldAddr.typ = NewPointer(embedType)
3831 fieldAddr.name = fb.nextName()
3832 fb.emit(fieldAddr)
3833 var nextRecv SSAValue = fieldAddr
3834 if _, isEmbedPtr := safeUnderlying(embedType).(*Pointer); isEmbedPtr {
3835 ld := &SSAUnOp{Op: OpMul, X: fieldAddr}
3836 ld.typ = embedType
3837 ld.name = fb.nextName()
3838 fb.emit(ld)
3839 nextRecv = ld
3840 }
3841 if fn, r := fb.resolveEmbeddedMethod(embedSt, nextRecv, methodName, maxDepth-1); fn != nil {
3842 return fn, r
3843 }
3844 }
3845 return nil, nil
3846 }
3847
3848 func (fb *ssaFuncBuilder) buildIfaceMethodCall(sel *SelectorExpr, recv SSAValue, argExprs []Expr) SSAValue {
3849 typ := recv.SSAType()
3850 if p, ok := safeUnderlying(typ).(*Pointer); ok {
3851 typ = p.Elem()
3852 }
3853 iface, ok := safeUnderlying(typ).(*TCInterface)
3854 if !ok {
3855 return nil
3856 }
3857 methodSig := findIfaceMethod(iface, sel.Sel.Value)
3858 var retType Type
3859 if methodSig != nil && methodSig.Results() != nil {
3860 if methodSig.Results().Len() == 1 {
3861 retType = methodSig.Results().At(0).Type()
3862 } else if methodSig.Results().Len() > 1 {
3863 retType = methodSig.Results()
3864 }
3865 }
3866 args := fb.buildArgs(argExprs)
3867 inv := &SSAInvoke{
3868 X: recv,
3869 MethodName: sel.Sel.Value,
3870 IfaceType: iface,
3871 Args: args,
3872 }
3873 inv.typ = retType
3874 inv.name = fb.nextName()
3875 fb.emit(inv)
3876 return inv
3877 }
3878
3879 func findIfaceMethod(iface *TCInterface, name string) *Signature {
3880 for i := 0; i < iface.NumMethods(); i++ {
3881 if iface.Method(i).Name() == name {
3882 return iface.Method(i).Sig()
3883 }
3884 }
3885 for j := 0; j < iface.NumEmbeddeds(); j++ {
3886 if ei, ok := safeUnderlying(iface.EmbeddedType(j)).(*TCInterface); ok {
3887 if sig := findIfaceMethod(ei, name); sig != nil {
3888 return sig
3889 }
3890 }
3891 }
3892 return nil
3893 }
3894
3895 func (fb *ssaFuncBuilder) resolveType(e Expr) Type {
3896 if fb.info != nil {
3897 if tv, ok := fb.info.Types[e]; ok && tv.Type != nil {
3898 return tv.Type
3899 }
3900 }
3901 return fb.resolveTypeAST(e)
3902 }
3903
3904 func (fb *ssaFuncBuilder) resolveTypeAST(e Expr) Type {
3905 if e == nil {
3906 return nil
3907 }
3908 switch e := e.(type) {
3909 case *Name:
3910 if fb.typeSubst != nil {
3911 if t, ok := fb.typeSubst[e.Value]; ok {
3912 return t
3913 }
3914 }
3915 if t, ok := fb.localTypes[e.Value]; ok {
3916 return t
3917 }
3918 obj := fb.lookupObject(e.Value)
3919 if tn, ok := obj.(*TypeName); ok {
3920 if tp, ok2 := tn.Type().(*TypeParam); ok2 && fb.typeSubst != nil {
3921 if t, ok3 := fb.typeSubst[tp.String()]; ok3 {
3922 return t
3923 }
3924 }
3925 return tn.Type()
3926 }
3927 case *Operation:
3928 if e.Y == nil && e.Op == Mul {
3929 base := fb.resolveTypeAST(e.X)
3930 if base != nil {
3931 return NewPointer(base)
3932 }
3933 }
3934 case *SliceType:
3935 elem := fb.resolveTypeAST(e.Elem)
3936 if elem != nil {
3937 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3938 return Typ[TCString]
3939 }
3940 return NewSlice(elem)
3941 }
3942 case *ArrayType:
3943 elem := fb.resolveTypeAST(e.Elem)
3944 if elem != nil {
3945 n := int64(-1)
3946 if lit, ok := e.Len.(*BasicLit); ok {
3947 n = ssaParseInt64(lit.Value)
3948 } else if e.Len != nil {
3949 n = fb.evalConstArrayLen(e.Len)
3950 }
3951 return NewArray(elem, n)
3952 }
3953 case *MapType:
3954 key := fb.resolveTypeAST(e.Key)
3955 val := fb.resolveTypeAST(e.Value)
3956 if key != nil && val != nil {
3957 return NewTCMap(key, val)
3958 }
3959 case *StructType:
3960 return fb.resolveStructTypeAST(e)
3961 case *InterfaceType:
3962 return fb.resolveInterfaceTypeAST(e)
3963 case *ChanType:
3964 elem := fb.resolveTypeAST(e.Elem)
3965 if elem == nil {
3966 elem = NewTCStruct(nil, nil)
3967 }
3968 var dir TCChanDir
3969 switch e.Dir {
3970 case SendOnly:
3971 dir = TCSendOnly
3972 case RecvOnly:
3973 dir = TCRecvOnly
3974 default:
3975 dir = TCSendRecv
3976 }
3977 return NewTCChan(dir, elem)
3978 case *FuncType:
3979 return fb.resolveFuncTypeAST(e)
3980 case *SelectorExpr:
3981 if x, ok := e.X.(*Name); ok {
3982 obj := fb.lookupObject(x.Value)
3983 if pn, ok2 := obj.(*PkgName); ok2 && pn.Imported() != nil {
3984 sel := pn.Imported().Scope().Lookup(e.Sel.Value)
3985 if tn, ok3 := sel.(*TypeName); ok3 {
3986 return tn.Type()
3987 }
3988 }
3989 }
3990 case *ParenExpr:
3991 return fb.resolveTypeAST(e.X)
3992 case *DotsType:
3993 elem := fb.resolveTypeAST(e.Elem)
3994 if elem != nil {
3995 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3996 return Typ[TCString]
3997 }
3998 return NewSlice(elem)
3999 }
4000 }
4001 return nil
4002 }
4003
4004 func (fb *ssaFuncBuilder) resolveInterfaceTypeAST(e *InterfaceType) *TCInterface {
4005 var methods []*IfaceMethod
4006 for _, f := range e.MethodList {
4007 if f.Name == nil {
4008 continue
4009 }
4010 ft, ok := f.Type.(*FuncType)
4011 if !ok {
4012 continue
4013 }
4014 sig := fb.resolveFuncTypeAST(ft)
4015 if sig != nil {
4016 methods = append(methods, NewTCIfaceMethod(f.Name.Value, sig))
4017 }
4018 }
4019 iface := NewTCInterface(methods, nil)
4020 iface.Complete()
4021 return iface
4022 }
4023
4024 func (fb *ssaFuncBuilder) resolveStructTypeAST(e *StructType) *TCStruct {
4025 var fields []*TCVar
4026 var tags []string
4027 for i, f := range e.FieldList {
4028 typ := fb.resolveTypeAST(f.Type)
4029 if typ == nil {
4030 return nil
4031 }
4032 name := ""
4033 if f.Name != nil {
4034 name = f.Name.Value
4035 }
4036 fields = append(fields, NewTCField(fb.fn.Pkg.Pkg, name, typ, f.Name == nil))
4037 tag := ""
4038 if i < len(e.TagList) && e.TagList[i] != nil {
4039 tag = e.TagList[i].Value
4040 }
4041 tags = append(tags, tag)
4042 }
4043 return NewTCStruct(fields, tags)
4044 }
4045
4046 func (fb *ssaFuncBuilder) resolveFuncTypeAST(ft *FuncType) *Signature {
4047 if ft == nil {
4048 return nil
4049 }
4050 var params []*TCVar
4051 for _, p := range ft.ParamList {
4052 typ := fb.resolveTypeAST(p.Type)
4053 pname := ""
4054 if p.Name != nil {
4055 pname = p.Name.Value
4056 }
4057 params = append(params, NewTCVar(nil, pname, typ))
4058 }
4059 var results []*TCVar
4060 for _, r := range ft.ResultList {
4061 typ := fb.resolveTypeAST(r.Type)
4062 rname := ""
4063 if r.Name != nil {
4064 rname = r.Name.Value
4065 }
4066 results = append(results, NewTCVar(nil, rname, typ))
4067 }
4068 variadic := false
4069 if len(ft.ParamList) > 0 {
4070 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
4071 variadic = true
4072 }
4073 }
4074 var pTuple, rTuple *Tuple
4075 if len(params) > 0 {
4076 pTuple = NewTuple(params...)
4077 }
4078 if len(results) > 0 {
4079 rTuple = NewTuple(results...)
4080 }
4081 return NewSignature(nil, pTuple, rTuple, variadic)
4082 }
4083
4084 func (fb *ssaFuncBuilder) fieldIndex(t Type, name string) int32 {
4085 if t == nil {
4086 return -1
4087 }
4088 if pt, ok := safeUnderlying(t).(*Pointer); ok {
4089 t = pt.Elem()
4090 }
4091 if st, ok := safeUnderlying(t).(*TCStruct); ok && st != nil {
4092 for i := 0; i < st.NumFields(); i++ {
4093 if st.Field(i).Name() == name {
4094 return i
4095 }
4096 }
4097 }
4098 return -1
4099 }
4100
4101 func (fb *ssaFuncBuilder) findEmbeddedField(t Type, name string) (embedIdx int32, innerIdx int32) {
4102 path := fb.findEmbeddedFieldPath(t, name)
4103 if len(path) < 2 {
4104 return -1, -1
4105 }
4106 return path[0], path[1]
4107 }
4108
4109 func (fb *ssaFuncBuilder) findEmbeddedFieldPath(t Type, name string) []int32 {
4110 if t == nil {
4111 return nil
4112 }
4113 if pt, ok := safeUnderlying(t).(*Pointer); ok {
4114 t = pt.Elem()
4115 }
4116 st, ok := safeUnderlying(t).(*TCStruct)
4117 if !ok || st == nil {
4118 return nil
4119 }
4120 for i := 0; i < st.NumFields(); i++ {
4121 f := st.Field(i)
4122 if !f.Anonymous() {
4123 continue
4124 }
4125 embedType := f.Type()
4126 if pt, ok := safeUnderlying(embedType).(*Pointer); ok {
4127 embedType = pt.Elem()
4128 }
4129 inner := fb.fieldIndex(embedType, name)
4130 if inner >= 0 {
4131 return []int32{i, inner}
4132 }
4133 sub := fb.findEmbeddedFieldPath(embedType, name)
4134 if len(sub) > 0 {
4135 return append([]int32{i}, sub...)
4136 }
4137 }
4138 return nil
4139 }
4140
4141 func (fb *ssaFuncBuilder) fieldType(t Type, idx int32) Type {
4142 if t == nil {
4143 return nil
4144 }
4145 if pt, ok := safeUnderlying(t).(*Pointer); ok {
4146 t = pt.Elem()
4147 }
4148 if st, ok := safeUnderlying(t).(*TCStruct); ok && st != nil {
4149 if idx >= 0 && idx < st.NumFields() {
4150 return st.Field(idx).Type()
4151 }
4152 }
4153 return nil
4154 }
4155
4156 func ssaExprNames(e Expr) []*Name {
4157 if e == nil {
4158 return nil
4159 }
4160 if n, ok := e.(*Name); ok {
4161 return []*Name{n}
4162 }
4163 if l, ok := e.(*ListExpr); ok {
4164 var names []*Name
4165 for _, el := range l.ElemList {
4166 if n, ok := el.(*Name); ok {
4167 names = append(names, n)
4168 }
4169 }
4170 return names
4171 }
4172 return nil
4173 }
4174
4175 func localizeConstVal(val ConstVal, typ Type) ConstVal {
4176 if val == nil {
4177 return nil
4178 }
4179 return val
4180 }
4181
4182 func mangleGenericName(baseName string, typeArgs []Type) string {
4183 s := baseName | "__"
4184 for i, t := range typeArgs {
4185 if i > 0 {
4186 s = s | "_"
4187 }
4188 if t == nil {
4189 s = s | "nil"
4190 } else {
4191 ts := t.String()
4192 for j := 0; j < len(ts); j++ {
4193 c := ts[j]
4194 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') {
4195 s = s | string([]byte{c})
4196 } else if c == '.' {
4197 s = s | "."
4198 } else {
4199 s = s | "_"
4200 }
4201 }
4202 }
4203 }
4204 return s
4205 }
4206
4207 func resolveTypeExprWithSubst(e Expr, typeSubst map[string]Type, pkgScope *Scope) Type {
4208 if e == nil {
4209 return nil
4210 }
4211 switch e := e.(type) {
4212 case *Name:
4213 if t, ok := typeSubst[e.Value]; ok {
4214 return t
4215 }
4216 _, obj := Universe.LookupParent(e.Value)
4217 if obj != nil {
4218 if tn, ok := obj.(*TypeName); ok {
4219 return tn.typ
4220 }
4221 }
4222 if pkgScope != nil {
4223 tobj := pkgScope.Lookup(e.Value)
4224 if tobj != nil {
4225 if tn, ok := tobj.(*TypeName); ok {
4226 return tn.typ
4227 }
4228 }
4229 }
4230 if importRegistry != nil {
4231 var regKeys []string
4232 for k := range importRegistry {
4233 regKeys = append(regKeys, k)
4234 }
4235 for i := 1; i < len(regKeys); i++ {
4236 for j := i; j > 0 && regKeys[j] < regKeys[j-1]; j-- {
4237 regKeys[j], regKeys[j-1] = regKeys[j-1], regKeys[j]
4238 }
4239 }
4240 for _, k := range regKeys {
4241 pkg := importRegistry[k]
4242 tobj := pkg.Scope().Lookup(e.Value)
4243 if tobj != nil {
4244 if tn, ok := tobj.(*TypeName); ok {
4245 return tn.typ
4246 }
4247 }
4248 }
4249 }
4250 return nil
4251 case *DotsType:
4252 elem := resolveTypeExprWithSubst(e.Elem, typeSubst, pkgScope)
4253 if elem != nil {
4254 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
4255 return Typ[TCString]
4256 }
4257 return NewSlice(elem)
4258 }
4259 case *SliceType:
4260 elem := resolveTypeExprWithSubst(e.Elem, typeSubst, pkgScope)
4261 if elem != nil {
4262 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
4263 return Typ[TCString]
4264 }
4265 return NewSlice(elem)
4266 }
4267 case *Operation:
4268 if e.Y == nil && e.Op == Mul {
4269 base := resolveTypeExprWithSubst(e.X, typeSubst, pkgScope)
4270 if base != nil {
4271 return NewPointer(base)
4272 }
4273 }
4274 case *MapType:
4275 key := resolveTypeExprWithSubst(e.Key, typeSubst, pkgScope)
4276 val := resolveTypeExprWithSubst(e.Value, typeSubst, pkgScope)
4277 if key != nil && val != nil {
4278 return NewTCMap(key, val)
4279 }
4280 case *FuncType:
4281 return resolveSignatureWithSubst(e, typeSubst, pkgScope)
4282 case *IndexExpr:
4283 return resolveTypeExprWithSubst(e.X, typeSubst, pkgScope)
4284 case *SelectorExpr:
4285 if pkgName, ok := e.X.(*Name); ok {
4286 if importRegistry != nil {
4287 var regKeys []string
4288 for k := range importRegistry {
4289 regKeys = append(regKeys, k)
4290 }
4291 for i := 1; i < len(regKeys); i++ {
4292 for j := i; j > 0 && regKeys[j] < regKeys[j-1]; j-- {
4293 regKeys[j], regKeys[j-1] = regKeys[j-1], regKeys[j]
4294 }
4295 }
4296 for _, k := range regKeys {
4297 pkg := importRegistry[k]
4298 if pkg.Name() == pkgName.Value {
4299 typeObj := pkg.Scope().Lookup(e.Sel.Value)
4300 if typeObj != nil {
4301 if tn, ok2 := typeObj.(*TypeName); ok2 {
4302 return tn.typ
4303 }
4304 }
4305 break
4306 }
4307 }
4308 }
4309 }
4310 }
4311 return nil
4312 }
4313
4314 func resolveSignatureWithSubst(ft *FuncType, typeSubst map[string]Type, pkgScope *Scope) *Signature {
4315 if ft == nil {
4316 return nil
4317 }
4318 var params []*TCVar
4319 variadic := false
4320 for _, p := range ft.ParamList {
4321 typ := resolveTypeExprWithSubst(p.Type, typeSubst, pkgScope)
4322 name := ""
4323 if p.Name != nil {
4324 name = p.Name.Value
4325 }
4326 params = append(params, NewTCVar(nil, name, typ))
4327 }
4328 if len(ft.ParamList) > 0 {
4329 last := ft.ParamList[len(ft.ParamList)-1]
4330 if _, ok := last.Type.(*DotsType); ok {
4331 variadic = true
4332 }
4333 }
4334 var results []*TCVar
4335 for _, r := range ft.ResultList {
4336 typ := resolveTypeExprWithSubst(r.Type, typeSubst, pkgScope)
4337 name := ""
4338 if r.Name != nil {
4339 name = r.Name.Value
4340 }
4341 results = append(results, NewTCVar(nil, name, typ))
4342 }
4343 var paramTuple *Tuple
4344 if len(params) > 0 {
4345 paramTuple = NewTuple(params...)
4346 }
4347 var resultTuple *Tuple
4348 if len(results) > 0 {
4349 resultTuple = NewTuple(results...)
4350 }
4351 return NewSignature(nil, paramTuple, resultTuple, variadic)
4352 }
4353
4354 func matchTypeParam(paramType Expr, argType Type, tparams []*Field, typeMap map[string]Type) {
4355 if paramType == nil || argType == nil {
4356 return
4357 }
4358 switch pt := paramType.(type) {
4359 case *Name:
4360 for _, tp := range tparams {
4361 if tp.Name != nil && tp.Name.Value == pt.Value {
4362 typeMap[pt.Value] = argType
4363 return
4364 }
4365 }
4366 case *DotsType:
4367 matchTypeParam(pt.Elem, argType, tparams, typeMap)
4368 case *SliceType:
4369 if sl, ok := safeUnderlying(argType).(*Slice); ok {
4370 matchTypeParam(pt.Elem, sl.Elem(), tparams, typeMap)
4371 }
4372 case *FuncType:
4373 sig, ok := safeUnderlying(argType).(*Signature)
4374 if !ok {
4375 return
4376 }
4377 for i, p := range pt.ParamList {
4378 if sig.Params() != nil && i < sig.Params().Len() {
4379 matchTypeParam(p.Type, sig.Params().At(i).Type(), tparams, typeMap)
4380 }
4381 }
4382 for i, r := range pt.ResultList {
4383 if sig.Results() != nil && i < sig.Results().Len() {
4384 matchTypeParam(r.Type, sig.Results().At(i).Type(), tparams, typeMap)
4385 }
4386 }
4387 }
4388 }
4389
4390 func inferFromConstraints(tparams []*Field, typeMap map[string]Type) {
4391 for _, tp := range tparams {
4392 if tp.Name == nil || tp.Type == nil {
4393 continue
4394 }
4395 knownType, ok := typeMap[tp.Name.Value]
4396 if !ok {
4397 continue
4398 }
4399 extractConstraintTypeParams(tp.Type, knownType, tparams, typeMap)
4400 }
4401 }
4402
4403 func extractConstraintTypeParams(constraint Expr, concreteType Type, tparams []*Field, typeMap map[string]Type) {
4404 if constraint == nil || concreteType == nil {
4405 return
4406 }
4407 switch c := constraint.(type) {
4408 case *Operation:
4409 if c.Op == Tilde && c.Y == nil {
4410 extractConstraintTypeParams(c.X, concreteType, tparams, typeMap)
4411 }
4412 case *SliceType:
4413 if sl, ok := safeUnderlying(concreteType).(*Slice); ok {
4414 if name, ok2 := c.Elem.(*Name); ok2 {
4415 for _, tp := range tparams {
4416 if tp.Name != nil && tp.Name.Value == name.Value {
4417 if _, already := typeMap[name.Value]; !already {
4418 typeMap[name.Value] = sl.Elem()
4419 }
4420 }
4421 }
4422 }
4423 }
4424 }
4425 }
4426
4427 func inferTypeArgsFromFunc(fd *FuncDecl, args []SSAValue) []Type {
4428 typeMap := map[string]Type{}
4429 if fd.Type != nil {
4430 for i, param := range fd.Type.ParamList {
4431 if i >= len(args) || args[i] == nil || args[i].SSAType() == nil {
4432 continue
4433 }
4434 matchTypeParam(param.Type, args[i].SSAType(), fd.TParamList, typeMap)
4435 }
4436 }
4437 inferFromConstraints(fd.TParamList, typeMap)
4438 var result []Type
4439 for _, tp := range fd.TParamList {
4440 if tp.Name != nil {
4441 result = append(result, typeMap[tp.Name.Value])
4442 }
4443 }
4444 return result
4445 }
4446
4447 func (fb *ssaFuncBuilder) monomorphizeAndCall(fd *FuncDecl, baseName string, typeArgs []Type, args []SSAValue, targetPkg *SSAPackage, srcPkgPath string, hasDots bool) SSAValue {
4448 mangledName := mangleGenericName(baseName, typeArgs)
4449 if fn, ok := targetPkg.Members[mangledName].(*SSAFunction); ok {
4450 return fb.emitCallToSSAFunc(fn, args, hasDots)
4451 }
4452 var srcScope *Scope
4453 if genericPkgScopes != nil {
4454 if sc, ok := genericPkgScopes[srcPkgPath]; ok {
4455 srcScope = sc
4456 }
4457 }
4458 typeSubst := map[string]Type{}
4459 for i, tp := range fd.TParamList {
4460 if tp.Name != nil && i < len(typeArgs) {
4461 if typeArgs[i] != nil {
4462 typeSubst[tp.Name.Value] = typeArgs[i]
4463 } else {
4464 constraint := resolveTypeExprWithSubst(tp.Type, typeSubst, srcScope)
4465 if constraint != nil {
4466 if _, isIface := safeUnderlying(constraint).(*TCInterface); isIface {
4467 typeSubst[tp.Name.Value] = constraint
4468 } else {
4469 typeSubst[tp.Name.Value] = Typ[UnsafePointer]
4470 }
4471 } else {
4472 typeSubst[tp.Name.Value] = Typ[UnsafePointer]
4473 }
4474 }
4475 }
4476 }
4477 sig := resolveSignatureWithSubst(fd.Type, typeSubst, srcScope)
4478 if sig == nil {
4479 return nil
4480 }
4481 fn := &SSAFunction{
4482 name: mangledName,
4483 Signature: sig,
4484 Pkg: targetPkg,
4485 Prog: fb.fn.Prog,
4486 }
4487 targetPkg.Members[mangledName] = fn
4488 subFb := newSSAFuncBuilder(fn, fb.info)
4489 subFb.typeSubst = typeSubst
4490 subFb.srcScope = srcScope
4491 subFb.buildBody(fd)
4492 return fb.emitCallToSSAFunc(fn, args, hasDots)
4493 }
4494
4495 func (fb *ssaFuncBuilder) emitCallToSSAFunc(fn *SSAFunction, args []SSAValue, hasDots bool) SSAValue {
4496 if fn.Signature != nil {
4497 if fn.Signature.Variadic() && !hasDots {
4498 args = fb.wrapVariadicArgs(args, fn.Signature)
4499 }
4500 args = fb.coerceArgsToInterface(args, fn.Signature)
4501 }
4502 var retType Type
4503 if fn.Signature != nil && fn.Signature.Results() != nil {
4504 if fn.Signature.Results().Len() == 1 {
4505 retType = fn.Signature.Results().At(0).Type()
4506 } else if fn.Signature.Results().Len() > 1 {
4507 retType = fn.Signature.Results()
4508 }
4509 }
4510 call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
4511 call.typ = retType
4512 call.name = fb.nextName()
4513 fb.emit(call)
4514 if retType == nil {
4515 return nil
4516 }
4517 return call
4518 }
4519
4520 func (fb *ssaFuncBuilder) tryGenericLocalCall(funcName string, argList []Expr, hasDots bool) SSAValue {
4521 pkgPath := fb.fn.Pkg.Pkg.Path()
4522 key := pkgPath + "." + funcName
4523 fd, ok := genericFuncDecls[key]
4524 if !ok {
4525 if fb.srcScope != nil && genericPkgScopes != nil {
4526 for gPkg, gScope := range genericPkgScopes {
4527 if gScope == fb.srcScope {
4528 key = gPkg + "." + funcName
4529 fd, ok = genericFuncDecls[key]
4530 if ok {
4531 pkgPath = gPkg
4532 break
4533 }
4534 }
4535 }
4536 }
4537 if !ok {
4538 return nil
4539 }
4540 }
4541 args := fb.buildArgs(argList)
4542 args = fb.expandTupleArgs(args, fd)
4543 typeArgs := inferTypeArgsFromFunc(fd, args)
4544 return fb.monomorphizeAndCall(fd, funcName, typeArgs, args, fb.fn.Pkg, pkgPath, hasDots)
4545 }
4546
4547 func (fb *ssaFuncBuilder) tryGenericPkgCall(pn *PkgName, funcName string, argList []Expr, hasDots bool) SSAValue {
4548 imported := pn.Imported()
4549 if imported == nil {
4550 return nil
4551 }
4552 key := imported.Path() + "." + funcName
4553 fd, ok := genericFuncDecls[key]
4554 if !ok {
4555 return nil
4556 }
4557 args := fb.buildArgs(argList)
4558 args = fb.expandTupleArgs(args, fd)
4559 typeArgs := inferTypeArgsFromFunc(fd, args)
4560 return fb.monomorphizeAndCall(fd, funcName, typeArgs, args, fb.fn.Pkg, imported.Path(), hasDots)
4561 }
4562
4563 func (fb *ssaFuncBuilder) expandTupleArgs(args []SSAValue, fd *FuncDecl) []SSAValue {
4564 nParams := len(fd.Type.ParamList)
4565 if len(args) == 1 && nParams > 1 {
4566 if tup, ok := args[0].SSAType().(*Tuple); ok && tup.Len() == nParams {
4567 expanded := []SSAValue{:0:nParams}
4568 for i := 0; i < tup.Len(); i++ {
4569 ext := &SSAExtract{Tuple: args[0], Index: i}
4570 ext.typ = tup.At(i).Type()
4571 ext.name = fb.nextName()
4572 fb.emit(ext)
4573 expanded = append(expanded, ext)
4574 }
4575 return expanded
4576 }
4577 }
4578 return args
4579 }
4580
4581 func (fb *ssaFuncBuilder) tryGenericCallFromIndex(ie *IndexExpr, argList []Expr, hasDots bool) SSAValue {
4582 switch x := ie.X.(type) {
4583 case *Name:
4584 pkgPath := fb.fn.Pkg.Pkg.Path()
4585 key := pkgPath + "." + x.Value
4586 fd, ok := genericFuncDecls[key]
4587 if !ok {
4588 if fb.srcScope != nil && genericPkgScopes != nil {
4589 for gPkg, gScope := range genericPkgScopes {
4590 if gScope == fb.srcScope {
4591 key = gPkg + "." + x.Value
4592 fd, ok = genericFuncDecls[key]
4593 if ok {
4594 pkgPath = gPkg
4595 break
4596 }
4597 }
4598 }
4599 }
4600 if !ok {
4601 return nil
4602 }
4603 }
4604 typeArgs := fb.resolveExplicitTypeArgs(ie.Index, fd)
4605 args := fb.buildArgs(argList)
4606 return fb.monomorphizeAndCall(fd, x.Value, typeArgs, args, fb.fn.Pkg, pkgPath, hasDots)
4607 case *SelectorExpr:
4608 if pkgName, ok2 := x.X.(*Name); ok2 {
4609 obj := fb.lookupObject(pkgName.Value)
4610 if pn, ok3 := obj.(*PkgName); ok3 && pn.Imported() != nil {
4611 key := pn.Imported().Path() + "." + x.Sel.Value
4612 fd, ok4 := genericFuncDecls[key]
4613 if !ok4 {
4614 return nil
4615 }
4616 typeArgs := fb.resolveExplicitTypeArgs(ie.Index, fd)
4617 args := fb.buildArgs(argList)
4618 return fb.monomorphizeAndCall(fd, x.Sel.Value, typeArgs, args, fb.fn.Pkg, pn.Imported().Path(), hasDots)
4619 }
4620 }
4621 }
4622 return nil
4623 }
4624
4625 func (fb *ssaFuncBuilder) resolveExplicitTypeArgs(indexExpr Expr, fd *FuncDecl) []Type {
4626 var typeExprs []Expr
4627 if le, ok := indexExpr.(*ListExpr); ok {
4628 typeExprs = le.ElemList
4629 } else {
4630 typeExprs = []Expr{indexExpr}
4631 }
4632 var result []Type
4633 for _, te := range typeExprs {
4634 t := fb.resolveTypeAST(te)
4635 result = append(result, t)
4636 }
4637 if len(result) < len(fd.TParamList) {
4638 typeMap := map[string]Type{}
4639 for i, tp := range fd.TParamList {
4640 if tp.Name != nil && i < len(result) && result[i] != nil {
4641 typeMap[tp.Name.Value] = result[i]
4642 }
4643 }
4644 inferFromConstraints(fd.TParamList, typeMap)
4645 result = nil
4646 for _, tp := range fd.TParamList {
4647 if tp.Name != nil {
4648 result = append(result, typeMap[tp.Name.Value])
4649 }
4650 }
4651 }
4652 return result
4653 }
4654