ir_emit.mx raw
1 package main
2
3 import (
4 "bytes"
5 "go/constant"
6 "go/token"
7 )
8
9 type irEmitter struct {
10 buf []byte
11 triple string
12 ptrBits int
13 pkg *SSAPackage
14 valName map[SSAValue]string
15 nextReg int
16 extDecls map[string]string
17 extGlobals map[string]string
18 strConst []string
19 strMap map[string]int
20 curFunc *SSAFunction
21 typeIDs map[string]bool
22 allocTypes map[SSAValue]string
23 hoisted map[SSAValue]bool
24 }
25
26 func newIREmitter(pkg *SSAPackage, triple string) *irEmitter {
27 ptrBits := 64
28 if len(triple) >= 4 && triple[:4] == "wasm" {
29 ptrBits = 32
30 }
31 return &irEmitter{
32 buf: []byte{:0:4096},
33 triple: triple,
34 ptrBits: ptrBits,
35 pkg: pkg,
36 valName: map[SSAValue]string{},
37 extDecls: map[string]string{},
38 extGlobals: map[string]string{},
39 strMap: map[string]int{},
40 allocTypes: map[SSAValue]string{},
41 }
42 }
43
44 func (e *irEmitter) dataLayout() string {
45 if len(e.triple) >= 6 && e.triple[:6] == "x86_64" {
46 return "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
47 }
48 if len(e.triple) >= 7 && e.triple[:7] == "aarch64" {
49 return "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
50 }
51 if len(e.triple) >= 6 && e.triple[:6] == "wasm32" {
52 return "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
53 }
54 if len(e.triple) >= 3 && e.triple[:3] == "arm" {
55 return "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
56 }
57 return ""
58 }
59
60 func (e *irEmitter) w(s string) {
61 e.buf = append(e.buf, s...)
62 }
63
64 func (e *irEmitter) regName(v SSAValue) string {
65 if n, ok := e.valName[v]; ok {
66 return n
67 }
68 name := v.SSAName()
69 if name == "" {
70 e.nextReg++
71 name = "r" | irItoa(e.nextReg)
72 }
73 n := "%" | name
74 e.valName[v] = n
75 return n
76 }
77
78 func (e *irEmitter) llvmType(t Type) string {
79 if t == nil {
80 return "void"
81 }
82 u := safeUnderlying(t)
83 if u == nil {
84 if _, ok := t.(*Slice); ok {
85 return e.sliceType()
86 }
87 if n, ok := t.(*Named); ok {
88 _ = n
89 return "ptr"
90 }
91 return "ptr"
92 }
93 t = u
94 switch t := t.(type) {
95 case *Basic:
96 return e.llvmBasicType(t)
97 case *Pointer:
98 return "ptr"
99 case *Slice:
100 return e.sliceType()
101 case *Array:
102 n := t.Len()
103 elem := e.llvmType(t.Elem())
104 return "[" | irItoa(int(n)) | " x " | elem | "]"
105 case *TCStruct:
106 return e.llvmStructType(t)
107 case *Signature:
108 return "{ptr, ptr}"
109 case *TCMap:
110 return "ptr"
111 case *TCChan:
112 return "ptr"
113 case *TCInterface:
114 return e.ifaceType()
115 case *Tuple:
116 if t.Len() == 0 {
117 return "void"
118 }
119 if t.Len() == 1 {
120 return e.llvmType(t.At(0).Type())
121 }
122 s := "{"
123 for i := 0; i < t.Len(); i++ {
124 if i > 0 {
125 s = s | ", "
126 }
127 ft := e.llvmType(t.At(i).Type())
128 if ft == "void" {
129 ft = "ptr"
130 }
131 s = s | ft
132 }
133 return s | "}"
134 }
135 return "i8"
136 }
137
138 func (e *irEmitter) llvmBasicType(t *Basic) string {
139 switch t.Kind() {
140 case Bool:
141 return "i1"
142 case Int8, Uint8:
143 return "i8"
144 case Int16, Uint16:
145 return "i16"
146 case Int32, Uint32:
147 return "i32"
148 case Int64, Uint64:
149 return "i64"
150 case Float32:
151 return "float"
152 case Float64:
153 return "double"
154 case TCString:
155 return e.sliceType()
156 case UnsafePointer:
157 return "ptr"
158 case UntypedBool:
159 return "i1"
160 case UntypedInt, UntypedRune:
161 return "i32"
162 case UntypedFloat:
163 return "double"
164 case UntypedString:
165 return e.sliceType()
166 }
167 return "i32"
168 }
169
170 func (e *irEmitter) ptrType() string {
171 return "ptr"
172 }
173
174 func (e *irEmitter) intptrType() string {
175 if e.ptrBits == 32 {
176 return "i32"
177 }
178 return "i64"
179 }
180
181 func (e *irEmitter) sliceType() string {
182 ipt := e.intptrType()
183 return "{ptr, " | ipt | ", " | ipt | "}"
184 }
185
186 func (e *irEmitter) ifaceType() string {
187 return "{ptr, ptr}"
188 }
189
190 func (e *irEmitter) llvmStructType(t *TCStruct) string {
191 s := "{"
192 for i := 0; i < t.NumFields(); i++ {
193 if i > 0 {
194 s = s | ", "
195 }
196 ft := e.llvmType(t.Field(i).Type())
197 if ft == "void" {
198 ft = "ptr"
199 }
200 s = s | ft
201 }
202 return s | "}"
203 }
204
205 func (e *irEmitter) declareRuntime(name, retType, params string) {
206 e.extDecls[name] = retType | " @" | name | "(" | params | ")"
207 }
208
209 func (e *irEmitter) declareExternalGlobal(g *SSAGlobal) {
210 if g.pkg == nil || g.pkg == e.pkg {
211 return
212 }
213 name := e.globalName(g)
214 if _, ok := e.extGlobals[name]; ok {
215 return
216 }
217 typ := e.llvmType(g.typ)
218 if p, ok := safeUnderlying(g.typ).(*Pointer); ok {
219 typ = e.llvmType(p.Elem())
220 }
221 e.extGlobals[name] = typ
222 }
223
224 func (e *irEmitter) declareExternalFunc(fn *SSAFunction) {
225 sym := e.funcSymbol(fn)
226 if _, ok := e.extDecls[sym]; ok {
227 return
228 }
229 retType := e.funcRetType(fn)
230 params := ""
231 if fn.Signature != nil && fn.Signature.Params() != nil {
232 for i := 0; i < fn.Signature.Params().Len(); i++ {
233 if i > 0 {
234 params = params | ", "
235 }
236 params = params | e.llvmType(fn.Signature.Params().At(i).Type())
237 }
238 }
239 if params != "" {
240 params = params | ", "
241 }
242 params = params | "ptr"
243 e.extDecls[sym] = retType | " " | sym | "(" | params | ")"
244 }
245
246 func (e *irEmitter) addStringConst(s string) int {
247 if idx, ok := e.strMap[s]; ok {
248 return idx
249 }
250 idx := len(e.strConst)
251 e.strConst = append(e.strConst, s)
252 e.strMap[s] = idx
253 return idx
254 }
255
256 func (e *irEmitter) strConstGlobal(idx int) string {
257 return "@.str." | irItoa(idx)
258 }
259
260 func irEscapeString(s string) string {
261 var buf []byte
262 for i := 0; i < len(s); i++ {
263 c := s[i]
264 if c >= 32 && c < 127 && c != '\\' && c != '"' {
265 buf = append(buf, c)
266 } else {
267 buf = append(buf, '\\')
268 buf = append(buf, "0123456789ABCDEF"[c>>4])
269 buf = append(buf, "0123456789ABCDEF"[c&0xf])
270 }
271 }
272 return string(buf)
273 }
274
275 func (e *irEmitter) emit() string {
276 dl := e.dataLayout()
277 if dl != "" {
278 e.w("target datalayout = \"")
279 e.w(dl)
280 e.w("\"\n")
281 }
282 e.w("target triple = \"")
283 e.w(e.triple)
284 e.w("\"\n\n")
285
286 for _, member := range e.pkgMembersSorted() {
287 switch m := member.(type) {
288 case *SSAGlobal:
289 if m.name != "_" {
290 e.emitGlobal(m)
291 }
292 }
293 }
294
295 for _, member := range e.pkgMembersSorted() {
296 switch m := member.(type) {
297 case *SSAFunction:
298 e.emitFunction(m)
299 e.emitAnonFuncs(m)
300 }
301 }
302
303 e.emitInitFunction()
304
305 for i, s := range e.strConst {
306 e.w(e.strConstGlobal(i))
307 e.w(" = private constant [")
308 e.w(irItoa(len(s)))
309 e.w(" x i8] c\"")
310 e.w(irEscapeString(s))
311 e.w("\"\n")
312 }
313
314 for name := range e.typeIDs {
315 e.w("@")
316 e.w(name)
317 e.w(" = private constant i8 0\n")
318 }
319
320 if len(e.extDecls) > 0 {
321 e.w("\n")
322 for _, decl := range e.extDecls {
323 e.w("declare ")
324 e.w(decl)
325 e.w("\n")
326 }
327 }
328
329 if len(e.extGlobals) > 0 {
330 e.w("\n")
331 for name, typ := range e.extGlobals {
332 e.w(name)
333 e.w(" = external global ")
334 e.w(typ)
335 e.w("\n")
336 }
337 }
338
339 return string(e.buf)
340 }
341
342 func (e *irEmitter) pkgMembersSorted() []SSAMember {
343 var members []SSAMember
344 for _, m := range e.pkg.Members {
345 members = append(members, m)
346 }
347 for i := 1; i < len(members); i++ {
348 for j := i; j > 0 && members[j].MemberName() < members[j-1].MemberName(); j-- {
349 members[j], members[j-1] = members[j-1], members[j]
350 }
351 }
352 return members
353 }
354
355 func (e *irEmitter) emitGlobal(g *SSAGlobal) {
356 name := e.globalName(g)
357 typ := e.llvmType(g.typ)
358 if p, ok := safeUnderlying(g.typ).(*Pointer); ok {
359 typ = e.llvmType(p.Elem())
360 }
361 e.w(name)
362 e.w(" = global ")
363 e.w(typ)
364 e.w(" zeroinitializer\n")
365 }
366
367 func (e *irEmitter) globalName(g *SSAGlobal) string {
368 pkg := e.pkg.Pkg.Path()
369 if g.pkg != nil {
370 pkg = g.pkg.Pkg.Path()
371 }
372 return irGlobalSymbol(pkg, g.name)
373 }
374
375 func irNeedsQuote(s string) bool {
376 for i := 0; i < len(s); i++ {
377 c := s[i]
378 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '$' {
379 continue
380 }
381 return true
382 }
383 return false
384 }
385
386 func irGlobalSymbol(pkg, name string) string {
387 sym := pkg | "." | name
388 if irNeedsQuote(sym) {
389 return "@\"" | sym | "\""
390 }
391 return "@" | sym
392 }
393
394 func (e *irEmitter) funcSymbol(f *SSAFunction) string {
395 pkg := e.pkg.Pkg.Path()
396 if f.Pkg != nil {
397 pkg = f.Pkg.Pkg.Path()
398 }
399 return irGlobalSymbol(pkg, f.name)
400 }
401
402 func (e *irEmitter) isPkgFunc(f *SSAFunction) bool {
403 if f.Pkg == e.pkg {
404 return true
405 }
406 if f.parent != nil {
407 return e.isPkgFunc(f.parent)
408 }
409 return false
410 }
411
412 func (e *irEmitter) emitAnonFuncs(f *SSAFunction) {
413 for _, af := range f.AnonFuncs {
414 e.emitFunction(af)
415 e.emitAnonFuncs(af)
416 }
417 }
418
419 func (e *irEmitter) emitInitFunction() {
420 pkgPath := e.pkg.Pkg.Path()
421 hasInit := false
422 for _, m := range e.pkg.Members {
423 if fn, ok := m.(*SSAFunction); ok && fn.name == "init" {
424 hasInit = true
425 break
426 }
427 }
428 if hasInit {
429 return
430 }
431 e.w("\ndefine void @")
432 e.w(pkgPath)
433 e.w(".init(ptr %context) {\nentry:\n ret void\n}\n")
434 }
435
436 func (e *irEmitter) emitFunction(f *SSAFunction) {
437 e.w("; [emit] " | f.name | "\n")
438 if len(f.Blocks) == 0 {
439 e.emitFuncDecl(f)
440 return
441 }
442 e.curFunc = f
443 e.nextReg = 0
444 e.valName = map[SSAValue]string{}
445
446 for i, p := range f.Params {
447 pname := p.SSAName()
448 if pname == "" {
449 pname = "p" | irItoa(i)
450 }
451 e.valName[p] = "%" | pname
452 }
453
454 e.w("\ndefine ")
455 e.w(e.funcRetType(f))
456 e.w(" ")
457 e.w(e.funcSymbol(f))
458 e.w("(")
459 for i, p := range f.Params {
460 if i > 0 {
461 e.w(", ")
462 }
463 e.w(e.llvmType(p.SSAType()))
464 e.w(" ")
465 e.w(e.regName(p))
466 }
467 if len(f.Params) > 0 {
468 e.w(", ")
469 }
470 ctxName := "context"
471 for _, p := range f.Params {
472 if p.SSAName() == "context" {
473 ctxName = "context.1"
474 break
475 }
476 }
477 e.w("ptr %")
478 e.w(ctxName)
479 e.w(") {\n")
480
481 // Pre-scan: set allocTypes, detect cross-block alloca references
482 allocBlock := map[SSAValue]int{}
483 for _, b := range f.Blocks {
484 for _, instr := range b.Instrs {
485 if n, ok := instr.(*SSANext); ok {
486 if ri, ok2 := n.Iter.(*SSARange); ok2 {
487 if arr, ok3 := safeUnderlying(ri.X.SSAType()).(*Array); ok3 {
488 elemType := e.llvmType(arr.Elem())
489 e.allocTypes[n] = "{i1, i32, " | elemType | "}"
490 }
491 }
492 }
493 if c, ok := instr.(*SSACall); ok {
494 if b2, ok2 := c.Call.Value.(*SSABuiltin); ok2 && b2.SSAName() == "recover" {
495 e.allocTypes[c] = e.ifaceType()
496 }
497 }
498 if a, ok := instr.(*SSAAlloc); ok {
499 allocBlock[a] = b.Index
500 }
501 }
502 }
503 hoistAllocs := map[SSAValue]bool{}
504 for _, b := range f.Blocks {
505 for _, instr := range b.Instrs {
506 refs := e.instrOperands(instr)
507 for _, ref := range refs {
508 if ab, ok := allocBlock[ref]; ok && ab != 0 && ab != b.Index {
509 hoistAllocs[ref] = true
510 }
511 }
512 }
513 }
514 e.hoisted = hoistAllocs
515
516 for _, b := range f.Blocks {
517 if b.Index == 0 {
518 e.w("entry:\n")
519 for v := range hoistAllocs {
520 if a, ok := v.(*SSAAlloc); ok {
521 e.emitAlloc(a)
522 }
523 }
524 if len(e.curFunc.FreeVars) > 0 {
525 e.emitFreeVarUnpack(e.curFunc)
526 }
527 for _, instr := range b.Instrs {
528 e.emitInstr(instr)
529 }
530 } else {
531 e.emitBlock(b)
532 }
533 }
534 e.hoisted = nil
535
536 e.w("}\n")
537 }
538
539 func (e *irEmitter) emitFuncDecl(f *SSAFunction) {
540 e.w("\ndeclare ")
541 e.w(e.funcRetType(f))
542 e.w(" ")
543 e.w(e.funcSymbol(f))
544 e.w("(")
545 if f.Signature != nil && f.Signature.Params() != nil {
546 for i := 0; i < f.Signature.Params().Len(); i++ {
547 if i > 0 {
548 e.w(", ")
549 }
550 e.w(e.llvmType(f.Signature.Params().At(i).Type()))
551 }
552 if f.Signature.Params().Len() > 0 {
553 e.w(", ")
554 }
555 }
556 e.w("ptr")
557 e.w(")\n")
558 }
559
560 func (e *irEmitter) funcRetType(f *SSAFunction) string {
561 if f.Signature == nil || f.Signature.Results() == nil || f.Signature.Results().Len() == 0 {
562 return "void"
563 }
564 if f.Signature.Results().Len() == 1 {
565 return e.llvmType(f.Signature.Results().At(0).Type())
566 }
567 s := "{"
568 for i := 0; i < f.Signature.Results().Len(); i++ {
569 if i > 0 {
570 s = s | ", "
571 }
572 s = s | e.llvmType(f.Signature.Results().At(i).Type())
573 }
574 return s | "}"
575 }
576
577 func (e *irEmitter) emitBlock(b *SSABasicBlock) {
578 label := "b" | irItoa(b.Index)
579 if b.Index == 0 {
580 label = "entry"
581 }
582 e.w(label)
583 e.w(":\n")
584
585 if b.Index == 0 && len(e.curFunc.FreeVars) > 0 {
586 e.emitFreeVarUnpack(e.curFunc)
587 }
588
589 for _, instr := range b.Instrs {
590 e.emitInstr(instr)
591 }
592 }
593
594 func (e *irEmitter) blockLabel(b *SSABasicBlock) string {
595 if b.Index == 0 {
596 return "%entry"
597 }
598 return "%b" | irItoa(b.Index)
599 }
600
601 func (e *irEmitter) emitInstr(instr SSAInstruction) {
602 switch i := instr.(type) {
603 case *SSAAlloc:
604 if e.hoisted != nil && e.hoisted[i] {
605 break
606 }
607 e.emitAlloc(i)
608 case *SSAStore:
609 e.emitStore(i)
610 case *SSABinOp:
611 e.emitBinOp(i)
612 case *SSAUnOp:
613 e.emitUnOp(i)
614 case *SSACall:
615 e.emitCall(i)
616 case *SSAPhi:
617 e.emitPhi(i)
618 case *SSAReturn:
619 e.emitReturn(i)
620 case *SSAJump:
621 e.emitJump(i)
622 case *SSAIf:
623 e.emitIf(i)
624 case *SSAConvert:
625 e.emitConvert(i)
626 case *SSAChangeType:
627 e.emitChangeType(i)
628 case *SSAFieldAddr:
629 e.emitFieldAddr(i)
630 case *SSAIndexAddr:
631 e.emitIndexAddr(i)
632 case *SSAExtract:
633 e.emitExtract(i)
634 case *SSAMakeSlice:
635 e.emitMakeSlice(i)
636 case *SSASlice:
637 e.emitSliceOp(i)
638 case *SSAMakeInterface:
639 e.emitMakeInterface(i)
640 case *SSAInvoke:
641 e.emitInvoke(i)
642 case *SSATypeAssert:
643 e.emitTypeAssert(i)
644 case *SSAMakeMap:
645 e.emitMakeMap(i)
646 case *SSAMapUpdate:
647 e.emitMapUpdate(i)
648 case *SSALookup:
649 e.emitLookup(i)
650 case *SSAMakeClosure:
651 e.emitMakeClosure(i)
652 case *SSAPanic:
653 e.emitPanic(i)
654 case *SSARunDefers:
655 e.w(" ; rundefers\n")
656 case *SSADefer:
657 e.w(" ; defer\n")
658 case *SSASend:
659 e.w(" ; send\n")
660 case *SSAGo:
661 e.w(" ; go\n")
662 case *SSASelect:
663 e.w(" ; select\n")
664 case *SSARange:
665 e.emitRange(i)
666 case *SSANext:
667 e.emitNext(i)
668 case *SSAMakeChan:
669 e.w(" ; makechan\n")
670 }
671 }
672
673 func (e *irEmitter) emitAlloc(a *SSAAlloc) {
674 reg := e.regName(a)
675 elemType := e.llvmType(a.SSAType())
676 nilElem := false
677 if p, ok := safeUnderlying(a.SSAType()).(*Pointer); ok {
678 if p.Elem() != nil {
679 elemType = e.llvmType(p.Elem())
680 } else {
681 nilElem = true
682 }
683 }
684 if elemType == "void" || (elemType == "ptr" && nilElem) {
685 inferred := e.inferAllocTypeFromStores(a)
686 if inferred != "ptr" || elemType == "void" {
687 elemType = inferred
688 }
689 e.allocTypes[a] = elemType
690 } else {
691 override := e.inferAllocTypeFromStores(a)
692 if override != "ptr" && override != elemType {
693 bothScalar := len(elemType) > 0 && elemType[0] == 'i' && len(override) > 0 && override[0] == 'i'
694 if !bothScalar {
695 elemType = override
696 e.allocTypes[a] = elemType
697 }
698 }
699 }
700 if a.Heap {
701 ipt := e.intptrType()
702 e.nextReg++
703 sz := "%ha" | irItoa(e.nextReg)
704 e.w(" ") ; e.w(sz)
705 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
706 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
707 e.w(" ") ; e.w(reg)
708 e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
709 e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
710 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
711 } else {
712 e.w(" ")
713 e.w(reg)
714 e.w(" = alloca ")
715 e.w(elemType)
716 e.w("\n")
717 }
718 }
719
720 func (e *irEmitter) inferAllocTypeFromStores(a *SSAAlloc) string {
721 for _, b := range e.curFunc.Blocks {
722 for _, instr := range b.Instrs {
723 if s, ok := instr.(*SSAStore); ok && s.Addr == a {
724 // Check allocTypes override first
725 if at, ok2 := e.allocTypes[s.Val]; ok2 && at != "ptr" && at != "void" {
726 return at
727 }
728 vt := e.llvmType(s.Val.SSAType())
729 if vt != "void" && vt != "" {
730 return vt
731 }
732 // Check if stored value is an append builtin call (result is always a slice)
733 if call, ok := s.Val.(*SSACall); ok {
734 if b, ok2 := call.Call.Value.(*SSABuiltin); ok2 && b.SSAName() == "append" {
735 return e.sliceType()
736 }
737 }
738 }
739 }
740 }
741 return "ptr"
742 }
743
744 func (e *irEmitter) emitStore(s *SSAStore) {
745 valType := e.llvmType(s.Val.SSAType())
746 val := e.operand(s.Val)
747 if at, ok := e.allocTypes[s.Val]; ok && at != valType {
748 bothScalar := len(valType) > 0 && valType[0] == 'i' && len(at) > 0 && at[0] == 'i'
749 if !bothScalar {
750 valType = at
751 if val == "null" && valType != "ptr" {
752 val = "zeroinitializer"
753 }
754 }
755 }
756 // If value type is still generic ptr but the address has a known alloc type, use that
757 if valType == "ptr" || valType == "void" {
758 if at, ok := e.allocTypes[s.Addr]; ok && at != "ptr" && at != "void" {
759 valType = at
760 if val == "null" && valType != "ptr" {
761 val = "zeroinitializer"
762 }
763 }
764 }
765 if valType == "void" {
766 if p, ok := safeUnderlying(s.Addr.SSAType()).(*Pointer); ok {
767 valType = e.llvmType(p.Elem())
768 }
769 if valType == "void" {
770 valType = "ptr"
771 }
772 if val == "null" && valType != "ptr" {
773 val = "zeroinitializer"
774 }
775 }
776 addr := e.operand(s.Addr)
777 e.w(" store ")
778 e.w(valType)
779 e.w(" ")
780 e.w(val)
781 e.w(", ptr ")
782 e.w(addr)
783 e.w("\n")
784 }
785
786 func (e *irEmitter) emitZeroReg(reg string, typ Type) {
787 rt := e.llvmType(typ)
788 if rt == "void" || rt == "" {
789 rt = "i32"
790 }
791 if rt == "ptr" {
792 e.w(" ") ; e.w(reg) ; e.w(" = inttoptr i64 0 to ptr\n")
793 } else if rt == "i1" {
794 e.w(" ") ; e.w(reg) ; e.w(" = add i1 false, false\n")
795 } else if e.intBits(rt) > 0 {
796 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(rt) ; e.w(" 0, 0\n")
797 } else {
798 e.w(" ") ; e.w(reg) ; e.w(" = add i32 0, 0\n")
799 }
800 }
801
802 func (e *irEmitter) emitBinOp(b *SSABinOp) {
803 if b.X == nil || b.X.SSAType() == nil {
804 e.emitZeroReg(e.regName(b), b.SSAType())
805 return
806 }
807 reg := e.regName(b)
808 lt := e.llvmType(b.X.SSAType())
809 if lt == "void" && b.Y != nil {
810 lt = e.llvmType(b.Y.SSAType())
811 }
812 if at, ok := e.allocTypes[b.X]; ok && at != "ptr" && at != "void" && at != lt {
813 lt = at
814 }
815 lv := e.operand(b.X)
816 rv := e.operand(b.Y)
817 if (b.Op == OpAdd || b.Op == OpOr) && b.X.SSAType() != nil {
818 if sl, ok := safeUnderlying(b.X.SSAType()).(*Slice); ok {
819 e.emitSliceConcat(reg, sl, lv, rv)
820 return
821 }
822 if e.isStringLike(b.X.SSAType()) {
823 e.emitSliceConcat(reg, NewSlice(Typ[Uint8]), lv, rv)
824 return
825 }
826 }
827 if b.X.SSAType() != nil && e.isStringLike(b.X.SSAType()) {
828 isActuallyIface := false
829 if at, ok := e.allocTypes[b.X]; ok && at == e.ifaceType() {
830 isActuallyIface = true
831 }
832 if !isActuallyIface {
833 e.emitStringCompare(reg, b.Op, lv, rv)
834 return
835 }
836 }
837 if (b.Op == OpEql || b.Op == OpNeq) && (rv == "null" || rv == "zeroinitializer" || lv == "null" || lv == "zeroinitializer") && b.X.SSAType() != nil {
838 u := safeUnderlying(b.X.SSAType())
839 _, isIface := u.(*TCInterface)
840 _, isSlice := u.(*Slice)
841 _, isSig := u.(*Signature)
842 _, isPtr := u.(*Pointer)
843 if !isIface && !isSlice && !isSig && !isPtr && u == nil && (lt == "{ptr, ptr}" || lt == "{ptr, i64}") {
844 isIface = true
845 }
846 if isIface || isSlice || isSig || e.isStringLike(b.X.SSAType()) {
847 e.nextReg++
848 extReg := "%ne" | irItoa(e.nextReg)
849 aggVal := lv
850 if lv == "null" || lv == "zeroinitializer" {
851 aggVal = rv
852 }
853 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(aggVal) ; e.w(", 0\n")
854 cmpOp := "icmp eq"
855 if b.Op == OpNeq {
856 cmpOp = "icmp ne"
857 }
858 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", null\n")
859 return
860 }
861 if isPtr {
862 cmpOp := "icmp eq"
863 if b.Op == OpNeq {
864 cmpOp = "icmp ne"
865 }
866 ptrVal := lv
867 if lv == "null" || lv == "zeroinitializer" {
868 ptrVal = rv
869 }
870 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(ptrVal) ; e.w(", null\n")
871 return
872 }
873 }
874 if (b.Op == OpEql || b.Op == OpNeq) && b.X.SSAType() != nil {
875 if st, ok := safeUnderlying(b.X.SSAType()).(*TCStruct); ok {
876 e.emitStructCompare(reg, b.Op, st, lt, lv, rv)
877 return
878 }
879 u2 := safeUnderlying(b.X.SSAType())
880 _, isSig2 := u2.(*Signature)
881 _, isIfce2 := u2.(*TCInterface)
882 if !isSig2 && !isIfce2 && u2 == nil && lt == "{ptr, ptr}" {
883 isIfce2 = true
884 }
885 if isSig2 || isIfce2 {
886 rt2 := "ptr"
887 if b.Y != nil && b.Y.SSAType() != nil {
888 rt2 = e.llvmType(b.Y.SSAType())
889 }
890 if lt == "{ptr, ptr}" && rt2 == "ptr" {
891 e.nextReg++
892 extReg := "%fc" | irItoa(e.nextReg)
893 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 0\n")
894 cmpOp := "icmp eq"
895 if b.Op == OpNeq { cmpOp = "icmp ne" }
896 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", ") ; e.w(rv) ; e.w("\n")
897 return
898 }
899 if lt == "ptr" && rt2 == "{ptr, ptr}" {
900 e.nextReg++
901 extReg := "%fc" | irItoa(e.nextReg)
902 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 0\n")
903 cmpOp := "icmp eq"
904 if b.Op == OpNeq { cmpOp = "icmp ne" }
905 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(lv) ; e.w(", ") ; e.w(extReg) ; e.w("\n")
906 return
907 }
908 e.nextReg++
909 pA := "%fc" | irItoa(e.nextReg)
910 e.nextReg++
911 pB := "%fc" | irItoa(e.nextReg)
912 e.nextReg++
913 qA := "%fc" | irItoa(e.nextReg)
914 e.nextReg++
915 qB := "%fc" | irItoa(e.nextReg)
916 e.nextReg++
917 cA := "%fc" | irItoa(e.nextReg)
918 e.nextReg++
919 cB := "%fc" | irItoa(e.nextReg)
920 e.w(" ") ; e.w(pA) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 0\n")
921 e.w(" ") ; e.w(pB) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 0\n")
922 e.w(" ") ; e.w(qA) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 1\n")
923 e.w(" ") ; e.w(qB) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 1\n")
924 cmpOp := "icmp eq"
925 combOp := "and"
926 if b.Op == OpNeq {
927 cmpOp = "icmp ne"
928 combOp = "or"
929 }
930 e.w(" ") ; e.w(cA) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(pA) ; e.w(", ") ; e.w(pB) ; e.w("\n")
931 e.w(" ") ; e.w(cB) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(qA) ; e.w(", ") ; e.w(qB) ; e.w("\n")
932 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(combOp) ; e.w(" i1 ") ; e.w(cA) ; e.w(", ") ; e.w(cB) ; e.w("\n")
933 return
934 }
935 }
936 if b.Op == OpAndNot {
937 e.nextReg++
938 notReg := "%an" | irItoa(e.nextReg)
939 allOnes := "-1"
940 e.w(" ") ; e.w(notReg) ; e.w(" = xor ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(allOnes) ; e.w("\n")
941 e.w(" ") ; e.w(reg) ; e.w(" = and ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(notReg) ; e.w("\n")
942 return
943 }
944 if b.Y == nil || b.Y.SSAType() == nil {
945 e.emitZeroReg(e.regName(b), b.SSAType())
946 return
947 }
948 rt := e.llvmType(b.Y.SSAType())
949 if lt != rt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
950 resType := e.llvmType(b.SSAType())
951 if e.intBits(resType) > 0 {
952 if lt != resType {
953 lv = e.coerceInt(lv, lt, resType)
954 lt = resType
955 }
956 if rt != resType {
957 rv = e.coerceInt(rv, rt, resType)
958 }
959 } else if e.intBits(lt) > e.intBits(rt) {
960 rv = e.coerceInt(rv, rt, lt)
961 } else {
962 lv = e.coerceInt(lv, lt, rt)
963 lt = rt
964 }
965 }
966 op := e.llvmBinOp(b.Op, b.X.SSAType())
967 if op == "" {
968 e.w(" ; unsupported binop\n")
969 return
970 }
971 e.w(" ")
972 e.w(reg)
973 e.w(" = ")
974 e.w(op)
975 e.w(" ")
976 e.w(lt)
977 e.w(" ")
978 e.w(lv)
979 e.w(", ")
980 e.w(rv)
981 e.w("\n")
982 }
983
984 func (e *irEmitter) emitSliceConcat(reg string, sl *Slice, lv, rv string) {
985 ipt := e.intptrType()
986 sty := "{ptr, " | ipt | ", " | ipt | "}"
987 elemType := e.llvmType(sl.Elem())
988 p := func(prefix string) string {
989 e.nextReg++
990 return "%" | prefix | irItoa(e.nextReg)
991 }
992 xPtr := p("cc")
993 e.w(" ") ; e.w(xPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 0\n")
994 xLen := p("cc")
995 e.w(" ") ; e.w(xLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 1\n")
996 yPtr := p("cc")
997 e.w(" ") ; e.w(yPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 0\n")
998 yLen := p("cc")
999 e.w(" ") ; e.w(yLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 1\n")
1000 elemSz := p("cc")
1001 e.w(" ") ; e.w(elemSz)
1002 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1003 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1004 retTy := "{ptr, " | ipt | ", " | ipt | "}"
1005 result := p("cc")
1006 e.w(" ") ; e.w(result)
1007 e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
1008 e.w(xPtr) ; e.w(", ptr ") ; e.w(yPtr)
1009 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
1010 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
1011 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(yLen)
1012 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
1013 e.w(")\n")
1014 newPtr := p("cc")
1015 e.w(" ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
1016 newLen := p("cc")
1017 e.w(" ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
1018 newCap := p("cc")
1019 e.w(" ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
1020 s1 := p("cc")
1021 e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
1022 s2 := p("cc")
1023 e.w(" ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n")
1024 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newCap) ; e.w(", 2\n")
1025 e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
1026 }
1027
1028 func (e *irEmitter) emitStringCompare(reg string, op SSAOp, lv, rv string) {
1029 ipt := e.intptrType()
1030 sty := "{ptr, " | ipt | ", " | ipt | "}"
1031 if lv == "null" { lv = "zeroinitializer" }
1032 if rv == "null" { rv = "zeroinitializer" }
1033 switch op {
1034 case OpEql:
1035 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringEqual(")
1036 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
1037 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
1038 case OpNeq:
1039 p := func() string {
1040 e.nextReg++
1041 return "%sc" | irItoa(e.nextReg)
1042 }
1043 tmp := p()
1044 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringEqual(")
1045 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
1046 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
1047 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
1048 case OpLss:
1049 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
1050 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
1051 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
1052 case OpGtr:
1053 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
1054 e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(")\n")
1055 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
1056 case OpLeq:
1057 p := func() string {
1058 e.nextReg++
1059 return "%sc" | irItoa(e.nextReg)
1060 }
1061 tmp := p()
1062 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
1063 e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(")\n")
1064 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
1065 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
1066 case OpGeq:
1067 p := func() string {
1068 e.nextReg++
1069 return "%sc" | irItoa(e.nextReg)
1070 }
1071 tmp := p()
1072 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
1073 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
1074 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
1075 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
1076 default:
1077 e.w(" ; unsupported string binop\n")
1078 }
1079 }
1080
1081 func (e *irEmitter) emitStructCompare(reg string, op SSAOp, st *TCStruct, lt, lv, rv string) {
1082 p := func(prefix string) string {
1083 e.nextReg++
1084 return "%" | prefix | irItoa(e.nextReg)
1085 }
1086 n := st.NumFields()
1087 if n == 0 {
1088 if op == OpEql {
1089 e.valName[nil] = "true"
1090 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
1091 } else {
1092 e.w(" ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
1093 }
1094 return
1095 }
1096 var lastCmp string
1097 for i := 0; i < n; i++ {
1098 ft := e.llvmType(st.Field(i).Type())
1099 lf := p("sf")
1100 rf := p("sf")
1101 e.w(" ") ; e.w(lf) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
1102 e.w(" ") ; e.w(rf) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
1103 cmp := p("sf")
1104 if e.isStringLike(st.Field(i).Type()) {
1105 sty := e.sliceType()
1106 e.w(" ") ; e.w(cmp) ; e.w(" = call i1 @runtime.stringEqual(") ; e.w(sty) ; e.w(" ") ; e.w(lf) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rf) ; e.w(")\n")
1107 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
1108 } else {
1109 e.w(" ") ; e.w(cmp) ; e.w(" = icmp eq ") ; e.w(ft) ; e.w(" ") ; e.w(lf) ; e.w(", ") ; e.w(rf) ; e.w("\n")
1110 }
1111 if i == 0 {
1112 lastCmp = cmp
1113 } else {
1114 acc := p("sf")
1115 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
1116 lastCmp = acc
1117 }
1118 }
1119 if op == OpNeq {
1120 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
1121 } else if n == 1 {
1122 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
1123 } else {
1124 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
1125 }
1126 }
1127
1128 func (e *irEmitter) llvmBinOp(op SSAOp, typ Type) string {
1129 isFloat := false
1130 isSigned := true
1131 if typ != nil {
1132 if b, ok := safeUnderlying(typ).(*Basic); ok {
1133 if b.Info()&IsFloat != 0 {
1134 isFloat = true
1135 }
1136 if b.Info()&IsUnsigned != 0 {
1137 isSigned = false
1138 }
1139 }
1140 }
1141 if isFloat {
1142 switch op {
1143 case OpAdd:
1144 return "fadd"
1145 case OpSub:
1146 return "fsub"
1147 case OpMul:
1148 return "fmul"
1149 case OpQuo:
1150 return "fdiv"
1151 case OpEql:
1152 return "fcmp oeq"
1153 case OpNeq:
1154 return "fcmp une"
1155 case OpLss:
1156 return "fcmp olt"
1157 case OpLeq:
1158 return "fcmp ole"
1159 case OpGtr:
1160 return "fcmp ogt"
1161 case OpGeq:
1162 return "fcmp oge"
1163 }
1164 return ""
1165 }
1166 switch op {
1167 case OpAdd:
1168 return "add"
1169 case OpSub:
1170 return "sub"
1171 case OpMul:
1172 return "mul"
1173 case OpQuo:
1174 if isSigned {
1175 return "sdiv"
1176 }
1177 return "udiv"
1178 case OpRem:
1179 if isSigned {
1180 return "srem"
1181 }
1182 return "urem"
1183 case OpAnd:
1184 return "and"
1185 case OpOr:
1186 return "or"
1187 case OpLand:
1188 return "and"
1189 case OpLor:
1190 return "or"
1191 case OpXor:
1192 return "xor"
1193 case OpShl:
1194 return "shl"
1195 case OpShr:
1196 if isSigned {
1197 return "ashr"
1198 }
1199 return "lshr"
1200 case OpAndNot:
1201 return ""
1202 case OpEql:
1203 return "icmp eq"
1204 case OpNeq:
1205 return "icmp ne"
1206 case OpLss:
1207 if isSigned {
1208 return "icmp slt"
1209 }
1210 return "icmp ult"
1211 case OpLeq:
1212 if isSigned {
1213 return "icmp sle"
1214 }
1215 return "icmp ule"
1216 case OpGtr:
1217 if isSigned {
1218 return "icmp sgt"
1219 }
1220 return "icmp ugt"
1221 case OpGeq:
1222 if isSigned {
1223 return "icmp sge"
1224 }
1225 return "icmp uge"
1226 }
1227 return ""
1228 }
1229
1230 func (e *irEmitter) emitUnOp(u *SSAUnOp) {
1231 reg := e.regName(u)
1232 if u.Op == OpMul {
1233 loadType := e.llvmType(u.SSAType())
1234 if loadType == "void" {
1235 if at, ok := e.allocTypes[u.X]; ok {
1236 loadType = at
1237 } else if a, ok := u.X.(*SSAAlloc); ok {
1238 loadType = e.inferAllocTypeFromStores(a)
1239 } else {
1240 loadType = "ptr"
1241 }
1242 e.allocTypes[u] = loadType
1243 } else if at, ok := e.allocTypes[u.X]; ok && at != "ptr" && at != "void" && at != loadType {
1244 bothScalar := len(loadType) > 0 && loadType[0] == 'i' && len(at) > 0 && at[0] == 'i'
1245 if !bothScalar {
1246 loadType = at
1247 e.allocTypes[u] = loadType
1248 }
1249 }
1250 addr := e.operand(u.X)
1251 e.w(" ")
1252 e.w(reg)
1253 e.w(" = load ")
1254 e.w(loadType)
1255 e.w(", ptr ")
1256 e.w(addr)
1257 e.w("\n")
1258 return
1259 }
1260 valType := e.llvmType(u.X.SSAType())
1261 val := e.operand(u.X)
1262 switch u.Op {
1263 case OpSub:
1264 isFloat := false
1265 if b, ok := safeUnderlying(u.X.SSAType()).(*Basic); ok {
1266 isFloat = b.Info()&IsFloat != 0
1267 }
1268 e.w(" ")
1269 e.w(reg)
1270 if isFloat {
1271 e.w(" = fneg ")
1272 } else {
1273 e.w(" = sub ")
1274 e.w(valType)
1275 e.w(" 0, ")
1276 val = val
1277 e.w(val)
1278 e.w("\n")
1279 return
1280 }
1281 e.w(valType)
1282 e.w(" ")
1283 e.w(val)
1284 e.w("\n")
1285 case OpNot:
1286 e.w(" ")
1287 e.w(reg)
1288 e.w(" = xor ")
1289 e.w(valType)
1290 e.w(" ")
1291 e.w(val)
1292 e.w(", -1\n")
1293 case OpXor:
1294 e.w(" ")
1295 e.w(reg)
1296 e.w(" = xor ")
1297 e.w(valType)
1298 e.w(" ")
1299 e.w(val)
1300 e.w(", -1\n")
1301 default:
1302 e.w(" ; unsupported unop\n")
1303 }
1304 }
1305
1306 func (e *irEmitter) callArgType(arg SSAValue, sig *Signature, i int) string {
1307 if at, ok := e.allocTypes[arg]; ok {
1308 return at
1309 }
1310 t := e.llvmType(arg.SSAType())
1311 if t != "void" {
1312 return t
1313 }
1314 if sig != nil && sig.Params() != nil && i < sig.Params().Len() {
1315 return e.llvmType(sig.Params().At(i).Type())
1316 }
1317 return "ptr"
1318 }
1319
1320 func (e *irEmitter) callSig(c *SSACall) *Signature {
1321 if fn, ok := c.Call.Value.(*SSAFunction); ok && fn.Signature != nil {
1322 return fn.Signature
1323 }
1324 if sig, ok := safeUnderlying(c.Call.Value.SSAType()).(*Signature); ok {
1325 return sig
1326 }
1327 return nil
1328 }
1329
1330 func (e *irEmitter) emitCall(c *SSACall) {
1331 if b, ok := c.Call.Value.(*SSABuiltin); ok {
1332 e.emitBuiltinCall(c, b)
1333 return
1334 }
1335 reg := e.regName(c)
1336 retType := e.llvmType(c.SSAType())
1337 isVoid := retType == "void"
1338 sig := e.callSig(c)
1339
1340 if fn, ok := c.Call.Value.(*SSAFunction); ok {
1341 if !e.isPkgFunc(fn) {
1342 e.declareExternalFunc(fn)
1343 }
1344 e.w(" ")
1345 if !isVoid {
1346 e.w(reg) ; e.w(" = ")
1347 }
1348 e.w("call ") ; e.w(retType) ; e.w(" ")
1349 e.w(e.funcSymbol(fn))
1350 e.w("(")
1351 for i, arg := range c.Call.Args {
1352 if i > 0 { e.w(", ") }
1353 at := e.callArgType(arg, sig, i)
1354 av := e.operand(arg)
1355 if av == "null" && at != "ptr" {
1356 av = "zeroinitializer"
1357 }
1358 e.w(at) ; e.w(" ") ; e.w(av)
1359 }
1360 if len(c.Call.Args) > 0 { e.w(", ") }
1361 e.w("ptr null")
1362 e.w(")\n")
1363 return
1364 }
1365
1366 p := func(prefix string) string {
1367 e.nextReg++
1368 return "%" | prefix | irItoa(e.nextReg)
1369 }
1370 funcVal := e.operand(c.Call.Value)
1371 funcPtr := p("fp")
1372 ctx := p("ctx")
1373 e.w(" ") ; e.w(funcPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(funcVal) ; e.w(", 1\n")
1374 e.w(" ") ; e.w(ctx) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(funcVal) ; e.w(", 0\n")
1375 e.w(" ")
1376 if !isVoid {
1377 e.w(reg) ; e.w(" = ")
1378 }
1379 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(funcPtr) ; e.w("(")
1380 for i, arg := range c.Call.Args {
1381 if i > 0 { e.w(", ") }
1382 at := e.callArgType(arg, sig, i)
1383 av := e.operand(arg)
1384 if av == "null" && at != "ptr" {
1385 av = "zeroinitializer"
1386 }
1387 e.w(at) ; e.w(" ") ; e.w(av)
1388 }
1389 if len(c.Call.Args) > 0 { e.w(", ") }
1390 e.w("ptr ") ; e.w(ctx)
1391 e.w(")\n")
1392 }
1393
1394 func (e *irEmitter) emitBuiltinCall(c *SSACall, b *SSABuiltin) {
1395 reg := e.regName(c)
1396 name := b.SSAName()
1397 ipt := e.intptrType()
1398 sty := e.sliceType()
1399 switch name {
1400 case "len":
1401 if len(c.Call.Args) == 1 {
1402 arg := e.operand(c.Call.Args[0])
1403 u := safeUnderlying(c.Call.Args[0].SSAType())
1404 if u == nil { u = c.Call.Args[0].SSAType() }
1405 if arr, ok := u.(*Array); ok {
1406 retType := e.llvmType(c.SSAType())
1407 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int(arr.Len()))) ; e.w(", 0\n")
1408 _ = arg
1409 return
1410 }
1411 _, isSlice := u.(*Slice)
1412 _, isMap := u.(*TCMap)
1413 isStr := e.isStringLike(c.Call.Args[0].SSAType())
1414 if !isSlice && !isMap && !isStr {
1415 isSlice = true
1416 }
1417 if isMap {
1418 retType := e.llvmType(c.SSAType())
1419 e.nextReg++
1420 tmp := "%bl" | irItoa(e.nextReg)
1421 e.w(" ") ; e.w(tmp) ; e.w(" = call ") ; e.w(ipt) ; e.w(" @runtime.hashmapLen(ptr ") ; e.w(arg) ; e.w(")\n")
1422 if retType != ipt {
1423 e.w(" ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
1424 } else {
1425 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(", 0\n")
1426 }
1427 e.declareRuntime("runtime.hashmapLen", ipt, "ptr")
1428 return
1429 }
1430 if isSlice || isStr {
1431 retType := e.llvmType(c.SSAType())
1432 if retType != ipt {
1433 e.nextReg++
1434 tmp := "%bl" | irItoa(e.nextReg)
1435 e.w(" ") ; e.w(tmp) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 1\n")
1436 e.w(" ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
1437 } else {
1438 e.w(" ") ; e.w(reg) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 1\n")
1439 }
1440 return
1441 }
1442 }
1443 case "cap":
1444 if len(c.Call.Args) == 1 {
1445 arg := e.operand(c.Call.Args[0])
1446 uc := safeUnderlying(c.Call.Args[0].SSAType())
1447 if uc == nil { uc = c.Call.Args[0].SSAType() }
1448 if arr, ok := uc.(*Array); ok {
1449 retType := e.llvmType(c.SSAType())
1450 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int(arr.Len()))) ; e.w(", 0\n")
1451 _ = arg
1452 return
1453 }
1454 _, isSlice := uc.(*Slice)
1455 isStr := e.isStringLike(c.Call.Args[0].SSAType())
1456 if isSlice || isStr {
1457 retType := e.llvmType(c.SSAType())
1458 if retType != ipt {
1459 e.nextReg++
1460 tmp := "%bl" | irItoa(e.nextReg)
1461 e.w(" ") ; e.w(tmp) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 2\n")
1462 e.w(" ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
1463 } else {
1464 e.w(" ") ; e.w(reg) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 2\n")
1465 }
1466 return
1467 }
1468 }
1469 case "append":
1470 if len(c.Call.Args) > 2 {
1471 src := e.operand(c.Call.Args[0])
1472 elemType := "i8"
1473 if sl, ok := safeUnderlying(c.Call.Args[0].SSAType()).(*Slice); ok {
1474 elemType = e.llvmType(sl.Elem())
1475 }
1476 if elemType == "i8" || elemType == "void" {
1477 for j := 1; j < len(c.Call.Args); j++ {
1478 et := e.llvmType(c.Call.Args[j].SSAType())
1479 if et != "void" && et != "" && et != "i8" {
1480 elemType = et
1481 break
1482 }
1483 }
1484 }
1485 nElems := len(c.Call.Args) - 1
1486 p := func(prefix string) string {
1487 e.nextReg++
1488 return "%" | prefix | irItoa(e.nextReg)
1489 }
1490 arrAlloca := p("ap")
1491 arrTy := "[" | irItoa(nElems) | " x " | elemType | "]"
1492 e.w(" ") ; e.w(arrAlloca) ; e.w(" = alloca ") ; e.w(arrTy) ; e.w("\n")
1493 for j := 1; j < len(c.Call.Args); j++ {
1494 elemVal := e.operand(c.Call.Args[j])
1495 gep := p("ap")
1496 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr inbounds ") ; e.w(arrTy)
1497 e.w(", ptr ") ; e.w(arrAlloca) ; e.w(", i32 0, i32 ") ; e.w(irItoa(j-1)) ; e.w("\n")
1498 e.w(" store ") ; e.w(elemType) ; e.w(" ") ; e.w(elemVal) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
1499 }
1500 srcBuf := p("ap")
1501 e.w(" ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
1502 srcLen := p("ap")
1503 e.w(" ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
1504 srcCap := p("ap")
1505 e.w(" ") ; e.w(srcCap) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 2\n")
1506 elemSz := p("ap")
1507 e.w(" ") ; e.w(elemSz)
1508 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1509 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1510 retTy := "{ptr, " | ipt | ", " | ipt | "}"
1511 result := p("ap")
1512 e.w(" ") ; e.w(result)
1513 e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
1514 e.w(srcBuf) ; e.w(", ptr ") ; e.w(arrAlloca)
1515 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcLen)
1516 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcCap)
1517 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(irItoa(nElems))
1518 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
1519 e.w(")\n")
1520 newPtr := p("ap")
1521 e.w(" ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
1522 newLen := p("ap")
1523 e.w(" ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
1524 newCap := p("ap")
1525 e.w(" ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
1526 s1 := p("ap")
1527 e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
1528 s2 := p("ap")
1529 e.w(" ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n")
1530 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newCap) ; e.w(", 2\n")
1531 e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
1532 return
1533 }
1534 if len(c.Call.Args) == 2 {
1535 src := e.operand(c.Call.Args[0])
1536 elems := e.operand(c.Call.Args[1])
1537 elemType := "i8"
1538 if sl, ok := safeUnderlying(c.Call.Args[0].SSAType()).(*Slice); ok {
1539 elemType = e.llvmType(sl.Elem())
1540 }
1541 if elemType == "i8" || elemType == "void" {
1542 et := e.llvmType(c.Call.Args[1].SSAType())
1543 if et != "void" && et != "" && et != "i8" {
1544 elemType = et
1545 }
1546 }
1547 p := func(prefix string) string {
1548 e.nextReg++
1549 return "%" | prefix | irItoa(e.nextReg)
1550 }
1551 srcBuf := p("ap")
1552 e.w(" ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
1553 srcLen := p("ap")
1554 e.w(" ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
1555 srcCap := p("ap")
1556 e.w(" ") ; e.w(srcCap) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 2\n")
1557 var elemsBuf, elemsLen string
1558 _, arg1IsSlice := safeUnderlying(c.Call.Args[1].SSAType()).(*Slice)
1559 if !arg1IsSlice {
1560 if b, ok := safeUnderlying(c.Call.Args[1].SSAType()).(*Basic); ok && b.Info()&IsString != 0 {
1561 arg1IsSlice = true
1562 }
1563 }
1564 if arg1IsSlice {
1565 elemsBuf = p("ap")
1566 e.w(" ") ; e.w(elemsBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(elems) ; e.w(", 0\n")
1567 elemsLen = p("ap")
1568 e.w(" ") ; e.w(elemsLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(elems) ; e.w(", 1\n")
1569 } else {
1570 alloca := p("ap")
1571 e.w(" ") ; e.w(alloca) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
1572 e.w(" store ") ; e.w(elemType) ; e.w(" ") ; e.w(elems) ; e.w(", ptr ") ; e.w(alloca) ; e.w("\n")
1573 elemsBuf = alloca
1574 elemsLen = "1"
1575 }
1576 elemSz := p("ap")
1577 e.w(" ") ; e.w(elemSz)
1578 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1579 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1580 retTy := "{ptr, " | ipt | ", " | ipt | "}"
1581 result := p("ap")
1582 e.w(" ") ; e.w(result)
1583 e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
1584 e.w(srcBuf) ; e.w(", ptr ") ; e.w(elemsBuf)
1585 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcLen)
1586 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcCap)
1587 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemsLen)
1588 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
1589 e.w(")\n")
1590 newPtr := p("ap")
1591 e.w(" ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
1592 newLen := p("ap")
1593 e.w(" ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
1594 newCap := p("ap")
1595 e.w(" ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
1596 s1 := p("ap")
1597 e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
1598 s2 := p("ap")
1599 e.w(" ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n")
1600 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newCap) ; e.w(", 2\n")
1601 e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
1602 return
1603 }
1604 case "copy":
1605 if len(c.Call.Args) == 2 {
1606 dst := e.operand(c.Call.Args[0])
1607 src := e.operand(c.Call.Args[1])
1608 elemType := "i8"
1609 if sl, ok := safeUnderlying(c.Call.Args[0].SSAType()).(*Slice); ok {
1610 elemType = e.llvmType(sl.Elem())
1611 }
1612 p := func(prefix string) string {
1613 e.nextReg++
1614 return "%" | prefix | irItoa(e.nextReg)
1615 }
1616 dstBuf := p("cp")
1617 e.w(" ") ; e.w(dstBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(dst) ; e.w(", 0\n")
1618 dstLen := p("cp")
1619 e.w(" ") ; e.w(dstLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(dst) ; e.w(", 1\n")
1620 srcBuf := p("cp")
1621 e.w(" ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
1622 srcLen := p("cp")
1623 e.w(" ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
1624 elemSz := p("cp")
1625 e.w(" ") ; e.w(elemSz)
1626 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1627 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1628 callReg := p("cp")
1629 e.w(" ") ; e.w(callReg)
1630 e.w(" = call ") ; e.w(ipt) ; e.w(" @runtime.sliceCopy(ptr ")
1631 e.w(dstBuf) ; e.w(", ptr ") ; e.w(srcBuf)
1632 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(dstLen)
1633 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcLen)
1634 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
1635 e.w(")\n")
1636 retType := e.llvmType(c.SSAType())
1637 if retType != ipt {
1638 e.w(" ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(callReg) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
1639 } else {
1640 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(callReg) ; e.w(", 0\n")
1641 }
1642 e.declareRuntime("runtime.sliceCopy", ipt, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt)
1643 return
1644 }
1645 case "print", "println":
1646 e.w(" call void @runtime.printlock()\n")
1647 for i, arg := range c.Call.Args {
1648 if i > 0 && name == "println" {
1649 e.w(" call void @runtime.printspace()\n")
1650 }
1651 av := e.operand(arg)
1652 at := arg.SSAType()
1653 e.emitPrintArg(av, at)
1654 }
1655 if name == "println" {
1656 e.w(" call void @runtime.printnl()\n")
1657 e.declareRuntime("runtime.printnl", "void", "")
1658 }
1659 e.w(" call void @runtime.printunlock()\n")
1660 e.declareRuntime("runtime.printlock", "void", "")
1661 e.declareRuntime("runtime.printunlock", "void", "")
1662 if name == "println" && len(c.Call.Args) > 1 {
1663 e.declareRuntime("runtime.printspace", "void", "")
1664 }
1665 return
1666 case "delete":
1667 if len(c.Call.Args) == 2 {
1668 mapVal := e.operand(c.Call.Args[0])
1669 keyVal := e.operand(c.Call.Args[1])
1670 mt, _ := safeUnderlying(c.Call.Args[0].SSAType()).(*TCMap)
1671 keyType := "i32"
1672 if mt != nil {
1673 keyType = e.llvmType(mt.Key())
1674 }
1675 p := func(prefix string) string {
1676 e.nextReg++
1677 return "%" | prefix | irItoa(e.nextReg)
1678 }
1679 keyAlloca := p("dl")
1680 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
1681 e.w(" store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
1682 e.w(" call void @runtime.hashmapBinaryDelete(ptr ") ; e.w(mapVal)
1683 e.w(", ptr ") ; e.w(keyAlloca) ; e.w(")\n")
1684 e.declareRuntime("runtime.hashmapBinaryDelete", "void", "ptr, ptr")
1685 return
1686 }
1687 case "close":
1688 if len(c.Call.Args) == 1 {
1689 e.w(" call void @runtime.chanClose(ptr ")
1690 e.w(e.operand(c.Call.Args[0]))
1691 e.w(")\n")
1692 return
1693 }
1694 case "min", "max":
1695 if len(c.Call.Args) >= 2 {
1696 retType := e.llvmType(c.SSAType())
1697 if retType == "" || retType == "void" {
1698 retType = "i32"
1699 }
1700 a := e.operand(c.Call.Args[0])
1701 b2 := e.operand(c.Call.Args[1])
1702 cmpOp := "slt"
1703 if name == "max" {
1704 cmpOp = "sgt"
1705 }
1706 u := safeUnderlying(c.SSAType())
1707 if bb, ok := u.(*Basic); ok && bb.Info()&IsUnsigned != 0 {
1708 cmpOp = "ult"
1709 if name == "max" {
1710 cmpOp = "ugt"
1711 }
1712 }
1713 e.nextReg++
1714 cmpReg := "%mm" | irItoa(e.nextReg)
1715 e.w(" ") ; e.w(cmpReg) ; e.w(" = icmp ") ; e.w(cmpOp) ; e.w(" ") ; e.w(retType) ; e.w(" ") ; e.w(a) ; e.w(", ") ; e.w(b2) ; e.w("\n")
1716 e.w(" ") ; e.w(reg) ; e.w(" = select i1 ") ; e.w(cmpReg) ; e.w(", ") ; e.w(retType) ; e.w(" ") ; e.w(a) ; e.w(", ") ; e.w(retType) ; e.w(" ") ; e.w(b2) ; e.w("\n")
1717 return
1718 }
1719 }
1720 e.w(" ; unhandled builtin: ")
1721 e.w(name)
1722 e.w("\n")
1723 retType := e.llvmType(c.SSAType())
1724 if name == "recover" {
1725 retType = e.ifaceType()
1726 }
1727 if retType != "void" && retType != "" {
1728 if retType == "ptr" || e.intBits(retType) > 0 || retType == "i1" {
1729 e.emitZeroReg(reg, c.SSAType())
1730 } else {
1731 // Aggregate type: use alloca to get zeroinitializer
1732 e.nextReg++
1733 tmp := "%ub" | irItoa(e.nextReg)
1734 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
1735 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
1736 e.allocTypes[c] = retType
1737 }
1738 }
1739 }
1740
1741 func (e *irEmitter) emitPrintArg(val string, t Type) {
1742 if t == nil {
1743 return
1744 }
1745 sty := e.sliceType()
1746 switch u := safeUnderlying(t).(type) {
1747 case *Basic:
1748 switch {
1749 case u.Info()&IsString != 0:
1750 e.w(" call void @runtime.printstring(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1751 e.declareRuntime("runtime.printstring", "void", sty)
1752 case u.Kind() == Bool || u.Kind() == UntypedBool:
1753 e.w(" call void @runtime.printbool(i1 ") ; e.w(val) ; e.w(")\n")
1754 e.declareRuntime("runtime.printbool", "void", "i1")
1755 case u.Kind() == Float32:
1756 e.w(" call void @runtime.printfloat32(float ") ; e.w(val) ; e.w(")\n")
1757 e.declareRuntime("runtime.printfloat32", "void", "float")
1758 case u.Kind() == Float64 || u.Kind() == UntypedFloat:
1759 e.w(" call void @runtime.printfloat64(double ") ; e.w(val) ; e.w(")\n")
1760 e.declareRuntime("runtime.printfloat64", "void", "double")
1761 case u.Info()&IsUnsigned != 0:
1762 lt := e.llvmType(t)
1763 fname := "runtime.printuint" | lt[1:]
1764 e.w(" call void @") ; e.w(fname) ; e.w("(") ; e.w(lt) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1765 e.declareRuntime(fname, "void", lt)
1766 case u.Info()&IsInteger != 0:
1767 lt := e.llvmType(t)
1768 fname := "runtime.printint" | lt[1:]
1769 e.w(" call void @") ; e.w(fname) ; e.w("(") ; e.w(lt) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1770 e.declareRuntime(fname, "void", lt)
1771 }
1772 case *Pointer:
1773 ipt := e.intptrType()
1774 e.nextReg++
1775 tmp := "%pr" | irItoa(e.nextReg)
1776 e.w(" ") ; e.w(tmp) ; e.w(" = ptrtoint ptr ") ; e.w(val) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
1777 e.w(" call void @runtime.printptr(") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(")\n")
1778 e.declareRuntime("runtime.printptr", "void", ipt)
1779 case *Slice:
1780 if b, ok := u.Elem().(*Basic); ok && (b.Kind() == Uint8 || b.Kind() == Int8) {
1781 e.w(" call void @runtime.printbytes(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1782 e.declareRuntime("runtime.printbytes", "void", sty)
1783 } else {
1784 e.w(" call void @runtime.printstring(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1785 e.declareRuntime("runtime.printstring", "void", sty)
1786 }
1787 case *TCMap:
1788 e.w(" call void @runtime.printmap(ptr ") ; e.w(val) ; e.w(")\n")
1789 e.declareRuntime("runtime.printmap", "void", "ptr")
1790 }
1791 }
1792
1793 func (e *irEmitter) emitPhi(p *SSAPhi) {
1794 reg := e.regName(p)
1795 typ := e.llvmType(p.SSAType())
1796 e.w(" ")
1797 e.w(reg)
1798 e.w(" = phi ")
1799 e.w(typ)
1800 e.w(" ")
1801 blk := p.InstrBlock()
1802 for i, edge := range p.Edges {
1803 if i > 0 {
1804 e.w(", ")
1805 }
1806 e.w("[")
1807 e.w(e.operand(edge))
1808 e.w(", ")
1809 if i < len(blk.Preds) {
1810 e.w(e.blockLabel(blk.Preds[i]))
1811 } else {
1812 e.w("%unknown")
1813 }
1814 e.w("]")
1815 }
1816 e.w("\n")
1817 }
1818
1819 func (e *irEmitter) coerceInt(valReg string, fromType string, toType string) string {
1820 if fromType == toType {
1821 return valReg
1822 }
1823 fromBits := e.intBits(fromType)
1824 toBits := e.intBits(toType)
1825 if fromBits == 0 || toBits == 0 {
1826 return valReg
1827 }
1828 e.nextReg++
1829 r := "%rc" | irItoa(e.nextReg)
1830 if fromBits > toBits {
1831 e.w(" ") ; e.w(r) ; e.w(" = trunc ") ; e.w(fromType) ; e.w(" ") ; e.w(valReg) ; e.w(" to ") ; e.w(toType) ; e.w("\n")
1832 } else {
1833 e.w(" ") ; e.w(r) ; e.w(" = sext ") ; e.w(fromType) ; e.w(" ") ; e.w(valReg) ; e.w(" to ") ; e.w(toType) ; e.w("\n")
1834 }
1835 return r
1836 }
1837
1838 func (e *irEmitter) intBits(ty string) int32 {
1839 switch ty {
1840 case "i1":
1841 return 1
1842 case "i8":
1843 return 8
1844 case "i16":
1845 return 16
1846 case "i32":
1847 return 32
1848 case "i64":
1849 return 64
1850 }
1851 return 0
1852 }
1853
1854 func (e *irEmitter) emitReturn(r *SSAReturn) {
1855 if len(r.Results) == 0 {
1856 rt := e.funcRetType(e.curFunc)
1857 if rt == "void" {
1858 e.w(" ret void\n")
1859 } else {
1860 e.w(" unreachable\n")
1861 }
1862 return
1863 }
1864 sig := e.curFunc.Signature
1865 if len(r.Results) == 1 {
1866 typ := e.llvmType(r.Results[0].SSAType())
1867 val := e.operand(r.Results[0])
1868 expectType := typ
1869 if sig != nil && sig.Results() != nil && sig.Results().Len() == 1 {
1870 expectType = e.llvmType(sig.Results().At(0).Type())
1871 }
1872 if val == "null" && expectType != "ptr" {
1873 val = "zeroinitializer"
1874 } else {
1875 val = e.coerceInt(val, typ, expectType)
1876 }
1877 if typ != expectType && val != "zeroinitializer" {
1878 if expectType == "ptr" && e.intBits(typ) > 0 {
1879 e.nextReg++
1880 r := "%rc" | irItoa(e.nextReg)
1881 e.w(" ") ; e.w(r) ; e.w(" = inttoptr ") ; e.w(typ) ; e.w(" ") ; e.w(val) ; e.w(" to ptr\n")
1882 val = r
1883 typ = "ptr"
1884 } else if typ == "ptr" && e.intBits(expectType) > 0 {
1885 e.nextReg++
1886 r := "%rc" | irItoa(e.nextReg)
1887 e.w(" ") ; e.w(r) ; e.w(" = ptrtoint ptr ") ; e.w(val) ; e.w(" to ") ; e.w(expectType) ; e.w("\n")
1888 val = r
1889 typ = expectType
1890 }
1891 if typ != expectType {
1892 val = "zeroinitializer"
1893 }
1894 }
1895 e.w(" ret ")
1896 e.w(expectType)
1897 e.w(" ")
1898 e.w(val)
1899 e.w("\n")
1900 return
1901 }
1902 var expectTypes []string
1903 if sig != nil && sig.Results() != nil {
1904 for i := 0; i < sig.Results().Len(); i++ {
1905 expectTypes = append(expectTypes, e.llvmType(sig.Results().At(i).Type()))
1906 }
1907 }
1908 retType := "{"
1909 for i, res := range r.Results {
1910 if i > 0 {
1911 retType = retType | ", "
1912 }
1913 if i < len(expectTypes) {
1914 retType = retType | expectTypes[i]
1915 } else {
1916 retType = retType | e.llvmType(res.SSAType())
1917 }
1918 }
1919 retType = retType | "}"
1920 prev := "undef"
1921 for i, res := range r.Results {
1922 valType := e.llvmType(res.SSAType())
1923 valOp := e.operand(res)
1924 elemType := valType
1925 if i < len(expectTypes) {
1926 elemType = expectTypes[i]
1927 if valOp == "null" && elemType != "ptr" {
1928 valOp = "zeroinitializer"
1929 } else {
1930 valOp = e.coerceInt(valOp, valType, elemType)
1931 }
1932 }
1933 e.nextReg++
1934 cur := "%rv" | irItoa(e.nextReg)
1935 e.w(" ")
1936 e.w(cur)
1937 e.w(" = insertvalue ")
1938 e.w(retType)
1939 e.w(" ")
1940 e.w(prev)
1941 e.w(", ")
1942 e.w(elemType)
1943 e.w(" ")
1944 e.w(valOp)
1945 e.w(", ")
1946 e.w(irItoa(i))
1947 e.w("\n")
1948 prev = cur
1949 }
1950 e.w(" ret ")
1951 e.w(retType)
1952 e.w(" ")
1953 e.w(prev)
1954 e.w("\n")
1955 }
1956
1957 func (e *irEmitter) emitJump(j *SSAJump) {
1958 blk := j.InstrBlock()
1959 if len(blk.Succs) > 0 {
1960 e.w(" br label ")
1961 e.w(e.blockLabel(blk.Succs[0]))
1962 e.w("\n")
1963 }
1964 }
1965
1966 func isComparisonOp(op SSAOp) bool {
1967 return op == OpEql || op == OpNeq || op == OpLss || op == OpLeq || op == OpGtr || op == OpGeq
1968 }
1969
1970 func (e *irEmitter) emitIf(i *SSAIf) {
1971 blk := i.InstrBlock()
1972 cond := e.operand(i.Cond)
1973 condType := e.llvmType(i.Cond.SSAType())
1974 if at, ok := e.allocTypes[i.Cond]; ok {
1975 condType = at
1976 }
1977 if bop, ok := i.Cond.(*SSABinOp); ok && isComparisonOp(bop.Op) {
1978 condType = "i1"
1979 }
1980 if condType != "i1" && condType != "" && condType != "void" {
1981 e.nextReg++
1982 truncReg := "%ift" | irItoa(e.nextReg)
1983 e.w(" ") ; e.w(truncReg) ; e.w(" = trunc ") ; e.w(condType) ; e.w(" ") ; e.w(cond) ; e.w(" to i1\n")
1984 cond = truncReg
1985 }
1986 if len(blk.Succs) >= 2 {
1987 e.w(" br i1 ")
1988 e.w(cond)
1989 e.w(", label ")
1990 e.w(e.blockLabel(blk.Succs[0]))
1991 e.w(", label ")
1992 e.w(e.blockLabel(blk.Succs[1]))
1993 e.w("\n")
1994 }
1995 }
1996
1997 func (e *irEmitter) emitConvert(c *SSAConvert) {
1998 reg := e.regName(c)
1999 srcType := e.llvmType(c.X.SSAType())
2000 dstType := e.llvmType(c.SSAType())
2001 val := e.operand(c.X)
2002
2003 if srcType == "void" || c.X.SSAType() == nil {
2004 if dstType == "ptr" {
2005 e.valName[c] = "null"
2006 } else {
2007 e.valName[c] = "zeroinitializer"
2008 }
2009 return
2010 }
2011
2012 if srcType == dstType {
2013 e.valName[c] = e.operand(c.X)
2014 return
2015 }
2016
2017 op := e.conversionOp(c.X.SSAType(), c.SSAType())
2018 if op == "ptrtoint" && e.intBits(dstType) == 0 {
2019 if dstType == e.ifaceType() {
2020 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} zeroinitializer, ptr ") ; e.w(val) ; e.w(", 1\n")
2021 } else {
2022 e.valName[c] = "zeroinitializer"
2023 }
2024 return
2025 }
2026 if op == "inttoptr" && e.intBits(srcType) == 0 {
2027 if srcType == e.ifaceType() {
2028 e.nextReg++
2029 r := "%cv" | irItoa(e.nextReg)
2030 e.w(" ") ; e.w(r) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
2031 e.valName[c] = r
2032 } else {
2033 e.valName[c] = "null"
2034 }
2035 return
2036 }
2037 e.w(" ")
2038 e.w(reg)
2039 e.w(" = ")
2040 e.w(op)
2041 e.w(" ")
2042 e.w(srcType)
2043 e.w(" ")
2044 e.w(val)
2045 e.w(" to ")
2046 e.w(dstType)
2047 e.w("\n")
2048 }
2049
2050 func (e *irEmitter) conversionOp(from, to Type) string {
2051 fromBits := e.typeBits(from)
2052 toBits := e.typeBits(to)
2053
2054 fromFloat := false
2055 toFloat := false
2056 fromSigned := true
2057 if b, ok := safeUnderlying(from).(*Basic); ok {
2058 fromFloat = b.Info()&IsFloat != 0
2059 if b.Info()&IsUnsigned != 0 {
2060 fromSigned = false
2061 }
2062 }
2063 if b, ok := safeUnderlying(to).(*Basic); ok {
2064 toFloat = b.Info()&IsFloat != 0
2065 }
2066
2067 if fromFloat && toFloat {
2068 if fromBits < toBits {
2069 return "fpext"
2070 }
2071 return "fptrunc"
2072 }
2073 if fromFloat && !toFloat {
2074 if fromSigned {
2075 return "fptosi"
2076 }
2077 return "fptoui"
2078 }
2079 if !fromFloat && toFloat {
2080 if fromSigned {
2081 return "sitofp"
2082 }
2083 return "uitofp"
2084 }
2085
2086 _, fromPtr := safeUnderlying(from).(*Pointer)
2087 _, toPtr := safeUnderlying(to).(*Pointer)
2088 if fromPtr && !toPtr {
2089 return "ptrtoint"
2090 }
2091 if !fromPtr && toPtr {
2092 return "inttoptr"
2093 }
2094
2095 if fromBits < toBits {
2096 if fromSigned {
2097 return "sext"
2098 }
2099 return "zext"
2100 }
2101 if fromBits > toBits {
2102 return "trunc"
2103 }
2104 return "bitcast"
2105 }
2106
2107 func (e *irEmitter) typeBits(t Type) int {
2108 if t == nil {
2109 return 0
2110 }
2111 switch t := safeUnderlying(t).(type) {
2112 case *Basic:
2113 switch t.Kind() {
2114 case Bool:
2115 return 1
2116 case Int8, Uint8:
2117 return 8
2118 case Int16, Uint16:
2119 return 16
2120 case Int32, Uint32:
2121 return 32
2122 case Int64, Uint64:
2123 return 64
2124 case Float32:
2125 return 32
2126 case Float64:
2127 return 64
2128 case UntypedInt, UntypedRune:
2129 return 32
2130 case UntypedFloat:
2131 return 64
2132 case UnsafePointer:
2133 return e.ptrBits
2134 }
2135 case *Pointer:
2136 return e.ptrBits
2137 }
2138 return 0
2139 }
2140
2141 func (e *irEmitter) emitChangeType(c *SSAChangeType) {
2142 srcType := e.llvmType(c.X.SSAType())
2143 dstType := e.llvmType(c.SSAType())
2144 if at, ok := e.allocTypes[c.X]; ok && at != "ptr" && at != "void" {
2145 srcType = at
2146 }
2147 if srcType == dstType || (srcType == "ptr" && dstType == "ptr") {
2148 e.valName[c] = e.operand(c.X)
2149 return
2150 }
2151 reg := e.regName(c)
2152 val := e.operand(c.X)
2153 e.nextReg++
2154 tmp := "%ct" | irItoa(e.nextReg)
2155 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(dstType) ; e.w("\n")
2156 e.w(" store ") ; e.w(srcType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
2157 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(dstType) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
2158 }
2159
2160 func (e *irEmitter) emitFieldAddr(f *SSAFieldAddr) {
2161 reg := e.regName(f)
2162 baseType := e.llvmType(f.X.SSAType())
2163 if p, ok := safeUnderlying(f.X.SSAType()).(*Pointer); ok && p.Elem() != nil {
2164 elem := p.Elem()
2165 if p2, ok2 := safeUnderlying(elem).(*Pointer); ok2 && p2.Elem() != nil {
2166 baseType = e.llvmType(p2.Elem())
2167 } else {
2168 baseType = e.llvmType(elem)
2169 }
2170 }
2171 if at, ok := e.allocTypes[f.X]; ok && at != "ptr" && at != "void" {
2172 baseType = at
2173 }
2174 base := e.operand(f.X)
2175 // If X is a load (struct by value), use the load's source alloca instead
2176 if uop, ok := f.X.(*SSAUnOp); ok {
2177 addrType := e.llvmType(uop.X.SSAType())
2178 useSource := false
2179 if p, ok2 := safeUnderlying(uop.X.SSAType()).(*Pointer); ok2 && p.Elem() != nil {
2180 elem := p.Elem()
2181 if p2, ok3 := safeUnderlying(elem).(*Pointer); ok3 && p2.Elem() != nil {
2182 // **Struct: load indirection, don't replace base
2183 baseType = e.llvmType(p2.Elem())
2184 } else {
2185 // *Struct: source is struct storage, safe to GEP directly
2186 baseType = e.llvmType(elem)
2187 useSource = true
2188 }
2189 }
2190 if useSource && addrType == "ptr" && baseType != "ptr" && baseType != "void" {
2191 base = e.operand(uop.X)
2192 }
2193 }
2194 if baseType == "ptr" || baseType == "void" {
2195 e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(base)
2196 e.w(", i32 0\n")
2197 return
2198 }
2199 e.w(" ")
2200 e.w(reg)
2201 e.w(" = getelementptr inbounds ")
2202 e.w(baseType)
2203 e.w(", ptr ")
2204 e.w(base)
2205 e.w(", i32 0, i32 ")
2206 e.w(irItoa(f.Field))
2207 e.w("\n")
2208 }
2209
2210 func (e *irEmitter) emitIndexAddr(idx *SSAIndexAddr) {
2211 reg := e.regName(idx)
2212 elemType := e.llvmType(idx.SSAType())
2213 if p, ok := safeUnderlying(idx.SSAType()).(*Pointer); ok {
2214 elemType = e.llvmType(p.Elem())
2215 }
2216 base := e.operand(idx.X)
2217 index := e.operand(idx.Index)
2218 _, isSlice := safeUnderlying(idx.X.SSAType()).(*Slice)
2219 if !isSlice {
2220 if b, ok := safeUnderlying(idx.X.SSAType()).(*Basic); ok && b.Info()&IsString != 0 {
2221 isSlice = true
2222 }
2223 }
2224 if isSlice {
2225 e.nextReg++
2226 dataPtr := "%sp" | irItoa(e.nextReg)
2227 e.w(" ")
2228 e.w(dataPtr)
2229 e.w(" = extractvalue ")
2230 e.w(e.sliceType())
2231 e.w(" ")
2232 e.w(base)
2233 e.w(", 0\n")
2234 e.w(" ")
2235 e.w(reg)
2236 e.w(" = getelementptr inbounds ")
2237 e.w(elemType)
2238 e.w(", ptr ")
2239 e.w(dataPtr)
2240 e.w(", ")
2241 e.w(e.llvmType(idx.Index.SSAType()))
2242 e.w(" ")
2243 e.w(index)
2244 e.w("\n")
2245 return
2246 }
2247 _, isArray := safeUnderlying(idx.X.SSAType()).(*Array)
2248 if isArray {
2249 e.nextReg++
2250 arrPtr := "%ai" | irItoa(e.nextReg)
2251 arrType := e.llvmType(idx.X.SSAType())
2252 e.w(" ") ; e.w(arrPtr) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
2253 e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(base) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w("\n")
2254 e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
2255 e.w(arrType) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w(", i32 0, ")
2256 e.w(e.llvmType(idx.Index.SSAType())) ; e.w(" ") ; e.w(index) ; e.w("\n")
2257 return
2258 }
2259 e.w(" ")
2260 e.w(reg)
2261 e.w(" = getelementptr inbounds ")
2262 e.w(elemType)
2263 e.w(", ptr ")
2264 e.w(base)
2265 e.w(", ")
2266 e.w(e.llvmType(idx.Index.SSAType()))
2267 e.w(" ")
2268 e.w(index)
2269 e.w("\n")
2270 }
2271
2272 func (e *irEmitter) emitExtract(ex *SSAExtract) {
2273 reg := e.regName(ex)
2274 tupType := e.llvmType(ex.Tuple.SSAType())
2275 if at, ok := e.allocTypes[ex.Tuple]; ok {
2276 tupType = at
2277 }
2278 val := e.operand(ex.Tuple)
2279 // Track extracted element type for downstream alloc/store consistency
2280 extractedType := extractTupleField(tupType, ex.Index)
2281 if extractedType != "" {
2282 ssaType := e.llvmType(ex.SSAType())
2283 if extractedType != ssaType {
2284 e.allocTypes[ex] = extractedType
2285 }
2286 }
2287 if tupType == "ptr" || tupType == "void" {
2288 elemType := e.llvmType(ex.SSAType())
2289 if elemType == "void" { elemType = "ptr" }
2290 e.nextReg++
2291 castReg := "%ev" | irItoa(e.nextReg)
2292 e.w(" ") ; e.w(castReg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(val) ; e.w(", i32 0\n")
2293 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(castReg) ; e.w("\n")
2294 e.allocTypes[ex] = elemType
2295 return
2296 }
2297 e.w(" ")
2298 e.w(reg)
2299 e.w(" = extractvalue ")
2300 e.w(tupType)
2301 e.w(" ")
2302 e.w(val)
2303 e.w(", ")
2304 e.w(irItoa(ex.Index))
2305 e.w("\n")
2306 }
2307
2308 func extractTupleField(tupType string, index int) string {
2309 if len(tupType) < 3 || tupType[0] != '{' {
2310 return ""
2311 }
2312 inner := tupType[1 : len(tupType)-1]
2313 depth := 0
2314 field := 0
2315 start := 0
2316 for i := 0; i < len(inner); i++ {
2317 c := inner[i]
2318 if c == '{' {
2319 depth++
2320 } else if c == '}' {
2321 depth--
2322 } else if c == ',' && depth == 0 {
2323 if field == index {
2324 s := inner[start:i]
2325 for len(s) > 0 && s[0] == ' ' { s = s[1:] }
2326 for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] }
2327 return s
2328 }
2329 field++
2330 start = i + 1
2331 }
2332 }
2333 if field == index {
2334 s := inner[start:]
2335 for len(s) > 0 && s[0] == ' ' { s = s[1:] }
2336 for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] }
2337 return s
2338 }
2339 return ""
2340 }
2341
2342 func (e *irEmitter) sextToIpt(val SSAValue, op string) string {
2343 ipt := e.intptrType()
2344 if val == nil {
2345 return op
2346 }
2347 valType := e.llvmType(val.SSAType())
2348 if valType == ipt {
2349 return op
2350 }
2351 e.nextReg++
2352 ext := "%sx" | irItoa(e.nextReg)
2353 e.w(" ") ; e.w(ext) ; e.w(" = sext ") ; e.w(valType) ; e.w(" ") ; e.w(op) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
2354 return ext
2355 }
2356
2357 func (e *irEmitter) emitMakeSlice(m *SSAMakeSlice) {
2358 reg := e.regName(m)
2359 ipt := e.intptrType()
2360 sty := e.sliceType()
2361 lenOp := e.sextToIpt(m.Len, e.operand(m.Len))
2362 capOp := lenOp
2363 if m.Cap != nil {
2364 capOp = e.sextToIpt(m.Cap, e.operand(m.Cap))
2365 }
2366 var dataPtr string
2367 if m.Data != nil {
2368 dataPtr = e.operand(m.Data)
2369 } else {
2370 elemType := "i8"
2371 if sl, ok := safeUnderlying(m.SSAType()).(*Slice); ok {
2372 elemType = e.llvmType(sl.Elem())
2373 }
2374 e.nextReg++
2375 elemSz := "%ms" | irItoa(e.nextReg)
2376 e.w(" ")
2377 e.w(elemSz)
2378 e.w(" = ptrtoint ptr getelementptr (")
2379 e.w(elemType)
2380 e.w(", ptr null, i32 1) to ")
2381 e.w(ipt)
2382 e.w("\n")
2383 e.nextReg++
2384 allocSz := "%ms" | irItoa(e.nextReg)
2385 e.w(" ")
2386 e.w(allocSz)
2387 e.w(" = mul ")
2388 e.w(ipt)
2389 e.w(" ")
2390 e.w(elemSz)
2391 e.w(", ")
2392 e.w(capOp)
2393 e.w("\n")
2394 e.nextReg++
2395 dataPtr = "%ms" | irItoa(e.nextReg)
2396 e.w(" ")
2397 e.w(dataPtr)
2398 e.w(" = call ptr @runtime.alloc(")
2399 e.w(ipt)
2400 e.w(" ")
2401 e.w(allocSz)
2402 e.w(", ptr null, ptr undef)\n")
2403 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
2404 }
2405 e.nextReg++
2406 s1 := "%ms" | irItoa(e.nextReg)
2407 e.w(" ")
2408 e.w(s1)
2409 e.w(" = insertvalue ")
2410 e.w(sty)
2411 e.w(" undef, ptr ")
2412 e.w(dataPtr)
2413 e.w(", 0\n")
2414 e.nextReg++
2415 s2 := "%ms" | irItoa(e.nextReg)
2416 e.w(" ")
2417 e.w(s2)
2418 e.w(" = insertvalue ")
2419 e.w(sty)
2420 e.w(" ")
2421 e.w(s1)
2422 e.w(", ")
2423 e.w(ipt)
2424 e.w(" ")
2425 e.w(lenOp)
2426 e.w(", 1\n")
2427 e.w(" ")
2428 e.w(reg)
2429 e.w(" = insertvalue ")
2430 e.w(sty)
2431 e.w(" ")
2432 e.w(s2)
2433 e.w(", ")
2434 e.w(ipt)
2435 e.w(" ")
2436 e.w(capOp)
2437 e.w(", 2\n")
2438 }
2439
2440 func (e *irEmitter) emitSliceOp(s *SSASlice) {
2441 reg := e.regName(s)
2442 ipt := e.intptrType()
2443 sty := e.sliceType()
2444 src := e.operand(s.X)
2445 var oldPtr, oldLen, oldCap string
2446 if arr, ok := safeUnderlying(s.X.SSAType()).(*Array); ok {
2447 arrType := e.llvmType(s.X.SSAType())
2448 e.nextReg++
2449 tmp := "%sl" | irItoa(e.nextReg)
2450 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
2451 e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(src) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
2452 oldPtr = tmp
2453 oldLen = irItoa64(arr.Len())
2454 oldCap = oldLen
2455 } else {
2456 e.nextReg++
2457 oldPtr = "%sl" | irItoa(e.nextReg)
2458 e.w(" ")
2459 e.w(oldPtr)
2460 e.w(" = extractvalue ")
2461 e.w(sty)
2462 e.w(" ")
2463 e.w(src)
2464 e.w(", 0\n")
2465 e.nextReg++
2466 oldLen = "%sl" | irItoa(e.nextReg)
2467 e.w(" ")
2468 e.w(oldLen)
2469 e.w(" = extractvalue ")
2470 e.w(sty)
2471 e.w(" ")
2472 e.w(src)
2473 e.w(", 1\n")
2474 e.nextReg++
2475 oldCap = "%sl" | irItoa(e.nextReg)
2476 e.w(" ")
2477 e.w(oldCap)
2478 e.w(" = extractvalue ")
2479 e.w(sty)
2480 e.w(" ")
2481 e.w(src)
2482 e.w(", 2\n")
2483 }
2484 toIpt := func(val SSAValue, operandStr string) string {
2485 if val == nil {
2486 return operandStr
2487 }
2488 valType := e.llvmType(val.SSAType())
2489 if valType == ipt {
2490 return operandStr
2491 }
2492 e.nextReg++
2493 ext := "%sl" | irItoa(e.nextReg)
2494 e.w(" ") ; e.w(ext) ; e.w(" = sext ") ; e.w(valType) ; e.w(" ") ; e.w(operandStr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
2495 return ext
2496 }
2497 low := "0"
2498 if s.Low != nil {
2499 low = toIpt(s.Low, e.operand(s.Low))
2500 }
2501 high := oldLen
2502 if s.High != nil {
2503 high = toIpt(s.High, e.operand(s.High))
2504 }
2505 maxCap := oldCap
2506 if s.Max != nil {
2507 maxCap = toIpt(s.Max, e.operand(s.Max))
2508 }
2509 elemType := "i8"
2510 if sl, ok := safeUnderlying(s.X.SSAType()).(*Slice); ok {
2511 elemType = e.llvmType(sl.Elem())
2512 } else if ar, ok := safeUnderlying(s.X.SSAType()).(*Array); ok {
2513 elemType = e.llvmType(ar.Elem())
2514 }
2515 e.nextReg++
2516 newPtr := "%sl" | irItoa(e.nextReg)
2517 e.w(" ")
2518 e.w(newPtr)
2519 e.w(" = getelementptr inbounds ")
2520 e.w(elemType)
2521 e.w(", ptr ")
2522 e.w(oldPtr)
2523 e.w(", ")
2524 e.w(ipt)
2525 e.w(" ")
2526 e.w(low)
2527 e.w("\n")
2528 e.nextReg++
2529 newLen := "%sl" | irItoa(e.nextReg)
2530 e.w(" ")
2531 e.w(newLen)
2532 e.w(" = sub ")
2533 e.w(ipt)
2534 e.w(" ")
2535 e.w(high)
2536 e.w(", ")
2537 e.w(low)
2538 e.w("\n")
2539 e.nextReg++
2540 newCap := "%sl" | irItoa(e.nextReg)
2541 e.w(" ")
2542 e.w(newCap)
2543 e.w(" = sub ")
2544 e.w(ipt)
2545 e.w(" ")
2546 e.w(maxCap)
2547 e.w(", ")
2548 e.w(low)
2549 e.w("\n")
2550 e.nextReg++
2551 s1 := "%sl" | irItoa(e.nextReg)
2552 e.w(" ")
2553 e.w(s1)
2554 e.w(" = insertvalue ")
2555 e.w(sty)
2556 e.w(" undef, ptr ")
2557 e.w(newPtr)
2558 e.w(", 0\n")
2559 e.nextReg++
2560 s2 := "%sl" | irItoa(e.nextReg)
2561 e.w(" ")
2562 e.w(s2)
2563 e.w(" = insertvalue ")
2564 e.w(sty)
2565 e.w(" ")
2566 e.w(s1)
2567 e.w(", ")
2568 e.w(ipt)
2569 e.w(" ")
2570 e.w(newLen)
2571 e.w(", 1\n")
2572 e.w(" ")
2573 e.w(reg)
2574 e.w(" = insertvalue ")
2575 e.w(sty)
2576 e.w(" ")
2577 e.w(s2)
2578 e.w(", ")
2579 e.w(ipt)
2580 e.w(" ")
2581 e.w(newCap)
2582 e.w(", 2\n")
2583 }
2584
2585 func (e *irEmitter) emitMakeInterface(m *SSAMakeInterface) {
2586 reg := e.regName(m)
2587 val := e.operand(m.X)
2588 valType := e.llvmType(m.X.SSAType())
2589 if at, ok := e.allocTypes[m.X]; ok && at != "ptr" && at != "void" {
2590 valType = at
2591 }
2592 p := func(prefix string) string {
2593 e.nextReg++
2594 return "%" | prefix | irItoa(e.nextReg)
2595 }
2596 if valType == e.ifaceType() {
2597 tp := p("mi")
2598 e.w(" ") ; e.w(tp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 0\n")
2599 dp := p("mi")
2600 e.w(" ") ; e.w(dp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
2601 t1 := p("mi")
2602 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(tp) ; e.w(", 0\n")
2603 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(dp) ; e.w(", 1\n")
2604 return
2605 }
2606 var valPtr string
2607 if valType == "ptr" {
2608 valPtr = val
2609 } else {
2610 valPtr = p("mi")
2611 e.w(" ") ; e.w(valPtr) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
2612 e.w(" store ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2613 }
2614 typeid := e.typeIDGlobal(m.X.SSAType())
2615 t1 := p("mi")
2616 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(typeid) ; e.w(", 0\n")
2617 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(valPtr) ; e.w(", 1\n")
2618 }
2619
2620 func (e *irEmitter) typeIDGlobal(t Type) string {
2621 name := e.typeIDName(t)
2622 if e.typeIDs == nil {
2623 e.typeIDs = map[string]bool{}
2624 }
2625 if !e.typeIDs[name] {
2626 e.typeIDs[name] = true
2627 }
2628 return "@" | name
2629 }
2630
2631 func (e *irEmitter) typeIDName(t Type) string {
2632 pkg := e.pkg.Pkg.Path()
2633 if named, ok := t.(*Named); ok && named.Obj() != nil {
2634 return pkg | ".typeid." | named.Obj().Name()
2635 }
2636 if p, ok := t.(*Pointer); ok {
2637 if named, ok := p.Elem().(*Named); ok && named.Obj() != nil {
2638 return pkg | ".typeid.ptr." | named.Obj().Name()
2639 }
2640 }
2641 raw := e.llvmType(t)
2642 safe := []byte{:len(raw)}
2643 safe = safe[:0]
2644 for i := 0; i < len(raw); i++ {
2645 c := raw[i]
2646 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '.' {
2647 safe = append(safe, c)
2648 } else if c == '{' || c == '}' || c == ',' || c == ' ' || c == '*' {
2649 safe = append(safe, '_')
2650 }
2651 }
2652 return pkg | ".typeid." | string(safe)
2653 }
2654
2655 func (e *irEmitter) findIfaceImpls(methodName string) []ifaceImpl {
2656 var impls []ifaceImpl
2657 for mname, m := range e.pkg.Members {
2658 fn, ok := m.(*SSAFunction)
2659 if !ok {
2660 continue
2661 }
2662 dotIdx := -1
2663 for i := 0; i < len(mname); i++ {
2664 if mname[i] == '.' {
2665 dotIdx = i
2666 break
2667 }
2668 }
2669 if dotIdx < 0 {
2670 continue
2671 }
2672 if mname[dotIdx+1:] != methodName {
2673 continue
2674 }
2675 tname := mname[:dotIdx]
2676 obj := e.pkg.Pkg.Scope().Lookup(tname)
2677 if obj == nil {
2678 continue
2679 }
2680 tn, ok2 := obj.(*TypeName)
2681 if !ok2 || tn.Type() == nil {
2682 continue
2683 }
2684 isPtrRecv := fn.object != nil && fn.object.HasPtrRecv()
2685 impls = append(impls, ifaceImpl{fn: fn, recvType: tn.Type(), ptrRecv: isPtrRecv})
2686 }
2687 return impls
2688 }
2689
2690 type ifaceImpl struct {
2691 fn *SSAFunction
2692 recvType Type
2693 ptrRecv bool
2694 }
2695
2696 func (e *irEmitter) emitInvoke(inv *SSAInvoke) {
2697 reg := e.regName(inv)
2698 ifaceVal := e.operand(inv.X)
2699 retType := e.llvmType(inv.SSAType())
2700 isVoid := retType == "void"
2701 p := func(prefix string) string {
2702 e.nextReg++
2703 return "%" | prefix | irItoa(e.nextReg)
2704 }
2705 tidPtr := p("tid")
2706 e.w(" ") ; e.w(tidPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(ifaceVal) ; e.w(", 0\n")
2707 valPtr := p("vp")
2708 e.w(" ") ; e.w(valPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(ifaceVal) ; e.w(", 1\n")
2709
2710 impls := e.findIfaceImpls(inv.MethodName)
2711
2712 if len(impls) == 0 {
2713 e.w(" ; invoke: no implementations for ") ; e.w(inv.MethodName) ; e.w("\n")
2714 if !isVoid {
2715 e.nextReg++
2716 zp := "%zp" | irItoa(e.nextReg)
2717 e.w(" ") ; e.w(zp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
2718 e.w(" store ") ; e.w(retType) ; e.w(" zeroinitializer, ptr ") ; e.w(zp) ; e.w("\n")
2719 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(zp) ; e.w("\n")
2720 }
2721 return
2722 }
2723
2724 if len(impls) == 1 {
2725 impl := impls[0]
2726 var recvLLVM, recv string
2727 if impl.ptrRecv {
2728 recvLLVM = "ptr"
2729 recv = valPtr
2730 } else {
2731 recvLLVM = e.llvmType(impl.recvType)
2732 if recvLLVM == "ptr" {
2733 recv = valPtr
2734 } else {
2735 recv = p("ld")
2736 e.w(" ") ; e.w(recv) ; e.w(" = load ") ; e.w(recvLLVM) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2737 }
2738 }
2739 e.w(" ")
2740 if !isVoid {
2741 e.w(reg) ; e.w(" = ")
2742 }
2743 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(e.funcSymbol(impl.fn)) ; e.w("(")
2744 e.w(recvLLVM) ; e.w(" ") ; e.w(recv)
2745 for i, arg := range inv.Args {
2746 argT := e.llvmType(arg.SSAType())
2747 if argT == "void" {
2748 argT = "ptr"
2749 }
2750 e.w(", ") ; e.w(argT) ; e.w(" ") ; e.w(e.operand(arg))
2751 _ = i
2752 }
2753 e.w(", ptr null)\n")
2754 return
2755 }
2756
2757 baseID := e.nextReg
2758 mergeLabel := "invoke.merge" | irItoa(baseID)
2759 var checkLabels []string
2760 var caseLabels []string
2761 var callRegs []string
2762 for i := range impls {
2763 checkLabels = append(checkLabels, "invoke.check" | irItoa(baseID) | "." | irItoa(i))
2764 caseLabels = append(caseLabels, "invoke.case" | irItoa(baseID) | "." | irItoa(i))
2765 if !isVoid {
2766 callRegs = append(callRegs, p("cr"))
2767 }
2768 }
2769 defaultLabel := "invoke.default" | irItoa(baseID)
2770
2771 e.w(" br label %") ; e.w(checkLabels[0]) ; e.w("\n")
2772
2773 for i, impl := range impls {
2774 nextCheck := defaultLabel
2775 if i < len(impls)-1 {
2776 nextCheck = checkLabels[i+1]
2777 }
2778 e.w(checkLabels[i]) ; e.w(":\n")
2779 tidGlobal := e.typeIDGlobal(impl.recvType)
2780 cmpReg := p("cmp")
2781 e.w(" ") ; e.w(cmpReg) ; e.w(" = icmp eq ptr ") ; e.w(tidPtr) ; e.w(", ") ; e.w(tidGlobal) ; e.w("\n")
2782 e.w(" br i1 ") ; e.w(cmpReg) ; e.w(", label %") ; e.w(caseLabels[i]) ; e.w(", label %") ; e.w(nextCheck) ; e.w("\n")
2783
2784 e.w(caseLabels[i]) ; e.w(":\n")
2785 var recvLLVM, recv string
2786 if impl.ptrRecv {
2787 recvLLVM = "ptr"
2788 recv = valPtr
2789 } else {
2790 recvLLVM = e.llvmType(impl.recvType)
2791 if recvLLVM == "ptr" {
2792 recv = valPtr
2793 } else {
2794 recv = p("ld")
2795 e.w(" ") ; e.w(recv) ; e.w(" = load ") ; e.w(recvLLVM) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2796 }
2797 }
2798 e.w(" ")
2799 if !isVoid {
2800 e.w(callRegs[i]) ; e.w(" = ")
2801 }
2802 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(e.funcSymbol(impl.fn)) ; e.w("(")
2803 e.w(recvLLVM) ; e.w(" ") ; e.w(recv)
2804 for ii, arg := range inv.Args {
2805 argT := e.llvmType(arg.SSAType())
2806 if argT == "void" {
2807 argT = "ptr"
2808 }
2809 e.w(", ") ; e.w(argT) ; e.w(" ") ; e.w(e.operand(arg))
2810 _ = ii
2811 }
2812 e.w(", ptr null)\n")
2813 e.w(" br label %") ; e.w(mergeLabel) ; e.w("\n")
2814 }
2815
2816 e.w(defaultLabel) ; e.w(":\n")
2817 e.w(" unreachable\n")
2818
2819 e.w(mergeLabel) ; e.w(":\n")
2820 if !isVoid {
2821 e.w(" ") ; e.w(reg) ; e.w(" = phi ") ; e.w(retType) ; e.w(" ")
2822 for i := range impls {
2823 if i > 0 { e.w(", ") }
2824 e.w("[ ") ; e.w(callRegs[i]) ; e.w(", %") ; e.w(caseLabels[i]) ; e.w(" ]")
2825 }
2826 e.w("\n")
2827 }
2828 }
2829
2830 func (e *irEmitter) emitTypeAssert(t *SSATypeAssert) {
2831 reg := e.regName(t)
2832 val := e.operand(t.X)
2833 assertedType := e.llvmType(t.AssertedType)
2834 voidAssert := assertedType == "void"
2835 if voidAssert {
2836 assertedType = "ptr"
2837 }
2838 p := func(prefix string) string {
2839 e.nextReg++
2840 return "%" | prefix | irItoa(e.nextReg)
2841 }
2842 // Check if input is already a concrete ptr (not an interface {ptr, ptr})
2843 inputType := e.llvmType(t.X.SSAType())
2844 if at, ok := e.allocTypes[t.X]; ok {
2845 inputType = at
2846 }
2847 var valPtr, typePtr string
2848 if inputType == "ptr" {
2849 valPtr = val
2850 typePtr = "null"
2851 } else {
2852 valPtr = p("ta")
2853 e.w(" ") ; e.w(valPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
2854 typePtr = p("ta")
2855 e.w(" ") ; e.w(typePtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 0\n")
2856 }
2857 if t.CommaOk {
2858 tidGlobal := e.typeIDGlobal(t.AssertedType)
2859 ok := p("ta")
2860 e.w(" ") ; e.w(ok) ; e.w(" = icmp eq ptr ") ; e.w(typePtr) ; e.w(", ") ; e.w(tidGlobal) ; e.w("\n")
2861 loaded := p("ta")
2862 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(assertedType) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2863 tupType := "{" | assertedType | ", i1}"
2864 t1 := p("ta")
2865 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, ") ; e.w(assertedType) ; e.w(" ") ; e.w(loaded) ; e.w(", 0\n")
2866 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t1) ; e.w(", i1 ") ; e.w(ok) ; e.w(", 1\n")
2867 if voidAssert {
2868 e.allocTypes[t] = tupType
2869 }
2870 } else {
2871 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(assertedType) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2872 if voidAssert {
2873 e.allocTypes[t] = assertedType
2874 }
2875 }
2876 }
2877
2878 func (e *irEmitter) emitMakeMap(m *SSAMakeMap) {
2879 reg := e.regName(m)
2880 ipt := e.intptrType()
2881 mt, _ := safeUnderlying(m.SSAType()).(*TCMap)
2882 keyType := "i32"
2883 valType := "i32"
2884 alg := "0"
2885 if mt != nil {
2886 keyType = e.llvmType(mt.Key())
2887 valType = e.llvmType(mt.Elem())
2888 if e.isStringLike(mt.Key()) {
2889 alg = "1"
2890 }
2891 }
2892 p := func(prefix string) string {
2893 e.nextReg++
2894 return "%" | prefix | irItoa(e.nextReg)
2895 }
2896 keySz := p("mm")
2897 e.w(" ") ; e.w(keySz) ; e.w(" = ptrtoint ptr getelementptr (")
2898 e.w(keyType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
2899 valSz := p("mm")
2900 e.w(" ") ; e.w(valSz) ; e.w(" = ptrtoint ptr getelementptr (")
2901 e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
2902 hint := "8"
2903 if m.Reserve != nil {
2904 hint = e.operand(m.Reserve)
2905 }
2906 e.w(" ") ; e.w(reg) ; e.w(" = call ptr @runtime.hashmapMake(")
2907 e.w(ipt) ; e.w(" ") ; e.w(keySz) ; e.w(", ")
2908 e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(", ")
2909 e.w(ipt) ; e.w(" ") ; e.w(hint) ; e.w(", i8 ") ; e.w(alg) ; e.w(")\n")
2910 e.declareRuntime("runtime.hashmapMake", "ptr", ipt | ", " | ipt | ", " | ipt | ", i8")
2911 }
2912
2913 func (e *irEmitter) emitMapUpdate(m *SSAMapUpdate) {
2914 mapVal := e.operand(m.Map)
2915 keyVal := e.operand(m.Key)
2916 valVal := e.operand(m.Value)
2917 mapType := m.Map.SSAType()
2918 if pt, ok := safeUnderlying(mapType).(*Pointer); ok {
2919 mapType = pt.Elem()
2920 }
2921 mt, _ := safeUnderlying(mapType).(*TCMap)
2922 keyType := "i32"
2923 valType := "i32"
2924 if mt != nil {
2925 keyType = e.llvmType(mt.Key())
2926 valType = e.llvmType(mt.Elem())
2927 }
2928 p := func(prefix string) string {
2929 e.nextReg++
2930 return "%" | prefix | irItoa(e.nextReg)
2931 }
2932 if keyVal == "null" && keyType != "ptr" { keyVal = "zeroinitializer" }
2933 if valVal == "null" && valType != "ptr" { valVal = "zeroinitializer" }
2934 keyAlloca := p("mu")
2935 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
2936 e.w(" store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
2937 valAlloca := p("mu")
2938 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
2939 e.w(" store ") ; e.w(valType) ; e.w(" ") ; e.w(valVal) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
2940 if mt != nil && e.isStringLike(mt.Key()) {
2941 e.w(" call void @runtime.hashmapContentSet(ptr ") ; e.w(mapVal)
2942 e.w(", ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal)
2943 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
2944 e.declareRuntime("runtime.hashmapContentSet", "void", "ptr, " | keyType | ", ptr")
2945 } else {
2946 e.w(" call void @runtime.hashmapBinarySet(ptr ") ; e.w(mapVal)
2947 e.w(", ptr ") ; e.w(keyAlloca)
2948 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
2949 e.declareRuntime("runtime.hashmapBinarySet", "void", "ptr, ptr, ptr")
2950 }
2951 }
2952
2953 func (e *irEmitter) emitLookup(l *SSALookup) {
2954 reg := e.regName(l)
2955 ipt := e.intptrType()
2956 mapVal := e.operand(l.X)
2957 keyVal := e.operand(l.Index)
2958 mt, _ := safeUnderlying(l.X.SSAType()).(*TCMap)
2959 keyType := "i32"
2960 valType := "i32"
2961 if mt != nil {
2962 keyType = e.llvmType(mt.Key())
2963 valType = e.llvmType(mt.Elem())
2964 }
2965 p := func(prefix string) string {
2966 e.nextReg++
2967 return "%" | prefix | irItoa(e.nextReg)
2968 }
2969 valAlloca := p("ml")
2970 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
2971 valSz := p("ml")
2972 e.w(" ") ; e.w(valSz) ; e.w(" = ptrtoint ptr getelementptr (")
2973 e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
2974 if mt != nil && e.isStringLike(mt.Key()) {
2975 okReg := p("ml")
2976 e.w(" ") ; e.w(okReg) ; e.w(" = call i1 @runtime.hashmapContentGet(ptr ") ; e.w(mapVal)
2977 e.w(", ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal)
2978 e.w(", ptr ") ; e.w(valAlloca)
2979 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(")\n")
2980 e.declareRuntime("runtime.hashmapContentGet", "i1", "ptr, " | keyType | ", ptr, " | ipt)
2981 if l.CommaOk {
2982 loaded := p("ml")
2983 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
2984 tupType := "{" | valType | ", i1}"
2985 t1 := p("ml")
2986 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, ") ; e.w(valType) ; e.w(" ") ; e.w(loaded) ; e.w(", 0\n")
2987 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t1) ; e.w(", i1 ") ; e.w(okReg) ; e.w(", 1\n")
2988 } else {
2989 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
2990 }
2991 } else {
2992 keyAlloca := p("ml")
2993 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
2994 e.w(" store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
2995 okReg := p("ml")
2996 e.w(" ") ; e.w(okReg) ; e.w(" = call i1 @runtime.hashmapBinaryGet(ptr ") ; e.w(mapVal)
2997 e.w(", ptr ") ; e.w(keyAlloca)
2998 e.w(", ptr ") ; e.w(valAlloca)
2999 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(")\n")
3000 e.declareRuntime("runtime.hashmapBinaryGet", "i1", "ptr, ptr, ptr, " | ipt)
3001 if l.CommaOk {
3002 loaded := p("ml")
3003 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
3004 tupType := "{" | valType | ", i1}"
3005 t1 := p("ml")
3006 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, ") ; e.w(valType) ; e.w(" ") ; e.w(loaded) ; e.w(", 0\n")
3007 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t1) ; e.w(", i1 ") ; e.w(okReg) ; e.w(", 1\n")
3008 } else {
3009 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
3010 }
3011 }
3012 }
3013
3014 func (e *irEmitter) isStringLike(t Type) bool {
3015 if t == nil {
3016 return false
3017 }
3018 if b, ok := safeUnderlying(t).(*Basic); ok {
3019 return b.Info()&IsString != 0
3020 }
3021 return false
3022 }
3023
3024 func (e *irEmitter) emitMakeClosure(m *SSAMakeClosure) {
3025 reg := e.regName(m)
3026 fn, _ := m.Fn.(*SSAFunction)
3027 p := func(prefix string) string {
3028 e.nextReg++
3029 return "%" | prefix | irItoa(e.nextReg)
3030 }
3031 ipt := e.intptrType()
3032
3033 if len(m.Bindings) == 0 {
3034 t1 := p("mc")
3035 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr null, 0\n")
3036 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1)
3037 e.w(", ptr ") ; e.w(e.funcSymbol(fn)) ; e.w(", 1\n")
3038 return
3039 }
3040
3041 ctxType := e.closureContextType(m.Bindings)
3042 ctxSz := p("mc")
3043 e.w(" ") ; e.w(ctxSz) ; e.w(" = ptrtoint ptr getelementptr (")
3044 e.w(ctxType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
3045 ctxPtr := p("mc")
3046 e.w(" ") ; e.w(ctxPtr) ; e.w(" = call ptr @runtime.alloc(")
3047 e.w(ipt) ; e.w(" ") ; e.w(ctxSz) ; e.w(", ptr null, ptr undef)\n")
3048 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
3049
3050 for i, b := range m.Bindings {
3051 bval := e.operand(b)
3052 btype := e.llvmType(b.SSAType())
3053 gep := p("mc")
3054 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(ctxType) ; e.w(", ptr ")
3055 e.w(ctxPtr) ; e.w(", i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
3056 e.w(" store ") ; e.w(btype) ; e.w(" ") ; e.w(bval) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
3057 }
3058
3059 t1 := p("mc")
3060 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(ctxPtr) ; e.w(", 0\n")
3061 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1)
3062 e.w(", ptr ") ; e.w(e.funcSymbol(fn)) ; e.w(", 1\n")
3063 }
3064
3065 func (e *irEmitter) closureContextType(bindings []SSAValue) string {
3066 s := "{"
3067 for i, b := range bindings {
3068 if i > 0 {
3069 s = s | ", "
3070 }
3071 s = s | e.llvmType(b.SSAType())
3072 }
3073 return s | "}"
3074 }
3075
3076 func (e *irEmitter) emitFreeVarUnpack(f *SSAFunction) {
3077 ctxTypes := []string{:len(f.FreeVars)}
3078 for i, fv := range f.FreeVars {
3079 ctxTypes[i] = e.llvmType(fv.SSAType())
3080 }
3081 ctxType := "{"
3082 for i, t := range ctxTypes {
3083 if i > 0 {
3084 ctxType = ctxType | ", "
3085 }
3086 ctxType = ctxType | t
3087 }
3088 ctxType = ctxType | "}"
3089
3090 for i, fv := range f.FreeVars {
3091 fvName := e.regName(fv)
3092 e.nextReg++
3093 gep := "%fv" | irItoa(e.nextReg)
3094 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(ctxType)
3095 e.w(", ptr %context, i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
3096 e.w(" ") ; e.w(fvName) ; e.w(" = load ") ; e.w(ctxTypes[i])
3097 e.w(", ptr ") ; e.w(gep) ; e.w("\n")
3098 }
3099 }
3100
3101 func (e *irEmitter) emitPanic(p *SSAPanic) {
3102 e.w(" call void @runtime._panic(ptr null)\n")
3103 e.w(" unreachable\n")
3104 e.declareRuntime("runtime._panic", "void", "ptr")
3105 }
3106
3107 func (e *irEmitter) emitRange(r *SSARange) {
3108 reg := e.regName(r)
3109 if _, ok := safeUnderlying(r.X.SSAType()).(*TCMap); ok {
3110 e.w(" ") ; e.w(reg) ; e.w(" = alloca [48 x i8]\n")
3111 e.w(" call void @llvm.memset.p0.i64(ptr ") ; e.w(reg) ; e.w(", i8 0, i64 48, i1 false)\n")
3112 e.declareRuntime("llvm.memset.p0.i64", "void", "ptr, i8, i64, i1")
3113 return
3114 }
3115 ipt := e.intptrType()
3116 e.w(" ") ; e.w(reg) ; e.w(" = alloca ") ; e.w(ipt) ; e.w("\n")
3117 e.w(" store ") ; e.w(ipt) ; e.w(" 0, ptr ") ; e.w(reg) ; e.w("\n")
3118 }
3119
3120 func (e *irEmitter) emitNext(n *SSANext) {
3121 reg := e.regName(n)
3122 rangeInstr := n.Iter.(*SSARange)
3123 iterPtr := e.regName(rangeInstr)
3124 collVal := e.operand(rangeInstr.X)
3125 p := func(prefix string) string {
3126 e.nextReg++
3127 return "%" | prefix | irItoa(e.nextReg)
3128 }
3129 if mt, ok := safeUnderlying(rangeInstr.X.SSAType()).(*TCMap); ok {
3130 e.emitNextMap(reg, iterPtr, collVal, mt, n, p)
3131 return
3132 }
3133 if arr, ok := safeUnderlying(rangeInstr.X.SSAType()).(*Array); ok {
3134 e.emitNextArray(reg, iterPtr, collVal, arr, n, p)
3135 return
3136 }
3137 collLLVM := e.llvmType(rangeInstr.X.SSAType())
3138 if len(collLLVM) > 0 && collLLVM[0] == 'i' {
3139 tupType := e.llvmType(n.SSAType())
3140 if at, ok := e.allocTypes[n]; ok {
3141 tupType = at
3142 }
3143 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" zeroinitializer, i1 false, 0\n")
3144 return
3145 }
3146 e.emitNextSlice(reg, iterPtr, collVal, rangeInstr, n, p)
3147 }
3148
3149 func (e *irEmitter) emitNextSlice(reg, iterPtr, collVal string, rangeInstr *SSARange, n *SSANext, p func(string) string) {
3150 ipt := e.intptrType()
3151 sty := e.sliceType()
3152 idx := p("rn")
3153 e.w(" ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
3154 slLen := p("rn")
3155 e.w(" ") ; e.w(slLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(collVal) ; e.w(", 1\n")
3156 ok := p("rn")
3157 e.w(" ") ; e.w(ok) ; e.w(" = icmp ult ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", ") ; e.w(slLen) ; e.w("\n")
3158 key := p("rn")
3159 e.w(" ") ; e.w(key) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(" to i32\n")
3160 dataPtr := p("rn")
3161 e.w(" ") ; e.w(dataPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(collVal) ; e.w(", 0\n")
3162 elemType := "i32"
3163 if sl, ok2 := safeUnderlying(rangeInstr.X.SSAType()).(*Slice); ok2 {
3164 elemType = e.llvmType(sl.Elem())
3165 }
3166 eptr := p("rn")
3167 e.w(" ") ; e.w(eptr) ; e.w(" = getelementptr ") ; e.w(elemType)
3168 e.w(", ptr ") ; e.w(dataPtr) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
3169 fallback := p("rn")
3170 e.w(" ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
3171 safePtr := p("rn")
3172 e.w(" ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
3173 e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
3174 elem := p("rn")
3175 e.w(" ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
3176 inc := p("rn")
3177 e.w(" ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
3178 newCnt := p("rn")
3179 e.w(" ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
3180 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
3181 e.w(" store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
3182 tupType := e.llvmType(n.SSAType())
3183 t1 := p("rn")
3184 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
3185 t2 := p("rn")
3186 e.w(" ") ; e.w(t2) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t1) ; e.w(", i32 ") ; e.w(key) ; e.w(", 1\n")
3187 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t2) ; e.w(", ") ; e.w(elemType) ; e.w(" ") ; e.w(elem) ; e.w(", 2\n")
3188 }
3189
3190 func (e *irEmitter) emitNextArray(reg, iterPtr, collVal string, arr *Array, n *SSANext, p func(string) string) {
3191 ipt := e.intptrType()
3192 arrLen := arr.Len()
3193 elemType := e.llvmType(arr.Elem())
3194 arrType := "[" | irItoa(int(arrLen)) | " x " | elemType | "]"
3195 idx := p("rn")
3196 e.w(" ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
3197 ok := p("rn")
3198 e.w(" ") ; e.w(ok) ; e.w(" = icmp ult ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", ") ; e.w(irItoa(int(arrLen))) ; e.w("\n")
3199 key := p("rn")
3200 e.w(" ") ; e.w(key) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(" to i32\n")
3201 // Store array to memory to get element pointer via GEP
3202 arrAlloca := p("rn")
3203 e.w(" ") ; e.w(arrAlloca) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
3204 e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(collVal) ; e.w(", ptr ") ; e.w(arrAlloca) ; e.w("\n")
3205 eptr := p("rn")
3206 e.w(" ") ; e.w(eptr) ; e.w(" = getelementptr inbounds ") ; e.w(arrType)
3207 e.w(", ptr ") ; e.w(arrAlloca) ; e.w(", i32 0, ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
3208 fallback := p("rn")
3209 e.w(" ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
3210 safePtr := p("rn")
3211 e.w(" ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
3212 e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
3213 elem := p("rn")
3214 e.w(" ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
3215 inc := p("rn")
3216 e.w(" ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
3217 newCnt := p("rn")
3218 e.w(" ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
3219 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
3220 e.w(" store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
3221 tupType := "{i1, i32, " | elemType | "}"
3222 e.allocTypes[n] = tupType
3223 t1 := p("rn")
3224 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
3225 t2 := p("rn")
3226 e.w(" ") ; e.w(t2) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t1) ; e.w(", i32 ") ; e.w(key) ; e.w(", 1\n")
3227 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t2) ; e.w(", ") ; e.w(elemType) ; e.w(" ") ; e.w(elem) ; e.w(", 2\n")
3228 }
3229
3230 func (e *irEmitter) emitNextMap(reg, iterPtr, collVal string, mt *TCMap, n *SSANext, p func(string) string) {
3231 keyType := e.llvmType(mt.Key())
3232 valType := e.llvmType(mt.Elem())
3233 keyAlloca := p("mn")
3234 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
3235 valAlloca := p("mn")
3236 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
3237 ok := p("mn")
3238 e.w(" ") ; e.w(ok) ; e.w(" = call i1 @runtime.hashmapNext(ptr ") ; e.w(collVal)
3239 e.w(", ptr ") ; e.w(iterPtr)
3240 e.w(", ptr ") ; e.w(keyAlloca)
3241 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
3242 key := p("mn")
3243 e.w(" ") ; e.w(key) ; e.w(" = load ") ; e.w(keyType) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
3244 val := p("mn")
3245 e.w(" ") ; e.w(val) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
3246 tupType := e.llvmType(n.SSAType())
3247 t1 := p("mn")
3248 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
3249 t2 := p("mn")
3250 e.w(" ") ; e.w(t2) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t1) ; e.w(", ") ; e.w(keyType) ; e.w(" ") ; e.w(key) ; e.w(", 1\n")
3251 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" ") ; e.w(t2) ; e.w(", ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(", 2\n")
3252 e.declareRuntime("runtime.hashmapNext", "i1", "ptr, ptr, ptr, ptr")
3253 }
3254
3255 func (e *irEmitter) operand(v SSAValue) string {
3256 if v == nil {
3257 return "zeroinitializer"
3258 }
3259 if c, ok := v.(*SSAConst); ok {
3260 return e.constOperand(c)
3261 }
3262 if b, ok := v.(*SSABuiltin); ok {
3263 return "@runtime." | b.SSAName()
3264 }
3265 if f, ok := v.(*SSAFunction); ok {
3266 return "{ ptr null, ptr " | e.funcSymbol(f) | " }"
3267 }
3268 if g, ok := v.(*SSAGlobal); ok {
3269 e.declareExternalGlobal(g)
3270 return e.globalName(g)
3271 }
3272 return e.regName(v)
3273 }
3274
3275 func (e *irEmitter) constOperand(c *SSAConst) string {
3276 if c.val == nil {
3277 if c.typ == nil {
3278 return "null"
3279 }
3280 typ := e.llvmType(c.typ)
3281 if typ == "ptr" {
3282 return "null"
3283 }
3284 if typ == "i1" {
3285 return "false"
3286 }
3287 return "zeroinitializer"
3288 }
3289 b := underlyingBasic(c.typ)
3290 if b != nil {
3291 switch b.kind {
3292 case Bool, UntypedBool:
3293 s := c.val.String()
3294 if s == "true" {
3295 return "true"
3296 }
3297 return "false"
3298 case Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64,
3299 UntypedInt, UntypedRune:
3300 return c.val.String()
3301 case Float32, Float64, UntypedFloat:
3302 return c.val.String()
3303 case TCString, UntypedString:
3304 cv, ok := c.val.(constant.Value)
3305 if !ok {
3306 return "zeroinitializer"
3307 }
3308 s := constant.StringVal(cv)
3309 if len(s) == 0 {
3310 return "zeroinitializer"
3311 }
3312 idx := e.addStringConst(s)
3313 ipt := e.intptrType()
3314 slen := irItoa64(int64(len(s)))
3315 return "{ ptr " | e.strConstGlobal(idx) | ", " | ipt | " " | slen | ", " | ipt | " " | slen | " }"
3316 }
3317 }
3318 if c.typ == nil {
3319 return c.val.String()
3320 }
3321 return "zeroinitializer"
3322 }
3323
3324 func underlyingBasic(t Type) *Basic {
3325 if t == nil {
3326 return nil
3327 }
3328 u := safeUnderlying(t)
3329 if u == nil {
3330 return nil
3331 }
3332 b, ok := u.(*Basic)
3333 if !ok {
3334 return nil
3335 }
3336 return b
3337 }
3338
3339 func newTCPackageWithUniverse(path, name string) *TCPackage {
3340 return &TCPackage{
3341 path: path,
3342 name: name,
3343 scope: NewScope(Universe),
3344 }
3345 }
3346
3347 func irItoa(n int) string {
3348 if n == 0 {
3349 return "0"
3350 }
3351 neg := n < 0
3352 if neg {
3353 n = -n
3354 }
3355 buf := []byte{:0:20}
3356 for n > 0 {
3357 buf = append(buf, byte('0'+n%10))
3358 n /= 10
3359 }
3360 if neg {
3361 buf = append(buf, '-')
3362 }
3363 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
3364 buf[i], buf[j] = buf[j], buf[i]
3365 }
3366 return string(buf)
3367 }
3368
3369 func irItoa64(n int64) string {
3370 if n == 0 {
3371 return "0"
3372 }
3373 neg := n < 0
3374 if neg {
3375 n = -n
3376 }
3377 buf := []byte{:0:20}
3378 for n > 0 {
3379 buf = append(buf, byte('0'+n%10))
3380 n /= 10
3381 }
3382 if neg {
3383 buf = append(buf, '-')
3384 }
3385 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
3386 buf[i], buf[j] = buf[j], buf[i]
3387 }
3388 return string(buf)
3389 }
3390
3391 func irFtoa(f float64) string {
3392 return "0.0"
3393 }
3394
3395 func irParseInt64(s string) int64 {
3396 var n int64
3397 for i := 0; i < len(s); i++ {
3398 c := s[i]
3399 if c < '0' || c > '9' {
3400 break
3401 }
3402 n = n*10 + int64(c-'0')
3403 }
3404 return n
3405 }
3406
3407 func CompileToIR(src []byte, name string, triple string) string {
3408 initUniverse()
3409 prog := NewSSAProgram()
3410 pkg := newTCPackageWithUniverse(name, name)
3411 scope := pkg.Scope()
3412
3413 src = rewriteSliceMakeLiterals(src)
3414 src = stripDuplicatePackageClauses(src)
3415
3416 var parseErrors []string
3417 errh := func(err error) {
3418 parseErrors = append(parseErrors, err.Error())
3419 }
3420 r := bytes.NewReader(src)
3421 file, err := Parse(NewFileBase(name|".mx"), r, errh, nil, 0)
3422 if err != nil || file == nil {
3423 msg := "; parse error"
3424 for _, e := range parseErrors {
3425 msg = msg | ": " | e
3426 }
3427 return msg | "\n"
3428 }
3429
3430 for _, d := range file.DeclList {
3431 switch d := d.(type) {
3432 case *ImportDecl:
3433 if d.Path == nil {
3434 continue
3435 }
3436 path := d.Path.Value
3437 if len(path) >= 2 && path[0] == '"' {
3438 path = path[1 : len(path)-1]
3439 }
3440 ensureImportRegistry()
3441 imported := importRegistry[path]
3442 if imported == nil {
3443 continue
3444 }
3445 if path == "unsafe" && imported.Scope().Lookup("Pointer") == nil {
3446 imported.Scope().Insert(NewTypeName(imported, "Pointer", Typ[UnsafePointer]))
3447 }
3448 localName := imported.Name()
3449 if d.LocalPkgName != nil {
3450 localName = d.LocalPkgName.Value
3451 }
3452 scope.Insert(NewPkgName(pkg, localName, imported))
3453 case *VarDecl:
3454 for _, n := range d.NameList {
3455 scope.Insert(NewTCVar(pkg, n.Value, nil))
3456 }
3457 case *FuncDecl:
3458 if d.Recv == nil && d.Name.Value != "init" {
3459 scope.Insert(NewTCFunc(pkg, d.Name.Value, nil))
3460 }
3461 case *TypeDecl:
3462 scope.Insert(NewTypeName(pkg, d.Name.Value, nil))
3463 case *ConstDecl:
3464 for _, n := range d.NameList {
3465 scope.Insert(NewTCConst(pkg, n.Value, nil, nil))
3466 }
3467 }
3468 }
3469
3470 var curConstGroup *Group
3471 var prevConstValues Expr
3472 var prevConstType Expr
3473 iotaVal := int64(-1)
3474
3475 for _, d := range file.DeclList {
3476 if td, ok := d.(*TypeDecl); ok {
3477 obj := scope.Lookup(td.Name.Value)
3478 if obj != nil {
3479 if tn, ok2 := obj.(*TypeName); ok2 {
3480 NewNamed(tn, nil)
3481 }
3482 }
3483 }
3484 }
3485 for _, d := range file.DeclList {
3486 if td, ok := d.(*TypeDecl); ok {
3487 obj := scope.Lookup(td.Name.Value)
3488 if obj != nil {
3489 if tn, ok2 := obj.(*TypeName); ok2 {
3490 named, ok3 := tn.typ.(*Named)
3491 if ok3 {
3492 typ := tcResolveNameInline(td.Type, scope)
3493 named.SetUnderlying(typ)
3494 }
3495 }
3496 }
3497 }
3498 }
3499
3500 for _, d := range file.DeclList {
3501 switch d := d.(type) {
3502 case *VarDecl:
3503 typ := tcResolveNameInline(d.Type, scope)
3504 if arr, ok := typ.(*Array); ok && arr.Len() < 0 && d.Values != nil {
3505 if cl, ok2 := d.Values.(*CompositeLit); ok2 {
3506 typ = NewArray(arr.Elem(), int64(len(cl.ElemList)))
3507 }
3508 }
3509 if typ == nil && d.Values != nil {
3510 typ = tcInferTypeFromExpr(d.Values, scope)
3511 }
3512 for _, n := range d.NameList {
3513 obj := scope.Lookup(n.Value)
3514 if obj != nil {
3515 if v, ok := obj.(*TCVar); ok {
3516 v.typ = typ
3517 }
3518 }
3519 }
3520 case *FuncDecl:
3521 if d.Recv == nil && d.Name.Value != "init" {
3522 sig := tcResolveFuncInline(d.Type, scope)
3523 obj := scope.Lookup(d.Name.Value)
3524 if obj != nil {
3525 if fn, ok := obj.(*TCFunc); ok && sig != nil {
3526 fn.typ = sig
3527 }
3528 }
3529 }
3530 case *ConstDecl:
3531 if d.Group == nil || d.Group != curConstGroup {
3532 curConstGroup = d.Group
3533 iotaVal = 0
3534 prevConstValues = nil
3535 prevConstType = nil
3536 } else {
3537 iotaVal++
3538 }
3539 valExpr := d.Values
3540 typeExpr := d.Type
3541 if valExpr == nil {
3542 valExpr = prevConstValues
3543 }
3544 if typeExpr == nil && d.Type == nil {
3545 typeExpr = prevConstType
3546 }
3547 if d.Values != nil {
3548 prevConstValues = d.Values
3549 }
3550 if d.Type != nil {
3551 prevConstType = d.Type
3552 }
3553 typ := tcResolveNameInline(typeExpr, scope)
3554 if typ == nil && valExpr != nil {
3555 typ = tcInferTypeFromExpr(valExpr, scope)
3556 }
3557 var val ConstVal
3558 if valExpr != nil {
3559 val = tcEvalConstExpr(valExpr, scope, iotaVal)
3560 }
3561 if typ == nil && val != nil {
3562 typ = Typ[UntypedInt]
3563 }
3564 for _, n := range d.NameList {
3565 obj := scope.Lookup(n.Value)
3566 if obj != nil {
3567 if c, ok := obj.(*TCConst); ok {
3568 c.typ = typ
3569 c.val = val
3570 }
3571 }
3572 }
3573 }
3574 }
3575 for _, d := range file.DeclList {
3576 if fd, ok := d.(*FuncDecl); ok && fd.Recv != nil {
3577 recvType := tcResolveRecvType(fd.Recv, scope)
3578 if recvType == nil {
3579 continue
3580 }
3581 sig := tcResolveFuncInlineWithRecv(fd.Type, fd.Recv, scope)
3582 fn := NewTCFunc(pkg, fd.Name.Value, sig)
3583 isPtr := false
3584 var named *Named
3585 if pt, ok := recvType.(*Pointer); ok {
3586 named, _ = pt.Elem().(*Named)
3587 isPtr = true
3588 } else {
3589 named, _ = recvType.(*Named)
3590 }
3591 if named != nil {
3592 if isPtr {
3593 fn.hasPtrRecv = true
3594 }
3595 named.AddMethod(fn)
3596 }
3597 }
3598 }
3599
3600 ssaPkg := prog.CreatePackage(pkg, []*File{file}, nil)
3601 emitter := newIREmitter(ssaPkg, triple)
3602 return emitter.emit()
3603 }
3604
3605 func tcInferTypeFromExpr(e Expr, scope *Scope) Type {
3606 switch e := e.(type) {
3607 case *BasicLit:
3608 switch e.Kind {
3609 case StringLit:
3610 return Typ[TCString]
3611 case IntLit:
3612 return Typ[Int32]
3613 case FloatLit:
3614 return Typ[Float64]
3615 }
3616 case *Name:
3617 if e.Value == "true" || e.Value == "false" {
3618 return Typ[Bool]
3619 }
3620 return tcResolveNameInline(e, scope)
3621 case *CallExpr:
3622 return tcResolveNameInline(e.Fun, scope)
3623 case *CompositeLit:
3624 t := tcResolveNameInline(e.Type, scope)
3625 if arr, ok := t.(*Array); ok && arr.Len() < 0 {
3626 return NewArray(arr.Elem(), int64(len(e.ElemList)))
3627 }
3628 return t
3629 case *Operation:
3630 if e.Y == nil && e.Op == And {
3631 return NewPointer(tcInferTypeFromExpr(e.X, scope))
3632 }
3633 }
3634 return nil
3635 }
3636
3637 func tcEvalConstExpr(e Expr, scope *Scope, iotaVal int64) ConstVal {
3638 if e == nil {
3639 return nil
3640 }
3641 switch e := e.(type) {
3642 case *BasicLit:
3643 return evalBasicLit(e)
3644 case *Name:
3645 if e.Value == "iota" && iotaVal >= 0 {
3646 return constant.MakeInt64(iotaVal)
3647 }
3648 if scope != nil {
3649 _, obj := scope.LookupParent(e.Value)
3650 if c, ok := obj.(*TCConst); ok && c.val != nil {
3651 return c.val
3652 }
3653 }
3654 case *Operation:
3655 if e.Y == nil {
3656 return tcEvalConstExpr(e.X, scope, iotaVal)
3657 }
3658 xr := tcEvalConstExpr(e.X, scope, iotaVal)
3659 yr := tcEvalConstExpr(e.Y, scope, iotaVal)
3660 if xr == nil || yr == nil {
3661 return nil
3662 }
3663 xv, _ := xr.(constant.Value)
3664 yv, _ := yr.(constant.Value)
3665 if xv == nil || yv == nil {
3666 return nil
3667 }
3668 switch e.Op {
3669 case Add:
3670 return constant.BinaryOp(xv, token.ADD, yv)
3671 case Sub:
3672 return constant.BinaryOp(xv, token.SUB, yv)
3673 case Mul:
3674 return constant.BinaryOp(xv, token.MUL, yv)
3675 case Div:
3676 return constant.BinaryOp(xv, token.QUO, yv)
3677 case Shl:
3678 shift, _ := constant.Uint64Val(yv)
3679 return constant.Shift(xv, token.SHL, uint(shift))
3680 case Shr:
3681 shift, _ := constant.Uint64Val(yv)
3682 return constant.Shift(xv, token.SHR, uint(shift))
3683 case Or:
3684 return constant.BinaryOp(xv, token.OR, yv)
3685 case And:
3686 return constant.BinaryOp(xv, token.AND, yv)
3687 case Xor:
3688 return constant.BinaryOp(xv, token.XOR, yv)
3689 }
3690 case *ParenExpr:
3691 return tcEvalConstExpr(e.X, scope, iotaVal)
3692 }
3693 return nil
3694 }
3695
3696 func tcResolveNameInline(e Expr, scope *Scope) Type {
3697 if e == nil {
3698 return nil
3699 }
3700 switch e := e.(type) {
3701 case *Name:
3702 var obj Object
3703 if scope != nil {
3704 _, obj = scope.LookupParent(e.Value)
3705 } else {
3706 _, obj = Universe.LookupParent(e.Value)
3707 }
3708 if obj != nil {
3709 if tn, ok := obj.(*TypeName); ok {
3710 return tn.typ
3711 }
3712 }
3713 case *SelectorExpr:
3714 pkgName, ok := e.X.(*Name)
3715 if ok && scope != nil {
3716 _, pkgObj := scope.LookupParent(pkgName.Value)
3717 if pn, ok2 := pkgObj.(*PkgName); ok2 && pn.imported != nil {
3718 typeObj := pn.imported.scope.Lookup(e.Sel.Value)
3719 if typeObj != nil {
3720 if tn, ok3 := typeObj.(*TypeName); ok3 {
3721 return tn.typ
3722 }
3723 }
3724 }
3725 }
3726 // Fallback: check importRegistry directly for external package types
3727 if pkgName, ok := e.X.(*Name); ok {
3728 for _, pkg := range importRegistry {
3729 if pkg.Name() == pkgName.Value {
3730 typeObj := pkg.Scope().Lookup(e.Sel.Value)
3731 if typeObj != nil {
3732 if tn, ok2 := typeObj.(*TypeName); ok2 {
3733 return tn.typ
3734 }
3735 }
3736 break
3737 }
3738 }
3739 }
3740 case *Operation:
3741 if e.Y == nil && e.Op == Mul {
3742 base := tcResolveNameInline(e.X, scope)
3743 if base == nil {
3744 base = Typ[Int8]
3745 }
3746 return NewPointer(base)
3747 }
3748 case *SliceType:
3749 elem := tcResolveNameInline(e.Elem, scope)
3750 if elem != nil {
3751 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3752 return Typ[TCString]
3753 }
3754 return NewSlice(elem)
3755 }
3756 case *ArrayType:
3757 elem := tcResolveNameInline(e.Elem, scope)
3758 if elem != nil {
3759 n := int64(-1)
3760 if lit, ok := e.Len.(*BasicLit); ok {
3761 n = irParseInt64(lit.Value)
3762 } else if e.Len != nil {
3763 cv := tcEvalConstExpr(e.Len, scope, -1)
3764 if cv != nil {
3765 if gv, ok := cv.(constant.Value); ok {
3766 if iv, ok2 := constant.Int64Val(gv); ok2 {
3767 n = iv
3768 }
3769 }
3770 }
3771 }
3772 return NewArray(elem, n)
3773 }
3774 case *MapType:
3775 key := tcResolveNameInline(e.Key, scope)
3776 val := tcResolveNameInline(e.Value, scope)
3777 if key != nil && val != nil {
3778 return NewTCMap(key, val)
3779 }
3780 case *StructType:
3781 var fields []*TCVar
3782 var tags []string
3783 for i, field := range e.FieldList {
3784 typ := tcResolveNameInline(field.Type, scope)
3785 fname := ""
3786 if field.Name != nil {
3787 fname = field.Name.Value
3788 }
3789 fields = append(fields, NewTCField(nil, fname, typ, field.Name == nil))
3790 tag := ""
3791 if i < len(e.TagList) && e.TagList[i] != nil {
3792 tag = e.TagList[i].Value
3793 }
3794 tags = append(tags, tag)
3795 }
3796 return NewTCStruct(fields, tags)
3797 case *FuncType:
3798 return tcResolveFuncInline(e, scope)
3799 case *InterfaceType:
3800 return tcResolveInterfaceInline(e, scope)
3801 case *DotsType:
3802 elem := tcResolveNameInline(e.Elem, scope)
3803 if elem != nil {
3804 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3805 return Typ[TCString]
3806 }
3807 return NewSlice(elem)
3808 }
3809 }
3810 return nil
3811 }
3812
3813 func tcResolveInterfaceInline(e *InterfaceType, scope *Scope) *TCInterface {
3814 var methods []*IfaceMethod
3815 for _, f := range e.MethodList {
3816 if f.Name == nil {
3817 continue
3818 }
3819 ft, ok := f.Type.(*FuncType)
3820 if !ok {
3821 continue
3822 }
3823 sig := tcResolveFuncInline(ft, scope)
3824 if sig != nil {
3825 methods = append(methods, NewTCIfaceMethod(f.Name.Value, sig))
3826 }
3827 }
3828 iface := NewTCInterface(methods, nil)
3829 iface.Complete()
3830 return iface
3831 }
3832
3833 func stripDuplicatePackageClauses(src []byte) []byte {
3834 found := false
3835 var out []byte
3836 i := 0
3837 for i < len(src) {
3838 nlIdx := bytes.IndexByte(src[i:], '\n')
3839 var line []byte
3840 var lineEnd int
3841 if nlIdx < 0 {
3842 line = src[i:]
3843 lineEnd = len(src)
3844 } else {
3845 line = src[i : i+nlIdx]
3846 lineEnd = i + nlIdx + 1
3847 }
3848 trimmed := bytes.TrimSpace(line)
3849 if bytes.HasPrefix(trimmed, "package ") {
3850 if found {
3851 if out == nil {
3852 out = []byte{:0:len(src)}
3853 out = append(out, src[:i]...)
3854 }
3855 for k := 0; k < len(line); k++ {
3856 out = append(out, ' ')
3857 }
3858 if nlIdx >= 0 {
3859 out = append(out, '\n')
3860 }
3861 i = lineEnd
3862 continue
3863 }
3864 found = true
3865 }
3866 if out != nil {
3867 out = append(out, src[i:lineEnd]...)
3868 }
3869 i = lineEnd
3870 }
3871 if out == nil {
3872 return src
3873 }
3874 return out
3875 }
3876
3877 func rewriteSliceMakeLiterals(src []byte) []byte {
3878 var out []byte
3879 i := 0
3880 for i < len(src) {
3881 start := bytes.Index(src[i:], []byte("{:"))
3882 if start < 0 {
3883 out = append(out, src[i:]...)
3884 break
3885 }
3886 start = start + i
3887 lbrack := findSliceTypeStart(src, start)
3888 if lbrack < 0 {
3889 out = append(out, src[i:start+2]...)
3890 i = start + 2
3891 continue
3892 }
3893 close := findMatchingBrace(src, start)
3894 if close < 0 {
3895 out = append(out, src[i:start+2]...)
3896 i = start + 2
3897 continue
3898 }
3899 inner := src[start+2 : close]
3900 colonIdx := bytes.IndexByte(inner, ':')
3901 typeText := src[lbrack:start]
3902 out = append(out, src[i:lbrack]...)
3903 if colonIdx < 0 {
3904 out = append(out, "make("...)
3905 out = append(out, typeText...)
3906 out = append(out, ", "...)
3907 out = append(out, bytes.TrimSpace(inner)...)
3908 out = append(out, ')')
3909 } else {
3910 lenExpr := bytes.TrimSpace(inner[:colonIdx])
3911 capExpr := bytes.TrimSpace(inner[colonIdx+1:])
3912 out = append(out, "make("...)
3913 out = append(out, typeText...)
3914 out = append(out, ", "...)
3915 out = append(out, lenExpr...)
3916 out = append(out, ", "...)
3917 out = append(out, capExpr...)
3918 out = append(out, ')')
3919 }
3920 i = close + 1
3921 }
3922 if out == nil {
3923 return src
3924 }
3925 return out
3926 }
3927
3928 func findSliceTypeStart(src []byte, braceIdx int) int {
3929 j := braceIdx - 1
3930 for j >= 0 && (src[j] == ' ' || src[j] == '\t' || src[j] == '\n') {
3931 j--
3932 }
3933 if j < 0 {
3934 return -1
3935 }
3936 depth := 0
3937 parenDepth := 0
3938 for j >= 0 {
3939 ch := src[j]
3940 if ch == ')' {
3941 parenDepth++
3942 } else if ch == '(' {
3943 parenDepth--
3944 } else if parenDepth > 0 {
3945 j--
3946 continue
3947 }
3948 if ch == ']' {
3949 depth++
3950 } else if ch == '[' {
3951 depth--
3952 if depth == 0 {
3953 return j
3954 }
3955 } else if depth == 0 && parenDepth == 0 {
3956 if ch == ' ' || ch == '\t' || ch == '\n' || ch == '*' || ch == '(' || ch == ')' {
3957 j--
3958 continue
3959 }
3960 if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '.' {
3961 j--
3962 continue
3963 }
3964 return -1
3965 }
3966 j--
3967 }
3968 return -1
3969 }
3970
3971 func findMatchingBrace(src []byte, openIdx int) int {
3972 depth := 1
3973 for i := openIdx + 1; i < len(src); i++ {
3974 if src[i] == '{' {
3975 depth++
3976 } else if src[i] == '}' {
3977 depth--
3978 if depth == 0 {
3979 return i
3980 }
3981 }
3982 }
3983 return -1
3984 }
3985
3986 func tcResolveRecvType(recv *Field, scope *Scope) Type {
3987 if recv == nil {
3988 return nil
3989 }
3990 return tcResolveNameInline(recv.Type, scope)
3991 }
3992
3993 func tcResolveFuncInlineWithRecv(ft *FuncType, recv *Field, scope *Scope) *Signature {
3994 if ft == nil {
3995 return nil
3996 }
3997 var recvVar *TCVar
3998 if recv != nil {
3999 recvTyp := tcResolveNameInline(recv.Type, scope)
4000 recvName := ""
4001 if recv.Name != nil {
4002 recvName = recv.Name.Value
4003 }
4004 recvVar = NewTCVar(nil, recvName, recvTyp)
4005 }
4006 params := tcResolveFieldList(ft.ParamList, scope)
4007 results := tcResolveFieldList(ft.ResultList, scope)
4008 variadic := false
4009 if len(ft.ParamList) > 0 {
4010 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
4011 variadic = true
4012 }
4013 }
4014 return NewSignature(recvVar, params, results, variadic)
4015 }
4016
4017 func tcResolveFieldList(fields []*Field, scope *Scope) *Tuple {
4018 if len(fields) == 0 {
4019 return nil
4020 }
4021 var vars []*TCVar
4022 for _, f := range fields {
4023 typ := tcResolveNameInline(f.Type, scope)
4024 pname := ""
4025 if f.Name != nil {
4026 pname = f.Name.Value
4027 }
4028 vars = append(vars, NewTCVar(nil, pname, typ))
4029 }
4030 return NewTuple(vars...)
4031 }
4032
4033 func tcResolveFuncInline(ft *FuncType, scope *Scope) *Signature {
4034 if ft == nil {
4035 return nil
4036 }
4037 var params []*TCVar
4038 for _, p := range ft.ParamList {
4039 typ := tcResolveNameInline(p.Type, scope)
4040 pname := ""
4041 if p.Name != nil {
4042 pname = p.Name.Value
4043 }
4044 params = append(params, NewTCVar(nil, pname, typ))
4045 }
4046 var results []*TCVar
4047 for _, r := range ft.ResultList {
4048 typ := tcResolveNameInline(r.Type, scope)
4049 rname := ""
4050 if r.Name != nil {
4051 rname = r.Name.Value
4052 }
4053 results = append(results, NewTCVar(nil, rname, typ))
4054 }
4055 variadic := false
4056 if len(ft.ParamList) > 0 {
4057 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
4058 variadic = true
4059 }
4060 }
4061 var pTuple *Tuple
4062 if len(params) > 0 {
4063 pTuple = NewTuple(params...)
4064 }
4065 var rTuple *Tuple
4066 if len(results) > 0 {
4067 rTuple = NewTuple(results...)
4068 }
4069 return NewSignature(nil, pTuple, rTuple, variadic)
4070 }
4071
4072 func (e *irEmitter) instrOperands(instr SSAInstruction) []SSAValue {
4073 switch i := instr.(type) {
4074 case *SSAStore:
4075 return []SSAValue{i.Addr, i.Val}
4076 case *SSAUnOp:
4077 return []SSAValue{i.X}
4078 case *SSABinOp:
4079 return []SSAValue{i.X, i.Y}
4080 case *SSACall:
4081 out := []SSAValue{i.Call.Value}
4082 for _, a := range i.Call.Args {
4083 out = append(out, a)
4084 }
4085 return out
4086 case *SSAFieldAddr:
4087 return []SSAValue{i.X}
4088 case *SSAIndexAddr:
4089 return []SSAValue{i.X, i.Index}
4090 case *SSAExtract:
4091 return []SSAValue{i.Tuple}
4092 case *SSAPhi:
4093 return i.Edges
4094 case *SSAReturn:
4095 var out []SSAValue
4096 for _, r := range i.Results {
4097 out = append(out, r)
4098 }
4099 return out
4100 case *SSAIf:
4101 return []SSAValue{i.Cond}
4102 case *SSAConvert:
4103 return []SSAValue{i.X}
4104 case *SSAChangeType:
4105 return []SSAValue{i.X}
4106 case *SSAMakeInterface:
4107 return []SSAValue{i.X}
4108 case *SSATypeAssert:
4109 return []SSAValue{i.X}
4110 case *SSASlice:
4111 out := []SSAValue{i.X}
4112 if i.Low != nil { out = append(out, i.Low) }
4113 if i.High != nil { out = append(out, i.High) }
4114 if i.Max != nil { out = append(out, i.Max) }
4115 return out
4116 case *SSAMapUpdate:
4117 return []SSAValue{i.Map, i.Key, i.Value}
4118 case *SSALookup:
4119 return []SSAValue{i.X, i.Index}
4120 case *SSARange:
4121 return []SSAValue{i.X}
4122 case *SSANext:
4123 return []SSAValue{i.Iter}
4124 case *SSASend:
4125 return []SSAValue{i.Chan, i.X}
4126 case *SSAMakeSlice:
4127 out := []SSAValue{i.Len}
4128 if i.Cap != nil { out = append(out, i.Cap) }
4129 if i.Data != nil { out = append(out, i.Data) }
4130 return out
4131 }
4132 return nil
4133 }
4134
4135