ir_emit.mx raw
1 package main
2
3 import (
4 "bytes"
5 )
6
7 var parseErrors []string
8 var genericFuncDecls map[string]*FuncDecl
9 var genericPkgScopes map[string]*Scope
10
11 type irEmitter struct {
12 buf []byte
13 triple string
14 ptrBits int32
15 pkg *SSAPackage
16 valName map[SSAValue]string
17 nextReg int32
18 extDecls map[string]string
19 extGlobals map[string]string
20 strConst []string
21 strMap map[string]int32
22 curFunc *SSAFunction
23 typeIDs map[string]int32
24 typeIDNext int32
25 extTypeIDs map[string]bool
26 localTypeIDs map[string]bool
27 allocTypes map[SSAValue]string
28 regTypes map[string]string
29 hoisted map[SSAValue]bool
30 blockExitLabel map[int32]string
31 nameUsed map[string]bool
32 missingStores map[SSAValue]SSAValue
33 globalTypes map[string]string
34 globalDeclTypes map[string]string
35 sortedMembers []SSAMember
36 loadToGlobal map[string]*SSAGlobal
37 allocBlock map[SSAValue]int32
38 storedTo map[string]bool
39 usedAs map[string]bool
40 deferList []*SSADefer
41 deferID int32
42 }
43
44 func sortedKeys(m map[string]bool) []string {
45 var keys []string
46 for k := range m {
47 keys = append(keys, k)
48 }
49 for i := 1; i < len(keys); i++ {
50 for j := i; j > 0 && keys[j] < keys[j-1]; j-- {
51 keys[j], keys[j-1] = keys[j-1], keys[j]
52 }
53 }
54 return keys
55 }
56
57 func newIREmitter(pkg *SSAPackage, triple string) *irEmitter {
58 ptrBits := 64
59 if len(triple) >= 4 && triple[:4] == "wasm" {
60 ptrBits = 32
61 }
62 return &irEmitter{
63 buf: []byte{:0:4096},
64 triple: triple,
65 ptrBits: ptrBits,
66 pkg: pkg,
67 valName: map[SSAValue]string{},
68 extDecls: map[string]string{},
69 extGlobals: map[string]string{},
70 strMap: map[string]int32{},
71 allocTypes: map[SSAValue]string{},
72 regTypes: map[string]string{},
73 blockExitLabel: map[int32]string{},
74 nameUsed: map[string]bool{},
75 }
76 }
77
78 func (e *irEmitter) dataLayout() string {
79 if len(e.triple) >= 6 && e.triple[:6] == "x86_64" {
80 return "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
81 }
82 if len(e.triple) >= 7 && e.triple[:7] == "aarch64" {
83 return "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
84 }
85 if len(e.triple) >= 6 && e.triple[:6] == "wasm32" {
86 return "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
87 }
88 if len(e.triple) >= 3 && e.triple[:3] == "arm" {
89 return "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
90 }
91 return ""
92 }
93
94 func (e *irEmitter) w(s string) {
95 e.buf = append(e.buf, s...)
96 }
97
98 func (e *irEmitter) regName(v SSAValue) string {
99 if v == nil {
100 e.nextReg++
101 return "%r" | irItoa(e.nextReg)
102 }
103 if n, ok := e.valName[v]; ok {
104 return n
105 }
106 name := v.SSAName()
107 if name == "" {
108 e.nextReg++
109 name = "r" | irItoa(e.nextReg)
110 }
111 n := "%" | name
112 for e.nameUsed[n] {
113 e.nextReg++
114 n = "%r" | irItoa(e.nextReg)
115 }
116 e.valName[v] = n
117 e.nameUsed[n] = true
118 return n
119 }
120
121 func (e *irEmitter) setRegType(v SSAValue, reg string, typ string) {
122 e.allocTypes[v] = typ
123 if len(reg) > 0 && reg[0] == '%' {
124 e.regTypes[reg] = typ
125 }
126 }
127
128 func (e *irEmitter) resolvedType(v SSAValue, fallback string) string {
129 if at, ok := e.allocTypes[v]; ok {
130 return at
131 }
132 if n, ok := e.valName[v]; ok {
133 if rt, ok2 := e.regTypes[n]; ok2 {
134 return rt
135 }
136 }
137 op := e.operandNoSideEffect(v)
138 if len(op) > 0 && op[0] == '%' {
139 if rt, ok := e.regTypes[op]; ok {
140 return rt
141 }
142 }
143 return fallback
144 }
145
146 func (e *irEmitter) llvmType(t Type) string {
147 if t == nil {
148 return "void"
149 }
150 u := safeUnderlying(t)
151 if u == nil {
152 if _, ok := t.(*Slice); ok {
153 return e.sliceType()
154 }
155 if n, ok := t.(*Named); ok {
156 _ = n
157 return "ptr"
158 }
159 return "ptr"
160 }
161 t = u
162 switch t := t.(type) {
163 case *Basic:
164 return e.llvmBasicType(t)
165 case *Pointer:
166 return "ptr"
167 case *Slice:
168 return e.sliceType()
169 case *Array:
170 n := t.Len()
171 if n < 0 {
172 return e.sliceType()
173 }
174 elem := e.llvmType(t.Elem())
175 return "[" | irItoa(int32(n)) | " x " | elem | "]"
176 case *TCStruct:
177 return e.llvmStructType(t)
178 case *Signature:
179 return "{ptr, ptr}"
180 case *TCMap:
181 return "ptr"
182 case *TCChan:
183 return "ptr"
184 case *TCInterface:
185 return e.ifaceType()
186 case *Named:
187 if t.obj != nil && t.obj.Name() == "error" {
188 return e.ifaceType()
189 }
190 if t.NumMethods() > 0 {
191 return e.ifaceType()
192 }
193 return "ptr"
194 case *Tuple:
195 if t == nil || t.Len() == 0 {
196 return "void"
197 }
198 if t.Len() == 1 {
199 return e.llvmType(t.At(0).Type())
200 }
201 s := "{"
202 for i := 0; i < t.Len(); i++ {
203 if i > 0 {
204 s = s | ", "
205 }
206 ft := e.llvmType(t.At(i).Type())
207 if ft == "void" {
208 ft = "ptr"
209 }
210 s = s | ft
211 }
212 return s | "}"
213 }
214 return "i8"
215 }
216
217 func (e *irEmitter) llvmBasicType(t *Basic) string {
218 switch t.Kind() {
219 case Bool:
220 return "i1"
221 case Int8, Uint8:
222 return "i8"
223 case Int16, Uint16:
224 return "i16"
225 case Int32, Uint32:
226 return "i32"
227 case Int64, Uint64:
228 return "i64"
229 case Float32:
230 return "float"
231 case Float64:
232 return "double"
233 case TCString:
234 return e.sliceType()
235 case UnsafePointer:
236 return "ptr"
237 case UntypedBool:
238 return "i1"
239 case UntypedInt, UntypedRune:
240 return "i32"
241 case UntypedFloat:
242 return "double"
243 case UntypedString:
244 return e.sliceType()
245 }
246 return "i32"
247 }
248
249 func (e *irEmitter) ptrType() string {
250 return "ptr"
251 }
252
253 func (e *irEmitter) intptrType() string {
254 if e.ptrBits == 32 {
255 return "i32"
256 }
257 return "i64"
258 }
259
260 func (e *irEmitter) sliceType() string {
261 ipt := e.intptrType()
262 return "{ptr, " | ipt | ", " | ipt | "}"
263 }
264
265 func (e *irEmitter) ifaceType() string {
266 return "{ptr, ptr}"
267 }
268
269 func (e *irEmitter) nextReg2(prefix string) string {
270 e.nextReg++
271 return "%" | prefix | irItoa(e.nextReg)
272 }
273
274 func (e *irEmitter) llvmStructType(t *TCStruct) string {
275 s := "{"
276 for i := 0; i < t.NumFields(); i++ {
277 if i > 0 {
278 s = s | ", "
279 }
280 ft := e.llvmType(t.Field(i).Type())
281 if ft == "void" {
282 ft = "ptr"
283 }
284 s = s | ft
285 }
286 return s | "}"
287 }
288
289 func (e *irEmitter) declareRuntime(name, retType, params string) {
290 e.extDecls[name] = retType | " @" | name | "(" | params | ")"
291 }
292
293 func (e *irEmitter) declareExternalGlobal(g *SSAGlobal) {
294 if g.pkg == nil || g.pkg == e.pkg {
295 return
296 }
297 name := e.globalName(g)
298 if _, ok := e.extGlobals[name]; ok {
299 return
300 }
301 typ := e.llvmType(g.typ)
302 if p, ok := safeUnderlying(g.typ).(*Pointer); ok {
303 typ = e.llvmType(p.Elem())
304 }
305 e.extGlobals[name] = typ
306 }
307
308 func (e *irEmitter) declareExternalFunc(fn *SSAFunction) {
309 sym := e.funcSymbol(fn)
310 if _, ok := e.extDecls[sym]; ok {
311 return
312 }
313 retType := e.funcRetType(fn)
314 params := ""
315 hasRecv := fn.Signature != nil && fn.Signature.Recv() != nil
316 if hasRecv {
317 params = "ptr"
318 }
319 if fn.Signature != nil && fn.Signature.Params() != nil {
320 for i := 0; i < fn.Signature.Params().Len(); i++ {
321 if params != "" {
322 params = params | ", "
323 }
324 params = params | e.llvmType(fn.Signature.Params().At(i).Type())
325 }
326 }
327 if !fn.isExternC {
328 if params != "" {
329 params = params | ", "
330 }
331 params = params | "ptr"
332 }
333 e.extDecls[sym] = retType | " " | sym | "(" | params | ")"
334 }
335
336 func (e *irEmitter) addStringConst(s string) int32 {
337 if idx, ok := e.strMap[s]; ok {
338 return idx
339 }
340 idx := len(e.strConst)
341 e.strConst = append(e.strConst, s)
342 e.strMap[s] = idx
343 return idx
344 }
345
346 func (e *irEmitter) strConstGlobal(idx int32) string {
347 return "@.str." | irItoa(idx)
348 }
349
350 func irEscapeString(s string) string {
351 var buf []byte
352 for i := 0; i < len(s); i++ {
353 c := s[i]
354 if c >= 32 && c < 127 && c != '\\' && c != '"' {
355 buf = append(buf, c)
356 } else {
357 buf = append(buf, '\\')
358 buf = append(buf, "0123456789ABCDEF"[c>>4])
359 buf = append(buf, "0123456789ABCDEF"[c&0xf])
360 }
361 }
362 return string(buf)
363 }
364
365 func (e *irEmitter) emit() string {
366 dl := e.dataLayout()
367 if dl != "" {
368 e.w("target datalayout = \"")
369 e.w(dl)
370 e.w("\"\n")
371 }
372 e.w("target triple = \"")
373 e.w(e.triple)
374 e.w("\"\n\n")
375
376 e.globalTypes = map[string]string{}
377 e.globalDeclTypes = map[string]string{}
378 sortedM := e.pkgMembersSorted()
379 for _, member := range sortedM {
380 fn, ok := member.(*SSAFunction)
381 if !ok { continue }
382 for _, b := range fn.Blocks {
383 for _, instr := range b.Instrs {
384 if s, ok2 := instr.(*SSAStore); ok2 && s.Addr != nil && s.Val != nil {
385 if g, ok3 := s.Addr.(*SSAGlobal); ok3 {
386 vt := e.llvmType(s.Val.SSAType())
387 if vt != "ptr" && vt != "void" && vt != "i1" && vt != "" {
388 name := e.globalName(g)
389 gt := ""
390 if p, ok4 := safeUnderlying(g.typ).(*Pointer); ok4 {
391 gt = e.llvmType(p.Elem())
392 }
393 if gt != "" && gt != "ptr" && gt != "i8" && gt[0] == '{' && vt[0] != '{' {
394 vt = gt
395 }
396 e.globalTypes[name] = vt
397 }
398 }
399 }
400 }
401 }
402 e.loadToGlobal = map[string]*SSAGlobal{}
403 for _, b := range fn.Blocks {
404 for _, instr := range b.Instrs {
405 load, ok2 := instr.(*SSAUnOp)
406 if !ok2 || load.Op != OpMul { continue }
407 g, ok3 := load.X.(*SSAGlobal)
408 if !ok3 { continue }
409 e.loadToGlobal[load.SSAName()] = g
410 }
411 }
412 for _, b := range fn.Blocks {
413 for _, instr := range b.Instrs {
414 if ret, ok2 := instr.(*SSAReturn); ok2 {
415 if fn.Signature == nil { continue }
416 rets := fn.Signature.Results()
417 if rets == nil || rets.Len() == 0 { continue }
418 for i, res := range ret.Results {
419 if i >= rets.Len() { break }
420 if g, ok3 := e.loadToGlobal[res.SSAName()]; ok3 {
421 rt := rets.At(i)
422 if rt == nil { continue }
423 expectType := e.llvmType(rt.Type())
424 if expectType != "ptr" && expectType != "void" && expectType != "i1" && expectType != "" {
425 name := e.globalName(g)
426 if _, exists := e.globalTypes[name]; !exists {
427 e.globalTypes[name] = expectType
428 }
429 }
430 }
431 }
432 }
433 call, ok2 := instr.(*SSACall)
434 if !ok2 { continue }
435 callee := call.Call.Value
436 if callee == nil { continue }
437 var sig *Signature
438 if cfn, ok3 := callee.(*SSAFunction); ok3 && cfn.Signature != nil {
439 sig = cfn.Signature
440 } else {
441 ct := callee.SSAType()
442 if ct != nil {
443 if okv, okok := safeUnderlying(ct).(*Signature); okok {
444 sig = okv
445 }
446 }
447 }
448 if sig == nil { continue }
449 params := sig.Params()
450 if params == nil || params.Len() == 0 { continue }
451 recvOff := 0
452 if sig.Recv() != nil {
453 recvOff = 1
454 }
455 for i, arg := range call.Call.Args {
456 if arg == nil { continue }
457 sigIdx := i - recvOff
458 if sigIdx < 0 || sigIdx >= params.Len() { continue }
459 pt := params.At(sigIdx)
460 if pt == nil { continue }
461 g, found := e.loadToGlobal[arg.SSAName()]
462 if !found { continue }
463 expectType := e.llvmType(pt.Type())
464 name := e.globalName(g)
465 if expectType != "void" && expectType != "i1" && expectType != "" {
466 if _, exists := e.globalTypes[name]; !exists {
467 e.globalTypes[name] = expectType
468 }
469 }
470 }
471 }
472 }
473 for _, b := range fn.Blocks {
474 for _, instr := range b.Instrs {
475 if rng, ok2 := instr.(*SSARange); ok2 && rng.X != nil {
476 if g, ok3 := e.loadToGlobal[rng.X.SSAName()]; ok3 {
477 name := e.globalName(g)
478 if _, exists := e.globalTypes[name]; !exists {
479 e.globalTypes[name] = "ptr"
480 }
481 }
482 }
483 if mu, ok2 := instr.(*SSAMapUpdate); ok2 && mu.Map != nil {
484 if g, ok3 := e.loadToGlobal[mu.Map.SSAName()]; ok3 {
485 name := e.globalName(g)
486 if _, exists := e.globalTypes[name]; !exists {
487 e.globalTypes[name] = "ptr"
488 }
489 }
490 }
491 if lu, ok2 := instr.(*SSALookup); ok2 && lu.X != nil {
492 if g, ok3 := e.loadToGlobal[lu.X.SSAName()]; ok3 {
493 name := e.globalName(g)
494 if _, exists := e.globalTypes[name]; !exists {
495 e.globalTypes[name] = "ptr"
496 }
497 }
498 }
499 bop, ok2 := instr.(*SSABinOp)
500 if !ok2 { continue }
501 if bop.X == nil || bop.Y == nil { continue }
502 gx, xIsGlobal := e.loadToGlobal[bop.X.SSAName()]
503 gy, yIsGlobal := e.loadToGlobal[bop.Y.SSAName()]
504 if xIsGlobal {
505 yt := e.llvmType(bop.Y.SSAType())
506 if yt != "ptr" && yt != "void" && yt != "i1" && yt != "" {
507 name := e.globalName(gx)
508 if _, exists := e.globalTypes[name]; !exists {
509 e.globalTypes[name] = yt
510 }
511 }
512 }
513 if yIsGlobal {
514 xt := e.llvmType(bop.X.SSAType())
515 if xt != "ptr" && xt != "void" && xt != "i1" && xt != "" {
516 name := e.globalName(gy)
517 if _, exists := e.globalTypes[name]; !exists {
518 e.globalTypes[name] = xt
519 }
520 }
521 }
522 }
523 }
524 }
525
526 for _, member := range e.pkgMembersSorted() {
527 switch m := member.(type) {
528 case *SSAGlobal:
529 if m.name != "_" {
530 e.emitGlobal(m)
531 }
532 }
533 }
534 for _, member := range e.pkgMembersSorted() {
535 switch m := member.(type) {
536 case *SSAFunction:
537 e.emitFunction(m)
538 e.emitAnonFuncs(m)
539 m.Blocks = nil
540 m.Locals = nil
541 m.Params = nil
542 m.FreeVars = nil
543 m.NamedResults = nil
544 m.vars = nil
545 }
546 }
547 e.emitLibMain()
548
549 for i, s := range e.strConst {
550 e.w(e.strConstGlobal(i))
551 e.w(" = private constant [")
552 e.w(irItoa(len(s)))
553 e.w(" x i8] c\"")
554 e.w(irEscapeString(s))
555 e.w("\"\n")
556 }
557
558 var tidKeys []string
559 for name := range e.typeIDs {
560 tidKeys = append(tidKeys, name)
561 }
562 for i := 1; i < len(tidKeys); i++ {
563 for j := i; j > 0 && tidKeys[j] < tidKeys[j-1]; j-- {
564 tidKeys[j], tidKeys[j-1] = tidKeys[j-1], tidKeys[j]
565 }
566 }
567 for _, name := range tidKeys {
568 if hasPrefix(name, "reflect/types.type:") {
569 quoted := "\"" | name | "\""
570 if e.extTypeIDs != nil {
571 if _, dup := e.extTypeIDs[quoted]; dup {
572 continue
573 }
574 }
575 if e.localTypeIDs != nil && e.localTypeIDs[quoted] {
576 e.w("@\"")
577 e.w(name)
578 e.w("\" = global i8 0\n")
579 } else {
580 e.w("@\"")
581 e.w(name)
582 e.w("\" = external global i8\n")
583 }
584 } else {
585 e.w("@")
586 e.w(name)
587 e.w(" = private constant i32 0\n")
588 }
589 }
590
591 if len(e.extDecls) > 0 {
592 e.w("\n")
593 var edKeys []string
594 for k := range e.extDecls {
595 edKeys = append(edKeys, k)
596 }
597 for i := 1; i < len(edKeys); i++ {
598 for j := i; j > 0 && edKeys[j] < edKeys[j-1]; j-- {
599 edKeys[j], edKeys[j-1] = edKeys[j-1], edKeys[j]
600 }
601 }
602 for _, k := range edKeys {
603 decl := e.extDecls[k]
604 if decl == "" {
605 continue
606 }
607 e.w("declare ")
608 e.w(decl)
609 e.w("\n")
610 }
611 }
612
613 if len(e.extGlobals) > 0 {
614 e.w("\n")
615 var egKeys []string
616 for name := range e.extGlobals {
617 egKeys = append(egKeys, name)
618 }
619 for i := 1; i < len(egKeys); i++ {
620 for j := i; j > 0 && egKeys[j] < egKeys[j-1]; j-- {
621 egKeys[j], egKeys[j-1] = egKeys[j-1], egKeys[j]
622 }
623 }
624 for _, name := range egKeys {
625 e.w(name)
626 e.w(" = external global ")
627 e.w(e.extGlobals[name])
628 e.w("\n")
629 }
630 }
631
632 if len(e.extTypeIDs) > 0 {
633 e.w("\n")
634 for _, tid := range sortedKeys(e.extTypeIDs) {
635 e.w("@") ; e.w(tid) ; e.w(" = external global i8\n")
636 }
637 }
638
639 return string(e.buf)
640 }
641
642 func (e *irEmitter) releaseAfterEmit() {
643 e.buf = nil
644 e.valName = nil
645 e.extDecls = nil
646 e.extGlobals = nil
647 e.strMap = nil
648 e.strConst = nil
649 e.typeIDs = nil
650 e.extTypeIDs = nil
651 e.localTypeIDs = nil
652 e.allocTypes = nil
653 e.regTypes = nil
654 e.hoisted = nil
655 e.blockExitLabel = nil
656 e.nameUsed = nil
657 e.missingStores = nil
658 e.globalTypes = nil
659 e.globalDeclTypes = nil
660 e.sortedMembers = nil
661 e.loadToGlobal = nil
662 e.allocBlock = nil
663 e.storedTo = nil
664 e.usedAs = nil
665 e.pkg = nil
666 e.curFunc = nil
667 }
668
669 func (e *irEmitter) pkgMembersSorted() []SSAMember {
670 if e.sortedMembers != nil {
671 return e.sortedMembers
672 }
673 var members []SSAMember
674 for _, m := range e.pkg.Members {
675 members = append(members, m)
676 }
677 for i := 1; i < len(members); i++ {
678 for j := i; j > 0 && members[j].MemberName() < members[j-1].MemberName(); j-- {
679 members[j], members[j-1] = members[j-1], members[j]
680 }
681 }
682 e.sortedMembers = members
683 return members
684 }
685
686 func (e *irEmitter) inferGlobalTypeFromLoads(g *SSAGlobal) string {
687 gname := g.SSAName()
688 for _, member := range e.pkgMembersSorted() {
689 fn, ok := member.(*SSAFunction)
690 if !ok { continue }
691 for _, b := range fn.Blocks {
692 for _, instr := range b.Instrs {
693 if load, ok2 := instr.(*SSAUnOp); ok2 && load.Op == OpMul {
694 if lg, ok3 := load.X.(*SSAGlobal); ok3 && lg.SSAName() == gname {
695 lt := e.llvmType(load.SSAType())
696 if lt != "void" && lt != "i8" && lt != "ptr" {
697 return lt
698 }
699 }
700 }
701 }
702 }
703 }
704 return ""
705 }
706
707 func (e *irEmitter) resolveGlobalDeclType(g *SSAGlobal) string {
708 name := e.globalName(g)
709 if dt, ok := e.globalDeclTypes[name]; ok {
710 return dt
711 }
712 typ := e.llvmType(g.typ)
713 gtu := safeUnderlying(g.typ)
714 elemNil := false
715 if p, ok := gtu.(*Pointer); ok {
716 pElem := p.Elem()
717 if pElem == nil {
718 elemNil = true
719 typ = e.ifaceType()
720 } else {
721 typ = e.llvmType(pElem)
722 }
723 }
724 if !elemNil && (typ == "ptr" || typ == "i8") {
725 if gt, ok := e.globalTypes[name]; ok && gt != "ptr" && gt != "void" && gt != "" {
726 typ = gt
727 }
728 }
729 if typ == "void" {
730 typ = "i1"
731 }
732 e.globalDeclTypes[name] = typ
733 return typ
734 }
735
736 func (e *irEmitter) emitGlobal(g *SSAGlobal) {
737 name := e.globalName(g)
738 typ := e.resolveGlobalDeclType(g)
739 e.w(name)
740 e.w(" = global ")
741 e.w(typ)
742 e.w(" ")
743 if g.initConst != nil && g.initType != nil {
744 cv := e.globalConstValue(g.initConst, g.initType, typ)
745 if cv != "" {
746 e.w(cv)
747 e.w("\n")
748 return
749 }
750 }
751 e.w("zeroinitializer\n")
752 }
753
754 func (e *irEmitter) globalConstValue(cv ConstVal, srcType Type, irType string) string {
755 if ci, ok := cv.(constInt); ok {
756 v := ci.v
757 b := underlyingBasic(srcType)
758 if b != nil {
759 switch b.kind {
760 case Int8:
761 v = int32(int8(v))
762 case Uint8:
763 v = int32(uint8(v))
764 case Int16:
765 v = int32(int16(v))
766 case Uint16:
767 v = int32(uint16(v))
768 case Int32:
769 v = int32(int32(v))
770 case Uint32:
771 v = int32(uint32(v))
772 }
773 }
774 return irItoa64(v)
775 }
776 if cf, ok := cv.(constFloat); ok {
777 writeStr(2, " FLOAT-GLOBAL v=" | cf.String() | " lit=" | cf.lit | " hex=" | irFloatHex(cf.v) | "\n")
778 return irFloatHex(cf.v)
779 }
780 if cb, ok := cv.(constBool); ok {
781 if cb.v {
782 return "true"
783 }
784 return "false"
785 }
786 if cs, ok := cv.(constStr); ok {
787 if len(cs.s) == 0 {
788 return "zeroinitializer"
789 }
790 idx := e.addStringConst(cs.s)
791 ipt := e.intptrType()
792 slen := irItoa64(int32(len(cs.s)))
793 return "{ ptr " | e.strConstGlobal(idx) | ", " | ipt | " " | slen | ", " | ipt | " " | slen | " }"
794 }
795 return ""
796 }
797
798 func (e *irEmitter) globalName(g *SSAGlobal) string {
799 pkg := e.pkg.Pkg.Path()
800 if g.pkg != nil {
801 pkg = g.pkg.Pkg.Path()
802 }
803 return irGlobalSymbol(pkg, g.name)
804 }
805
806 func irNeedsQuote(s string) bool {
807 for i := 0; i < len(s); i++ {
808 c := s[i]
809 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '$' {
810 continue
811 }
812 return true
813 }
814 return false
815 }
816
817 func irGlobalSymbol(pkg, name string) string {
818 sym := pkg | "." | name
819 if irNeedsQuote(sym) {
820 return "@\"" | sym | "\""
821 }
822 return "@" | sym
823 }
824
825 func (e *irEmitter) funcSymbol(f *SSAFunction) string {
826 if f.externalSymbol != "" {
827 sym := f.externalSymbol
828 if irNeedsQuote(sym) {
829 return "@\"" | sym | "\""
830 }
831 return "@" | sym
832 }
833 pkg := e.pkg.Pkg.Path()
834 if f.Pkg != nil {
835 pkg = f.Pkg.Pkg.Path()
836 }
837 return irGlobalSymbol(pkg, f.name)
838 }
839
840 func (e *irEmitter) isPkgFunc(f *SSAFunction) bool {
841 if f.Pkg == e.pkg {
842 return true
843 }
844 if f.parent != nil {
845 return e.isPkgFunc(f.parent)
846 }
847 return false
848 }
849
850 func (e *irEmitter) emitAnonFuncs(f *SSAFunction) {
851 for _, af := range f.AnonFuncs {
852 e.emitFunction(af)
853 e.emitAnonFuncs(af)
854 af.Blocks = nil
855 af.Locals = nil
856 af.Params = nil
857 af.FreeVars = nil
858 af.NamedResults = nil
859 af.vars = nil
860 }
861 f.AnonFuncs = nil
862 }
863
864 func (e *irEmitter) emitLibMain() {
865 pkgPath := e.pkg.Pkg.Path()
866 if pkgPath == "main" {
867 return
868 }
869 hasMain := false
870 for _, m := range e.pkg.Members {
871 if fn, ok := m.(*SSAFunction); ok && fn.name == "main" {
872 hasMain = true
873 break
874 }
875 }
876 if hasMain {
877 return
878 }
879 sym := irGlobalSymbol(pkgPath, "main")
880 e.w("\ndefine void ")
881 e.w(sym)
882 e.w("(ptr %context) {\nentry:\n ret void\n}\n")
883 }
884
885 func (e *irEmitter) emitFunction(f *SSAFunction) {
886 e.w("; [emit] " | f.name | "\n")
887 if len(f.Blocks) == 0 {
888 e.emitFuncDecl(f)
889 return
890 }
891 e.curFunc = f
892 e.nextReg = 0
893 e.deferList = nil
894 e.deferID = 0
895 e.valName = map[SSAValue]string{}
896 e.nameUsed = map[string]bool{}
897 e.allocTypes = map[SSAValue]string{}
898 e.regTypes = map[string]string{}
899 e.blockExitLabel = map[int32]string{}
900
901 usedNames := map[string]int32{}
902 for i, p := range f.Params {
903 pname := p.SSAName()
904 if pname == "" {
905 pname = "p" | irItoa(i)
906 }
907 if cnt, ok := usedNames[pname]; ok {
908 pname = pname | "." | irItoa(cnt)
909 }
910 usedNames[p.SSAName()]++
911 e.valName[p] = "%" | pname
912 }
913
914 e.w("\ndefine ")
915 if f.parent != nil {
916 e.w("hidden ")
917 }
918 e.w(e.funcRetType(f))
919 e.w(" ")
920 e.w(e.funcSymbol(f))
921 e.w("(")
922 for i, p := range f.Params {
923 if i > 0 {
924 e.w(", ")
925 }
926 pt := e.llvmType(p.SSAType())
927 if pt == "void" {
928 pt = "ptr"
929 }
930 e.w(pt)
931 e.w(" ")
932 e.w(e.regName(p))
933 }
934 if !f.isExternC {
935 if len(f.Params) > 0 {
936 e.w(", ")
937 }
938 ctxName := "context"
939 for _, p := range f.Params {
940 if p.SSAName() == "context" {
941 ctxName = "context.1"
942 break
943 }
944 }
945 e.w("ptr %")
946 e.w(ctxName)
947 }
948 e.w(") {\n")
949
950 // Pre-scan: set allocTypes, detect cross-block alloca references
951 e.allocBlock = map[SSAValue]int32{}
952 for _, b := range f.Blocks {
953 for _, instr := range b.Instrs {
954 if n, ok := instr.(*SSANext); ok {
955 if ri, ok2 := n.Iter.(*SSARange); ok2 {
956 if arr, ok3 := safeUnderlying(ri.X.SSAType()).(*Array); ok3 {
957 elemType := e.llvmType(arr.Elem())
958 e.allocTypes[n] = "{i1, i32, " | elemType | "}"
959 } else if sl, ok3 := safeUnderlying(ri.X.SSAType()).(*Slice); ok3 {
960 elemType := e.llvmType(sl.Elem())
961 e.allocTypes[n] = "{i1, i32, " | elemType | "}"
962 }
963 }
964 }
965 if c, ok := instr.(*SSACall); ok {
966 if b2, ok2 := c.Call.Value.(*SSABuiltin); ok2 && b2.SSAName() == "recover" {
967 e.allocTypes[c] = e.ifaceType()
968 }
969 }
970 if a, ok := instr.(*SSAAlloc); ok {
971 e.allocBlock[a] = b.Index
972 }
973 }
974 }
975 hoistAllocs := map[SSAValue]bool{}
976 for _, b := range f.Blocks {
977 for _, instr := range b.Instrs {
978 refs := e.instrOperands(instr)
979 for _, ref := range refs {
980 if ab, ok := e.allocBlock[ref]; ok && ab != 0 && ab != b.Index {
981 hoistAllocs[ref] = true
982 }
983 }
984 }
985 }
986 e.hoisted = hoistAllocs
987 e.missingStores = nil
988 e.storedTo = map[string]bool{}
989 for _, b := range f.Blocks {
990 for _, instr := range b.Instrs {
991 if s, ok := instr.(*SSAStore); ok && s.Addr != nil {
992 e.storedTo[s.Addr.SSAName()] = true
993 }
994 }
995 }
996 e.usedAs = map[string]bool{}
997 for _, b := range f.Blocks {
998 for _, instr := range b.Instrs {
999 refs := e.instrOperands(instr)
1000 for _, ref := range refs {
1001 if ref != nil {
1002 e.usedAs[ref.SSAName()] = true
1003 }
1004 }
1005 }
1006 }
1007 for _, b := range f.Blocks {
1008 for i := 0; i+1 < len(b.Instrs); i++ {
1009 load, isLoad := b.Instrs[i].(*SSAUnOp)
1010 if !isLoad || load.Op != OpMul {
1011 continue
1012 }
1013 alloc, isAlloc := b.Instrs[i+1].(*SSAAlloc)
1014 if !isAlloc {
1015 continue
1016 }
1017 if !e.usedAs[load.SSAName()] && !e.storedTo[alloc.SSAName()] && hoistAllocs[alloc] {
1018 srcAlloc, isSrcAlloc := load.X.(*SSAAlloc)
1019 if !isSrcAlloc {
1020 continue
1021 }
1022 srcType := e.llvmType(srcAlloc.SSAType())
1023 if p, ok := safeUnderlying(srcAlloc.SSAType()).(*Pointer); ok && p.Elem() != nil {
1024 srcType = e.llvmType(p.Elem())
1025 }
1026 if len(srcType) > 0 && srcType[0] == '[' {
1027 if e.missingStores == nil {
1028 e.missingStores = map[SSAValue]SSAValue{}
1029 }
1030 e.missingStores[load] = alloc
1031 e.allocTypes[alloc] = srcType
1032 }
1033 }
1034 }
1035 }
1036 var hoistList []*SSAAlloc
1037 for v := range hoistAllocs {
1038 if a, ok := v.(*SSAAlloc); ok {
1039 hoistList = append(hoistList, a)
1040 }
1041 }
1042 for i := 1; i < len(hoistList); i++ {
1043 for j := i; j > 0 && hoistList[j].SSAName() < hoistList[j-1].SSAName(); j-- {
1044 hoistList[j], hoistList[j-1] = hoistList[j-1], hoistList[j]
1045 }
1046 }
1047 for _, b := range f.Blocks {
1048 for _, instr := range b.Instrs {
1049 if d, ok := instr.(*SSADefer); ok {
1050 e.deferList = append(e.deferList, d)
1051 }
1052 }
1053 }
1054 for _, b := range f.Blocks {
1055 if b.Index == 0 {
1056 e.w("entry:\n")
1057 for _, a := range hoistList {
1058 e.emitAlloc(a)
1059 }
1060 if len(e.deferList) > 0 {
1061 e.w(" %deferPtr = alloca ptr\n")
1062 e.w(" store ptr null, ptr %deferPtr\n")
1063 }
1064 if len(e.curFunc.FreeVars) > 0 {
1065 e.emitFreeVarUnpack(e.curFunc)
1066 }
1067 for _, instr := range b.Instrs {
1068 e.emitInstr(instr)
1069 }
1070 } else {
1071 e.emitBlock(b)
1072 }
1073 }
1074 e.hoisted = nil
1075
1076 e.w("}\n")
1077 }
1078
1079 func (e *irEmitter) emitFuncDecl(f *SSAFunction) {
1080 sym := e.funcSymbol(f)
1081 if _, ok := e.extDecls[sym]; ok {
1082 return
1083 }
1084 e.w("\ndeclare ")
1085 e.w(e.funcRetType(f))
1086 e.w(" ")
1087 e.w(sym)
1088 e.w("(")
1089 n := 0
1090 hasRecv := f.Signature != nil && f.Signature.Recv() != nil
1091 if hasRecv {
1092 e.w("ptr")
1093 n++
1094 }
1095 if f.Signature != nil && f.Signature.Params() != nil {
1096 for i := 0; i < f.Signature.Params().Len(); i++ {
1097 if n > 0 {
1098 e.w(", ")
1099 }
1100 e.w(e.llvmType(f.Signature.Params().At(i).Type()))
1101 n++
1102 }
1103 }
1104 if !f.isExternC {
1105 if n > 0 {
1106 e.w(", ")
1107 }
1108 e.w("ptr")
1109 }
1110 e.w(")\n")
1111 e.extDecls[sym] = ""
1112 }
1113
1114 func (e *irEmitter) resolveResultType(t Type) string {
1115 rt := e.llvmType(t)
1116 if rt != "void" { return rt }
1117 if t == nil { return "ptr" }
1118 u := safeUnderlying(t)
1119 if u == nil { return "ptr" }
1120 switch u.(type) {
1121 case *TCInterface:
1122 return e.ifaceType()
1123 case *Signature:
1124 return "{ptr, ptr}"
1125 case *TCStruct:
1126 return e.llvmStructType(u.(*TCStruct))
1127 case *Slice:
1128 return e.sliceType()
1129 }
1130 return "ptr"
1131 }
1132
1133 func (e *irEmitter) funcRetType(f *SSAFunction) string {
1134 if f.Signature == nil || f.Signature.Results() == nil || f.Signature.Results().Len() == 0 {
1135 return "void"
1136 }
1137 if f.Signature.Results().Len() == 1 {
1138 return e.resolveResultType(f.Signature.Results().At(0).Type())
1139 }
1140 s := "{"
1141 for i := 0; i < f.Signature.Results().Len(); i++ {
1142 if i > 0 {
1143 s = s | ", "
1144 }
1145 s = s | e.resolveResultType(f.Signature.Results().At(i).Type())
1146 }
1147 return s | "}"
1148 }
1149
1150 func (e *irEmitter) emitBlock(b *SSABasicBlock) {
1151 label := "b" | irItoa(b.Index)
1152 if b.Index == 0 {
1153 label = "entry"
1154 }
1155 e.w(label)
1156 e.w(":\n")
1157 e.blockExitLabel[b.Index] = "%" | label
1158
1159 if b.Index == 0 && len(e.curFunc.FreeVars) > 0 {
1160 e.emitFreeVarUnpack(e.curFunc)
1161 }
1162
1163 for _, instr := range b.Instrs {
1164 e.emitInstr(instr)
1165 if e.missingStores != nil {
1166 if v, ok2 := instr.(SSAValue); ok2 {
1167 if dst, ok3 := e.missingStores[v]; ok3 {
1168 loadReg := e.regName(v)
1169 dstReg := e.regName(dst)
1170 arrType := e.allocTypes[dst]
1171 e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(loadReg) ; e.w(", ptr ") ; e.w(dstReg) ; e.w("\n")
1172 }
1173 }
1174 }
1175 }
1176
1177 hasTerminator := false
1178 if n := len(b.Instrs); n > 0 {
1179 switch b.Instrs[n-1].(type) {
1180 case *SSAJump, *SSAIf, *SSAReturn:
1181 hasTerminator = true
1182 }
1183 }
1184 if !hasTerminator {
1185 e.w(" unreachable\n")
1186 }
1187 }
1188
1189 func (e *irEmitter) blockLabel(b *SSABasicBlock) string {
1190 if b.Index == 0 {
1191 return "%entry"
1192 }
1193 return "%b" | irItoa(b.Index)
1194 }
1195
1196 func (e *irEmitter) emitInstr(instr SSAInstruction) {
1197 switch i := instr.(type) {
1198 case *SSAAlloc:
1199 if e.hoisted != nil && e.hoisted[i] {
1200 break
1201 }
1202 e.emitAlloc(i)
1203 case *SSAStore:
1204 e.emitStore(i)
1205 case *SSABinOp:
1206 e.emitBinOp(i)
1207 case *SSAUnOp:
1208 e.emitUnOp(i)
1209 case *SSACall:
1210 e.emitCall(i)
1211 case *SSAPhi:
1212 e.emitPhi(i)
1213 case *SSAReturn:
1214 e.emitReturn(i)
1215 case *SSAJump:
1216 e.emitJump(i)
1217 case *SSAIf:
1218 e.emitIf(i)
1219 case *SSAConvert:
1220 e.emitConvert(i)
1221 case *SSAChangeType:
1222 e.emitChangeType(i)
1223 case *SSAFieldAddr:
1224 e.emitFieldAddr(i)
1225 case *SSAIndexAddr:
1226 e.emitIndexAddr(i)
1227 case *SSAExtract:
1228 e.emitExtract(i)
1229 case *SSAMakeSlice:
1230 e.emitMakeSlice(i)
1231 case *SSASlice:
1232 e.emitSliceOp(i)
1233 case *SSAMakeInterface:
1234 e.emitMakeInterface(i)
1235 case *SSAInvoke:
1236 e.emitInvoke(i)
1237 case *SSATypeAssert:
1238 e.emitTypeAssert(i)
1239 case *SSAMakeMap:
1240 e.emitMakeMap(i)
1241 case *SSAMapUpdate:
1242 e.emitMapUpdate(i)
1243 case *SSALookup:
1244 e.emitLookup(i)
1245 case *SSAMakeClosure:
1246 e.emitMakeClosure(i)
1247 case *SSAPanic:
1248 e.emitPanic(i)
1249 case *SSARunDefers:
1250 e.emitRunDefers()
1251 case *SSADefer:
1252 e.emitDefer(i)
1253 case *SSASend:
1254 e.w(" ; send\n")
1255 case *SSAGo:
1256 e.w(" ; go\n")
1257 case *SSASelect:
1258 e.w(" ; select\n")
1259 case *SSARange:
1260 e.emitRange(i)
1261 case *SSANext:
1262 e.emitNext(i)
1263 case *SSAMakeChan:
1264 e.w(" ; makechan\n")
1265 }
1266 }
1267
1268 func (e *irEmitter) emitAlloc(a *SSAAlloc) {
1269 reg := e.regName(a)
1270 if at, ok := e.allocTypes[a]; ok && len(at) > 0 && at[0] == '[' {
1271 if a.Heap {
1272 ipt := e.intptrType()
1273 e.nextReg++
1274 sz := "%ha" | irItoa(e.nextReg)
1275 e.w(" ") ; e.w(sz)
1276 e.w(" = ptrtoint ptr getelementptr (") ; e.w(at)
1277 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1278 e.w(" ") ; e.w(reg)
1279 e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
1280 e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
1281 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
1282 } else {
1283 e.w(" ") ; e.w(reg) ; e.w(" = alloca ") ; e.w(at) ; e.w("\n")
1284 e.w(" store ") ; e.w(at) ; e.w(" zeroinitializer, ptr ") ; e.w(reg) ; e.w("\n")
1285 }
1286 return
1287 }
1288 elemType := e.llvmType(a.SSAType())
1289 nilElem := false
1290 if p, ok := safeUnderlying(a.SSAType()).(*Pointer); ok {
1291 if p.Elem() != nil {
1292 elemType = e.llvmType(p.Elem())
1293 } else {
1294 nilElem = true
1295 }
1296 }
1297 isDoublePtr := false
1298 if p, ok := safeUnderlying(a.SSAType()).(*Pointer); ok && p.Elem() != nil {
1299 if _, ok2 := safeUnderlying(p.Elem()).(*Pointer); ok2 {
1300 isDoublePtr = true
1301 }
1302 }
1303 if isDoublePtr && elemType == "ptr" {
1304 e.allocTypes[a] = elemType
1305 } else if elemType == "void" || (elemType == "ptr" && nilElem) {
1306 inferred := e.inferAllocTypeFromStores(a)
1307 if inferred != "ptr" || elemType == "void" {
1308 elemType = inferred
1309 }
1310 e.allocTypes[a] = elemType
1311 } else {
1312 override := e.inferAllocTypeFromStores(a)
1313 if override != "ptr" && override != elemType {
1314 bothScalar := len(elemType) > 0 && elemType[0] == 'i' && len(override) > 0 && override[0] == 'i'
1315 isFloatToInt := (elemType == "double" || elemType == "float") && len(override) > 0 && override[0] == 'i'
1316 isScalarToAgg := len(elemType) > 0 && (elemType[0] == 'i' || elemType == "double" || elemType == "float") && len(override) > 0 && override[0] == '{'
1317 if !bothScalar && !isFloatToInt && !isScalarToAgg {
1318 elemType = override
1319 e.allocTypes[a] = elemType
1320 }
1321 }
1322 if elemType == "i32" && override == "ptr" {
1323 usage := e.inferAllocTypeFromUsage(a)
1324 if usage != "ptr" && usage != "i32" {
1325 elemType = usage
1326 e.allocTypes[a] = elemType
1327 }
1328 }
1329 }
1330 if !isDoublePtr {
1331 if faType := e.inferAllocTypeFromFieldAddrs(a, elemType); faType != "" {
1332 retType := e.inferAllocTypeFromReturn(a)
1333 callType := e.inferAllocTypeFromCallArgs(a)
1334 appendType := e.inferAllocTypeFromAppendUsage(a)
1335 best := faType
1336 if retType != "" && len(retType) > len(best) {
1337 best = retType
1338 }
1339 if callType != "" && len(callType) > len(best) {
1340 best = callType
1341 }
1342 if appendType != "" && len(appendType) > len(best) {
1343 best = appendType
1344 }
1345 if elemType != best {
1346 elemType = best
1347 e.allocTypes[a] = elemType
1348 }
1349 }
1350 }
1351 if a.Heap {
1352 ipt := e.intptrType()
1353 e.nextReg++
1354 sz := "%ha" | irItoa(e.nextReg)
1355 e.w(" ") ; e.w(sz)
1356 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1357 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1358 e.w(" ") ; e.w(reg)
1359 e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
1360 e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
1361 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
1362 } else {
1363 e.w(" ")
1364 e.w(reg)
1365 e.w(" = alloca ")
1366 e.w(elemType)
1367 e.w("\n")
1368 e.w(" store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(reg) ; e.w("\n")
1369 }
1370 }
1371
1372 func (e *irEmitter) inferAllocTypeFromStores(a *SSAAlloc) string {
1373 allocName := a.SSAName()
1374 for _, b := range e.curFunc.Blocks {
1375 for _, instr := range b.Instrs {
1376 if s, ok := instr.(*SSAStore); ok && s.Addr != nil && s.Addr.SSAName() == allocName {
1377 if at, ok2 := e.allocTypes[s.Val]; ok2 && at != "ptr" && at != "void" {
1378 return at
1379 }
1380 vt := e.llvmType(s.Val.SSAType())
1381 if vt != "void" && vt != "" {
1382 return vt
1383 }
1384 if call, ok := s.Val.(*SSACall); ok {
1385 if b2, ok2 := call.Call.Value.(*SSABuiltin); ok2 && b2.SSAName() == "append" {
1386 return e.sliceType()
1387 }
1388 }
1389 if _, ok := s.Val.(*SSASlice); ok {
1390 return e.sliceType()
1391 }
1392 if _, ok := s.Val.(*SSAMakeSlice); ok {
1393 return e.sliceType()
1394 }
1395 }
1396 }
1397 }
1398 return "ptr"
1399 }
1400
1401 func (e *irEmitter) inferAllocTypeFromReturn(a *SSAAlloc) string {
1402 allocName := a.SSAName()
1403 for _, b := range e.curFunc.Blocks {
1404 for _, instr := range b.Instrs {
1405 ret, ok := instr.(*SSAReturn)
1406 if !ok {
1407 continue
1408 }
1409 for i, rv := range ret.Results {
1410 if rv == nil {
1411 continue
1412 }
1413 if uop, ok2 := rv.(*SSAUnOp); ok2 && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
1414 sig := e.curFunc.Signature
1415 if sig != nil && sig.Results() != nil && i < sig.Results().Len() {
1416 rt := e.llvmType(sig.Results().At(i).Type())
1417 if rt != "void" && rt != "ptr" && rt != "" {
1418 return rt
1419 }
1420 }
1421 return ""
1422 }
1423 }
1424 }
1425 }
1426 return ""
1427 }
1428
1429 func (e *irEmitter) inferAllocTypeFromCallArgs(a *SSAAlloc) string {
1430 allocName := a.SSAName()
1431 loadNames := map[string]bool{}
1432 for _, b := range e.curFunc.Blocks {
1433 for _, instr := range b.Instrs {
1434 if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
1435 loadNames[uop.SSAName()] = true
1436 }
1437 }
1438 }
1439 for _, b := range e.curFunc.Blocks {
1440 for _, instr := range b.Instrs {
1441 call, ok := instr.(*SSACall)
1442 if !ok { continue }
1443 callee := call.Call.Value
1444 if callee == nil { continue }
1445 var sig *Signature
1446 if cfn, ok2 := callee.(*SSAFunction); ok2 && cfn.Signature != nil {
1447 sig = cfn.Signature
1448 } else {
1449 if okv, okok := safeUnderlying(callee.SSAType()).(*Signature); okok {
1450 sig = okv
1451 }
1452 }
1453 if sig == nil || sig.Params() == nil { continue }
1454 recvOff := 0
1455 if sig.Recv() != nil { recvOff = 1 }
1456 for i, arg := range call.Call.Args {
1457 if arg == nil { continue }
1458 if !loadNames[arg.SSAName()] { continue }
1459 sigIdx := i - recvOff
1460 if sigIdx < 0 || sigIdx >= sig.Params().Len() { continue }
1461 pt := e.llvmType(sig.Params().At(sigIdx).Type())
1462 if pt != "void" && pt != "ptr" && pt != "" && len(pt) > 0 && pt[0] == '{' {
1463 return pt
1464 }
1465 }
1466 }
1467 }
1468 return ""
1469 }
1470
1471 func (e *irEmitter) inferAllocTypeFromAppendUsage(a *SSAAlloc) string {
1472 allocName := a.SSAName()
1473 loadNames := map[string]bool{}
1474 for _, b := range e.curFunc.Blocks {
1475 for _, instr := range b.Instrs {
1476 if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
1477 loadNames[uop.SSAName()] = true
1478 }
1479 }
1480 }
1481 if len(loadNames) == 0 {
1482 return ""
1483 }
1484 for _, b := range e.curFunc.Blocks {
1485 for _, instr := range b.Instrs {
1486 call, ok := instr.(*SSACall)
1487 if !ok {
1488 continue
1489 }
1490 bi, ok2 := call.Call.Value.(*SSABuiltin)
1491 if !ok2 || bi.SSAName() != "append" {
1492 continue
1493 }
1494 if len(call.Call.Args) < 2 {
1495 continue
1496 }
1497 for j := 1; j < len(call.Call.Args); j++ {
1498 arg := call.Call.Args[j]
1499 if arg == nil {
1500 continue
1501 }
1502 if !loadNames[arg.SSAName()] {
1503 continue
1504 }
1505 sliceArg := call.Call.Args[0]
1506 if sl, ok3 := safeUnderlying(sliceArg.SSAType()).(*Slice); ok3 {
1507 et := e.llvmType(sl.Elem())
1508 if et != "" && et != "void" && et != "ptr" && len(et) > 0 && et[0] == '{' {
1509 return et
1510 }
1511 }
1512 if sl, ok3 := sliceArg.SSAType().(*Slice); ok3 {
1513 et := e.llvmType(sl.Elem())
1514 if et != "" && et != "void" && et != "ptr" && len(et) > 0 && et[0] == '{' {
1515 return et
1516 }
1517 }
1518 }
1519 }
1520 }
1521 return ""
1522 }
1523
1524 func (e *irEmitter) inferAllocTypeFromFieldAddrs(a *SSAAlloc, baseType string) string {
1525 allocName := a.SSAName()
1526 names := map[string]bool{allocName: true}
1527 for _, b := range e.curFunc.Blocks {
1528 for _, instr := range b.Instrs {
1529 if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
1530 names[uop.SSAName()] = true
1531 }
1532 }
1533 }
1534 maxField := -1
1535 fieldTypes := map[int32]string{}
1536 for _, b := range e.curFunc.Blocks {
1537 for _, instr := range b.Instrs {
1538 fa, ok := instr.(*SSAFieldAddr)
1539 if !ok || fa.X == nil || !names[fa.X.SSAName()] {
1540 continue
1541 }
1542 if fa.Field > maxField {
1543 maxField = fa.Field
1544 }
1545 faName := fa.SSAName()
1546 for _, b2 := range e.curFunc.Blocks {
1547 for _, i2 := range b2.Instrs {
1548 if s, ok2 := i2.(*SSAStore); ok2 && s.Addr != nil && s.Addr.SSAName() == faName {
1549 ft := e.llvmType(s.Val.SSAType())
1550 if ft != "void" && ft != "" {
1551 fieldTypes[fa.Field] = ft
1552 }
1553 }
1554 if ld, ok2 := i2.(*SSAUnOp); ok2 && ld.Op == OpMul && ld.X != nil && ld.X.SSAName() == faName {
1555 ft := e.llvmType(ld.SSAType())
1556 if ft != "void" && ft != "" && ft != "ptr" {
1557 if _, exists := fieldTypes[fa.Field]; !exists {
1558 fieldTypes[fa.Field] = ft
1559 }
1560 }
1561 }
1562 }
1563 }
1564 }
1565 }
1566 if maxField < 0 {
1567 return ""
1568 }
1569 baseFields := parseStructFields(baseType)
1570 top := maxField
1571 if len(baseFields)-1 > top {
1572 top = len(baseFields) - 1
1573 }
1574 s := "{"
1575 for i := 0; i <= top; i++ {
1576 if i > 0 {
1577 s = s | ", "
1578 }
1579 ft, ok := fieldTypes[i]
1580 if !ok {
1581 if i < len(baseFields) && baseFields[i] != "" {
1582 ft = baseFields[i]
1583 } else {
1584 ft = "ptr"
1585 }
1586 } else if i < len(baseFields) && baseFields[i] != "" {
1587 bw := irParseIntWidth(baseFields[i])
1588 fw := irParseIntWidth(ft)
1589 if bw > 0 && fw > 0 && bw > fw {
1590 ft = baseFields[i]
1591 }
1592 }
1593 s = s | ft
1594 }
1595 return s | "}"
1596 }
1597
1598 func parseStructFields(s string) []string {
1599 if len(s) < 2 || s[0] != '{' || s[len(s)-1] != '}' {
1600 return nil
1601 }
1602 inner := s[1 : len(s)-1]
1603 var fields []string
1604 depth := 0
1605 start := int32(0)
1606 for i := int32(0); i < int32(len(inner)); i++ {
1607 switch inner[i] {
1608 case '{':
1609 depth++
1610 case '}':
1611 depth--
1612 case ',':
1613 if depth == 0 {
1614 f := llvmTrimSpace(string(inner[start:i]))
1615 fields = append(fields, f)
1616 start = i + 1
1617 }
1618 }
1619 }
1620 f := llvmTrimSpace(string(inner[start:]))
1621 if f != "" {
1622 fields = append(fields, f)
1623 }
1624 return fields
1625 }
1626
1627 func llvmTrimSpace(s string) string {
1628 i := int32(0)
1629 for i < int32(len(s)) && s[i] == ' ' {
1630 i++
1631 }
1632 j := int32(len(s))
1633 for j > i && s[j-1] == ' ' {
1634 j--
1635 }
1636 return string(s[i:j])
1637 }
1638
1639 func (e *irEmitter) inferAllocTypeFromUsage(a *SSAAlloc) string {
1640 allocName := a.SSAName()
1641 loadNames := map[string]bool{}
1642 for _, b := range e.curFunc.Blocks {
1643 for _, instr := range b.Instrs {
1644 load, ok := instr.(*SSAUnOp)
1645 if !ok || load.Op != OpMul {
1646 continue
1647 }
1648 if load.X != nil && load.X.SSAName() == allocName {
1649 loadNames[load.SSAName()] = true
1650 }
1651 }
1652 }
1653 if len(loadNames) == 0 {
1654 return "ptr"
1655 }
1656 for _, b := range e.curFunc.Blocks {
1657 for _, instr := range b.Instrs {
1658 switch u := instr.(type) {
1659 case *SSASlice:
1660 if u.X != nil && loadNames[u.X.SSAName()] {
1661 return e.sliceType()
1662 }
1663 case *SSAIndexAddr:
1664 if u.X != nil && loadNames[u.X.SSAName()] {
1665 return e.sliceType()
1666 }
1667 case *SSACall:
1668 for _, arg := range u.Call.Args {
1669 if arg != nil && loadNames[arg.SSAName()] {
1670 if bi, ok2 := u.Call.Value.(*SSABuiltin); ok2 {
1671 nm := bi.SSAName()
1672 if nm == "append" || nm == "copy" || nm == "len" || nm == "cap" {
1673 return e.sliceType()
1674 }
1675 }
1676 }
1677 }
1678 }
1679 }
1680 }
1681 return "ptr"
1682 }
1683
1684 func (e *irEmitter) emitStore(s *SSAStore) {
1685 if s.Val == nil || s.Addr == nil {
1686 e.w(" ; store with nil val/addr\n")
1687 return
1688 }
1689 valType := e.llvmType(s.Val.SSAType())
1690 val := e.operand(s.Val)
1691 if c, isConst := s.Val.(*SSAConst); isConst {
1692 if b := underlyingBasic(c.typ); b != nil && (b.kind == UntypedInt || b.kind == UntypedRune) {
1693 addrType := e.llvmType(s.Addr.SSAType())
1694 if p, ok := safeUnderlying(s.Addr.SSAType()).(*Pointer); ok && p.Elem() != nil {
1695 addrType = e.llvmType(p.Elem())
1696 }
1697 if addrType == "i64" {
1698 valType = "i64"
1699 }
1700 }
1701 }
1702 if load, ok := s.Val.(*SSAUnOp); ok && load.Op == OpMul {
1703 if g, ok2 := load.X.(*SSAGlobal); ok2 {
1704 valType = e.resolveGlobalDeclType(g)
1705 }
1706 }
1707 if _, isAlloc := s.Val.(*SSAAlloc); !isAlloc {
1708 if _, isIdxAddr := s.Val.(*SSAIndexAddr); isIdxAddr {
1709 valType = "ptr"
1710 } else if at, ok := e.allocTypes[s.Val]; ok && at != valType {
1711 bothScalar := len(valType) > 0 && valType[0] == 'i' && len(at) > 0 && at[0] == 'i'
1712 if !bothScalar {
1713 valType = at
1714 if val == "null" && valType != "ptr" {
1715 val = "zeroinitializer"
1716 }
1717 }
1718 }
1719 }
1720 if len(valType) > 0 && (valType[0] == '[' || valType[0] == '{') {
1721 if addrAt, ok := e.allocTypes[s.Addr]; ok && addrAt != valType {
1722 if len(valType) >= len(addrAt) || (valType[0] == '[' && addrAt[0] == '{') {
1723 e.allocTypes[s.Addr] = valType
1724 }
1725 }
1726 }
1727 if valType == "void" {
1728 if at, ok := e.allocTypes[s.Addr]; ok && at != "ptr" && at != "void" {
1729 valType = at
1730 if val == "null" && valType != "ptr" {
1731 val = "zeroinitializer"
1732 }
1733 }
1734 } else if valType == "ptr" {
1735 if uop, ok := s.Val.(*SSAUnOp); ok && uop.Op == OpMul {
1736 if at, ok2 := e.allocTypes[s.Addr]; ok2 && at != "ptr" && at != "void" {
1737 valType = at
1738 if val == "null" && valType != "ptr" {
1739 val = "zeroinitializer"
1740 }
1741 }
1742 }
1743 }
1744 if valType == "void" {
1745 if _, isFV := s.Addr.(*SSAFreeVar); isFV {
1746 valType = e.llvmType(s.Addr.SSAType())
1747 } else if p, ok := safeUnderlying(s.Addr.SSAType()).(*Pointer); ok {
1748 valType = e.llvmType(p.Elem())
1749 }
1750 if valType == "void" {
1751 valType = "ptr"
1752 }
1753 if val == "null" && valType != "ptr" {
1754 val = "zeroinitializer"
1755 }
1756 }
1757 addr := e.operand(s.Addr)
1758 if at, ok := e.allocTypes[s.Addr]; ok && (at == "double" || at == "float") && len(valType) > 0 && valType[0] == 'i' {
1759 if isConstOperand(val) {
1760 val = ensureFloatLit(val)
1761 } else {
1762 e.nextReg++
1763 conv := "%si2f" | irItoa(e.nextReg)
1764 e.w(" ") ; e.w(conv) ; e.w(" = sitofp ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(" to ") ; e.w(at) ; e.w("\n")
1765 val = conv
1766 }
1767 valType = at
1768 }
1769 if at, ok2 := e.allocTypes[s.Addr]; ok2 && len(at) > 0 && at[0] == '{' && len(valType) > 0 && valType[0] == 'i' {
1770 if val == "0" || val == "zeroinitializer" {
1771 val = "zeroinitializer"
1772 valType = at
1773 }
1774 }
1775 if at, ok2 := e.allocTypes[s.Addr]; ok2 && len(at) > 0 && at[0] == 'i' && len(valType) > 0 && valType[0] == '{' {
1776 valType = at
1777 val = "zeroinitializer"
1778 }
1779 if p, ok := safeUnderlying(s.Addr.SSAType()).(*Pointer); ok {
1780 elemT := e.llvmType(p.Elem())
1781 if len(elemT) > 1 && elemT[0] == 'i' && len(valType) > 1 && valType[0] == 'i' && elemT != valType {
1782 vw := irParseIntWidth(valType)
1783 ew := irParseIntWidth(elemT)
1784 if ew > 0 && vw > ew {
1785 e.nextReg++
1786 trunc := "%tr" | irItoa(e.nextReg)
1787 e.w(" ")
1788 e.w(trunc)
1789 e.w(" = trunc ")
1790 e.w(valType)
1791 e.w(" ")
1792 e.w(val)
1793 e.w(" to ")
1794 e.w(elemT)
1795 e.w("\n")
1796 val = trunc
1797 valType = elemT
1798 } else if ew > 0 && vw > 0 && vw < ew {
1799 e.nextReg++
1800 ext := "%se" | irItoa(e.nextReg)
1801 e.w(" ")
1802 e.w(ext)
1803 e.w(" = sext ")
1804 e.w(valType)
1805 e.w(" ")
1806 e.w(val)
1807 e.w(" to ")
1808 e.w(elemT)
1809 e.w("\n")
1810 val = ext
1811 valType = elemT
1812 }
1813 }
1814 }
1815 e.w(" store ")
1816 e.w(valType)
1817 e.w(" ")
1818 e.w(val)
1819 e.w(", ptr ")
1820 e.w(addr)
1821 e.w("\n")
1822 }
1823
1824 func (e *irEmitter) emitZeroReg(reg string, typ Type) {
1825 rt := e.llvmType(typ)
1826 if rt == "void" || rt == "" {
1827 rt = "i32"
1828 }
1829 if rt == "ptr" {
1830 e.w(" ") ; e.w(reg) ; e.w(" = inttoptr i64 0 to ptr\n")
1831 } else if rt == "i1" {
1832 e.w(" ") ; e.w(reg) ; e.w(" = add i1 false, false\n")
1833 } else if e.intBits(rt) > 0 {
1834 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(rt) ; e.w(" 0, 0\n")
1835 } else {
1836 e.w(" ") ; e.w(reg) ; e.w(" = add i32 0, 0\n")
1837 }
1838 }
1839
1840 func (e *irEmitter) emitBinOp(b *SSABinOp) {
1841 if b.X == nil || b.X.SSAType() == nil {
1842 recov := false
1843 if b.X == nil {
1844 for _, blk := range e.curFunc.Blocks {
1845 for i, inst := range blk.Instrs {
1846 if inst == b && i > 0 {
1847 if prev, ok := blk.Instrs[i-1].(*SSAUnOp); ok && prev.Op == OpMul {
1848 b.X = prev
1849 recov = true
1850 }
1851 }
1852 }
1853 if recov { break }
1854 }
1855 }
1856 if !recov && b.X != nil {
1857 rt := e.resolvedType(b.X, "i32")
1858 if rt != "i32" && rt != "" {
1859 reg := e.regName(b)
1860 lv := e.operand(b.X)
1861 rv := e.operand(b.Y)
1862 op := e.llvmBinOp(b.Op, nil)
1863 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(op) ; e.w(" ") ; e.w(rt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(rv) ; e.w("\n")
1864 e.setRegType(b, reg, rt)
1865 return
1866 }
1867 }
1868 if !recov {
1869 e.emitZeroReg(e.regName(b), b.SSAType())
1870 return
1871 }
1872 }
1873 reg := e.regName(b)
1874 lt := e.llvmType(b.X.SSAType())
1875 if lt == "void" && b.Y != nil {
1876 lt = e.llvmType(b.Y.SSAType())
1877 }
1878 if at, ok := e.allocTypes[b.X]; ok && at != "ptr" && at != "void" && at != lt {
1879 isScalarToAgg := len(lt) > 0 && (lt[0] == 'i' || lt == "double" || lt == "float") && len(at) > 0 && at[0] == '{'
1880 if !isScalarToAgg {
1881 lt = at
1882 }
1883 }
1884 lv := e.operand(b.X)
1885 rv := e.operand(b.Y)
1886 if (b.Op == OpAdd || b.Op == OpOr) && b.X.SSAType() != nil {
1887 if sl, ok := safeUnderlying(b.X.SSAType()).(*Slice); ok {
1888 e.emitSliceConcat(reg, sl, lv, rv)
1889 return
1890 }
1891 if e.isStringLike(b.X.SSAType()) {
1892 e.emitSliceConcat(reg, NewSlice(Typ[Uint8]), lv, rv)
1893 return
1894 }
1895 }
1896 if b.X.SSAType() != nil && e.isStringLike(b.X.SSAType()) && (lt == e.sliceType() || lt == "ptr" || lt == "void") {
1897 isActuallyIface := false
1898 if at, ok := e.allocTypes[b.X]; ok && at == e.ifaceType() {
1899 isActuallyIface = true
1900 }
1901 rvOK := true
1902 if b.Y != nil {
1903 rvType := e.llvmType(b.Y.SSAType())
1904 rvResolved := e.resolvedType(b.Y, rvType)
1905 if load, ok := b.Y.(*SSAUnOp); ok && load.Op == OpMul {
1906 if g, ok2 := load.X.(*SSAGlobal); ok2 {
1907 if gt, ok3 := e.globalTypes[e.globalName(g)]; ok3 {
1908 rvResolved = gt
1909 }
1910 }
1911 }
1912 if e.intBits(rvResolved) > 0 {
1913 rvOK = false
1914 }
1915 }
1916 if !isActuallyIface && rvOK {
1917 e.emitStringCompare(reg, b.Op, lv, rv)
1918 return
1919 }
1920 }
1921 if lt == e.sliceType() {
1922 rvOK2 := true
1923 if b.Y != nil {
1924 if load, ok := b.Y.(*SSAUnOp); ok && load.Op == OpMul {
1925 if g, ok2 := load.X.(*SSAGlobal); ok2 {
1926 if gt, ok3 := e.globalTypes[e.globalName(g)]; ok3 && e.intBits(gt) > 0 {
1927 rvOK2 = false
1928 }
1929 }
1930 }
1931 }
1932 if rvOK2 {
1933 e.emitStringCompare(reg, b.Op, lv, rv)
1934 return
1935 }
1936 }
1937 if (b.Op == OpEql || b.Op == OpNeq) && (rv == "null" || rv == "zeroinitializer" || lv == "null" || lv == "zeroinitializer") && b.X.SSAType() != nil {
1938 u := safeUnderlying(b.X.SSAType())
1939 _, isIface := u.(*TCInterface)
1940 _, isSlice := u.(*Slice)
1941 _, isSig := u.(*Signature)
1942 _, isPtr := u.(*Pointer)
1943 _, isMap := u.(*TCMap)
1944 _, isChan := u.(*TCChan)
1945 if isMap || isChan {
1946 isPtr = true
1947 }
1948 if !isIface && !isSlice && !isSig && !isPtr && u == nil && (lt == "{ptr, ptr}" || lt == "{ptr, i64}") {
1949 isIface = true
1950 }
1951 if isSig {
1952 e.nextReg++
1953 extReg := "%ne" | irItoa(e.nextReg)
1954 aggVal := lv
1955 if lv == "null" || lv == "zeroinitializer" {
1956 aggVal = rv
1957 }
1958 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(aggVal) ; e.w(", 1\n")
1959 cmpOp := "icmp eq"
1960 if b.Op == OpNeq {
1961 cmpOp = "icmp ne"
1962 }
1963 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", null\n")
1964 return
1965 }
1966 if isIface || isSlice || e.isStringLike(b.X.SSAType()) {
1967 e.nextReg++
1968 extReg := "%ne" | irItoa(e.nextReg)
1969 aggVal := lv
1970 if lv == "null" || lv == "zeroinitializer" {
1971 aggVal = rv
1972 }
1973 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(aggVal) ; e.w(", 0\n")
1974 cmpOp := "icmp eq"
1975 if b.Op == OpNeq {
1976 cmpOp = "icmp ne"
1977 }
1978 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", null\n")
1979 return
1980 }
1981 if isPtr {
1982 cmpOp := "icmp eq"
1983 if b.Op == OpNeq {
1984 cmpOp = "icmp ne"
1985 }
1986 ptrVal := lv
1987 if lv == "null" || lv == "zeroinitializer" {
1988 ptrVal = rv
1989 }
1990 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(ptrVal) ; e.w(", null\n")
1991 return
1992 }
1993 }
1994 if (b.Op == OpEql || b.Op == OpNeq) && b.X.SSAType() != nil {
1995 if st, ok := safeUnderlying(b.X.SSAType()).(*TCStruct); ok && len(lt) > 0 && lt[0] == '{' {
1996 slt := e.llvmStructType(st)
1997 e.emitStructCompare(reg, b.Op, st, slt, lv, rv)
1998 return
1999 }
2000 if ar, ok := safeUnderlying(b.X.SSAType()).(*Array); ok && len(lt) > 0 && lt[0] == '[' {
2001 e.emitArrayCompare(reg, b.Op, ar, lt, lv, rv)
2002 return
2003 }
2004 u2 := safeUnderlying(b.X.SSAType())
2005 _, isSig2 := u2.(*Signature)
2006 _, isIfce2 := u2.(*TCInterface)
2007 if !isSig2 && !isIfce2 && u2 == nil && lt == "{ptr, ptr}" {
2008 isIfce2 = true
2009 }
2010 if isSig2 || isIfce2 {
2011 nilField := "0"
2012 if isSig2 {
2013 nilField = "1"
2014 }
2015 rt2 := "ptr"
2016 if b.Y != nil && b.Y.SSAType() != nil {
2017 rt2 = e.llvmType(b.Y.SSAType())
2018 }
2019 if lt == "{ptr, ptr}" && rt2 == "ptr" {
2020 e.nextReg++
2021 extReg := "%fc" | irItoa(e.nextReg)
2022 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", ") ; e.w(nilField) ; e.w("\n")
2023 cmpOp := "icmp eq"
2024 if b.Op == OpNeq { cmpOp = "icmp ne" }
2025 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", ") ; e.w(rv) ; e.w("\n")
2026 return
2027 }
2028 if lt == "ptr" && rt2 == "{ptr, ptr}" {
2029 e.nextReg++
2030 extReg := "%fc" | irItoa(e.nextReg)
2031 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", ") ; e.w(nilField) ; e.w("\n")
2032 cmpOp := "icmp eq"
2033 if b.Op == OpNeq { cmpOp = "icmp ne" }
2034 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(lv) ; e.w(", ") ; e.w(extReg) ; e.w("\n")
2035 return
2036 }
2037 if lt == "{ptr, ptr}" && rt2 != "{ptr, ptr}" && rt2 != "ptr" {
2038 sty := e.sliceType()
2039 e.nextReg++
2040 tmp := "%fc" | irItoa(e.nextReg)
2041 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(rt2) ; e.w("\n")
2042 e.w(" store ") ; e.w(rt2) ; e.w(" ") ; e.w(rv) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
2043 e.nextReg++
2044 dp := "%fc" | irItoa(e.nextReg)
2045 e.w(" ") ; e.w(dp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 1\n")
2046 if rt2 == sty {
2047 e.nextReg++
2048 ldp := "%fc" | irItoa(e.nextReg)
2049 e.w(" ") ; e.w(ldp) ; e.w(" = load ") ; e.w(sty) ; e.w(", ptr ") ; e.w(dp) ; e.w("\n")
2050 e.nextReg++
2051 lpA := "%fc" | irItoa(e.nextReg)
2052 e.w(" ") ; e.w(lpA) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(ldp) ; e.w(", 0\n")
2053 e.nextReg++
2054 lpB := "%fc" | irItoa(e.nextReg)
2055 e.w(" ") ; e.w(lpB) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 0\n")
2056 e.nextReg++
2057 llA := "%fc" | irItoa(e.nextReg)
2058 e.w(" ") ; e.w(llA) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(ldp) ; e.w(", 1\n")
2059 e.nextReg++
2060 llB := "%fc" | irItoa(e.nextReg)
2061 e.w(" ") ; e.w(llB) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 1\n")
2062 e.nextReg++
2063 cA := "%fc" | irItoa(e.nextReg)
2064 e.nextReg++
2065 cB := "%fc" | irItoa(e.nextReg)
2066 cmpOp := "icmp eq"
2067 combOp := "and"
2068 if b.Op == OpNeq {
2069 cmpOp = "icmp ne"
2070 combOp = "or"
2071 }
2072 e.w(" ") ; e.w(cA) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(lpA) ; e.w(", ") ; e.w(lpB) ; e.w("\n")
2073 e.w(" ") ; e.w(cB) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(llA) ; e.w(", ") ; e.w(llB) ; e.w("\n")
2074 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(combOp) ; e.w(" i1 ") ; e.w(cA) ; e.w(", ") ; e.w(cB) ; e.w("\n")
2075 return
2076 }
2077 cmpOp := "icmp eq"
2078 if b.Op == OpNeq { cmpOp = "icmp ne" }
2079 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(dp) ; e.w(", ") ; e.w(tmp) ; e.w("\n")
2080 return
2081 }
2082 e.nextReg++
2083 pA := "%fc" | irItoa(e.nextReg)
2084 e.nextReg++
2085 pB := "%fc" | irItoa(e.nextReg)
2086 e.nextReg++
2087 qA := "%fc" | irItoa(e.nextReg)
2088 e.nextReg++
2089 qB := "%fc" | irItoa(e.nextReg)
2090 e.nextReg++
2091 cA := "%fc" | irItoa(e.nextReg)
2092 e.nextReg++
2093 cB := "%fc" | irItoa(e.nextReg)
2094 e.w(" ") ; e.w(pA) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 0\n")
2095 e.w(" ") ; e.w(pB) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 0\n")
2096 e.w(" ") ; e.w(qA) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 1\n")
2097 e.w(" ") ; e.w(qB) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 1\n")
2098 cmpOp := "icmp eq"
2099 combOp := "and"
2100 if b.Op == OpNeq {
2101 cmpOp = "icmp ne"
2102 combOp = "or"
2103 }
2104 e.w(" ") ; e.w(cA) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(pA) ; e.w(", ") ; e.w(pB) ; e.w("\n")
2105 e.w(" ") ; e.w(cB) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(qA) ; e.w(", ") ; e.w(qB) ; e.w("\n")
2106 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(combOp) ; e.w(" i1 ") ; e.w(cA) ; e.w(", ") ; e.w(cB) ; e.w("\n")
2107 return
2108 }
2109 }
2110 if b.Op == OpAndNot {
2111 rt := ""
2112 if b.Y != nil && b.Y.SSAType() != nil {
2113 rt = e.llvmType(b.Y.SSAType())
2114 }
2115 if rt != "" && rt != lt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
2116 rv = e.coerceInt(rv, rt, lt)
2117 }
2118 e.nextReg++
2119 notReg := "%an" | irItoa(e.nextReg)
2120 allOnes := "-1"
2121 e.w(" ") ; e.w(notReg) ; e.w(" = xor ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(allOnes) ; e.w("\n")
2122 e.w(" ") ; e.w(reg) ; e.w(" = and ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(notReg) ; e.w("\n")
2123 return
2124 }
2125 if b.Y == nil || b.Y.SSAType() == nil {
2126 e.emitZeroReg(e.regName(b), b.SSAType())
2127 return
2128 }
2129 rt := e.llvmType(b.Y.SSAType())
2130 atl0 := e.resolvedType(b.X, lt)
2131 if atl0 != lt {
2132 lt = atl0
2133 }
2134 atr0 := e.resolvedType(b.Y, rt)
2135 if atr0 != rt {
2136 rt = atr0
2137 }
2138 if lt != rt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
2139 isCmp := b.Op == OpEql || b.Op == OpNeq || b.Op == OpLss || b.Op == OpGtr || b.Op == OpLeq || b.Op == OpGeq
2140 resType := e.llvmType(b.SSAType())
2141 if !isCmp && e.intBits(resType) > 0 {
2142 if lt != resType {
2143 lv = e.coerceInt(lv, lt, resType)
2144 lt = resType
2145 }
2146 if rt != resType {
2147 rv = e.coerceInt(rv, rt, resType)
2148 }
2149 } else if e.intBits(lt) > e.intBits(rt) {
2150 rv = e.coerceInt(rv, rt, lt)
2151 } else {
2152 lv = e.coerceInt(lv, lt, rt)
2153 lt = rt
2154 }
2155 }
2156 atl := e.resolvedType(b.X, lt)
2157 if atl != lt {
2158 lt = atl
2159 }
2160 if b.Y != nil {
2161 atr := e.resolvedType(b.Y, rt)
2162 if atr != rt {
2163 rt = atr
2164 }
2165 }
2166 resultIsInt := e.intBits(e.llvmType(b.SSAType())) > 0
2167 isLF := lt == "double" || lt == "float"
2168 isRF := rt == "double" || rt == "float"
2169 if !isRF && isConstOperand(rv) && looksLikeFloat(rv) {
2170 if resultIsInt {
2171 if iv, ok := floatLitToInt(rv); ok {
2172 rv = irItoa64(iv)
2173 }
2174 } else {
2175 isRF = true
2176 rt = "double"
2177 }
2178 }
2179 if !isLF && isConstOperand(lv) && looksLikeFloat(lv) {
2180 if resultIsInt {
2181 if iv, ok := floatLitToInt(lv); ok {
2182 lv = irItoa64(iv)
2183 }
2184 } else {
2185 isLF = true
2186 lt = "double"
2187 }
2188 }
2189 if isLF && isRF {
2190 ssaLT := e.llvmType(b.X.SSAType())
2191 ssaRT := ""
2192 if b.Y != nil && b.Y.SSAType() != nil {
2193 ssaRT = e.llvmType(b.Y.SSAType())
2194 }
2195 if !isConstOperand(lv) && e.intBits(ssaLT) > 0 {
2196 _, hasRT := e.regTypes[lv]
2197 if !hasRT {
2198 lv = e.intToFloat(lv, ssaLT, lt)
2199 }
2200 }
2201 if !isConstOperand(rv) && e.intBits(ssaRT) > 0 {
2202 _, hasRT := e.regTypes[rv]
2203 if !hasRT {
2204 rv = e.intToFloat(rv, ssaRT, rt)
2205 }
2206 }
2207 } else if !isLF && isRF && e.intBits(lt) > 0 {
2208 if resultIsInt {
2209 demoted := false
2210 if yc, ok := b.Y.(*SSAConst); ok {
2211 if cf, ok2 := yc.val.(constFloat); ok2 {
2212 iv, ok3 := constFloatToInt(cf)
2213 if !ok3 && cf.lit != "" {
2214 iv, ok3 = floatLitToInt(cf.lit)
2215 }
2216 if ok3 {
2217 rv = irItoa64(iv)
2218 rt = lt
2219 isRF = false
2220 demoted = true
2221 }
2222 }
2223 }
2224 if !demoted {
2225 if isConstOperand(lv) {
2226 lv = ensureFloatLit(lv)
2227 } else {
2228 lv = e.intToFloat(lv, lt, rt)
2229 }
2230 lt = rt
2231 }
2232 } else {
2233 if isConstOperand(lv) {
2234 lv = ensureFloatLit(lv)
2235 } else {
2236 lv = e.intToFloat(lv, lt, rt)
2237 }
2238 lt = rt
2239 }
2240 } else if isLF && !isRF && e.intBits(rt) > 0 {
2241 if resultIsInt {
2242 if xc, ok := b.X.(*SSAConst); ok {
2243 if cf, ok2 := xc.val.(constFloat); ok2 {
2244 iv, ok3 := constFloatToInt(cf)
2245 if !ok3 && cf.lit != "" {
2246 iv, ok3 = floatLitToInt(cf.lit)
2247 }
2248 if ok3 {
2249 lv = irItoa64(iv)
2250 lt = rt
2251 isLF = false
2252 }
2253 }
2254 }
2255 if isLF {
2256 if isConstOperand(rv) {
2257 rv = ensureFloatLit(rv)
2258 } else {
2259 rv = e.intToFloat(rv, rt, lt)
2260 }
2261 rt = lt
2262 }
2263 } else {
2264 if isConstOperand(rv) {
2265 rv = ensureFloatLit(rv)
2266 } else {
2267 rv = e.intToFloat(rv, rt, lt)
2268 }
2269 rt = lt
2270 }
2271 }
2272 if lt == "float" && rt == "double" {
2273 e.nextReg++
2274 tmp := "%fext" | irItoa(e.nextReg)
2275 e.w(" ") ; e.w(tmp) ; e.w(" = fpext float ") ; e.w(lv) ; e.w(" to double\n")
2276 lv = tmp
2277 lt = "double"
2278 } else if lt == "double" && rt == "float" {
2279 e.nextReg++
2280 tmp := "%fext" | irItoa(e.nextReg)
2281 e.w(" ") ; e.w(tmp) ; e.w(" = fpext float ") ; e.w(rv) ; e.w(" to double\n")
2282 rv = tmp
2283 rt = "double"
2284 }
2285 op := e.llvmBinOp(b.Op, b.X.SSAType())
2286 if op == "" {
2287 e.w(" ; unsupported binop\n")
2288 return
2289 }
2290 isCmpOp := b.Op == OpEql || b.Op == OpNeq || b.Op == OpLss || b.Op == OpGtr || b.Op == OpLeq || b.Op == OpGeq
2291 if lt == "double" || lt == "float" {
2292 rv = ensureFloatLit(rv)
2293 lv = ensureFloatLit(lv)
2294 op = e.floatBinOp(b.Op)
2295 if !isCmpOp {
2296 e.setRegType(b, reg, lt)
2297 }
2298 } else if !isCmpOp {
2299 ssaLT := e.llvmType(b.X.SSAType())
2300 if ssaLT != lt {
2301 e.setRegType(b, reg, lt)
2302 }
2303 }
2304 if len(lt) > 0 && lt[0] == '[' && (b.Op == OpEql || b.Op == OpNeq) {
2305 e.emitArrayCompareByLLVM(reg, b.Op, lt, lv, rv)
2306 return
2307 }
2308 if lt == "ptr" && !isCmpOp {
2309 e.nextReg++
2310 pi := "%pi" | irItoa(e.nextReg)
2311 e.w(" ") ; e.w(pi) ; e.w(" = ptrtoint ptr ") ; e.w(lv) ; e.w(" to ") ; e.w(e.intptrType()) ; e.w("\n")
2312 e.nextReg++
2313 ri := "%pi" | irItoa(e.nextReg)
2314 rvCoerced := rv
2315 if rv != "0" && rv != "1" && rv != "-1" {
2316 e.w(" ") ; e.w(ri) ; e.w(" = ptrtoint ptr ") ; e.w(rv) ; e.w(" to ") ; e.w(e.intptrType()) ; e.w("\n")
2317 rvCoerced = ri
2318 }
2319 e.nextReg++
2320 ai := "%pi" | irItoa(e.nextReg)
2321 e.w(" ") ; e.w(ai) ; e.w(" = ") ; e.w(op) ; e.w(" ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(pi) ; e.w(", ") ; e.w(rvCoerced) ; e.w("\n")
2322 e.w(" ") ; e.w(reg) ; e.w(" = inttoptr ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(ai) ; e.w(" to ptr\n")
2323 return
2324 }
2325 e.w(" ")
2326 e.w(reg)
2327 e.w(" = ")
2328 e.w(op)
2329 e.w(" ")
2330 e.w(lt)
2331 e.w(" ")
2332 e.w(lv)
2333 e.w(", ")
2334 e.w(rv)
2335 e.w("\n")
2336 }
2337
2338 func looksLikeFloat(s string) bool {
2339 if len(s) == 0 {
2340 return false
2341 }
2342 if s[0] != '-' && s[0] != '+' && (s[0] < '0' || s[0] > '9') {
2343 return false
2344 }
2345 for i := 0; i < len(s); i++ {
2346 if s[i] == '.' || s[i] == 'e' || s[i] == 'E' {
2347 return true
2348 }
2349 }
2350 return false
2351 }
2352
2353 func constFloatToInt(cf constFloat) (int32, bool) {
2354 iv := int32(cf.v)
2355 if float64(iv) == cf.v {
2356 return iv, true
2357 }
2358 return 0, false
2359 }
2360
2361 func floatLitToInt(s string) (int32, bool) {
2362 if len(s) == 0 {
2363 return 0, false
2364 }
2365 i := 0
2366 neg := false
2367 if s[0] == '-' {
2368 neg = true
2369 i = 1
2370 } else if s[0] == '+' {
2371 i = 1
2372 }
2373 var intPart int32
2374 for ; i < len(s); i++ {
2375 ch := s[i]
2376 if ch == '_' {
2377 continue
2378 }
2379 if ch < '0' || ch > '9' {
2380 break
2381 }
2382 intPart = intPart*10 + int32(ch-'0')
2383 }
2384 var fracDigits int32
2385 if i < len(s) && s[i] == '.' {
2386 i++
2387 for ; i < len(s); i++ {
2388 ch := s[i]
2389 if ch == '_' {
2390 continue
2391 }
2392 if ch < '0' || ch > '9' {
2393 break
2394 }
2395 if ch != '0' {
2396 return 0, false
2397 }
2398 fracDigits++
2399 }
2400 }
2401 _ = fracDigits
2402 exp := 0
2403 if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
2404 i++
2405 expNeg := false
2406 if i < len(s) && s[i] == '-' {
2407 expNeg = true
2408 i++
2409 } else if i < len(s) && s[i] == '+' {
2410 i++
2411 }
2412 for ; i < len(s); i++ {
2413 ch := s[i]
2414 if ch < '0' || ch > '9' {
2415 break
2416 }
2417 exp = exp*10 + int32(ch-'0')
2418 }
2419 if expNeg {
2420 return 0, false
2421 }
2422 }
2423 result := intPart
2424 for j := 0; j < exp; j++ {
2425 result = result * 10
2426 if result < 0 {
2427 return 0, false
2428 }
2429 }
2430 if neg {
2431 result = -result
2432 }
2433 if result == 0 {
2434 return 0, false
2435 }
2436 return result, true
2437 }
2438
2439 func isConstOperand(s string) bool {
2440 if len(s) == 0 {
2441 return false
2442 }
2443 return s[0] != '%' && s[0] != '@'
2444 }
2445
2446 func ensureFloatLit(s string) string {
2447 if len(s) == 0 || s[0] == '%' || s[0] == '@' {
2448 return s
2449 }
2450 hasDecimal := false
2451 for i := 0; i < len(s); i++ {
2452 if s[i] == '.' || s[i] == 'e' || s[i] == 'E' {
2453 hasDecimal = true
2454 break
2455 }
2456 }
2457 if !hasDecimal {
2458 return s | ".0"
2459 }
2460 return s
2461 }
2462
2463 func (e *irEmitter) emitSliceConcat(reg string, sl *Slice, lv, rv string) {
2464 ipt := e.intptrType()
2465 sty := "{ptr, " | ipt | ", " | ipt | "}"
2466 if isBareLiteral(lv) { lv = "zeroinitializer" }
2467 if isBareLiteral(rv) { rv = "zeroinitializer" }
2468 elemType := e.llvmType(sl.Elem())
2469 xPtr := e.nextReg2("cc")
2470 e.w(" ") ; e.w(xPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 0\n")
2471 xLen := e.nextReg2("cc")
2472 e.w(" ") ; e.w(xLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 1\n")
2473 yPtr := e.nextReg2("cc")
2474 e.w(" ") ; e.w(yPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 0\n")
2475 yLen := e.nextReg2("cc")
2476 e.w(" ") ; e.w(yLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 1\n")
2477 elemSz := e.nextReg2("cc")
2478 e.w(" ") ; e.w(elemSz)
2479 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
2480 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
2481 retTy := "{ptr, " | ipt | ", " | ipt | "}"
2482 result := e.nextReg2("cc")
2483 e.w(" ") ; e.w(result)
2484 e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
2485 e.w(xPtr) ; e.w(", ptr ") ; e.w(yPtr)
2486 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
2487 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
2488 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(yLen)
2489 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
2490 e.w(")\n")
2491 newPtr := e.nextReg2("cc")
2492 e.w(" ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
2493 newLen := e.nextReg2("cc")
2494 e.w(" ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
2495 newCap := e.nextReg2("cc")
2496 e.w(" ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
2497 s1 := e.nextReg2("cc")
2498 e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
2499 s2 := e.nextReg2("cc")
2500 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")
2501 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")
2502 e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
2503 }
2504
2505 func isBareLiteral(s string) bool {
2506 if len(s) == 0 { return false }
2507 return s[0] >= '0' && s[0] <= '9'
2508 }
2509
2510 func (e *irEmitter) emitStringCompare(reg string, op SSAOp, lv, rv string) {
2511 ipt := e.intptrType()
2512 sty := "{ptr, " | ipt | ", " | ipt | "}"
2513 if lv == "null" { lv = "zeroinitializer" }
2514 if rv == "null" { rv = "zeroinitializer" }
2515 if isBareLiteral(lv) { lv = "zeroinitializer" }
2516 if isBareLiteral(rv) { rv = "zeroinitializer" }
2517 switch op {
2518 case OpEql:
2519 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringEqual(")
2520 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
2521 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
2522 case OpNeq:
2523 tmp := e.nextReg2("sc")
2524 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringEqual(")
2525 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
2526 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
2527 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
2528 case OpLss:
2529 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
2530 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
2531 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
2532 case OpGtr:
2533 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
2534 e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(")\n")
2535 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
2536 case OpLeq:
2537 tmp := e.nextReg2("sc")
2538 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
2539 e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(")\n")
2540 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
2541 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
2542 case OpGeq:
2543 tmp := e.nextReg2("sc")
2544 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
2545 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
2546 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
2547 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
2548 default:
2549 e.w(" ; unsupported string binop\n")
2550 }
2551 }
2552
2553 func (e *irEmitter) emitStructCompare(reg string, op SSAOp, st *TCStruct, lt, lv, rv string) {
2554 n := st.NumFields()
2555 if n == 0 {
2556 if op == OpEql {
2557 e.valName[nil] = "true"
2558 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
2559 } else {
2560 e.w(" ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
2561 }
2562 return
2563 }
2564 var lastCmp string
2565 for i := 0; i < n; i++ {
2566 ft := e.llvmType(st.Field(i).Type())
2567 lf := e.nextReg2("sf")
2568 rf := e.nextReg2("sf")
2569 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")
2570 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")
2571 cmp := e.nextReg2("sf")
2572 if e.isStringLike(st.Field(i).Type()) {
2573 sty := e.sliceType()
2574 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")
2575 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
2576 } else {
2577 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")
2578 }
2579 if i == 0 {
2580 lastCmp = cmp
2581 } else {
2582 acc := e.nextReg2("sf")
2583 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
2584 lastCmp = acc
2585 }
2586 }
2587 if op == OpNeq {
2588 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
2589 } else if n == 1 {
2590 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
2591 } else {
2592 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
2593 }
2594 }
2595
2596 func (e *irEmitter) emitArrayCompare(reg string, op SSAOp, ar *Array, lt, lv, rv string) {
2597 n := int32(ar.Len())
2598 if n == 0 {
2599 if op == OpEql {
2600 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
2601 } else {
2602 e.w(" ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
2603 }
2604 return
2605 }
2606 et := e.llvmType(ar.Elem())
2607 isZeroL := lv == "0" || lv == "zeroinitializer"
2608 isZeroR := rv == "0" || rv == "zeroinitializer"
2609 var lastCmp string
2610 for i := 0; i < n; i++ {
2611 var lfr, rfr string
2612 if isZeroL {
2613 lfr = "0"
2614 } else {
2615 lfr = e.nextReg2("ae")
2616 e.w(" ") ; e.w(lfr) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
2617 }
2618 if isZeroR {
2619 rfr = "0"
2620 } else {
2621 rfr = e.nextReg2("ae")
2622 e.w(" ") ; e.w(rfr) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
2623 }
2624 cmp := e.nextReg2("ae")
2625 e.w(" ") ; e.w(cmp) ; e.w(" = icmp eq ") ; e.w(et) ; e.w(" ") ; e.w(lfr) ; e.w(", ") ; e.w(rfr) ; e.w("\n")
2626 if i == 0 {
2627 lastCmp = cmp
2628 } else {
2629 acc := e.nextReg2("ae")
2630 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
2631 lastCmp = acc
2632 }
2633 }
2634 if op == OpNeq {
2635 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
2636 } else {
2637 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
2638 }
2639 }
2640
2641 func parseArrayType(lt string) (int32, string) {
2642 if len(lt) < 5 || lt[0] != '[' {
2643 return 0, ""
2644 }
2645 i := 1
2646 for i < len(lt) && lt[i] >= '0' && lt[i] <= '9' {
2647 i++
2648 }
2649 n := 0
2650 for j := 1; j < i; j++ {
2651 n = n*10 + int32(lt[j]-'0')
2652 }
2653 if i+3 >= len(lt) || lt[i] != ' ' || lt[i+1] != 'x' || lt[i+2] != ' ' {
2654 return 0, ""
2655 }
2656 et := lt[i+3 : len(lt)-1]
2657 return n, et
2658 }
2659
2660 func (e *irEmitter) emitArrayCompareByLLVM(reg string, op SSAOp, lt, lv, rv string) {
2661 n, et := parseArrayType(lt)
2662 if n == 0 {
2663 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
2664 return
2665 }
2666 isZeroL := lv == "0" || lv == "zeroinitializer"
2667 isZeroR := rv == "0" || rv == "zeroinitializer"
2668 var lastCmp string
2669 for i := 0; i < n; i++ {
2670 var lfr, rfr string
2671 if isZeroL {
2672 lfr = "0"
2673 } else {
2674 lfr = e.nextReg2("ae")
2675 e.w(" ") ; e.w(lfr) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
2676 }
2677 if isZeroR {
2678 rfr = "0"
2679 } else {
2680 rfr = e.nextReg2("ae")
2681 e.w(" ") ; e.w(rfr) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
2682 }
2683 cmp := e.nextReg2("ae")
2684 e.w(" ") ; e.w(cmp) ; e.w(" = icmp eq ") ; e.w(et) ; e.w(" ") ; e.w(lfr) ; e.w(", ") ; e.w(rfr) ; e.w("\n")
2685 if i == 0 {
2686 lastCmp = cmp
2687 } else {
2688 acc := e.nextReg2("ae")
2689 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
2690 lastCmp = acc
2691 }
2692 }
2693 if op == OpNeq {
2694 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
2695 } else {
2696 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
2697 }
2698 }
2699
2700 func (e *irEmitter) llvmBinOp(op SSAOp, typ Type) string {
2701 isFloat := false
2702 isSigned := true
2703 if typ != nil {
2704 if b, ok := safeUnderlying(typ).(*Basic); ok {
2705 if b.Info()&IsFloat != 0 {
2706 isFloat = true
2707 }
2708 if b.Info()&IsUnsigned != 0 {
2709 isSigned = false
2710 }
2711 }
2712 }
2713 if isFloat {
2714 switch op {
2715 case OpAdd:
2716 return "fadd"
2717 case OpSub:
2718 return "fsub"
2719 case OpMul:
2720 return "fmul"
2721 case OpQuo:
2722 return "fdiv"
2723 case OpEql:
2724 return "fcmp oeq"
2725 case OpNeq:
2726 return "fcmp une"
2727 case OpLss:
2728 return "fcmp olt"
2729 case OpLeq:
2730 return "fcmp ole"
2731 case OpGtr:
2732 return "fcmp ogt"
2733 case OpGeq:
2734 return "fcmp oge"
2735 }
2736 return ""
2737 }
2738 switch op {
2739 case OpAdd:
2740 return "add"
2741 case OpSub:
2742 return "sub"
2743 case OpMul:
2744 return "mul"
2745 case OpQuo:
2746 if isSigned {
2747 return "sdiv"
2748 }
2749 return "udiv"
2750 case OpRem:
2751 if isSigned {
2752 return "srem"
2753 }
2754 return "urem"
2755 case OpAnd, OpLand:
2756 return "and"
2757 case OpOr, OpLor:
2758 return "or"
2759 case OpXor:
2760 return "xor"
2761 case OpShl:
2762 return "shl"
2763 case OpShr:
2764 if isSigned {
2765 return "ashr"
2766 }
2767 return "lshr"
2768 case OpAndNot:
2769 return ""
2770 case OpEql:
2771 return "icmp eq"
2772 case OpNeq:
2773 return "icmp ne"
2774 case OpLss:
2775 if isSigned {
2776 return "icmp slt"
2777 }
2778 return "icmp ult"
2779 case OpLeq:
2780 if isSigned {
2781 return "icmp sle"
2782 }
2783 return "icmp ule"
2784 case OpGtr:
2785 if isSigned {
2786 return "icmp sgt"
2787 }
2788 return "icmp ugt"
2789 case OpGeq:
2790 if isSigned {
2791 return "icmp sge"
2792 }
2793 return "icmp uge"
2794 }
2795 return ""
2796 }
2797
2798 func (e *irEmitter) emitUnOp(u *SSAUnOp) {
2799 reg := e.regName(u)
2800 if u.Op == OpMul {
2801 loadType := e.llvmType(u.SSAType())
2802 if loadType == "void" {
2803 if at, ok := e.allocTypes[u.X]; ok {
2804 loadType = at
2805 } else if a, ok := u.X.(*SSAAlloc); ok {
2806 loadType = e.inferAllocTypeFromStores(a)
2807 } else {
2808 loadType = "ptr"
2809 }
2810 e.allocTypes[u] = loadType
2811 }
2812 if g, ok := u.X.(*SSAGlobal); ok {
2813 loadType = e.resolveGlobalDeclType(g)
2814 }
2815 if at, ok := e.allocTypes[u.X]; ok && at != "ptr" && at != "void" && at != loadType {
2816 bothScalar := len(loadType) > 0 && loadType[0] == 'i' && len(at) > 0 && at[0] == 'i'
2817 isArrayElem := len(at) > 0 && at[0] == '[' && len(loadType) > 0 && loadType[0] != '{' && loadType != at
2818 bothAgg := len(loadType) > 0 && loadType[0] == '{' && len(at) > 0 && at[0] == '{'
2819 if !bothScalar && !isArrayElem && !bothAgg {
2820 loadType = at
2821 e.allocTypes[u] = loadType
2822 }
2823 }
2824 addr := e.operand(u.X)
2825 e.w(" ")
2826 e.w(reg)
2827 e.w(" = load ")
2828 e.w(loadType)
2829 e.w(", ptr ")
2830 e.w(addr)
2831 e.w("\n")
2832 if loadType == "double" || loadType == "float" {
2833 e.setRegType(u, reg, loadType)
2834 }
2835 return
2836 }
2837 valType := e.llvmType(u.X.SSAType())
2838 resolved := e.resolvedType(u.X, valType)
2839 if resolved != valType {
2840 valType = resolved
2841 }
2842 val := e.operand(u.X)
2843 if u.Op == OpSub {
2844 isFloat := false
2845 if b, ok := safeUnderlying(u.X.SSAType()).(*Basic); ok {
2846 isFloat = b.Info()&IsFloat != 0
2847 }
2848 if !isFloat && (valType == "double" || valType == "float") {
2849 isFloat = true
2850 }
2851 if !isFloat && isConstOperand(val) && looksLikeFloat(val) {
2852 isFloat = true
2853 valType = "double"
2854 }
2855 e.w(" ")
2856 e.w(reg)
2857 if isFloat {
2858 e.w(" = fneg ")
2859 e.w(valType)
2860 e.w(" ")
2861 e.w(val)
2862 e.w("\n")
2863 e.setRegType(u, reg, valType)
2864 } else {
2865 e.w(" = sub ")
2866 e.w(valType)
2867 e.w(" 0, ")
2868 e.w(val)
2869 e.w("\n")
2870 }
2871 return
2872 }
2873 if u.Op == OpNot || u.Op == OpXor {
2874 e.w(" ")
2875 e.w(reg)
2876 e.w(" = xor ")
2877 e.w(valType)
2878 e.w(" ")
2879 e.w(val)
2880 e.w(", -1\n")
2881 return
2882 }
2883 e.w(" ; unsupported unop op=")
2884 e.w(u.Op.String())
2885 e.w("\n")
2886 }
2887
2888 func (e *irEmitter) callArgType(arg SSAValue, sig *Signature, i int32) string {
2889 if _, isFreeVar := arg.(*SSAFreeVar); isFreeVar {
2890 return "ptr"
2891 }
2892 t := e.llvmType(arg.SSAType())
2893 if _, isAlloc := arg.(*SSAAlloc); !isAlloc {
2894 resolved := e.resolvedType(arg, t)
2895 if resolved != t {
2896 t = resolved
2897 }
2898 }
2899 if (t == "ptr" || t == "i1") && sig != nil && sig.Params() != nil {
2900 _, isCall := arg.(*SSACall)
2901 _, isAlloc := arg.(*SSAAlloc)
2902 if !isCall && !isAlloc {
2903 sigIdx := i
2904 if sig.Recv() != nil {
2905 sigIdx = i - 1
2906 }
2907 if sigIdx >= 0 && sigIdx < sig.Params().Len() {
2908 sigT := e.llvmType(sig.Params().At(sigIdx).Type())
2909 if sigT != "ptr" && sigT != "void" && sigT != "i1" && sigT != "" {
2910 return sigT
2911 }
2912 }
2913 }
2914 }
2915 if t == "ptr" || t == "i1" {
2916 if load, ok := arg.(*SSAUnOp); ok && load.Op == OpMul {
2917 if g, ok2 := load.X.(*SSAGlobal); ok2 {
2918 if gt, ok3 := e.globalTypes[e.globalName(g)]; ok3 {
2919 return gt
2920 }
2921 }
2922 }
2923 }
2924 if t != "void" {
2925 return t
2926 }
2927 if sig != nil && sig.Params() != nil {
2928 sigIdx := i
2929 if sig.Recv() != nil {
2930 sigIdx = i - 1
2931 }
2932 if sigIdx >= 0 && sigIdx < sig.Params().Len() {
2933 return e.llvmType(sig.Params().At(sigIdx).Type())
2934 }
2935 }
2936 return "ptr"
2937 }
2938
2939 func (e *irEmitter) callSig(c *SSACall) *Signature {
2940 if fn, ok := c.Call.Value.(*SSAFunction); ok && fn.Signature != nil {
2941 return fn.Signature
2942 }
2943 if sig, ok := safeUnderlying(c.Call.Value.SSAType()).(*Signature); ok {
2944 return sig
2945 }
2946 return nil
2947 }
2948
2949 func (e *irEmitter) emitCall(c *SSACall) {
2950 if b, ok := c.Call.Value.(*SSABuiltin); ok {
2951 e.emitBuiltinCall(c, b)
2952 return
2953 }
2954 reg := e.regName(c)
2955 retType := e.llvmType(c.SSAType())
2956 isVoid := retType == "void"
2957 sig := e.callSig(c)
2958
2959 if fn, ok := c.Call.Value.(*SSAFunction); ok {
2960 if !e.isPkgFunc(fn) {
2961 e.declareExternalFunc(fn)
2962 }
2963 e.w(" ")
2964 if !isVoid {
2965 e.w(reg) ; e.w(" = ")
2966 }
2967 e.w("call ") ; e.w(retType) ; e.w(" ")
2968 e.w(e.funcSymbol(fn))
2969 e.w("(")
2970 for i, arg := range c.Call.Args {
2971 if i > 0 { e.w(", ") }
2972 if arg == nil {
2973 e.w("ptr null")
2974 continue
2975 }
2976 at := e.callArgType(arg, sig, i)
2977 av := e.operand(arg)
2978 if av == "null" && at != "ptr" {
2979 av = "zeroinitializer"
2980 }
2981 e.w(at) ; e.w(" ") ; e.w(av)
2982 }
2983 if !fn.isExternC {
2984 if len(c.Call.Args) > 0 { e.w(", ") }
2985 e.w("ptr null")
2986 }
2987 e.w(")\n")
2988 return
2989 }
2990
2991 funcVal := e.operand(c.Call.Value)
2992 funcPtr := e.nextReg2("fp")
2993 ctx := e.nextReg2("ctx")
2994 e.w(" ") ; e.w(funcPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(funcVal) ; e.w(", 1\n")
2995 e.w(" ") ; e.w(ctx) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(funcVal) ; e.w(", 0\n")
2996 e.w(" ")
2997 if !isVoid {
2998 e.w(reg) ; e.w(" = ")
2999 }
3000 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(funcPtr) ; e.w("(")
3001 for i, arg := range c.Call.Args {
3002 if i > 0 { e.w(", ") }
3003 at := e.callArgType(arg, sig, i)
3004 av := e.operand(arg)
3005 if av == "null" && at != "ptr" {
3006 av = "zeroinitializer"
3007 }
3008 e.w(at) ; e.w(" ") ; e.w(av)
3009 }
3010 if len(c.Call.Args) > 0 { e.w(", ") }
3011 e.w("ptr ") ; e.w(ctx)
3012 e.w(")\n")
3013 }
3014
3015 func (e *irEmitter) emitBuiltinCall(c *SSACall, b *SSABuiltin) {
3016 reg := e.regName(c)
3017 name := b.SSAName()
3018 if name == "recover" {
3019 e.w(" ; unhandled builtin: recover\n")
3020 retType := e.ifaceType()
3021 e.nextReg++
3022 tmp := "%ub" | irItoa(e.nextReg)
3023 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
3024 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
3025 e.allocTypes[c] = retType
3026 return
3027 }
3028 ipt := e.intptrType()
3029 sty := e.sliceType()
3030 if name == "len" {
3031 if len(c.Call.Args) == 1 {
3032 arg := e.operand(c.Call.Args[0])
3033 u := safeUnderlying(c.Call.Args[0].SSAType())
3034 if u == nil { u = c.Call.Args[0].SSAType() }
3035 if arr, ok := u.(*Array); ok {
3036 retType := e.llvmType(c.SSAType())
3037 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int32(arr.Len()))) ; e.w(", 0\n")
3038 _ = arg
3039 return
3040 }
3041 if p, ok := u.(*Pointer); ok && p.Elem() != nil {
3042 if arr, ok2 := safeUnderlying(p.Elem()).(*Array); ok2 {
3043 retType := e.llvmType(c.SSAType())
3044 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int32(arr.Len()))) ; e.w(", 0\n")
3045 _ = arg
3046 return
3047 }
3048 }
3049 _, isSlice := u.(*Slice)
3050 _, isMap := u.(*TCMap)
3051 isStr := e.isStringLike(c.Call.Args[0].SSAType())
3052 if !isSlice && !isMap && !isStr {
3053 isSlice = true
3054 }
3055 if isMap {
3056 retType := e.llvmType(c.SSAType())
3057 e.nextReg++
3058 tmp := "%bl" | irItoa(e.nextReg)
3059 e.w(" ") ; e.w(tmp) ; e.w(" = call ") ; e.w(ipt) ; e.w(" @runtime.hashmapLen(ptr ") ; e.w(arg) ; e.w(")\n")
3060 if retType != ipt {
3061 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")
3062 } else {
3063 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(", 0\n")
3064 }
3065 e.declareRuntime("runtime.hashmapLen", ipt, "ptr")
3066 return
3067 }
3068 if isSlice || isStr {
3069 retType := e.llvmType(c.SSAType())
3070 if retType != ipt {
3071 e.nextReg++
3072 tmp := "%bl" | irItoa(e.nextReg)
3073 e.w(" ") ; e.w(tmp) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 1\n")
3074 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")
3075 } else {
3076 e.w(" ") ; e.w(reg) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 1\n")
3077 }
3078 return
3079 }
3080 }
3081 } else if name == "cap" {
3082 if len(c.Call.Args) == 1 {
3083 arg := e.operand(c.Call.Args[0])
3084 uc := safeUnderlying(c.Call.Args[0].SSAType())
3085 if uc == nil { uc = c.Call.Args[0].SSAType() }
3086 if arr, ok := uc.(*Array); ok {
3087 retType := e.llvmType(c.SSAType())
3088 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int32(arr.Len()))) ; e.w(", 0\n")
3089 _ = arg
3090 return
3091 }
3092 if p, ok := uc.(*Pointer); ok && p.Elem() != nil {
3093 if arr, ok2 := safeUnderlying(p.Elem()).(*Array); ok2 {
3094 retType := e.llvmType(c.SSAType())
3095 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int32(arr.Len()))) ; e.w(", 0\n")
3096 _ = arg
3097 return
3098 }
3099 }
3100 _, isSlice := uc.(*Slice)
3101 isStr := e.isStringLike(c.Call.Args[0].SSAType())
3102 if isSlice || isStr {
3103 retType := e.llvmType(c.SSAType())
3104 if retType != ipt {
3105 e.nextReg++
3106 tmp := "%bl" | irItoa(e.nextReg)
3107 e.w(" ") ; e.w(tmp) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 2\n")
3108 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")
3109 } else {
3110 e.w(" ") ; e.w(reg) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 2\n")
3111 }
3112 return
3113 }
3114 }
3115 } else if name == "append" {
3116 if len(c.Call.Args) > 2 {
3117 src := e.operand(c.Call.Args[0])
3118 elemType := ""
3119 if sl, ok := safeUnderlying(c.Call.Args[0].SSAType()).(*Slice); ok {
3120 elemType = e.llvmType(sl.Elem())
3121 }
3122 if sl, ok := c.Call.Args[0].SSAType().(*Slice); ok && (elemType == "" || elemType == "void") {
3123 elemType = e.llvmType(sl.Elem())
3124 }
3125 if elemType == "" || elemType == "void" {
3126 et := e.llvmType(c.Call.Args[1].SSAType())
3127 if et != "" && et != "void" {
3128 elemType = et
3129 } else {
3130 elemType = "i8"
3131 }
3132 }
3133 nElems := len(c.Call.Args) - 1
3134 arrAlloca := e.nextReg2("ap")
3135 arrTy := "[" | irItoa(nElems) | " x " | elemType | "]"
3136 e.w(" ") ; e.w(arrAlloca) ; e.w(" = alloca ") ; e.w(arrTy) ; e.w("\n")
3137 for j := 1; j < len(c.Call.Args); j++ {
3138 elemVal := e.operand(c.Call.Args[j])
3139 argLLT := e.llvmType(c.Call.Args[j].SSAType())
3140 if len(argLLT) > 1 && argLLT[0] == 'i' && len(elemType) > 1 && elemType[0] == 'i' && argLLT != elemType {
3141 aw := irParseIntWidth(argLLT)
3142 ew := irParseIntWidth(elemType)
3143 if ew > 0 && aw > ew {
3144 tr := e.nextReg2("ap")
3145 e.w(" ") ; e.w(tr) ; e.w(" = trunc ") ; e.w(argLLT) ; e.w(" ") ; e.w(elemVal) ; e.w(" to ") ; e.w(elemType) ; e.w("\n")
3146 elemVal = tr
3147 }
3148 }
3149 gep := e.nextReg2("ap")
3150 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr inbounds ") ; e.w(arrTy)
3151 e.w(", ptr ") ; e.w(arrAlloca) ; e.w(", i32 0, i32 ") ; e.w(irItoa(j-1)) ; e.w("\n")
3152 e.w(" store ") ; e.w(elemType) ; e.w(" ") ; e.w(elemVal) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
3153 }
3154 srcBuf := e.nextReg2("ap")
3155 e.w(" ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
3156 srcLen := e.nextReg2("ap")
3157 e.w(" ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
3158 srcCap := e.nextReg2("ap")
3159 e.w(" ") ; e.w(srcCap) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 2\n")
3160 elemSz := e.nextReg2("ap")
3161 e.w(" ") ; e.w(elemSz)
3162 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
3163 e.w(", ptr null, i32 1) to ") ; e.w(e.intptrType()) ; e.w("\n")
3164 retTy := e.sliceType()
3165 result := e.nextReg2("ap")
3166 e.w(" ") ; e.w(result)
3167 e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
3168 e.w(srcBuf) ; e.w(", ptr ") ; e.w(arrAlloca)
3169 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcLen)
3170 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcCap)
3171 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(irItoa(nElems))
3172 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(elemSz)
3173 e.w(")\n")
3174 newPtr := e.nextReg2("ap")
3175 e.w(" ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
3176 newLen := e.nextReg2("ap")
3177 e.w(" ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
3178 newCap := e.nextReg2("ap")
3179 e.w(" ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
3180 s1 := e.nextReg2("ap")
3181 e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
3182 s2 := e.nextReg2("ap")
3183 e.w(" ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n")
3184 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(newCap) ; e.w(", 2\n")
3185 e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType())
3186 return
3187 }
3188 if len(c.Call.Args) == 2 {
3189 src := e.operand(c.Call.Args[0])
3190 elems := e.operand(c.Call.Args[1])
3191 elemType := ""
3192 arg0t := c.Call.Args[0].SSAType()
3193 if sl, ok := safeUnderlying(arg0t).(*Slice); ok {
3194 elemType = e.llvmType(sl.Elem())
3195 }
3196 if sl, ok := arg0t.(*Slice); ok && (elemType == "" || elemType == "void") {
3197 elemType = e.llvmType(sl.Elem())
3198 }
3199 if elemType == "" || elemType == "void" {
3200 et := e.llvmType(c.Call.Args[1].SSAType())
3201 if et != "" && et != "void" {
3202 elemType = et
3203 } else {
3204 elemType = "i8"
3205 }
3206 }
3207 srcBuf := e.nextReg2("ap")
3208 e.w(" ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
3209 srcLen := e.nextReg2("ap")
3210 e.w(" ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
3211 srcCap := e.nextReg2("ap")
3212 e.w(" ") ; e.w(srcCap) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 2\n")
3213 var elemsBuf, elemsLen string
3214 arg1IsSlice := c.Call.HasDots
3215 if !arg1IsSlice && c.Call.Args[1] != nil {
3216 arg1t := c.Call.Args[1].SSAType()
3217 if arg1t != nil {
3218 arg1LT := e.llvmType(arg1t)
3219 if arg1LT == e.sliceType() && elemType != e.sliceType() {
3220 arg1IsSlice = true
3221 }
3222 }
3223 if !arg1IsSlice {
3224 arg0t := c.Call.Args[0].SSAType()
3225 if arg0t != nil && arg1t != nil {
3226 if Identical(arg0t, arg1t) {
3227 if _, ok := safeUnderlying(arg0t).(*Slice); ok {
3228 arg1IsSlice = true
3229 }
3230 }
3231 }
3232 }
3233 }
3234 if arg1IsSlice {
3235 elemsBuf = e.nextReg2("ap")
3236 e.w(" ") ; e.w(elemsBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(elems) ; e.w(", 0\n")
3237 elemsLen = e.nextReg2("ap")
3238 e.w(" ") ; e.w(elemsLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(elems) ; e.w(", 1\n")
3239 } else {
3240 alloca := e.nextReg2("ap")
3241 e.w(" ") ; e.w(alloca) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
3242 e.w(" store ") ; e.w(elemType) ; e.w(" ") ; e.w(elems) ; e.w(", ptr ") ; e.w(alloca) ; e.w("\n")
3243 elemsBuf = alloca
3244 elemsLen = "1"
3245 }
3246 elemSz := e.nextReg2("ap")
3247 e.w(" ") ; e.w(elemSz)
3248 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
3249 e.w(", ptr null, i32 1) to ") ; e.w(e.intptrType()) ; e.w("\n")
3250 retTy := e.sliceType()
3251 result := e.nextReg2("ap")
3252 e.w(" ") ; e.w(result)
3253 e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
3254 e.w(srcBuf) ; e.w(", ptr ") ; e.w(elemsBuf)
3255 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcLen)
3256 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcCap)
3257 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(elemsLen)
3258 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(elemSz)
3259 e.w(")\n")
3260 newPtr := e.nextReg2("ap")
3261 e.w(" ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
3262 newLen := e.nextReg2("ap")
3263 e.w(" ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
3264 newCap := e.nextReg2("ap")
3265 e.w(" ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
3266 s1 := e.nextReg2("ap")
3267 e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
3268 s2 := e.nextReg2("ap")
3269 e.w(" ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n")
3270 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(newCap) ; e.w(", 2\n")
3271 e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType())
3272 return
3273 }
3274 } else if name == "copy" {
3275 if len(c.Call.Args) == 2 {
3276 dst := e.operand(c.Call.Args[0])
3277 src := e.operand(c.Call.Args[1])
3278 elemType := "i8"
3279 if sl, ok := safeUnderlying(c.Call.Args[0].SSAType()).(*Slice); ok {
3280 elemType = e.llvmType(sl.Elem())
3281 }
3282 dstBuf := e.nextReg2("cp")
3283 e.w(" ") ; e.w(dstBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(dst) ; e.w(", 0\n")
3284 dstLen := e.nextReg2("cp")
3285 e.w(" ") ; e.w(dstLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(dst) ; e.w(", 1\n")
3286 srcBuf := e.nextReg2("cp")
3287 e.w(" ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
3288 srcLen := e.nextReg2("cp")
3289 e.w(" ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
3290 elemSz := e.nextReg2("cp")
3291 e.w(" ") ; e.w(elemSz)
3292 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
3293 e.w(", ptr null, i32 1) to ") ; e.w(e.intptrType()) ; e.w("\n")
3294 callReg := e.nextReg2("cp")
3295 e.w(" ") ; e.w(callReg)
3296 e.w(" = call ") ; e.w(e.intptrType()) ; e.w(" @runtime.sliceCopy(ptr ")
3297 e.w(dstBuf) ; e.w(", ptr ") ; e.w(srcBuf)
3298 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(dstLen)
3299 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcLen)
3300 e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(elemSz)
3301 e.w(")\n")
3302 retType := e.llvmType(c.SSAType())
3303 if retType != e.intptrType() {
3304 e.w(" ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(callReg) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
3305 } else {
3306 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(callReg) ; e.w(", 0\n")
3307 }
3308 e.declareRuntime("runtime.sliceCopy", e.intptrType(), "ptr, ptr, " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType())
3309 return
3310 }
3311 } else if name == "print" || name == "println" {
3312 e.w(" call void @runtime.printlock()\n")
3313 for i, arg := range c.Call.Args {
3314 if i > 0 && b.id == BuiltinPrintln {
3315 e.w(" call void @runtime.printspace()\n")
3316 }
3317 av := e.operand(arg)
3318 at := arg.SSAType()
3319 e.emitPrintArg(av, at)
3320 }
3321 if b.id == BuiltinPrintln {
3322 e.w(" call void @runtime.printnl()\n")
3323 e.declareRuntime("runtime.printnl", "void", "")
3324 }
3325 e.w(" call void @runtime.printunlock()\n")
3326 e.declareRuntime("runtime.printlock", "void", "")
3327 e.declareRuntime("runtime.printunlock", "void", "")
3328 if b.id == BuiltinPrintln && len(c.Call.Args) > 1 {
3329 e.declareRuntime("runtime.printspace", "void", "")
3330 }
3331 return
3332 } else if name == "delete" {
3333 if len(c.Call.Args) == 2 {
3334 mapVal := e.operand(c.Call.Args[0])
3335 keyVal := e.operand(c.Call.Args[1])
3336 var mt *TCMap
3337 if okv, okok := safeUnderlying(c.Call.Args[0].SSAType()).(*TCMap); okok {
3338 mt = okv
3339 }
3340 keyType := "i32"
3341 if mt != nil {
3342 keyType = e.llvmType(mt.Key())
3343 }
3344 keyAlloca := e.nextReg2("dl")
3345 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
3346 e.w(" store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
3347 e.w(" call void @runtime.hashmapBinaryDelete(ptr ") ; e.w(mapVal)
3348 e.w(", ptr ") ; e.w(keyAlloca) ; e.w(")\n")
3349 e.declareRuntime("runtime.hashmapBinaryDelete", "void", "ptr, ptr")
3350 return
3351 }
3352 } else if name == "close" {
3353 if len(c.Call.Args) == 1 {
3354 e.w(" call void @runtime.chanClose(ptr ")
3355 e.w(e.operand(c.Call.Args[0]))
3356 e.w(")\n")
3357 e.declareRuntime("runtime.chanClose", "void", "ptr")
3358 return
3359 }
3360 } else if name == "min" || name == "max" {
3361 if len(c.Call.Args) >= 2 {
3362 retType := e.llvmType(c.SSAType())
3363 if retType == "" || retType == "void" {
3364 retType = "i32"
3365 }
3366 a := e.operand(c.Call.Args[0])
3367 b2 := e.operand(c.Call.Args[1])
3368 cmpOp := "slt"
3369 if b.id == BuiltinMax {
3370 cmpOp = "sgt"
3371 }
3372 u := safeUnderlying(c.SSAType())
3373 if bb, ok := u.(*Basic); ok && bb.Info()&IsUnsigned != 0 {
3374 cmpOp = "ult"
3375 if b.id == BuiltinMax {
3376 cmpOp = "ugt"
3377 }
3378 }
3379 e.nextReg++
3380 cmpReg := "%mm" | irItoa(e.nextReg)
3381 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")
3382 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")
3383 return
3384 }
3385 }
3386 e.w(" ; unhandled builtin: ")
3387 e.w(name)
3388 e.w("\n")
3389 retType := e.llvmType(c.SSAType())
3390 if retType != "void" && retType != "" {
3391 if retType == "ptr" || e.intBits(retType) > 0 || retType == "i1" {
3392 e.emitZeroReg(reg, c.SSAType())
3393 } else {
3394 e.nextReg++
3395 tmp := "%ub" | irItoa(e.nextReg)
3396 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
3397 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
3398 e.allocTypes[c] = retType
3399 }
3400 }
3401 }
3402
3403 func (e *irEmitter) emitPrintArg(val string, t Type) {
3404 if t == nil {
3405 return
3406 }
3407 sty := e.sliceType()
3408 switch u := safeUnderlying(t).(type) {
3409 case *Basic:
3410 switch {
3411 case u.Info()&IsString != 0:
3412 e.w(" call void @runtime.printstring(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
3413 e.declareRuntime("runtime.printstring", "void", sty)
3414 case u.Kind() == Bool || u.Kind() == UntypedBool:
3415 e.w(" call void @runtime.printbool(i1 ") ; e.w(val) ; e.w(")\n")
3416 e.declareRuntime("runtime.printbool", "void", "i1")
3417 case u.Kind() == Float32:
3418 e.w(" call void @runtime.printfloat32(float ") ; e.w(val) ; e.w(")\n")
3419 e.declareRuntime("runtime.printfloat32", "void", "float")
3420 case u.Kind() == Float64 || u.Kind() == UntypedFloat:
3421 e.w(" call void @runtime.printfloat64(double ") ; e.w(val) ; e.w(")\n")
3422 e.declareRuntime("runtime.printfloat64", "void", "double")
3423 case u.Info()&IsUnsigned != 0:
3424 lt := e.llvmType(t)
3425 fname := "runtime.printuint" | lt[1:]
3426 e.w(" call void @") ; e.w(fname) ; e.w("(") ; e.w(lt) ; e.w(" ") ; e.w(val) ; e.w(")\n")
3427 e.declareRuntime(fname, "void", lt)
3428 case u.Info()&IsInteger != 0:
3429 lt := e.llvmType(t)
3430 fname := "runtime.printint" | lt[1:]
3431 e.w(" call void @") ; e.w(fname) ; e.w("(") ; e.w(lt) ; e.w(" ") ; e.w(val) ; e.w(")\n")
3432 e.declareRuntime(fname, "void", lt)
3433 }
3434 case *Pointer:
3435 ipt := e.intptrType()
3436 e.nextReg++
3437 tmp := "%pr" | irItoa(e.nextReg)
3438 e.w(" ") ; e.w(tmp) ; e.w(" = ptrtoint ptr ") ; e.w(val) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
3439 e.w(" call void @runtime.printptr(") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(")\n")
3440 e.declareRuntime("runtime.printptr", "void", ipt)
3441 case *Slice:
3442 if b, ok := u.Elem().(*Basic); ok && (b.Kind() == Uint8 || b.Kind() == Int8) {
3443 e.w(" call void @runtime.printbytes(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
3444 e.declareRuntime("runtime.printbytes", "void", sty)
3445 } else {
3446 e.w(" call void @runtime.printstring(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
3447 e.declareRuntime("runtime.printstring", "void", sty)
3448 }
3449 case *TCMap:
3450 e.w(" call void @runtime.printmap(ptr ") ; e.w(val) ; e.w(")\n")
3451 e.declareRuntime("runtime.printmap", "void", "ptr")
3452 }
3453 }
3454
3455 func (e *irEmitter) emitPhi(p *SSAPhi) {
3456 reg := e.regName(p)
3457 typ := e.llvmType(p.SSAType())
3458 e.w(" ")
3459 e.w(reg)
3460 e.w(" = phi ")
3461 e.w(typ)
3462 e.w(" ")
3463 blk := p.InstrBlock()
3464 if blk == nil {
3465 return
3466 }
3467 for i, edge := range p.Edges {
3468 if i > 0 {
3469 e.w(", ")
3470 }
3471 e.w("[")
3472 e.w(e.operand(edge))
3473 e.w(", ")
3474 if blk != nil && i < len(blk.Preds) {
3475 pred := blk.Preds[i]
3476 if pred != nil {
3477 if exitLbl, ok := e.blockExitLabel[pred.Index]; ok {
3478 e.w(exitLbl)
3479 } else {
3480 e.w(e.blockLabel(pred))
3481 }
3482 } else {
3483 e.w("%unknown")
3484 }
3485 } else {
3486 e.w("%unknown")
3487 }
3488 e.w("]")
3489 }
3490 e.w("\n")
3491 }
3492
3493 func isNumericLiteral(s string) bool {
3494 if len(s) == 0 {
3495 return false
3496 }
3497 c := s[0]
3498 if c == '-' && len(s) > 1 {
3499 c = s[1]
3500 }
3501 return c >= '0' && c <= '9'
3502 }
3503
3504 func (e *irEmitter) coerceInt(valReg string, fromType string, toType string) string {
3505 if fromType == toType {
3506 return valReg
3507 }
3508 fromBits := e.intBits(fromType)
3509 toBits := e.intBits(toType)
3510 if fromBits == 0 || toBits == 0 {
3511 return valReg
3512 }
3513 if isNumericLiteral(valReg) {
3514 return valReg
3515 }
3516 e.nextReg++
3517 r := "%rc" | irItoa(e.nextReg)
3518 if fromBits > toBits {
3519 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")
3520 } else {
3521 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")
3522 }
3523 return r
3524 }
3525
3526 func (e *irEmitter) intBits(ty string) int32 {
3527 switch ty {
3528 case "i1":
3529 return 1
3530 case "i8":
3531 return 8
3532 case "i16":
3533 return 16
3534 case "i32":
3535 return 32
3536 case "i64":
3537 return 64
3538 }
3539 return 0
3540 }
3541
3542 func (e *irEmitter) intToFloat(valReg string, fromType string, toType string) string {
3543 if rt, ok := e.regTypes[valReg]; ok && (rt == "double" || rt == "float") {
3544 return valReg
3545 }
3546 e.nextReg++
3547 r := "%itf" | irItoa(e.nextReg)
3548 e.w(" ") ; e.w(r) ; e.w(" = sitofp ") ; e.w(fromType) ; e.w(" ") ; e.w(valReg) ; e.w(" to ") ; e.w(toType) ; e.w("\n")
3549 return r
3550 }
3551
3552 func (e *irEmitter) floatBinOp(op SSAOp) string {
3553 switch op {
3554 case OpAdd: return "fadd"
3555 case OpSub: return "fsub"
3556 case OpMul: return "fmul"
3557 case OpQuo: return "fdiv"
3558 case OpEql: return "fcmp oeq"
3559 case OpNeq: return "fcmp une"
3560 case OpLss: return "fcmp olt"
3561 case OpGtr: return "fcmp ogt"
3562 case OpLeq: return "fcmp ole"
3563 case OpGeq: return "fcmp oge"
3564 }
3565 return "fadd"
3566 }
3567
3568 func (e *irEmitter) arrayElemType(arrType string) string {
3569 // "[6 x double]" -> "double"
3570 xPos := -1
3571 for i := 0; i < len(arrType); i++ {
3572 if arrType[i] == 'x' && i > 0 && arrType[i-1] == ' ' {
3573 xPos = i
3574 break
3575 }
3576 }
3577 if xPos < 0 || xPos+2 >= len(arrType) {
3578 return arrType
3579 }
3580 end := len(arrType)
3581 if arrType[end-1] == ']' {
3582 end = end - 1
3583 }
3584 return arrType[xPos+2 : end]
3585 }
3586
3587 func (e *irEmitter) emitReturn(r *SSAReturn) {
3588 if len(e.deferList) > 0 {
3589 e.emitRunDefers()
3590 }
3591 frt := e.funcRetType(e.curFunc)
3592 if len(r.Results) == 0 {
3593 rt := e.funcRetType(e.curFunc)
3594 if rt == "void" {
3595 e.w(" ret void\n")
3596 } else if len(e.curFunc.NamedResults) > 0 {
3597 if len(e.curFunc.NamedResults) == 1 {
3598 nr := e.curFunc.NamedResults[0]
3599 nrt := e.llvmType(nr.SSAType())
3600 e.nextReg++
3601 tmp := "%nr" | irItoa(e.nextReg)
3602 e.w(" ") ; e.w(tmp) ; e.w(" = load ") ; e.w(nrt) ; e.w(", ptr ") ; e.w(e.regName(nr)) ; e.w("\n")
3603 e.w(" ret ") ; e.w(nrt) ; e.w(" ") ; e.w(tmp) ; e.w("\n")
3604 } else {
3605 retType := rt
3606 e.nextReg++
3607 agg := "%nr" | irItoa(e.nextReg)
3608 e.w(" ") ; e.w(agg) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
3609 e.w(" store ") ; e.w(retType) ; e.w(" zeroinitializer, ptr ") ; e.w(agg) ; e.w("\n")
3610 for i, nr := range e.curFunc.NamedResults {
3611 nrt := e.llvmType(nr.SSAType())
3612 e.nextReg++
3613 tmp := "%nr" | irItoa(e.nextReg)
3614 e.w(" ") ; e.w(tmp) ; e.w(" = load ") ; e.w(nrt) ; e.w(", ptr ") ; e.w(e.regName(nr)) ; e.w("\n")
3615 e.nextReg++
3616 gep := "%nr" | irItoa(e.nextReg)
3617 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(retType) ; e.w(", ptr ") ; e.w(agg) ; e.w(", i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
3618 e.w(" store ") ; e.w(nrt) ; e.w(" ") ; e.w(tmp) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
3619 }
3620 e.nextReg++
3621 rv := "%nr" | irItoa(e.nextReg)
3622 e.w(" ") ; e.w(rv) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(agg) ; e.w("\n")
3623 e.w(" ret ") ; e.w(retType) ; e.w(" ") ; e.w(rv) ; e.w("\n")
3624 }
3625 } else {
3626 e.w(" ret ") ; e.w(rt) ; e.w(" zeroinitializer\n")
3627 }
3628 return
3629 }
3630 sig := e.curFunc.Signature
3631 if len(r.Results) == 1 {
3632 typ := e.llvmType(r.Results[0].SSAType())
3633 val := e.operand(r.Results[0])
3634 expectType := typ
3635 if sig != nil && sig.Results() != nil && sig.Results().Len() == 1 {
3636 expectType = e.llvmType(sig.Results().At(0).Type())
3637 }
3638 if typ == "void" { typ = frt }
3639 if expectType == "void" { expectType = frt }
3640 if val == "null" && expectType != "ptr" {
3641 val = "zeroinitializer"
3642 } else {
3643 val = e.coerceInt(val, typ, expectType)
3644 }
3645 if typ != expectType && val != "zeroinitializer" {
3646 if expectType == "ptr" && e.intBits(typ) > 0 {
3647 e.nextReg++
3648 rc := "%rc" | irItoa(e.nextReg)
3649 e.w(" ") ; e.w(rc) ; e.w(" = inttoptr ") ; e.w(typ) ; e.w(" ") ; e.w(val) ; e.w(" to ptr\n")
3650 val = rc
3651 typ = "ptr"
3652 } else if typ == "ptr" && e.intBits(expectType) > 0 {
3653 e.nextReg++
3654 rc := "%rc" | irItoa(e.nextReg)
3655 e.w(" ") ; e.w(rc) ; e.w(" = ptrtoint ptr ") ; e.w(val) ; e.w(" to ") ; e.w(expectType) ; e.w("\n")
3656 val = rc
3657 typ = expectType
3658 }
3659 if typ != expectType {
3660 val = "zeroinitializer"
3661 }
3662 }
3663 e.w(" ret ")
3664 e.w(expectType)
3665 e.w(" ")
3666 e.w(val)
3667 e.w("\n")
3668 return
3669 }
3670 var expectTypes []string
3671 if sig != nil && sig.Results() != nil {
3672 for i := 0; i < sig.Results().Len(); i++ {
3673 expectTypes = append(expectTypes, e.resolveResultType(sig.Results().At(i).Type()))
3674 }
3675 }
3676 retType := "{"
3677 for i := 0; i < len(r.Results); i++ {
3678 res := r.Results[i]
3679 if i > 0 {
3680 retType = retType | ", "
3681 }
3682 if i < len(expectTypes) {
3683 retType = retType | expectTypes[i]
3684 } else {
3685 retType = retType | e.llvmType(res.SSAType())
3686 }
3687 }
3688 retType = retType | "}"
3689 prev := "undef"
3690 for i := 0; i < len(r.Results); i++ {
3691 res := r.Results[i]
3692 valType := e.llvmType(res.SSAType())
3693 valOp := e.operand(res)
3694 elemType := valType
3695 if i < len(expectTypes) {
3696 elemType = expectTypes[i]
3697 if valOp == "null" && elemType != "ptr" {
3698 valOp = "zeroinitializer"
3699 } else if (elemType == "double" || elemType == "float") && isConstOperand(valOp) {
3700 valOp = ensureFloatLit(valOp)
3701 } else if (elemType == "double" || elemType == "float") && e.intBits(valType) > 0 {
3702 valOp = e.intToFloat(valOp, valType, elemType)
3703 } else {
3704 valOp = e.coerceInt(valOp, valType, elemType)
3705 }
3706 }
3707 e.nextReg++
3708 cur := "%rv" | irItoa(e.nextReg)
3709 e.w(" ")
3710 e.w(cur)
3711 e.w(" = insertvalue ")
3712 e.w(retType)
3713 e.w(" ")
3714 e.w(prev)
3715 e.w(", ")
3716 e.w(elemType)
3717 e.w(" ")
3718 e.w(valOp)
3719 e.w(", ")
3720 e.w(irItoa(i))
3721 e.w("\n")
3722 prev = cur
3723 }
3724 e.w(" ret ")
3725 e.w(retType)
3726 e.w(" ")
3727 e.w(prev)
3728 e.w("\n")
3729 }
3730
3731 func (e *irEmitter) emitJump(j *SSAJump) {
3732 blk := j.InstrBlock()
3733 if blk == nil {
3734 return
3735 }
3736 if len(blk.Succs) > 0 {
3737 e.w(" br label ")
3738 e.w(e.blockLabel(blk.Succs[0]))
3739 e.w("\n")
3740 }
3741 }
3742
3743 func isComparisonOp(op SSAOp) bool {
3744 return op == OpEql || op == OpNeq || op == OpLss || op == OpLeq || op == OpGtr || op == OpGeq
3745 }
3746
3747 func (e *irEmitter) emitIf(i *SSAIf) {
3748 blk := i.InstrBlock()
3749 if i.Cond == nil {
3750 if len(blk.Succs) >= 2 {
3751 e.w(" br label ")
3752 e.w(e.blockLabel(blk.Succs[1]))
3753 e.w("\n")
3754 } else {
3755 e.w(" unreachable\n")
3756 }
3757 return
3758 }
3759 cond := e.operand(i.Cond)
3760 condType := e.llvmType(i.Cond.SSAType())
3761 if at, ok := e.allocTypes[i.Cond]; ok {
3762 condType = at
3763 }
3764 if bop, ok := i.Cond.(*SSABinOp); ok && isComparisonOp(bop.Op) {
3765 condType = "i1"
3766 }
3767 if condType != "i1" && condType != "" && condType != "void" {
3768 e.nextReg++
3769 truncReg := "%ift" | irItoa(e.nextReg)
3770 if condType == "ptr" {
3771 e.w(" ") ; e.w(truncReg) ; e.w(" = icmp ne ptr ") ; e.w(cond) ; e.w(", null\n")
3772 } else if len(condType) > 0 && condType[0] == '{' {
3773 e.nextReg++
3774 extReg := "%ife" | irItoa(e.nextReg)
3775 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(condType) ; e.w(" ") ; e.w(cond) ; e.w(", 0\n")
3776 e.w(" ") ; e.w(truncReg) ; e.w(" = icmp ne ptr ") ; e.w(extReg) ; e.w(", null\n")
3777 } else {
3778 e.w(" ") ; e.w(truncReg) ; e.w(" = trunc ") ; e.w(condType) ; e.w(" ") ; e.w(cond) ; e.w(" to i1\n")
3779 }
3780 cond = truncReg
3781 }
3782 if len(blk.Succs) >= 2 {
3783 e.w(" br i1 ")
3784 e.w(cond)
3785 e.w(", label ")
3786 e.w(e.blockLabel(blk.Succs[0]))
3787 e.w(", label ")
3788 e.w(e.blockLabel(blk.Succs[1]))
3789 e.w("\n")
3790 }
3791 }
3792
3793 func (e *irEmitter) emitConvert(c *SSAConvert) {
3794 reg := e.regName(c)
3795 srcType := e.llvmType(c.X.SSAType())
3796 dstType := e.llvmType(c.SSAType())
3797 val := e.operand(c.X)
3798
3799 if srcType != "ptr" {
3800 resolved := e.resolvedType(c.X, srcType)
3801 if resolved != srcType {
3802 srcType = resolved
3803 }
3804 }
3805
3806 if srcType == "void" || c.X.SSAType() == nil {
3807 if dstType == "ptr" {
3808 e.valName[c] = "null"
3809 } else {
3810 e.valName[c] = "zeroinitializer"
3811 }
3812 return
3813 }
3814
3815 if srcType == dstType {
3816 e.valName[c] = val
3817 e.allocTypes[c] = srcType
3818 return
3819 }
3820
3821 srcIsInt := false
3822 if b, ok := safeUnderlying(c.X.SSAType()).(*Basic); ok {
3823 srcIsInt = b.Info()&IsInteger != 0
3824 }
3825 if !srcIsInt && len(srcType) > 0 && srcType[0] == 'i' {
3826 srcIsInt = true
3827 }
3828 if e.isStringLike(c.SSAType()) && srcIsInt {
3829 if k, ok := c.X.(*SSAConst); ok {
3830 rv := int32(0)
3831 if ci, ok2 := k.val.(constInt); ok2 {
3832 rv = ci.v
3833 }
3834 s := runeToUTF8(rune(rv))
3835 idx := e.addStringConst(s)
3836 ipt := e.intptrType()
3837 slen := irItoa64(int32(len(s)))
3838 e.valName[c] = "{ ptr " | e.strConstGlobal(idx) | ", " | ipt | " " | slen | ", " | ipt | " " | slen | " }"
3839 return
3840 }
3841 e.declareRuntime("runtime.stringFromUnicode", e.sliceType(), "i32, ptr")
3842 srcVal := val
3843 if srcType != "i32" {
3844 e.nextReg++
3845 srcVal = "%cv" | irItoa(e.nextReg)
3846 if e.typeBits(c.X.SSAType()) < 32 {
3847 e.w(" ") ; e.w(srcVal) ; e.w(" = sext ") ; e.w(srcType) ; e.w(" ") ; e.w(val) ; e.w(" to i32\n")
3848 } else if e.typeBits(c.X.SSAType()) > 32 {
3849 e.w(" ") ; e.w(srcVal) ; e.w(" = trunc ") ; e.w(srcType) ; e.w(" ") ; e.w(val) ; e.w(" to i32\n")
3850 }
3851 }
3852 e.w(" ") ; e.w(reg) ; e.w(" = call ") ; e.w(e.sliceType()) ; e.w(" @runtime.stringFromUnicode(i32 ") ; e.w(srcVal) ; e.w(", ptr null)\n")
3853 return
3854 }
3855
3856 op := e.conversionOp(c.X.SSAType(), c.SSAType())
3857 srcBitsLLVM := e.intBits(srcType)
3858 dstBitsLLVM := e.intBits(dstType)
3859 if (op == "sext" || op == "zext") && srcBitsLLVM > 0 && dstBitsLLVM > 0 && srcBitsLLVM > dstBitsLLVM {
3860 op = "trunc"
3861 } else if op == "trunc" && srcBitsLLVM > 0 && dstBitsLLVM > 0 && srcBitsLLVM < dstBitsLLVM {
3862 op = "sext"
3863 }
3864 srcIsFloat := srcType == "double" || srcType == "float"
3865 dstIsFloat := dstType == "double" || dstType == "float"
3866 if op == "trunc" && srcIsFloat && !dstIsFloat {
3867 op = "fptosi"
3868 } else if op == "trunc" && !srcIsFloat && dstIsFloat {
3869 op = "sitofp"
3870 } else if (op == "sext" || op == "zext") && !srcIsFloat && dstIsFloat {
3871 op = "sitofp"
3872 } else if (op == "sext" || op == "zext") && srcIsFloat && !dstIsFloat {
3873 op = "fptosi"
3874 } else if op == "bitcast" && srcIsFloat != dstIsFloat {
3875 if srcIsFloat {
3876 op = "fptosi"
3877 } else {
3878 op = "sitofp"
3879 }
3880 } else if (op == "sext" || op == "zext" || op == "trunc") && srcIsFloat && dstIsFloat {
3881 if e.intBits(srcType) < e.intBits(dstType) {
3882 op = "fpext"
3883 } else {
3884 op = "fptrunc"
3885 }
3886 }
3887 if op == "ptrtoint" && e.intBits(dstType) == 0 {
3888 if dstType == e.ifaceType() {
3889 typeid := e.typeIDGlobal(c.X.SSAType())
3890 t1 := e.nextReg2("cv")
3891 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(typeid) ; e.w(", 0\n")
3892 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(val) ; e.w(", 1\n")
3893 } else {
3894 e.valName[c] = "zeroinitializer"
3895 }
3896 return
3897 }
3898 if op == "inttoptr" && e.intBits(srcType) == 0 {
3899 if srcType == e.ifaceType() {
3900 e.nextReg++
3901 r := "%cv" | irItoa(e.nextReg)
3902 e.w(" ") ; e.w(r) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
3903 e.valName[c] = r
3904 } else {
3905 e.valName[c] = "null"
3906 }
3907 return
3908 }
3909 e.w(" ")
3910 e.w(reg)
3911 e.w(" = ")
3912 e.w(op)
3913 e.w(" ")
3914 e.w(srcType)
3915 e.w(" ")
3916 e.w(val)
3917 e.w(" to ")
3918 e.w(dstType)
3919 e.w("\n")
3920 }
3921
3922 func (e *irEmitter) conversionOp(from, to Type) string {
3923 fromBits := e.typeBits(from)
3924 toBits := e.typeBits(to)
3925
3926 fromFloat := false
3927 toFloat := false
3928 fromSigned := true
3929 if b, ok := safeUnderlying(from).(*Basic); ok {
3930 fromFloat = b.Info()&IsFloat != 0
3931 if b.Info()&IsUnsigned != 0 {
3932 fromSigned = false
3933 }
3934 }
3935 if b, ok := safeUnderlying(to).(*Basic); ok {
3936 toFloat = b.Info()&IsFloat != 0
3937 }
3938
3939 if fromFloat && toFloat {
3940 if fromBits < toBits {
3941 return "fpext"
3942 }
3943 return "fptrunc"
3944 }
3945 if fromFloat && !toFloat {
3946 if fromSigned {
3947 return "fptosi"
3948 }
3949 return "fptoui"
3950 }
3951 if !fromFloat && toFloat {
3952 if fromSigned {
3953 return "sitofp"
3954 }
3955 return "uitofp"
3956 }
3957
3958 _, fromPtr := safeUnderlying(from).(*Pointer)
3959 _, toPtr := safeUnderlying(to).(*Pointer)
3960 if !fromPtr && e.llvmType(from) == "ptr" {
3961 fromPtr = true
3962 }
3963 if !toPtr && e.llvmType(to) == "ptr" {
3964 toPtr = true
3965 }
3966 if fromPtr && !toPtr {
3967 return "ptrtoint"
3968 }
3969 if !fromPtr && toPtr {
3970 return "inttoptr"
3971 }
3972
3973 if fromBits < toBits {
3974 if fromSigned {
3975 return "sext"
3976 }
3977 return "zext"
3978 }
3979 if fromBits > toBits {
3980 return "trunc"
3981 }
3982 return "bitcast"
3983 }
3984
3985 func (e *irEmitter) typeBits(t Type) int32 {
3986 if t == nil {
3987 return 0
3988 }
3989 switch t := safeUnderlying(t).(type) {
3990 case *Basic:
3991 switch t.Kind() {
3992 case Bool:
3993 return 1
3994 case Int8, Uint8:
3995 return 8
3996 case Int16, Uint16:
3997 return 16
3998 case Int32, Uint32:
3999 return 32
4000 case Int64, Uint64:
4001 return 64
4002 case Float32:
4003 return 32
4004 case Float64:
4005 return 64
4006 case UntypedInt, UntypedRune:
4007 return 32
4008 case UntypedFloat:
4009 return 64
4010 case UnsafePointer:
4011 return e.ptrBits
4012 }
4013 case *Pointer:
4014 return e.ptrBits
4015 }
4016 return 0
4017 }
4018
4019 func (e *irEmitter) emitChangeType(c *SSAChangeType) {
4020 srcType := e.llvmType(c.X.SSAType())
4021 dstType := e.llvmType(c.SSAType())
4022 if at, ok := e.allocTypes[c.X]; ok && at != "ptr" && at != "void" {
4023 srcType = at
4024 }
4025 if srcType == dstType || (srcType == "ptr" && dstType == "ptr") {
4026 e.valName[c] = e.operand(c.X)
4027 return
4028 }
4029 reg := e.regName(c)
4030 val := e.operand(c.X)
4031 e.nextReg++
4032 tmp := "%ct" | irItoa(e.nextReg)
4033 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(dstType) ; e.w("\n")
4034 e.w(" store ") ; e.w(srcType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
4035 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(dstType) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
4036 }
4037
4038 func (e *irEmitter) emitFieldAddr(f *SSAFieldAddr) {
4039 reg := e.regName(f)
4040 baseType := e.llvmType(f.X.SSAType())
4041 if p, ok := safeUnderlying(f.X.SSAType()).(*Pointer); ok && p.Elem() != nil {
4042 elem := p.Elem()
4043 if p2, ok2 := safeUnderlying(elem).(*Pointer); ok2 && p2.Elem() != nil {
4044 baseType = e.llvmType(p2.Elem())
4045 } else {
4046 baseType = e.llvmType(elem)
4047 }
4048 }
4049 if at, ok := e.allocTypes[f.X]; ok && at != "ptr" && at != "void" {
4050 baseType = at
4051 }
4052 base := e.operand(f.X)
4053 if uop, ok := f.X.(*SSAUnOp); ok {
4054 _, isFreeVar := uop.X.(*SSAFreeVar)
4055 addrType := e.llvmType(uop.X.SSAType())
4056 useSource := false
4057 if p, ok2 := safeUnderlying(uop.X.SSAType()).(*Pointer); ok2 && p.Elem() != nil {
4058 elem := p.Elem()
4059 if _, ok3 := safeUnderlying(elem).(*Pointer); ok3 {
4060 // double-pointer: alloca holds **T, keep the loaded *T as base
4061 } else {
4062 baseType = e.llvmType(elem)
4063 useSource = true
4064 }
4065 }
4066 if useSource && !isFreeVar && addrType == "ptr" && baseType != "ptr" && baseType != "void" {
4067 base = e.operand(uop.X)
4068 }
4069 }
4070 if baseType == "ptr" || baseType == "void" {
4071 e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(base)
4072 e.w(", i32 0\n")
4073 return
4074 }
4075 e.w(" ")
4076 e.w(reg)
4077 e.w(" = getelementptr inbounds ")
4078 e.w(baseType)
4079 e.w(", ptr ")
4080 e.w(base)
4081 e.w(", i32 0, i32 ")
4082 e.w(irItoa(f.Field))
4083 e.w("\n")
4084 }
4085
4086 func (e *irEmitter) emitIndexAddr(idx *SSAIndexAddr) {
4087 reg := e.regName(idx)
4088 elemType := e.llvmType(idx.SSAType())
4089 if p, ok := safeUnderlying(idx.SSAType()).(*Pointer); ok {
4090 elemType = e.llvmType(p.Elem())
4091 }
4092 base := e.operand(idx.X)
4093 index := e.operand(idx.Index)
4094 baseType := e.llvmType(idx.X.SSAType())
4095 resolvedBase := e.resolvedType(idx.X, baseType)
4096 _, isSlice := safeUnderlying(idx.X.SSAType()).(*Slice)
4097 if !isSlice {
4098 if b, ok := safeUnderlying(idx.X.SSAType()).(*Basic); ok && b.Info()&IsString != 0 {
4099 isSlice = true
4100 }
4101 }
4102 if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' {
4103 isSlice = false
4104 } else if !isSlice && (baseType == e.sliceType() || resolvedBase == e.sliceType()) {
4105 isSlice = true
4106 }
4107 if isSlice && elemType == "void" {
4108 elemType = "i8"
4109 }
4110 if isSlice {
4111 e.nextReg++
4112 dataPtr := "%sp" | irItoa(e.nextReg)
4113 e.w(" ")
4114 e.w(dataPtr)
4115 e.w(" = extractvalue ")
4116 e.w(e.sliceType())
4117 e.w(" ")
4118 e.w(base)
4119 e.w(", 0\n")
4120 e.w(" ")
4121 e.w(reg)
4122 e.w(" = getelementptr inbounds ")
4123 e.w(elemType)
4124 e.w(", ptr ")
4125 e.w(dataPtr)
4126 e.w(", ")
4127 e.w(e.llvmType(idx.Index.SSAType()))
4128 e.w(" ")
4129 e.w(index)
4130 e.w("\n")
4131 e.allocTypes[idx] = elemType
4132 return
4133 }
4134 arr, isArray := safeUnderlying(idx.X.SSAType()).(*Array)
4135 if !isArray {
4136 if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' {
4137 isArray = true
4138 }
4139 }
4140 if !isArray {
4141 if load, ok4 := idx.X.(*SSAUnOp); ok4 && load.Op == OpMul {
4142 if at, ok5 := e.allocTypes[load.X]; ok5 && len(at) > 0 && at[0] == '[' {
4143 isArray = true
4144 e.allocTypes[idx.X] = at
4145 allocBase := e.operand(load.X)
4146 e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
4147 e.w(at) ; e.w(", ptr ") ; e.w(allocBase) ; e.w(", i32 0, ")
4148 e.w(e.llvmType(idx.Index.SSAType())) ; e.w(" ") ; e.w(index) ; e.w("\n")
4149 aet := e.arrayElemType(at)
4150 if aet != "" { e.setRegType(idx, reg, aet) }
4151 return
4152 }
4153 }
4154 }
4155 if isArray {
4156 arrType := e.llvmType(idx.X.SSAType())
4157 if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' {
4158 arrType = at
4159 }
4160 _, isGlobal := idx.X.(*SSAGlobal)
4161 _, isAlloc := idx.X.(*SSAAlloc)
4162 if isGlobal || isAlloc {
4163 _ = arr
4164 e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
4165 e.w(arrType) ; e.w(", ptr ") ; e.w(base) ; e.w(", i32 0, ")
4166 e.w(e.llvmType(idx.Index.SSAType())) ; e.w(" ") ; e.w(index) ; e.w("\n")
4167 return
4168 }
4169 e.nextReg++
4170 arrPtr := "%ai" | irItoa(e.nextReg)
4171 e.w(" ") ; e.w(arrPtr) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
4172 e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(base) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w("\n")
4173 e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
4174 e.w(arrType) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w(", i32 0, ")
4175 e.w(e.llvmType(idx.Index.SSAType())) ; e.w(" ") ; e.w(index) ; e.w("\n")
4176 aet := e.arrayElemType(arrType)
4177 if aet != "" {
4178 e.setRegType(idx, reg, aet)
4179 }
4180 return
4181 }
4182 if len(elemType) > 0 && elemType[0] == '[' {
4183 aet := e.arrayElemType(elemType)
4184 e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
4185 e.w(elemType) ; e.w(", ptr ") ; e.w(base) ; e.w(", i32 0, ")
4186 e.w(e.llvmType(idx.Index.SSAType())) ; e.w(" ") ; e.w(index) ; e.w("\n")
4187 e.setRegType(idx, reg, aet)
4188 return
4189 }
4190 e.w(" ")
4191 e.w(reg)
4192 e.w(" = getelementptr inbounds ")
4193 e.w(elemType)
4194 e.w(", ptr ")
4195 e.w(base)
4196 e.w(", ")
4197 e.w(e.llvmType(idx.Index.SSAType()))
4198 e.w(" ")
4199 e.w(index)
4200 e.w("\n")
4201 }
4202
4203 func (e *irEmitter) emitExtract(ex *SSAExtract) {
4204 reg := e.regName(ex)
4205 tupType := e.llvmType(ex.Tuple.SSAType())
4206 if at, ok := e.allocTypes[ex.Tuple]; ok {
4207 tupType = at
4208 }
4209 if n, ok := ex.Tuple.(*SSANext); ok {
4210 rangeInstr := n.Iter.(*SSARange)
4211 if mt, ok2 := safeUnderlying(rangeInstr.X.SSAType()).(*TCMap); ok2 {
4212 tupType = "{i1, " | e.llvmType(mt.Key()) | ", " | e.llvmType(mt.Elem()) | "}"
4213 } else if arr, ok2 := safeUnderlying(rangeInstr.X.SSAType()).(*Array); ok2 {
4214 tupType = "{i1, i32, " | e.llvmType(arr.Elem()) | "}"
4215 } else {
4216 et := "i32"
4217 if sl, ok2 := safeUnderlying(rangeInstr.X.SSAType()).(*Slice); ok2 {
4218 et = e.llvmType(sl.Elem())
4219 }
4220 tupType = "{i1, i32, " | et | "}"
4221 }
4222 }
4223 val := e.operand(ex.Tuple)
4224 // Track extracted element type for downstream alloc/store consistency
4225 extractedType := extractTupleField(tupType, ex.Index)
4226 if extractedType != "" {
4227 ssaType := e.llvmType(ex.SSAType())
4228 if extractedType != ssaType {
4229 e.allocTypes[ex] = extractedType
4230 }
4231 }
4232 if tupType == "ptr" || tupType == "void" {
4233 elemType := e.llvmType(ex.SSAType())
4234 if elemType == "void" { elemType = "ptr" }
4235 e.nextReg++
4236 castReg := "%ev" | irItoa(e.nextReg)
4237 e.w(" ") ; e.w(castReg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(val) ; e.w(", i32 0\n")
4238 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(castReg) ; e.w("\n")
4239 e.allocTypes[ex] = elemType
4240 return
4241 }
4242 e.w(" ")
4243 e.w(reg)
4244 e.w(" = extractvalue ")
4245 e.w(tupType)
4246 e.w(" ")
4247 e.w(val)
4248 e.w(", ")
4249 e.w(irItoa(ex.Index))
4250 e.w("\n")
4251 }
4252
4253 func extractTupleField(tupType string, index int32) string {
4254 if len(tupType) < 3 || tupType[0] != '{' {
4255 return ""
4256 }
4257 inner := tupType[1 : len(tupType)-1]
4258 depth := 0
4259 field := 0
4260 start := 0
4261 for i := 0; i < len(inner); i++ {
4262 c := inner[i]
4263 if c == '{' {
4264 depth++
4265 } else if c == '}' {
4266 depth--
4267 } else if c == ',' && depth == 0 {
4268 if field == index {
4269 s := inner[start:i]
4270 for len(s) > 0 && s[0] == ' ' { s = s[1:] }
4271 for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] }
4272 return s
4273 }
4274 field++
4275 start = i + 1
4276 }
4277 }
4278 if field == index {
4279 s := inner[start:]
4280 for len(s) > 0 && s[0] == ' ' { s = s[1:] }
4281 for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] }
4282 return s
4283 }
4284 return ""
4285 }
4286
4287 func (e *irEmitter) sextToIpt(val SSAValue, op string) string {
4288 ipt := e.intptrType()
4289 if val == nil {
4290 return op
4291 }
4292 valType := e.llvmType(val.SSAType())
4293 if valType == ipt {
4294 return op
4295 }
4296 e.nextReg++
4297 ext := "%sx" | irItoa(e.nextReg)
4298 extOp := "sext"
4299 if b, ok := safeUnderlying(val.SSAType()).(*Basic); ok && b.Info()&IsUnsigned != 0 {
4300 extOp = "zext"
4301 }
4302 e.w(" ") ; e.w(ext) ; e.w(" = ") ; e.w(extOp) ; e.w(" ") ; e.w(valType) ; e.w(" ") ; e.w(op) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
4303 return ext
4304 }
4305
4306 func (e *irEmitter) emitMakeSlice(m *SSAMakeSlice) {
4307 reg := e.regName(m)
4308 ipt := e.intptrType()
4309 sty := e.sliceType()
4310 lenOp := e.sextToIpt(m.Len, e.operand(m.Len))
4311 capOp := lenOp
4312 if m.Cap != nil {
4313 capOp = e.sextToIpt(m.Cap, e.operand(m.Cap))
4314 }
4315 var dataPtr string
4316 if m.Data != nil {
4317 dataPtr = e.operand(m.Data)
4318 } else {
4319 elemType := "i8"
4320 if sl, ok := safeUnderlying(m.SSAType()).(*Slice); ok {
4321 elemType = e.llvmType(sl.Elem())
4322 }
4323 e.nextReg++
4324 elemSz := "%ms" | irItoa(e.nextReg)
4325 e.w(" ")
4326 e.w(elemSz)
4327 e.w(" = ptrtoint ptr getelementptr (")
4328 e.w(elemType)
4329 e.w(", ptr null, i32 1) to ")
4330 e.w(ipt)
4331 e.w("\n")
4332 e.nextReg++
4333 allocSz := "%ms" | irItoa(e.nextReg)
4334 e.w(" ")
4335 e.w(allocSz)
4336 e.w(" = mul ")
4337 e.w(ipt)
4338 e.w(" ")
4339 e.w(elemSz)
4340 e.w(", ")
4341 e.w(capOp)
4342 e.w("\n")
4343 e.nextReg++
4344 dataPtr = "%ms" | irItoa(e.nextReg)
4345 e.w(" ")
4346 e.w(dataPtr)
4347 e.w(" = call ptr @runtime.alloc(")
4348 e.w(ipt)
4349 e.w(" ")
4350 e.w(allocSz)
4351 e.w(", ptr null, ptr undef)\n")
4352 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
4353 }
4354 e.nextReg++
4355 s1 := "%ms" | irItoa(e.nextReg)
4356 e.w(" ")
4357 e.w(s1)
4358 e.w(" = insertvalue ")
4359 e.w(sty)
4360 e.w(" undef, ptr ")
4361 e.w(dataPtr)
4362 e.w(", 0\n")
4363 e.nextReg++
4364 s2 := "%ms" | irItoa(e.nextReg)
4365 e.w(" ")
4366 e.w(s2)
4367 e.w(" = insertvalue ")
4368 e.w(sty)
4369 e.w(" ")
4370 e.w(s1)
4371 e.w(", ")
4372 e.w(ipt)
4373 e.w(" ")
4374 e.w(lenOp)
4375 e.w(", 1\n")
4376 e.w(" ")
4377 e.w(reg)
4378 e.w(" = insertvalue ")
4379 e.w(sty)
4380 e.w(" ")
4381 e.w(s2)
4382 e.w(", ")
4383 e.w(ipt)
4384 e.w(" ")
4385 e.w(capOp)
4386 e.w(", 2\n")
4387 }
4388
4389 func (e *irEmitter) emitSliceOp(s *SSASlice) {
4390 reg := e.regName(s)
4391 ipt := e.intptrType()
4392 sty := e.sliceType()
4393 src := e.operand(s.X)
4394 var oldPtr, oldLen, oldCap string
4395 srcType := safeUnderlying(s.X.SSAType())
4396 if p, ok := srcType.(*Pointer); ok && p.Elem() != nil {
4397 if arr, ok2 := safeUnderlying(p.Elem()).(*Array); ok2 {
4398 oldPtr = src
4399 oldLen = irItoa64(arr.Len())
4400 oldCap = oldLen
4401 srcType = nil
4402 }
4403 }
4404 if arr, ok := srcType.(*Array); ok {
4405 arrType := e.llvmType(s.X.SSAType())
4406 e.nextReg++
4407 tmp := "%sl" | irItoa(e.nextReg)
4408 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
4409 e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(src) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
4410 oldPtr = tmp
4411 oldLen = irItoa64(arr.Len())
4412 oldCap = oldLen
4413 } else if srcType != nil {
4414 e.nextReg++
4415 oldPtr = "%sl" | irItoa(e.nextReg)
4416 e.w(" ")
4417 e.w(oldPtr)
4418 e.w(" = extractvalue ")
4419 e.w(sty)
4420 e.w(" ")
4421 e.w(src)
4422 e.w(", 0\n")
4423 e.nextReg++
4424 oldLen = "%sl" | irItoa(e.nextReg)
4425 e.w(" ")
4426 e.w(oldLen)
4427 e.w(" = extractvalue ")
4428 e.w(sty)
4429 e.w(" ")
4430 e.w(src)
4431 e.w(", 1\n")
4432 e.nextReg++
4433 oldCap = "%sl" | irItoa(e.nextReg)
4434 e.w(" ")
4435 e.w(oldCap)
4436 e.w(" = extractvalue ")
4437 e.w(sty)
4438 e.w(" ")
4439 e.w(src)
4440 e.w(", 2\n")
4441 }
4442 low := "0"
4443 if s.Low != nil {
4444 low = e.sliceIdxToIpt(s.Low, ipt)
4445 }
4446 high := oldLen
4447 if s.High != nil {
4448 high = e.sliceIdxToIpt(s.High, ipt)
4449 }
4450 maxCap := oldCap
4451 if s.Max != nil {
4452 maxCap = e.sliceIdxToIpt(s.Max, ipt)
4453 }
4454 elemType := "i8"
4455 if sl, ok := safeUnderlying(s.X.SSAType()).(*Slice); ok {
4456 elemType = e.llvmType(sl.Elem())
4457 } else if ar, ok := safeUnderlying(s.X.SSAType()).(*Array); ok {
4458 elemType = e.llvmType(ar.Elem())
4459 } else if p, ok := safeUnderlying(s.X.SSAType()).(*Pointer); ok && p.Elem() != nil {
4460 if ar, ok2 := safeUnderlying(p.Elem()).(*Array); ok2 {
4461 elemType = e.llvmType(ar.Elem())
4462 }
4463 }
4464 e.nextReg++
4465 newPtr := "%sl" | irItoa(e.nextReg)
4466 e.w(" ")
4467 e.w(newPtr)
4468 e.w(" = getelementptr inbounds ")
4469 e.w(elemType)
4470 e.w(", ptr ")
4471 e.w(oldPtr)
4472 e.w(", ")
4473 e.w(ipt)
4474 e.w(" ")
4475 e.w(low)
4476 e.w("\n")
4477 e.nextReg++
4478 newLen := "%sl" | irItoa(e.nextReg)
4479 e.w(" ")
4480 e.w(newLen)
4481 e.w(" = sub ")
4482 e.w(ipt)
4483 e.w(" ")
4484 e.w(high)
4485 e.w(", ")
4486 e.w(low)
4487 e.w("\n")
4488 e.nextReg++
4489 newCap := "%sl" | irItoa(e.nextReg)
4490 e.w(" ")
4491 e.w(newCap)
4492 e.w(" = sub ")
4493 e.w(ipt)
4494 e.w(" ")
4495 e.w(maxCap)
4496 e.w(", ")
4497 e.w(low)
4498 e.w("\n")
4499 e.nextReg++
4500 s1 := "%sl" | irItoa(e.nextReg)
4501 e.w(" ")
4502 e.w(s1)
4503 e.w(" = insertvalue ")
4504 e.w(sty)
4505 e.w(" undef, ptr ")
4506 e.w(newPtr)
4507 e.w(", 0\n")
4508 e.nextReg++
4509 s2 := "%sl" | irItoa(e.nextReg)
4510 e.w(" ")
4511 e.w(s2)
4512 e.w(" = insertvalue ")
4513 e.w(sty)
4514 e.w(" ")
4515 e.w(s1)
4516 e.w(", ")
4517 e.w(ipt)
4518 e.w(" ")
4519 e.w(newLen)
4520 e.w(", 1\n")
4521 e.w(" ")
4522 e.w(reg)
4523 e.w(" = insertvalue ")
4524 e.w(sty)
4525 e.w(" ")
4526 e.w(s2)
4527 e.w(", ")
4528 e.w(ipt)
4529 e.w(" ")
4530 e.w(newCap)
4531 e.w(", 2\n")
4532 }
4533
4534 func (e *irEmitter) sliceIdxToIpt(val SSAValue, ipt string) string {
4535 operandStr := e.operand(val)
4536 valType := e.llvmType(val.SSAType())
4537 if valType == ipt {
4538 return operandStr
4539 }
4540 e.nextReg++
4541 ext := "%sl" | irItoa(e.nextReg)
4542 op := "sext"
4543 if b, ok2 := safeUnderlying(val.SSAType()).(*Basic); ok2 && b.Info()&IsUnsigned != 0 {
4544 op = "zext"
4545 }
4546 e.w(" ") ; e.w(ext) ; e.w(" = ") ; e.w(op) ; e.w(" ") ; e.w(valType) ; e.w(" ") ; e.w(operandStr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
4547 return ext
4548 }
4549
4550 func (e *irEmitter) isScalarType(t string) bool {
4551 return t == "i1" || t == "i8" || t == "i16" || t == "i32" || t == "i64" || t == "float" || t == "double"
4552 }
4553
4554 func (e *irEmitter) emitMakeInterface(m *SSAMakeInterface) {
4555 reg := e.regName(m)
4556 val := e.operand(m.X)
4557 valType := e.llvmType(m.X.SSAType())
4558 if _, isAlloc := m.X.(*SSAAlloc); !isAlloc {
4559 if at, ok := e.allocTypes[m.X]; ok && at != "ptr" && at != "void" {
4560 valType = at
4561 }
4562 }
4563 if valType == e.ifaceType() {
4564 tp := e.nextReg2("mi")
4565 e.w(" ") ; e.w(tp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 0\n")
4566 dp := e.nextReg2("mi")
4567 e.w(" ") ; e.w(dp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
4568 t1 := e.nextReg2("mi")
4569 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(tp) ; e.w(", 0\n")
4570 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(dp) ; e.w(", 1\n")
4571 return
4572 }
4573 var valPtr string
4574 if valType == "ptr" {
4575 valPtr = val
4576 } else if e.isScalarType(valType) {
4577 ipt := e.intptrType()
4578 ext := e.nextReg2("mi")
4579 if valType == "i1" || valType == "i8" || valType == "i16" || valType == "i32" {
4580 e.w(" ") ; e.w(ext) ; e.w(" = zext ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
4581 } else if valType == "i64" {
4582 ext = val
4583 } else if valType == "float" {
4584 ftmp := e.nextReg2("mi")
4585 e.w(" ") ; e.w(ftmp) ; e.w(" = bitcast float ") ; e.w(val) ; e.w(" to i32\n")
4586 e.w(" ") ; e.w(ext) ; e.w(" = zext i32 ") ; e.w(ftmp) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
4587 } else if valType == "double" {
4588 ext = e.nextReg2("mi")
4589 e.w(" ") ; e.w(ext) ; e.w(" = bitcast double ") ; e.w(val) ; e.w(" to i64\n")
4590 } else {
4591 ext = val
4592 }
4593 valPtr = e.nextReg2("mi")
4594 e.w(" ") ; e.w(valPtr) ; e.w(" = inttoptr ") ; e.w(ipt) ; e.w(" ") ; e.w(ext) ; e.w(" to ptr\n")
4595 } else {
4596 ipt := e.intptrType()
4597 sz := e.nextReg2("ha")
4598 e.w(" ") ; e.w(sz) ; e.w(" = ptrtoint ptr getelementptr (") ; e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
4599 valPtr = e.nextReg2("mi")
4600 e.w(" ") ; e.w(valPtr) ; e.w(" = call ptr @runtime.alloc(") ; e.w(ipt) ; e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
4601 e.w(" store ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
4602 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
4603 }
4604 typeid := e.typeIDGlobal(m.X.SSAType())
4605 t1 := e.nextReg2("mi")
4606 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(typeid) ; e.w(", 0\n")
4607 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(valPtr) ; e.w(", 1\n")
4608 }
4609
4610 func (e *irEmitter) typeIDGlobal(t Type) string {
4611 name := e.reflectTypeName(t)
4612 if e.typeIDs == nil {
4613 e.typeIDs = map[string]int32{}
4614 }
4615 if _, ok := e.typeIDs[name]; !ok {
4616 e.typeIDNext++
4617 e.typeIDs[name] = e.typeIDNext
4618 }
4619 if hasPrefix(name, "reflect/types.type:") {
4620 return "@\"" | name | "\""
4621 }
4622 return "@" | name
4623 }
4624
4625 func (e *irEmitter) reflectTypeName(t Type) string {
4626 if b, ok := t.(*Basic); ok {
4627 switch b.Kind() {
4628 case Bool, UntypedBool:
4629 return "reflect/types.type:basic:bool"
4630 case Int8:
4631 return "reflect/types.type:basic:int8"
4632 case Int16:
4633 return "reflect/types.type:basic:int16"
4634 case Int32, UntypedInt, UntypedRune:
4635 return "reflect/types.type:basic:int32"
4636 case Int64:
4637 return "reflect/types.type:basic:int32"
4638 case Uint8:
4639 return "reflect/types.type:basic:uint8"
4640 case Uint16:
4641 return "reflect/types.type:basic:uint16"
4642 case Uint32:
4643 return "reflect/types.type:basic:uint32"
4644 case Uint64:
4645 return "reflect/types.type:basic:uint32"
4646 case Float32, UntypedFloat:
4647 return "reflect/types.type:basic:float32"
4648 case Float64:
4649 return "reflect/types.type:basic:float64"
4650 case TCString, UntypedString:
4651 return "reflect/types.type:basic:bytes"
4652 case UnsafePointer:
4653 return "reflect/types.type:basic:uintptr"
4654 }
4655 }
4656 if named, ok := t.(*Named); ok && named.Obj() != nil {
4657 pkg := ""
4658 if named.Obj().Pkg() != nil {
4659 pkg = named.Obj().Pkg().Path()
4660 }
4661 if pkg == "" {
4662 pkg = e.pkg.Pkg.Path()
4663 }
4664 result := "reflect/types.type:named:" | pkg | "." | named.Obj().Name()
4665 if pkg == e.pkg.Pkg.Path() {
4666 if e.localTypeIDs == nil {
4667 e.localTypeIDs = map[string]bool{}
4668 }
4669 e.localTypeIDs["\"" | result | "\""] = true
4670 }
4671 return result
4672 }
4673 if p, ok := t.(*Pointer); ok {
4674 inner := e.reflectTypeName(p.Elem())
4675 if hasPrefix(inner, "reflect/types.type:") {
4676 result := "reflect/types.type:pointer:" | inner[len("reflect/types.type:"):]
4677 quoted := "\"" | result | "\""
4678 if e.localTypeIDs != nil && e.localTypeIDs["\"" | inner | "\""] {
4679 e.localTypeIDs[quoted] = true
4680 }
4681 return result
4682 }
4683 return inner | ".ptr"
4684 }
4685 if _, ok := t.(*TCInterface); ok {
4686 result := "reflect/types.type:interface:{}"
4687 if e.localTypeIDs == nil {
4688 e.localTypeIDs = map[string]bool{}
4689 }
4690 e.localTypeIDs["\"" | result | "\""] = true
4691 return result
4692 }
4693 if sl, ok := t.(*Slice); ok {
4694 inner := e.reflectTypeName(sl.Elem())
4695 if hasPrefix(inner, "reflect/types.type:") {
4696 result := "reflect/types.type:slice:" | inner[len("reflect/types.type:"):]
4697 if e.localTypeIDs == nil {
4698 e.localTypeIDs = map[string]bool{}
4699 }
4700 e.localTypeIDs["\"" | result | "\""] = true
4701 return result
4702 }
4703 return inner | ".slice"
4704 }
4705 pkg := e.pkg.Pkg.Path()
4706 return pkg | ".typeid.unknown"
4707 }
4708
4709 func (e *irEmitter) findIfaceImpls(methodName string) []ifaceImpl {
4710 var impls []ifaceImpl
4711 hasType := map[string]bool{}
4712 var memberKeys []string
4713 for mname := range e.pkg.Members {
4714 memberKeys = append(memberKeys, mname)
4715 }
4716 for i := 1; i < len(memberKeys); i++ {
4717 for j := i; j > 0 && memberKeys[j] < memberKeys[j-1]; j-- {
4718 memberKeys[j], memberKeys[j-1] = memberKeys[j-1], memberKeys[j]
4719 }
4720 }
4721 for _, mname := range memberKeys {
4722 m := e.pkg.Members[mname]
4723 fn, ok := m.(*SSAFunction)
4724 if !ok {
4725 continue
4726 }
4727 dotIdx := -1
4728 for i := 0; i < len(mname); i++ {
4729 if mname[i] == '.' {
4730 dotIdx = i
4731 break
4732 }
4733 }
4734 if dotIdx < 0 {
4735 continue
4736 }
4737 if mname[dotIdx+1:] != methodName {
4738 continue
4739 }
4740 tname := mname[:dotIdx]
4741 looked := e.pkg.Pkg.Scope().Lookup(tname)
4742 if looked == nil {
4743 continue
4744 }
4745 tn, ok2 := looked.(*TypeName)
4746 if !ok2 || tn.Type() == nil {
4747 continue
4748 }
4749 isPtrRecv := fn.object != nil && fn.object.HasPtrRecv()
4750 recvT := tn.Type()
4751 if isPtrRecv {
4752 recvT = NewPointer(recvT)
4753 }
4754 impls = append(impls, ifaceImpl{fn: fn, recvType: recvT, ptrRecv: isPtrRecv})
4755 hasType[tname] = true
4756 }
4757 scopeNames := e.pkg.Pkg.Scope().Names()
4758 for sni := 0; sni < len(scopeNames); sni++ {
4759 sname := scopeNames[sni]
4760 tn2, ok4 := e.pkg.Pkg.Scope().Lookup(sname).(*TypeName)
4761 if !ok4 || tn2.Type() == nil {
4762 continue
4763 }
4764 if hasType[sname] {
4765 continue
4766 }
4767 chain, fn, embedT := e.findEmbedMethod(tn2.Type(), methodName, 0)
4768 if fn != nil {
4769 isPtrRecv := fn.object != nil && fn.object.HasPtrRecv()
4770 impls = append(impls, ifaceImpl{
4771 fn: fn,
4772 recvType: NewPointer(tn2.Type()),
4773 ptrRecv: isPtrRecv,
4774 embedField: chain[0],
4775 embedType: embedT,
4776 embedChain: chain,
4777 })
4778 hasType[sname] = true
4779 }
4780 }
4781 var regKeys []string
4782 for pkgPath := range importRegistry {
4783 regKeys = append(regKeys, pkgPath)
4784 }
4785 for i := 1; i < len(regKeys); i++ {
4786 for j := i; j > 0 && regKeys[j] < regKeys[j-1]; j-- {
4787 regKeys[j], regKeys[j-1] = regKeys[j-1], regKeys[j]
4788 }
4789 }
4790 for _, pkgPath := range regKeys {
4791 ipkg := importRegistry[pkgPath]
4792 if ipkg == nil {
4793 continue
4794 }
4795 names := ipkg.Scope().Names()
4796 for ni := 0; ni < len(names); ni++ {
4797 tname := names[ni]
4798 tn3, ok7 := ipkg.Scope().Lookup(tname).(*TypeName)
4799 if !ok7 || tn3.Type() == nil {
4800 continue
4801 }
4802 named3, ok8 := tn3.typ.(*Named)
4803 if !ok8 {
4804 continue
4805 }
4806 for mi := 0; mi < named3.NumMethods(); mi++ {
4807 m := named3.Method(mi)
4808 if m.Name() != methodName {
4809 continue
4810 }
4811 isPR := m.HasPtrRecv()
4812 sym := pkgPath | "." | tname | "." | methodName
4813 tid := ""
4814 if isPR {
4815 tid = "reflect/types.type:pointer:named:" | pkgPath | "." | tname
4816 } else {
4817 tid = "reflect/types.type:named:" | pkgPath | "." | tname
4818 }
4819 impls = append(impls, ifaceImpl{
4820 recvType: tn3.Type(),
4821 ptrRecv: isPR,
4822 extSymbol: sym,
4823 extTypeID: tid,
4824 })
4825 }
4826 }
4827 }
4828 for i := 1; i < len(impls); i++ {
4829 for j := i; j > 0 && impls[j].recvType.String() < impls[j-1].recvType.String(); j-- {
4830 impls[j], impls[j-1] = impls[j-1], impls[j]
4831 }
4832 }
4833 return impls
4834 }
4835
4836 func (e *irEmitter) findEmbedMethod(t Type, methodName string, depth int32) ([]int32, *SSAFunction, Type) {
4837 if depth > 5 {
4838 return nil, nil, nil
4839 }
4840 st, ok := safeUnderlying(t).(*TCStruct)
4841 if !ok {
4842 return nil, nil, nil
4843 }
4844 for fi := 0; fi < st.NumFields(); fi++ {
4845 f := st.Field(fi)
4846 if !f.Anonymous() {
4847 continue
4848 }
4849 embedType := f.Type()
4850 embedName := ""
4851 if en, ok2 := embedType.(*Named); ok2 && en.Obj() != nil {
4852 embedName = en.Obj().Name()
4853 }
4854 if embedName == "" {
4855 continue
4856 }
4857 embedMName := embedName | "." | methodName
4858 if fn, ok2 := e.pkg.Members[embedMName].(*SSAFunction); ok2 {
4859 return []int32{fi}, fn, embedType
4860 }
4861 sub, fn, embedT := e.findEmbedMethod(embedType, methodName, depth+1)
4862 if fn != nil {
4863 return append([]int32{fi}, sub...), fn, embedT
4864 }
4865 }
4866 return nil, nil, nil
4867 }
4868
4869 type ifaceImpl struct {
4870 fn *SSAFunction
4871 recvType Type
4872 ptrRecv bool
4873 embedField int32
4874 embedType Type
4875 embedChain []int32
4876 extSymbol string
4877 extTypeID string
4878 }
4879
4880 func (e *irEmitter) implFuncSym(impl ifaceImpl) string {
4881 if impl.extSymbol != "" {
4882 if irNeedsQuote(impl.extSymbol) {
4883 return "@\"" | impl.extSymbol | "\""
4884 }
4885 return "@" | impl.extSymbol
4886 }
4887 return e.funcSymbol(impl.fn)
4888 }
4889
4890 func (e *irEmitter) declareExtInvoke(impl ifaceImpl, inv *SSAInvoke) {
4891 if impl.extSymbol == "" {
4892 return
4893 }
4894 sym := e.implFuncSym(impl)
4895 if _, ok := e.extDecls[sym]; ok {
4896 return
4897 }
4898 retType := e.llvmType(inv.SSAType())
4899 params := "ptr"
4900 for _, arg := range inv.Args {
4901 argT := e.llvmType(arg.SSAType())
4902 if argT == "void" {
4903 argT = "ptr"
4904 }
4905 params = params | ", " | flattenTypeStr(argT)
4906 }
4907 params = params | ", ptr"
4908 e.extDecls[sym] = retType | " " | sym | "(" | params | ")"
4909 }
4910
4911 func flattenTypeStr(t string) string {
4912 if len(t) == 0 || t[0] != '{' {
4913 return t
4914 }
4915 result := ""
4916 depth := 0
4917 start := 1
4918 for i := 1; i < len(t)-1; i++ {
4919 if t[i] == '{' {
4920 depth++
4921 } else if t[i] == '}' {
4922 depth--
4923 } else if t[i] == ',' && depth == 0 {
4924 f := trimSpaces(t[start:i])
4925 if f != "" {
4926 sub := flattenTypeStr(f)
4927 if result != "" {
4928 result = result | ", " | sub
4929 } else {
4930 result = sub
4931 }
4932 }
4933 start = i + 1
4934 }
4935 }
4936 f := trimSpaces(t[start : len(t)-1])
4937 if f != "" {
4938 sub := flattenTypeStr(f)
4939 if result != "" {
4940 result = result | ", " | sub
4941 } else {
4942 result = sub
4943 }
4944 }
4945 return result
4946 }
4947
4948 func trimSpaces(s string) string {
4949 for len(s) > 0 && s[0] == ' ' {
4950 s = s[1:]
4951 }
4952 for len(s) > 0 && s[len(s)-1] == ' ' {
4953 s = s[:len(s)-1]
4954 }
4955 return s
4956 }
4957
4958 func (e *irEmitter) emitExtInvokeCall(reg, retType, funcSym, recvLLVM, recv string, inv *SSAInvoke, isVoid bool) {
4959 extracts := ""
4960 callArgs := recvLLVM | " " | recv
4961 for _, arg := range inv.Args {
4962 argT := e.llvmType(arg.SSAType())
4963 if argT == "void" {
4964 argT = "ptr"
4965 }
4966 argVal := e.operand(arg)
4967 if len(argT) > 0 && argT[0] == '{' {
4968 depth := 0
4969 start := 1
4970 fi := 0
4971 for i := 1; i < len(argT)-1; i++ {
4972 if argT[i] == '{' {
4973 depth++
4974 } else if argT[i] == '}' {
4975 depth--
4976 } else if argT[i] == ',' && depth == 0 {
4977 ft := trimSpaces(argT[start:i])
4978 if ft != "" {
4979 e.nextReg++
4980 ex := "%ef" | irItoa(e.nextReg)
4981 extracts = extracts | " " | ex | " = extractvalue " | argT | " " | argVal | ", " | irItoa(fi) | "\n"
4982 callArgs = callArgs | ", " | ft | " " | ex
4983 fi++
4984 }
4985 start = i + 1
4986 }
4987 }
4988 ft := trimSpaces(argT[start : len(argT)-1])
4989 if ft != "" {
4990 e.nextReg++
4991 ex := "%ef" | irItoa(e.nextReg)
4992 extracts = extracts | " " | ex | " = extractvalue " | argT | " " | argVal | ", " | irItoa(fi) | "\n"
4993 callArgs = callArgs | ", " | ft | " " | ex
4994 }
4995 } else {
4996 callArgs = callArgs | ", " | argT | " " | argVal
4997 }
4998 }
4999 callArgs = callArgs | ", ptr null"
5000 e.w(extracts)
5001 e.w(" ")
5002 if !isVoid {
5003 e.w(reg) ; e.w(" = ")
5004 }
5005 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(funcSym) ; e.w("(")
5006 e.w(callArgs)
5007 e.w(")\n")
5008 }
5009
5010 func (e *irEmitter) implTypeID(impl ifaceImpl) string {
5011 if impl.extTypeID != "" {
5012 if e.extTypeIDs == nil {
5013 e.extTypeIDs = map[string]bool{}
5014 }
5015 quoted := "\"" | impl.extTypeID | "\""
5016 e.extTypeIDs[quoted] = true
5017 return "@" | quoted
5018 }
5019 return e.typeIDGlobal(impl.recvType)
5020 }
5021
5022 func (e *irEmitter) emitEmbedChainGEP(impl ifaceImpl, valPtr string) string {
5023 chain := impl.embedChain
5024 if len(chain) == 0 {
5025 chain = []int32{impl.embedField}
5026 }
5027 outerType := impl.recvType
5028 if pt, ok := outerType.(*Pointer); ok {
5029 outerType = pt.Elem()
5030 }
5031 cur := valPtr
5032 curType := outerType
5033 for _, idx := range chain {
5034 outerLLVM := e.llvmType(curType)
5035 gep := e.nextReg2("eg")
5036 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr inbounds ") ; e.w(outerLLVM)
5037 e.w(", ptr ") ; e.w(cur) ; e.w(", i32 0, i32 ") ; e.w(irItoa(idx)) ; e.w("\n")
5038 cur = gep
5039 st, ok := safeUnderlying(curType).(*TCStruct)
5040 if ok && idx < st.NumFields() {
5041 curType = st.Field(idx).Type()
5042 }
5043 }
5044 return cur
5045 }
5046
5047 type invokeArg struct {
5048 typ string
5049 val string
5050 }
5051
5052 func (e *irEmitter) prepareInvokeArgs(inv *SSAInvoke, impl ifaceImpl) []invokeArg {
5053 var sig *Signature
5054 if impl.fn != nil {
5055 sig = impl.fn.Signature
5056 }
5057 var result []invokeArg
5058 for i, arg := range inv.Args {
5059 argT := e.llvmType(arg.SSAType())
5060 if at, ok := e.allocTypes[arg]; ok && at != "ptr" && at != "void" {
5061 argT = at
5062 }
5063 argV := e.operand(arg)
5064 if sig != nil && sig.Params() != nil && i < sig.Params().Len() {
5065 pt := e.llvmType(sig.Params().At(i).Type())
5066 if pt != "void" && pt != "ptr" && pt != "" && pt != argT && len(pt) > len(argT) {
5067 e.nextReg++
5068 tmp := "%icast" | irItoa(e.nextReg)
5069 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(pt) ; e.w("\n")
5070 e.w(" store ") ; e.w(pt) ; e.w(" zeroinitializer, ptr ") ; e.w(tmp) ; e.w("\n")
5071 e.w(" store ") ; e.w(argT) ; e.w(" ") ; e.w(argV) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
5072 e.nextReg++
5073 loaded := "%icld" | irItoa(e.nextReg)
5074 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(pt) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
5075 argT = pt
5076 argV = loaded
5077 }
5078 }
5079 if argT == "void" {
5080 argT = "ptr"
5081 }
5082 result = append(result, invokeArg{typ: argT, val: argV})
5083 }
5084 return result
5085 }
5086
5087 func (e *irEmitter) emitInvokeArgs(args []invokeArg) {
5088 for _, a := range args {
5089 e.w(", ") ; e.w(a.typ) ; e.w(" ") ; e.w(a.val)
5090 }
5091 }
5092
5093 func (e *irEmitter) emitInvoke(inv *SSAInvoke) {
5094 reg := e.regName(inv)
5095 ifaceVal := e.operand(inv.X)
5096 retType := e.llvmType(inv.SSAType())
5097 isVoid := retType == "void"
5098 tidPtr := e.nextReg2("tid")
5099 e.w(" ") ; e.w(tidPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(ifaceVal) ; e.w(", 0\n")
5100 valPtr := e.nextReg2("vp")
5101 e.w(" ") ; e.w(valPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(ifaceVal) ; e.w(", 1\n")
5102
5103 impls := e.findIfaceImpls(inv.MethodName)
5104 for _, impl := range impls {
5105 e.declareExtInvoke(impl, inv)
5106 }
5107
5108 if len(impls) == 0 {
5109 e.w(" ; invoke: no implementations for ") ; e.w(inv.MethodName) ; e.w("\n")
5110 if !isVoid {
5111 e.nextReg++
5112 zp := "%zp" | irItoa(e.nextReg)
5113 e.w(" ") ; e.w(zp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
5114 e.w(" store ") ; e.w(retType) ; e.w(" zeroinitializer, ptr ") ; e.w(zp) ; e.w("\n")
5115 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(zp) ; e.w("\n")
5116 }
5117 return
5118 }
5119
5120 if len(impls) == 1 {
5121 impl := impls[0]
5122 callRecv := valPtr
5123 if impl.embedType != nil {
5124 callRecv = e.emitEmbedChainGEP(impl, valPtr)
5125 }
5126 var recvLLVM, recv string
5127 if impl.ptrRecv {
5128 recvLLVM = "ptr"
5129 recv = callRecv
5130 } else {
5131 if impl.embedType != nil {
5132 recvLLVM = e.llvmType(impl.embedType)
5133 } else {
5134 recvType := impl.recvType
5135 if pt, ok := recvType.(*Pointer); ok {
5136 recvType = pt.Elem()
5137 }
5138 recvLLVM = e.llvmType(recvType)
5139 }
5140 if recvLLVM == "ptr" {
5141 recv = callRecv
5142 } else if e.isScalarType(recvLLVM) {
5143 recv = e.extractScalarFromIface(callRecv, recvLLVM)
5144 } else {
5145 recv = e.nextReg2("ld")
5146 e.w(" ") ; e.w(recv) ; e.w(" = load ") ; e.w(recvLLVM) ; e.w(", ptr ") ; e.w(callRecv) ; e.w("\n")
5147 }
5148 }
5149 if impl.extSymbol != "" {
5150 e.emitExtInvokeCall(reg, retType, e.implFuncSym(impl), recvLLVM, recv, inv, isVoid)
5151 } else {
5152 e.w(" ")
5153 prepArgs := e.prepareInvokeArgs(inv, impl)
5154 if !isVoid {
5155 e.w(reg) ; e.w(" = ")
5156 }
5157 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(e.implFuncSym(impl)) ; e.w("(")
5158 e.w(recvLLVM) ; e.w(" ") ; e.w(recv)
5159 e.emitInvokeArgs(prepArgs)
5160 e.w(", ptr null)\n")
5161 }
5162 return
5163 }
5164
5165 baseID := e.nextReg
5166 mergeLabel := "invoke.merge" | irItoa(baseID)
5167 var checkLabels []string
5168 var caseLabels []string
5169 var callRegs []string
5170 for i := range impls {
5171 checkLabels = append(checkLabels, "invoke.check" | irItoa(baseID) | "." | irItoa(i))
5172 caseLabels = append(caseLabels, "invoke.case" | irItoa(baseID) | "." | irItoa(i))
5173 if !isVoid {
5174 callRegs = append(callRegs, e.nextReg2("cr"))
5175 }
5176 }
5177 defaultLabel := "invoke.default" | irItoa(baseID)
5178
5179 e.w(" br label %") ; e.w(checkLabels[0]) ; e.w("\n")
5180
5181 for i, impl := range impls {
5182 nextCheck := defaultLabel
5183 if i < len(impls)-1 {
5184 nextCheck = checkLabels[i+1]
5185 }
5186 e.w(checkLabels[i]) ; e.w(":\n")
5187 tidGlobal := e.implTypeID(impl)
5188 cmpReg := e.nextReg2("cmp")
5189 e.w(" ") ; e.w(cmpReg) ; e.w(" = icmp eq ptr ") ; e.w(tidPtr) ; e.w(", ") ; e.w(tidGlobal) ; e.w("\n")
5190 e.w(" br i1 ") ; e.w(cmpReg) ; e.w(", label %") ; e.w(caseLabels[i]) ; e.w(", label %") ; e.w(nextCheck) ; e.w("\n")
5191
5192 e.w(caseLabels[i]) ; e.w(":\n")
5193 var recvLLVM, recv string
5194 callRecv := valPtr
5195 if impl.embedType != nil {
5196 callRecv = e.emitEmbedChainGEP(impl, valPtr)
5197 }
5198 if impl.ptrRecv {
5199 recvLLVM = "ptr"
5200 recv = callRecv
5201 } else {
5202 if impl.embedType != nil {
5203 recvLLVM = e.llvmType(impl.embedType)
5204 } else {
5205 recvType := impl.recvType
5206 if pt, ok := recvType.(*Pointer); ok {
5207 recvType = pt.Elem()
5208 }
5209 recvLLVM = e.llvmType(recvType)
5210 }
5211 if recvLLVM == "ptr" {
5212 recv = callRecv
5213 } else if e.isScalarType(recvLLVM) {
5214 recv = e.extractScalarFromIface(callRecv, recvLLVM)
5215 } else {
5216 recv = e.nextReg2("ld")
5217 e.w(" ") ; e.w(recv) ; e.w(" = load ") ; e.w(recvLLVM) ; e.w(", ptr ") ; e.w(callRecv) ; e.w("\n")
5218 }
5219 }
5220 if impl.extSymbol != "" {
5221 creg := ""
5222 if !isVoid {
5223 creg = callRegs[i]
5224 }
5225 e.emitExtInvokeCall(creg, retType, e.implFuncSym(impl), recvLLVM, recv, inv, isVoid)
5226 } else {
5227 prepArgs := e.prepareInvokeArgs(inv, impl)
5228 e.w(" ")
5229 if !isVoid {
5230 e.w(callRegs[i]) ; e.w(" = ")
5231 }
5232 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(e.implFuncSym(impl)) ; e.w("(")
5233 e.w(recvLLVM) ; e.w(" ") ; e.w(recv)
5234 e.emitInvokeArgs(prepArgs)
5235 e.w(", ptr null)\n")
5236 }
5237 e.w(" br label %") ; e.w(mergeLabel) ; e.w("\n")
5238 }
5239
5240 e.w(defaultLabel) ; e.w(":\n")
5241 e.w(" unreachable\n")
5242
5243 e.w(mergeLabel) ; e.w(":\n")
5244 if blk := inv.InstrBlock(); blk != nil {
5245 e.blockExitLabel[blk.Index] = "%" | mergeLabel
5246 }
5247 if !isVoid {
5248 e.w(" ") ; e.w(reg) ; e.w(" = phi ") ; e.w(retType) ; e.w(" ")
5249 for i := range impls {
5250 if i > 0 { e.w(", ") }
5251 e.w("[ ") ; e.w(callRegs[i]) ; e.w(", %") ; e.w(caseLabels[i]) ; e.w(" ]")
5252 }
5253 e.w("\n")
5254 }
5255 }
5256
5257 func (e *irEmitter) emitTypeAssert(t *SSATypeAssert) {
5258 reg := e.regName(t)
5259 val := e.operand(t.X)
5260 assertedType := e.llvmType(t.AssertedType)
5261 voidAssert := assertedType == "void"
5262 if voidAssert {
5263 assertedType = "ptr"
5264 }
5265 // Check if input is already a concrete ptr (not an interface {ptr, ptr})
5266 inputType := e.llvmType(t.X.SSAType())
5267 if at, ok := e.allocTypes[t.X]; ok {
5268 inputType = at
5269 }
5270 var valPtr, typePtr string
5271 if inputType == "ptr" {
5272 valPtr = val
5273 typePtr = "null"
5274 } else {
5275 valPtr = e.nextReg2("ta")
5276 e.w(" ") ; e.w(valPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
5277 typePtr = e.nextReg2("ta")
5278 e.w(" ") ; e.w(typePtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 0\n")
5279 }
5280 if t.CommaOk {
5281 tidGlobal := e.typeIDGlobal(t.AssertedType)
5282 ok := e.nextReg2("ta")
5283 e.w(" ") ; e.w(ok) ; e.w(" = icmp eq ptr ") ; e.w(typePtr) ; e.w(", ") ; e.w(tidGlobal) ; e.w("\n")
5284 var loaded string
5285 if assertedType == "ptr" {
5286 loaded = valPtr
5287 } else if e.isScalarType(assertedType) {
5288 loaded = e.extractScalarFromIface(valPtr, assertedType)
5289 } else {
5290 nonnull := e.nextReg2("ta")
5291 e.w(" ") ; e.w(nonnull) ; e.w(" = icmp ne ptr ") ; e.w(valPtr) ; e.w(", null\n")
5292 e.nextReg++
5293 safeLabel := "ta.safe" | irItoa(e.nextReg)
5294 e.nextReg++
5295 zeroLabel := "ta.zero" | irItoa(e.nextReg)
5296 e.nextReg++
5297 mergeLabel := "ta.merge" | irItoa(e.nextReg)
5298 e.w(" br i1 ") ; e.w(nonnull) ; e.w(", label %") ; e.w(safeLabel) ; e.w(", label %") ; e.w(zeroLabel) ; e.w("\n")
5299 e.w(safeLabel) ; e.w(":\n")
5300 realLoad := e.nextReg2("ta")
5301 e.w(" ") ; e.w(realLoad) ; e.w(" = load ") ; e.w(assertedType) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
5302 e.w(" br label %") ; e.w(mergeLabel) ; e.w("\n")
5303 e.w(zeroLabel) ; e.w(":\n")
5304 e.w(" br label %") ; e.w(mergeLabel) ; e.w("\n")
5305 e.w(mergeLabel) ; e.w(":\n")
5306 loaded = e.nextReg2("ta")
5307 e.w(" ") ; e.w(loaded) ; e.w(" = phi ") ; e.w(assertedType) ; e.w(" [ ") ; e.w(realLoad) ; e.w(", %") ; e.w(safeLabel) ; e.w(" ], [ zeroinitializer, %") ; e.w(zeroLabel) ; e.w(" ]\n")
5308 if blk := t.InstrBlock(); blk != nil {
5309 e.blockExitLabel[blk.Index] = "%" | mergeLabel
5310 }
5311 }
5312 tupType := "{" | assertedType | ", i1}"
5313 t1 := e.nextReg2("ta")
5314 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")
5315 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")
5316 if voidAssert {
5317 e.allocTypes[t] = tupType
5318 }
5319 } else {
5320 if assertedType == "ptr" {
5321 e.w(" ") ; e.w(reg) ; e.w(" = select i1 true, ptr ") ; e.w(valPtr) ; e.w(", ptr null\n")
5322 } else if e.isScalarType(assertedType) {
5323 extracted := e.extractScalarFromIface(valPtr, assertedType)
5324 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(assertedType) ; e.w(" ") ; e.w(extracted) ; e.w(", 0\n")
5325 } else {
5326 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(assertedType) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
5327 }
5328 if voidAssert {
5329 e.allocTypes[t] = assertedType
5330 }
5331 }
5332 }
5333
5334 func (e *irEmitter) extractScalarFromIface(valPtr string, assertedType string) string {
5335 ipt := e.intptrType()
5336 raw := e.nextReg2("ta")
5337 e.w(" ") ; e.w(raw) ; e.w(" = ptrtoint ptr ") ; e.w(valPtr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
5338 if assertedType == ipt {
5339 return raw
5340 }
5341 if assertedType == "i1" || assertedType == "i8" || assertedType == "i16" || assertedType == "i32" {
5342 tr := e.nextReg2("ta")
5343 e.w(" ") ; e.w(tr) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(raw) ; e.w(" to ") ; e.w(assertedType) ; e.w("\n")
5344 return tr
5345 }
5346 if assertedType == "float" {
5347 tr := e.nextReg2("ta")
5348 e.w(" ") ; e.w(tr) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(raw) ; e.w(" to i32\n")
5349 bc := e.nextReg2("ta")
5350 e.w(" ") ; e.w(bc) ; e.w(" = bitcast i32 ") ; e.w(tr) ; e.w(" to float\n")
5351 return bc
5352 }
5353 if assertedType == "double" {
5354 bc := e.nextReg2("ta")
5355 e.w(" ") ; e.w(bc) ; e.w(" = bitcast ") ; e.w(ipt) ; e.w(" ") ; e.w(raw) ; e.w(" to double\n")
5356 return bc
5357 }
5358 return raw
5359 }
5360
5361 func (e *irEmitter) emitMakeMap(m *SSAMakeMap) {
5362 reg := e.regName(m)
5363 ipt := e.intptrType()
5364 var mt *TCMap
5365 if okv, okok := safeUnderlying(m.SSAType()).(*TCMap); okok {
5366 mt = okv
5367 }
5368 keyType := "i32"
5369 valType := "i32"
5370 alg := "0"
5371 if mt != nil {
5372 keyType = e.llvmType(mt.Key())
5373 valType = e.llvmType(mt.Elem())
5374 if e.isStringLike(mt.Key()) {
5375 alg = "1"
5376 }
5377 }
5378 keySz := e.nextReg2("mm")
5379 e.w(" ") ; e.w(keySz) ; e.w(" = ptrtoint ptr getelementptr (")
5380 e.w(keyType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
5381 valSz := e.nextReg2("mm")
5382 e.w(" ") ; e.w(valSz) ; e.w(" = ptrtoint ptr getelementptr (")
5383 e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
5384 hint := "8"
5385 if m.Reserve != nil {
5386 hint = e.operand(m.Reserve)
5387 }
5388 e.w(" ") ; e.w(reg) ; e.w(" = call ptr @runtime.hashmapMake(")
5389 e.w(ipt) ; e.w(" ") ; e.w(keySz) ; e.w(", ")
5390 e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(", ")
5391 e.w(ipt) ; e.w(" ") ; e.w(hint) ; e.w(", i8 ") ; e.w(alg) ; e.w(")\n")
5392 e.declareRuntime("runtime.hashmapMake", "ptr", ipt | ", " | ipt | ", " | ipt | ", i8")
5393 }
5394
5395 func (e *irEmitter) emitMapUpdate(m *SSAMapUpdate) {
5396 mapVal := e.operand(m.Map)
5397 keyVal := e.operand(m.Key)
5398 valVal := e.operand(m.Value)
5399 mapType := m.Map.SSAType()
5400 if pt, ok := safeUnderlying(mapType).(*Pointer); ok {
5401 mapType = pt.Elem()
5402 }
5403 var mt *TCMap
5404 if okv, okok := safeUnderlying(mapType).(*TCMap); okok {
5405 mt = okv
5406 }
5407 keyType := "i32"
5408 valType := "i32"
5409 if mt != nil {
5410 keyType = e.llvmType(mt.Key())
5411 valType = e.llvmType(mt.Elem())
5412 }
5413 if keyVal == "null" && keyType != "ptr" { keyVal = "zeroinitializer" }
5414 if valVal == "null" && valType != "ptr" { valVal = "zeroinitializer" }
5415 keyAlloca := e.nextReg2("mu")
5416 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
5417 e.w(" store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
5418 valAlloca := e.nextReg2("mu")
5419 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
5420 e.w(" store ") ; e.w(valType) ; e.w(" ") ; e.w(valVal) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
5421 if mt != nil && e.isStringLike(mt.Key()) {
5422 kd := e.nextReg2("mu")
5423 kl := e.nextReg2("mu")
5424 kc := e.nextReg2("mu")
5425 e.w(" ") ; e.w(kd) ; e.w(" = extractvalue {ptr, i64, i64} ") ; e.w(keyVal) ; e.w(", 0\n")
5426 e.w(" ") ; e.w(kl) ; e.w(" = extractvalue {ptr, i64, i64} ") ; e.w(keyVal) ; e.w(", 1\n")
5427 e.w(" ") ; e.w(kc) ; e.w(" = extractvalue {ptr, i64, i64} ") ; e.w(keyVal) ; e.w(", 2\n")
5428 e.w(" call void @runtime.hashmapContentSet(ptr ") ; e.w(mapVal)
5429 e.w(", ptr ") ; e.w(kd)
5430 e.w(", i64 ") ; e.w(kl)
5431 e.w(", i64 ") ; e.w(kc)
5432 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
5433 e.declareRuntime("runtime.hashmapContentSet", "void", "ptr, ptr, i64, i64, ptr")
5434 } else {
5435 e.w(" call void @runtime.hashmapBinarySet(ptr ") ; e.w(mapVal)
5436 e.w(", ptr ") ; e.w(keyAlloca)
5437 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
5438 e.declareRuntime("runtime.hashmapBinarySet", "void", "ptr, ptr, ptr")
5439 }
5440 }
5441
5442 func (e *irEmitter) emitLookup(l *SSALookup) {
5443 reg := e.regName(l)
5444 ipt := e.intptrType()
5445 mapVal := e.operand(l.X)
5446 keyVal := e.operand(l.Index)
5447 var mt *TCMap
5448 if okv, okok := safeUnderlying(l.X.SSAType()).(*TCMap); okok {
5449 mt = okv
5450 }
5451 keyType := "i32"
5452 valType := "i32"
5453 if mt != nil {
5454 keyType = e.llvmType(mt.Key())
5455 valType = e.llvmType(mt.Elem())
5456 }
5457 valAlloca := e.nextReg2("ml")
5458 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
5459 valSz := e.nextReg2("ml")
5460 e.w(" ") ; e.w(valSz) ; e.w(" = ptrtoint ptr getelementptr (")
5461 e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
5462 if mt != nil && e.isStringLike(mt.Key()) {
5463 kd := e.nextReg2("ml")
5464 kl := e.nextReg2("ml")
5465 kc := e.nextReg2("ml")
5466 e.w(" ") ; e.w(kd) ; e.w(" = extractvalue {ptr, i64, i64} ") ; e.w(keyVal) ; e.w(", 0\n")
5467 e.w(" ") ; e.w(kl) ; e.w(" = extractvalue {ptr, i64, i64} ") ; e.w(keyVal) ; e.w(", 1\n")
5468 e.w(" ") ; e.w(kc) ; e.w(" = extractvalue {ptr, i64, i64} ") ; e.w(keyVal) ; e.w(", 2\n")
5469 okReg := e.nextReg2("ml")
5470 e.w(" ") ; e.w(okReg) ; e.w(" = call i1 @runtime.hashmapContentGet(ptr ") ; e.w(mapVal)
5471 e.w(", ptr ") ; e.w(kd)
5472 e.w(", i64 ") ; e.w(kl)
5473 e.w(", i64 ") ; e.w(kc)
5474 e.w(", ptr ") ; e.w(valAlloca)
5475 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(")\n")
5476 e.declareRuntime("runtime.hashmapContentGet", "i1", "ptr, ptr, i64, i64, ptr, " | ipt)
5477 if l.CommaOk {
5478 loaded := e.nextReg2("ml")
5479 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
5480 tupType := "{" | valType | ", i1}"
5481 t1 := e.nextReg2("ml")
5482 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")
5483 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")
5484 } else {
5485 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
5486 }
5487 } else {
5488 keyAlloca := e.nextReg2("ml")
5489 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
5490 e.w(" store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
5491 okReg := e.nextReg2("ml")
5492 e.w(" ") ; e.w(okReg) ; e.w(" = call i1 @runtime.hashmapBinaryGet(ptr ") ; e.w(mapVal)
5493 e.w(", ptr ") ; e.w(keyAlloca)
5494 e.w(", ptr ") ; e.w(valAlloca)
5495 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(")\n")
5496 e.declareRuntime("runtime.hashmapBinaryGet", "i1", "ptr, ptr, ptr, " | ipt)
5497 if l.CommaOk {
5498 loaded := e.nextReg2("ml")
5499 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
5500 tupType := "{" | valType | ", i1}"
5501 t1 := e.nextReg2("ml")
5502 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")
5503 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")
5504 } else {
5505 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
5506 }
5507 }
5508 }
5509
5510 func (e *irEmitter) isStringLike(t Type) bool {
5511 if t == nil {
5512 return false
5513 }
5514 if b, ok := safeUnderlying(t).(*Basic); ok {
5515 return b.Info()&IsString != 0
5516 }
5517 return false
5518 }
5519
5520 func (e *irEmitter) emitMakeClosure(m *SSAMakeClosure) {
5521 reg := e.regName(m)
5522 var fn *SSAFunction
5523 if okv, okok := m.Fn.(*SSAFunction); okok {
5524 fn = okv
5525 }
5526 ipt := e.intptrType()
5527
5528 if len(m.Bindings) == 0 {
5529 t1 := e.nextReg2("mc")
5530 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr null, 0\n")
5531 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1)
5532 e.w(", ptr ") ; e.w(e.funcSymbol(fn)) ; e.w(", 1\n")
5533 return
5534 }
5535
5536 ctxType := e.closureContextType(m.Bindings)
5537 ctxSz := e.nextReg2("mc")
5538 e.w(" ") ; e.w(ctxSz) ; e.w(" = ptrtoint ptr getelementptr (")
5539 e.w(ctxType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
5540 ctxPtr := e.nextReg2("mc")
5541 e.w(" ") ; e.w(ctxPtr) ; e.w(" = call ptr @runtime.alloc(")
5542 e.w(ipt) ; e.w(" ") ; e.w(ctxSz) ; e.w(", ptr null, ptr undef)\n")
5543 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
5544
5545 for i, b := range m.Bindings {
5546 bval := e.operand(b)
5547 bt := e.closureBindingType(b)
5548 gep := e.nextReg2("mc")
5549 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(ctxType) ; e.w(", ptr ")
5550 e.w(ctxPtr) ; e.w(", i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
5551 e.w(" store ") ; e.w(bt) ; e.w(" ") ; e.w(bval) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
5552 _ = b
5553 }
5554
5555 t1 := e.nextReg2("mc")
5556 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(ctxPtr) ; e.w(", 0\n")
5557 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1)
5558 e.w(", ptr ") ; e.w(e.funcSymbol(fn)) ; e.w(", 1\n")
5559 }
5560
5561 func (e *irEmitter) closureBindingType(b SSAValue) string {
5562 t := e.llvmType(b.SSAType())
5563 if t == "void" || t == "i32" {
5564 t = "ptr"
5565 }
5566 return t
5567 }
5568
5569 func (e *irEmitter) closureContextType(bindings []SSAValue) string {
5570 s := "{"
5571 for i, b := range bindings {
5572 if i > 0 {
5573 s = s | ", "
5574 }
5575 s = s | e.closureBindingType(b)
5576 }
5577 return s | "}"
5578 }
5579
5580 func (e *irEmitter) freeVarType(fv *SSAFreeVar) string {
5581 return "ptr"
5582 }
5583
5584 func (e *irEmitter) emitFreeVarUnpack(f *SSAFunction) {
5585 ctxType := "{"
5586 for i, fv := range f.FreeVars {
5587 if i > 0 {
5588 ctxType = ctxType | ", "
5589 }
5590 ctxType = ctxType | e.freeVarType(fv)
5591 }
5592 ctxType = ctxType | "}"
5593
5594 for i, fv := range f.FreeVars {
5595 fvName := e.regName(fv)
5596 e.nextReg++
5597 gep := "%fv" | irItoa(e.nextReg)
5598 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(ctxType)
5599 e.w(", ptr %context, i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
5600 e.w(" ") ; e.w(fvName) ; e.w(" = load ptr, ptr ") ; e.w(gep) ; e.w("\n")
5601 }
5602 }
5603
5604 func (e *irEmitter) emitPanic(p *SSAPanic) {
5605 if c, ok := p.X.(*SSAConst); ok && e.isStringLike(c.SSAType()) {
5606 arg := e.operand(c)
5607 sty := e.sliceType()
5608 e.w(" call void @runtime._panicstr(") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(")\n")
5609 e.declareRuntime("runtime._panicstr", "void", sty)
5610 e.w(" unreachable\n")
5611 return
5612 }
5613 e.w(" call void @runtime._panic(ptr null)\n")
5614 e.declareRuntime("runtime._panic", "void", "ptr")
5615 e.w(" unreachable\n")
5616 }
5617
5618 func (e *irEmitter) emitRange(r *SSARange) {
5619 reg := e.regName(r)
5620 if _, ok := safeUnderlying(r.X.SSAType()).(*TCMap); ok {
5621 e.w(" ") ; e.w(reg) ; e.w(" = alloca [48 x i8]\n")
5622 e.w(" call void @llvm.memset.p0.i64(ptr ") ; e.w(reg) ; e.w(", i8 0, i64 48, i1 false)\n")
5623 e.declareRuntime("llvm.memset.p0.i64", "void", "ptr, i8, i64, i1")
5624 return
5625 }
5626 ipt := e.intptrType()
5627 e.w(" ") ; e.w(reg) ; e.w(" = alloca ") ; e.w(ipt) ; e.w("\n")
5628 e.w(" store ") ; e.w(ipt) ; e.w(" 0, ptr ") ; e.w(reg) ; e.w("\n")
5629 }
5630
5631 func (e *irEmitter) emitNext(n *SSANext) {
5632 reg := e.regName(n)
5633 rangeInstr := n.Iter.(*SSARange)
5634 iterPtr := e.regName(rangeInstr)
5635 collVal := e.operand(rangeInstr.X)
5636 if mt, ok := safeUnderlying(rangeInstr.X.SSAType()).(*TCMap); ok {
5637 e.emitNextMap(reg, iterPtr, collVal, mt, n)
5638 return
5639 }
5640 if arr, ok := safeUnderlying(rangeInstr.X.SSAType()).(*Array); ok {
5641 e.emitNextArray(reg, iterPtr, collVal, arr, n)
5642 return
5643 }
5644 collLLVM := e.llvmType(rangeInstr.X.SSAType())
5645 if len(collLLVM) > 0 && collLLVM[0] == 'i' {
5646 tupType := e.llvmType(n.SSAType())
5647 if at, ok := e.allocTypes[n]; ok {
5648 tupType = at
5649 }
5650 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" zeroinitializer, i1 false, 0\n")
5651 return
5652 }
5653 e.emitNextSlice(reg, iterPtr, collVal, rangeInstr, n)
5654 }
5655
5656 func (e *irEmitter) emitNextSlice(reg, iterPtr, collVal string, rangeInstr *SSARange, n *SSANext) {
5657 ipt := e.intptrType()
5658 sty := e.sliceType()
5659 idx := e.nextReg2("rn")
5660 e.w(" ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
5661 slLen := e.nextReg2("rn")
5662 e.w(" ") ; e.w(slLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(collVal) ; e.w(", 1\n")
5663 ok := e.nextReg2("rn")
5664 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")
5665 key := e.nextReg2("rn")
5666 e.w(" ") ; e.w(key) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(" to i32\n")
5667 dataPtr := e.nextReg2("rn")
5668 e.w(" ") ; e.w(dataPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(collVal) ; e.w(", 0\n")
5669 elemType := "i32"
5670 if sl, ok2 := safeUnderlying(rangeInstr.X.SSAType()).(*Slice); ok2 {
5671 elemType = e.llvmType(sl.Elem())
5672 }
5673 eptr := e.nextReg2("rn")
5674 e.w(" ") ; e.w(eptr) ; e.w(" = getelementptr ") ; e.w(elemType)
5675 e.w(", ptr ") ; e.w(dataPtr) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
5676 fallback := e.nextReg2("rn")
5677 e.w(" ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
5678 e.w(" store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(fallback) ; e.w("\n")
5679 safePtr := e.nextReg2("rn")
5680 e.w(" ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
5681 e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
5682 elem := e.nextReg2("rn")
5683 e.w(" ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
5684 inc := e.nextReg2("rn")
5685 e.w(" ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
5686 newCnt := e.nextReg2("rn")
5687 e.w(" ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
5688 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
5689 e.w(" store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
5690 tupType := "{i1, i32, " | elemType | "}"
5691 e.allocTypes[n] = tupType
5692 t1 := e.nextReg2("rn")
5693 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
5694 t2 := e.nextReg2("rn")
5695 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")
5696 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")
5697 }
5698
5699 func (e *irEmitter) emitNextArray(reg, iterPtr, collVal string, arr *Array, n *SSANext) {
5700 ipt := e.intptrType()
5701 arrLen := arr.Len()
5702 elemType := e.llvmType(arr.Elem())
5703 arrType := "[" | irItoa(int32(arrLen)) | " x " | elemType | "]"
5704 idx := e.nextReg2("rn")
5705 e.w(" ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
5706 ok := e.nextReg2("rn")
5707 e.w(" ") ; e.w(ok) ; e.w(" = icmp ult ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", ") ; e.w(irItoa(int32(arrLen))) ; e.w("\n")
5708 key := e.nextReg2("rn")
5709 e.w(" ") ; e.w(key) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(" to i32\n")
5710 // Store array to memory to get element pointer via GEP
5711 arrAlloca := e.nextReg2("rn")
5712 e.w(" ") ; e.w(arrAlloca) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
5713 e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(collVal) ; e.w(", ptr ") ; e.w(arrAlloca) ; e.w("\n")
5714 eptr := e.nextReg2("rn")
5715 e.w(" ") ; e.w(eptr) ; e.w(" = getelementptr inbounds ") ; e.w(arrType)
5716 e.w(", ptr ") ; e.w(arrAlloca) ; e.w(", i32 0, ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
5717 fallback := e.nextReg2("rn")
5718 e.w(" ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
5719 e.w(" store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(fallback) ; e.w("\n")
5720 safePtr := e.nextReg2("rn")
5721 e.w(" ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
5722 e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
5723 elem := e.nextReg2("rn")
5724 e.w(" ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
5725 inc := e.nextReg2("rn")
5726 e.w(" ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
5727 newCnt := e.nextReg2("rn")
5728 e.w(" ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
5729 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
5730 e.w(" store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
5731 tupType := "{i1, i32, " | elemType | "}"
5732 e.allocTypes[n] = tupType
5733 t1 := e.nextReg2("rn")
5734 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
5735 t2 := e.nextReg2("rn")
5736 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")
5737 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")
5738 }
5739
5740 func (e *irEmitter) emitNextMap(reg, iterPtr, collVal string, mt *TCMap, n *SSANext) {
5741 keyType := e.llvmType(mt.Key())
5742 valType := e.llvmType(mt.Elem())
5743 keyAlloca := e.nextReg2("mn")
5744 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
5745 valAlloca := e.nextReg2("mn")
5746 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
5747 ok := e.nextReg2("mn")
5748 e.w(" ") ; e.w(ok) ; e.w(" = call i1 @runtime.hashmapNext(ptr ") ; e.w(collVal)
5749 e.w(", ptr ") ; e.w(iterPtr)
5750 e.w(", ptr ") ; e.w(keyAlloca)
5751 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
5752 key := e.nextReg2("mn")
5753 e.w(" ") ; e.w(key) ; e.w(" = load ") ; e.w(keyType) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
5754 val := e.nextReg2("mn")
5755 e.w(" ") ; e.w(val) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
5756 tupType := e.llvmType(n.SSAType())
5757 t1 := e.nextReg2("mn")
5758 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
5759 t2 := e.nextReg2("mn")
5760 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")
5761 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")
5762 e.declareRuntime("runtime.hashmapNext", "i1", "ptr, ptr, ptr, ptr")
5763 }
5764
5765 func (e *irEmitter) operandNoSideEffect(v SSAValue) string {
5766 if v == nil {
5767 return "zeroinitializer"
5768 }
5769 if c, ok := v.(*SSAConst); ok {
5770 return e.constOperand(c)
5771 }
5772 if n, ok := e.valName[v]; ok {
5773 return n
5774 }
5775 return ""
5776 }
5777
5778 func (e *irEmitter) operand(v SSAValue) string {
5779 if v == nil {
5780 return "zeroinitializer"
5781 }
5782 if c, ok := v.(*SSAConst); ok {
5783 return e.constOperand(c)
5784 }
5785 if b, ok := v.(*SSABuiltin); ok {
5786 return "@runtime." | b.SSAName()
5787 }
5788 if f, ok := v.(*SSAFunction); ok {
5789 return "{ ptr null, ptr " | e.funcSymbol(f) | " }"
5790 }
5791 if g, ok := v.(*SSAGlobal); ok {
5792 e.declareExternalGlobal(g)
5793 return e.globalName(g)
5794 }
5795 return e.regName(v)
5796 }
5797
5798 func (e *irEmitter) constOperand(c *SSAConst) string {
5799 if c.val == nil {
5800 if c.typ == nil {
5801 return "null"
5802 }
5803 typ := e.llvmType(c.typ)
5804 if typ == "ptr" {
5805 return "null"
5806 }
5807 if typ == "i1" {
5808 return "false"
5809 }
5810 return "zeroinitializer"
5811 }
5812 b := underlyingBasic(c.typ)
5813 if b != nil {
5814 switch b.kind {
5815 case Bool, UntypedBool:
5816 if cb, ok := c.val.(constBool); ok {
5817 if cb.v {
5818 return "true"
5819 }
5820 return "false"
5821 }
5822 s := c.val.String()
5823 if s == "true" {
5824 return "true"
5825 }
5826 return "false"
5827 case Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64,
5828 UntypedInt, UntypedRune:
5829 if ci, ok := c.val.(constInt); ok {
5830 v := ci.v
5831 switch b.kind {
5832 case Int8:
5833 v = int32(int8(v))
5834 case Uint8:
5835 v = int32(uint8(v))
5836 case Int16:
5837 v = int32(int16(v))
5838 case Uint16:
5839 v = int32(uint16(v))
5840 case Int32:
5841 v = int32(int32(v))
5842 case Uint32:
5843 v = int32(uint32(v))
5844 }
5845 return irItoa64(v)
5846 }
5847 if cf, ok := c.val.(constFloat); ok {
5848 return irItoa64(int32(cf.v))
5849 }
5850 return c.val.String()
5851 case Float32, Float64, UntypedFloat:
5852 if cf, ok := c.val.(constFloat); ok {
5853 return irFloatHex(cf.v)
5854 }
5855 return c.val.String()
5856 case TCString, UntypedString:
5857 if cs, ok := c.val.(constStr); ok {
5858 if len(cs.s) == 0 {
5859 return "zeroinitializer"
5860 }
5861 idx := e.addStringConst(cs.s)
5862 ipt := e.intptrType()
5863 slen := irItoa64(int32(len(cs.s)))
5864 return "{ ptr " | e.strConstGlobal(idx) | ", " | ipt | " " | slen | ", " | ipt | " " | slen | " }"
5865 }
5866 return "zeroinitializer"
5867 }
5868 }
5869 if c.typ == nil {
5870 return c.val.String()
5871 }
5872 return "zeroinitializer"
5873 }
5874
5875 func underlyingBasic(t Type) *Basic {
5876 if t == nil {
5877 return nil
5878 }
5879 u := safeUnderlying(t)
5880 if u == nil {
5881 return nil
5882 }
5883 b, ok := u.(*Basic)
5884 if !ok {
5885 return nil
5886 }
5887 return b
5888 }
5889
5890 func newTCPackageWithUniverse(path, name string) *TCPackage {
5891 return &TCPackage{
5892 path: path,
5893 name: name,
5894 scope: NewScope(Universe),
5895 }
5896 }
5897
5898 func irParseIntWidth(t string) int32 {
5899 if len(t) < 2 || t[0] != 'i' {
5900 return 0
5901 }
5902 n := 0
5903 for i := 1; i < len(t); i++ {
5904 if t[i] < '0' || t[i] > '9' {
5905 return 0
5906 }
5907 n = n*10 + int32(t[i]-'0')
5908 }
5909 return n
5910 }
5911
5912 func (e *irEmitter) deferRetType(d *SSADefer) string {
5913 if fn, ok := d.Call.Value.(*SSAFunction); ok {
5914 if fn.Signature == nil {
5915 return "void"
5916 }
5917 r := fn.Signature.Results()
5918 if r == nil {
5919 return "void"
5920 }
5921 return e.llvmType(r)
5922 }
5923 t := d.Call.Value.SSAType()
5924 if t == nil {
5925 return "void"
5926 }
5927 u := safeUnderlying(t)
5928 if sig, ok := u.(*Signature); ok {
5929 r := sig.Results()
5930 if r == nil || r.Len() == 0 {
5931 return "void"
5932 }
5933 return e.llvmType(r)
5934 }
5935 return "void"
5936 }
5937
5938 func (e *irEmitter) deferArgType(arg SSAValue) string {
5939 t := e.llvmType(arg.SSAType())
5940 if t == "void" {
5941 return "ptr"
5942 }
5943 return t
5944 }
5945
5946 func (e *irEmitter) deferIsDirectCall(d *SSADefer) bool {
5947 if _, ok := d.Call.Value.(*SSAFunction); ok {
5948 return true
5949 }
5950 if _, ok := d.Call.Value.(*SSABuiltin); ok {
5951 return true
5952 }
5953 return false
5954 }
5955
5956 func (e *irEmitter) deferStructType(d *SSADefer) string {
5957 ipt := e.intptrType()
5958 s := "{" | ipt | ", ptr"
5959 if !e.deferIsDirectCall(d) {
5960 s = s | ", {ptr, ptr}"
5961 }
5962 for _, arg := range d.Call.Args {
5963 s = s | ", " | e.deferArgType(arg)
5964 }
5965 return s | "}"
5966 }
5967
5968 func (e *irEmitter) emitDefer(d *SSADefer) {
5969 idx := -1
5970 for i, dd := range e.deferList {
5971 if dd == d {
5972 idx = i
5973 break
5974 }
5975 }
5976 if idx < 0 {
5977 e.w(" ; defer: not found in list\n")
5978 return
5979 }
5980 ipt := e.intptrType()
5981 id := e.deferID
5982 e.deferID++
5983 pfx := "%df" | irItoa(id) | "."
5984 sty := e.deferStructType(d)
5985
5986 e.w(" ") ; e.w(pfx) ; e.w("a = alloca ") ; e.w(sty) ; e.w("\n")
5987
5988 cbGep := pfx | "cb"
5989 e.w(" ") ; e.w(cbGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
5990 e.w(", ptr ") ; e.w(pfx) ; e.w("a, i32 0, i32 0\n")
5991 e.w(" store ") ; e.w(ipt) ; e.w(" ") ; e.w(irItoa(idx))
5992 e.w(", ptr ") ; e.w(cbGep) ; e.w("\n")
5993
5994 nxGep := pfx | "nx"
5995 e.w(" ") ; e.w(nxGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
5996 e.w(", ptr ") ; e.w(pfx) ; e.w("a, i32 0, i32 1\n")
5997 prev := pfx | "prev"
5998 e.w(" ") ; e.w(prev) ; e.w(" = load ptr, ptr %deferPtr\n")
5999 e.w(" store ptr ") ; e.w(prev) ; e.w(", ptr ") ; e.w(nxGep) ; e.w("\n")
6000
6001 fieldIdx := int32(2)
6002 if !e.deferIsDirectCall(d) {
6003 fvGep := pfx | "fv"
6004 e.w(" ") ; e.w(fvGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
6005 e.w(", ptr ") ; e.w(pfx) ; e.w("a, i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
6006 fvOp := e.operand(d.Call.Value)
6007 e.w(" store {ptr, ptr} ") ; e.w(fvOp)
6008 e.w(", ptr ") ; e.w(fvGep) ; e.w("\n")
6009 fieldIdx++
6010 }
6011
6012 for i, arg := range d.Call.Args {
6013 _ = i
6014 aGep := pfx | "a" | irItoa(int32(fieldIdx))
6015 e.w(" ") ; e.w(aGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
6016 e.w(", ptr ") ; e.w(pfx) ; e.w("a, i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
6017 at := e.deferArgType(arg)
6018 av := e.operand(arg)
6019 e.w(" store ") ; e.w(at) ; e.w(" ") ; e.w(av)
6020 e.w(", ptr ") ; e.w(aGep) ; e.w("\n")
6021 fieldIdx++
6022 }
6023
6024 e.w(" store ptr ") ; e.w(pfx) ; e.w("a, ptr %deferPtr\n")
6025 }
6026
6027 func (e *irEmitter) emitRunDefers() {
6028 if len(e.deferList) == 0 {
6029 return
6030 }
6031 ipt := e.intptrType()
6032 id := e.deferID
6033 e.deferID++
6034 pfx := "rundefers" | irItoa(id)
6035
6036 e.w(" br label %") ; e.w(pfx) ; e.w(".head\n")
6037 e.w(pfx) ; e.w(".head:\n")
6038 e.w(" %") ; e.w(pfx) ; e.w(".cur = load ptr, ptr %deferPtr\n")
6039 e.w(" %") ; e.w(pfx) ; e.w(".nil = icmp eq ptr %") ; e.w(pfx) ; e.w(".cur, null\n")
6040 e.w(" br i1 %") ; e.w(pfx) ; e.w(".nil, label %") ; e.w(pfx) ; e.w(".end, label %")
6041 e.w(pfx) ; e.w(".body\n")
6042
6043 e.w(pfx) ; e.w(".body:\n")
6044 e.w(" %") ; e.w(pfx) ; e.w(".cb = load ") ; e.w(ipt) ; e.w(", ptr %") ; e.w(pfx) ; e.w(".cur\n")
6045 nxGep := "%" | pfx | ".nxp"
6046 e.w(" ") ; e.w(nxGep) ; e.w(" = getelementptr inbounds {") ; e.w(ipt) ; e.w(", ptr}, ptr %")
6047 e.w(pfx) ; e.w(".cur, i32 0, i32 1\n")
6048 e.w(" %") ; e.w(pfx) ; e.w(".nx = load ptr, ptr ") ; e.w(nxGep) ; e.w("\n")
6049 e.w(" store ptr %") ; e.w(pfx) ; e.w(".nx, ptr %deferPtr\n")
6050
6051 for i, d := range e.deferList {
6052 checkLabel := pfx | ".c" | irItoa(i)
6053 callLabel := pfx | ".k" | irItoa(i)
6054 var nextLabel string
6055 if i+1 < len(e.deferList) {
6056 nextLabel = pfx | ".c" | irItoa(i+1)
6057 } else {
6058 nextLabel = pfx | ".head"
6059 }
6060 if i == 0 {
6061 e.w(" %") ; e.w(checkLabel) ; e.w(".eq = icmp eq ") ; e.w(ipt) ; e.w(" %")
6062 e.w(pfx) ; e.w(".cb, 0\n")
6063 e.w(" br i1 %") ; e.w(checkLabel) ; e.w(".eq, label %") ; e.w(callLabel)
6064 e.w(", label %") ; e.w(nextLabel) ; e.w("\n")
6065 } else {
6066 e.w(checkLabel) ; e.w(":\n")
6067 e.w(" %") ; e.w(checkLabel) ; e.w(".eq = icmp eq ") ; e.w(ipt) ; e.w(" %")
6068 e.w(pfx) ; e.w(".cb, ") ; e.w(irItoa(i)) ; e.w("\n")
6069 e.w(" br i1 %") ; e.w(checkLabel) ; e.w(".eq, label %") ; e.w(callLabel)
6070 e.w(", label %") ; e.w(nextLabel) ; e.w("\n")
6071 }
6072
6073 e.w(callLabel) ; e.w(":\n")
6074 e.emitDeferDispatch(d, pfx, i)
6075 e.w(" br label %") ; e.w(pfx) ; e.w(".head\n")
6076 }
6077
6078 e.w(pfx) ; e.w(".end:\n")
6079 }
6080
6081 func (e *irEmitter) emitDeferBuiltin(d *SSADefer, bi *SSABuiltin, pfx string, idx int32, sty string, dp string) {
6082 fieldIdx := int32(2)
6083 var args []string
6084 var argTypes []string
6085 for i, arg := range d.Call.Args {
6086 aGep := "%" | pfx | ".da" | irItoa(idx) | "f" | irItoa(i)
6087 e.w(" ") ; e.w(aGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
6088 e.w(", ptr ") ; e.w(dp) ; e.w(", i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
6089 at := e.deferArgType(arg)
6090 aVal := "%" | pfx | ".dv" | irItoa(idx) | "f" | irItoa(i)
6091 e.w(" ") ; e.w(aVal) ; e.w(" = load ") ; e.w(at) ; e.w(", ptr ") ; e.w(aGep) ; e.w("\n")
6092 args = append(args, aVal)
6093 argTypes = append(argTypes, at)
6094 fieldIdx++
6095 }
6096 name := bi.SSAName()
6097 if name == "close" && len(args) == 1 {
6098 e.declareRuntime("runtime.chanClose", "void", "ptr")
6099 e.w(" call void @runtime.chanClose(") ; e.w(argTypes[0]) ; e.w(" ") ; e.w(args[0]) ; e.w(")\n")
6100 } else if name == "panic" && len(args) == 1 {
6101 e.declareRuntime("runtime._panicstr", "void", argTypes[0])
6102 e.w(" call void @runtime._panicstr(") ; e.w(argTypes[0]) ; e.w(" ") ; e.w(args[0]) ; e.w(")\n")
6103 } else if name == "println" || name == "print" {
6104 e.declareRuntime("runtime.printlock", "void", "")
6105 e.declareRuntime("runtime.printunlock", "void", "")
6106 e.declareRuntime("runtime.printnl", "void", "")
6107 e.w(" call void @runtime.printlock()\n")
6108 for ai, av := range args {
6109 if ai > 0 {
6110 e.declareRuntime("runtime.printspace", "void", "")
6111 e.w(" call void @runtime.printspace()\n")
6112 }
6113 at := argTypes[ai]
6114 if at == e.sliceType() || at == "{ptr, i64, i64}" {
6115 e.declareRuntime("runtime.printstring", "void", e.sliceType())
6116 e.w(" call void @runtime.printstring(") ; e.w(at) ; e.w(" ") ; e.w(av) ; e.w(")\n")
6117 } else if at == "i1" {
6118 e.declareRuntime("runtime.printbool", "void", "i1")
6119 e.w(" call void @runtime.printbool(i1 ") ; e.w(av) ; e.w(")\n")
6120 } else if at == "i32" || at == "i64" || at == "i16" || at == "i8" {
6121 fname := "runtime.printint" | at[1:]
6122 e.declareRuntime(fname, "void", at)
6123 e.w(" call void @") ; e.w(fname) ; e.w("(") ; e.w(at) ; e.w(" ") ; e.w(av) ; e.w(")\n")
6124 } else if at == "ptr" {
6125 ipt := e.intptrType()
6126 e.declareRuntime("runtime.printptr", "void", ipt)
6127 tmp := "%" | pfx | ".ptmp" | irItoa(ai)
6128 e.w(" ") ; e.w(tmp) ; e.w(" = ptrtoint ptr ") ; e.w(av) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
6129 e.w(" call void @runtime.printptr(") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(")\n")
6130 }
6131 }
6132 if name == "println" {
6133 e.w(" call void @runtime.printnl()\n")
6134 }
6135 e.w(" call void @runtime.printunlock()\n")
6136 } else if name == "delete" && len(args) == 2 {
6137 e.declareRuntime("runtime.hashmapBinaryDelete", "void", "ptr, ptr, i32")
6138 e.w(" ; defer delete - not fully implemented\n")
6139 } else if name == "recover" {
6140 e.w(" ; defer recover() is a no-op\n")
6141 } else {
6142 e.w(" ; defer builtin ") ; e.w(name) ; e.w(" - not implemented\n")
6143 }
6144 }
6145
6146 func (e *irEmitter) emitDeferDispatch(d *SSADefer, pfx string, idx int32) {
6147 sty := e.deferStructType(d)
6148 dp := "%" | pfx | ".cur"
6149
6150 fieldIdx := int32(2)
6151 if bi, isBi := d.Call.Value.(*SSABuiltin); isBi {
6152 e.emitDeferBuiltin(d, bi, pfx, idx, sty, dp)
6153 return
6154 }
6155 if fn, isFn := d.Call.Value.(*SSAFunction); isFn {
6156 var args []string
6157 var argTypes []string
6158 for i, arg := range d.Call.Args {
6159 aGep := "%" | pfx | ".da" | irItoa(idx) | "f" | irItoa(i)
6160 e.w(" ") ; e.w(aGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
6161 e.w(", ptr ") ; e.w(dp) ; e.w(", i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
6162 at := e.deferArgType(arg)
6163 aVal := "%" | pfx | ".dv" | irItoa(idx) | "f" | irItoa(i)
6164 e.w(" ") ; e.w(aVal) ; e.w(" = load ") ; e.w(at) ; e.w(", ptr ") ; e.w(aGep) ; e.w("\n")
6165 args = append(args, aVal)
6166 argTypes = append(argTypes, at)
6167 fieldIdx++
6168 }
6169 if !e.isPkgFunc(fn) {
6170 e.declareExternalFunc(fn)
6171 }
6172 rt := e.deferRetType(d)
6173 e.w(" call ") ; e.w(rt) ; e.w(" ") ; e.w(e.funcSymbol(fn)) ; e.w("(")
6174 for i, av := range args {
6175 if i > 0 { e.w(", ") }
6176 e.w(argTypes[i]) ; e.w(" ") ; e.w(av)
6177 }
6178 if !fn.isExternC {
6179 if len(args) > 0 { e.w(", ") }
6180 e.w("ptr null")
6181 }
6182 e.w(")\n")
6183 } else {
6184 fvGep := "%" | pfx | ".dfv" | irItoa(idx)
6185 e.w(" ") ; e.w(fvGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
6186 e.w(", ptr ") ; e.w(dp) ; e.w(", i32 0, i32 2\n")
6187 fvVal := "%" | pfx | ".fvv" | irItoa(idx)
6188 e.w(" ") ; e.w(fvVal) ; e.w(" = load {ptr, ptr}, ptr ") ; e.w(fvGep) ; e.w("\n")
6189 fpReg := "%" | pfx | ".fp" | irItoa(idx)
6190 ctxReg := "%" | pfx | ".ctx" | irItoa(idx)
6191 e.w(" ") ; e.w(fpReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(fvVal) ; e.w(", 1\n")
6192 e.w(" ") ; e.w(ctxReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(fvVal) ; e.w(", 0\n")
6193 fieldIdx = 3
6194 var args []string
6195 var argTypes []string
6196 for i, arg := range d.Call.Args {
6197 aGep := "%" | pfx | ".da" | irItoa(idx) | "f" | irItoa(i)
6198 e.w(" ") ; e.w(aGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
6199 e.w(", ptr ") ; e.w(dp) ; e.w(", i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
6200 at := e.deferArgType(arg)
6201 aVal := "%" | pfx | ".dv" | irItoa(idx) | "f" | irItoa(i)
6202 e.w(" ") ; e.w(aVal) ; e.w(" = load ") ; e.w(at) ; e.w(", ptr ") ; e.w(aGep) ; e.w("\n")
6203 args = append(args, aVal)
6204 argTypes = append(argTypes, at)
6205 fieldIdx++
6206 }
6207 rt := e.deferRetType(d)
6208 e.w(" call ") ; e.w(rt) ; e.w(" ") ; e.w(fpReg) ; e.w("(")
6209 for i, av := range args {
6210 if i > 0 { e.w(", ") }
6211 e.w(argTypes[i]) ; e.w(" ") ; e.w(av)
6212 }
6213 if len(args) > 0 { e.w(", ") }
6214 e.w("ptr ") ; e.w(ctxReg)
6215 e.w(")\n")
6216 }
6217 }
6218
6219 func irItoa(n int32) string {
6220 if n == 0 {
6221 return "0"
6222 }
6223 neg := n < 0
6224 if neg {
6225 n = -n
6226 }
6227 buf := []byte{:0:20}
6228 for n > 0 {
6229 buf = append(buf, byte('0'+n%10))
6230 n /= 10
6231 }
6232 if neg {
6233 buf = append(buf, '-')
6234 }
6235 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
6236 buf[i], buf[j] = buf[j], buf[i]
6237 }
6238 return string(buf)
6239 }
6240
6241 func irItoa64(n int32) string {
6242 if n == 0 {
6243 return "0"
6244 }
6245 if n == -9223372036854775808 {
6246 return "-9223372036854775808"
6247 }
6248 neg := n < 0
6249 if neg {
6250 n = -n
6251 }
6252 buf := []byte{:0:20}
6253 for n > 0 {
6254 buf = append(buf, byte('0'+n%10))
6255 n /= 10
6256 }
6257 if neg {
6258 buf = append(buf, '-')
6259 }
6260 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
6261 buf[i], buf[j] = buf[j], buf[i]
6262 }
6263 return string(buf)
6264 }
6265
6266 func irFloatHex(f float64) string {
6267 bits := float64ToIEEE(f)
6268 buf := []byte{:0:18}
6269 buf = append(buf, '0', 'x')
6270 for i := 60; i >= 0; i -= 4 {
6271 nibble := (bits >> uint32(i)) & 0xF
6272 if nibble < 10 {
6273 buf = append(buf, byte('0'+nibble))
6274 } else {
6275 buf = append(buf, byte('A'+nibble-10))
6276 }
6277 }
6278 return string(buf)
6279 }
6280
6281 func isZeroFloat(f float64) bool {
6282 return !(f >= 5e-324) && !(f < -0.0)
6283 }
6284
6285 func float64ToIEEE(f float64) uint32 {
6286 // NaN: f is neither >= itself nor < itself (unordered)
6287 if !(f >= f) {
6288 return 0x7FF8000000000000
6289 }
6290 var sign uint32
6291 if f < 0.0 {
6292 sign = 1 << 63
6293 f = -f
6294 }
6295 if isZeroFloat(f) {
6296 return sign
6297 }
6298 // +Inf: larger than any finite value
6299 if f >= 1.7976931348623158e+308 && f+f >= f {
6300 return sign | 0x7FF0000000000000
6301 }
6302 e := int32(0)
6303 fv := f
6304 if fv >= 2.0 {
6305 for fv >= 2.0 {
6306 fv /= 2.0
6307 e++
6308 }
6309 } else if fv < 1.0 {
6310 for fv < 1.0 {
6311 fv *= 2.0
6312 e--
6313 }
6314 }
6315 // fv in [1, 2), e is unbiased exponent
6316 if e < -1022 {
6317 // denormal: shift mantissa down by (-1022 - e) positions
6318 shift := -1022 - e
6319 mant := uint32((fv - 1.0) * 4503599627370496.0) // (fv-1)*2^52
6320 mant |= 1 << 52 // add implicit 1
6321 mant >>= uint32(shift)
6322 return sign | mant
6323 }
6324 biasedExp := uint32(e+1023) << 52
6325 mant := uint32((fv - 1.0) * 4503599627370496.0)
6326 return sign | biasedExp | mant
6327 }
6328
6329 func irParseInt64(s string) int32 {
6330 var n int32
6331 for i := 0; i < len(s); i++ {
6332 c := s[i]
6333 if c < '0' || c > '9' {
6334 break
6335 }
6336 n = n*10 + int32(c-'0')
6337 }
6338 return n
6339 }
6340
6341 func runeToUTF8(r rune) string {
6342 if r < 0 || r > 0x10FFFF {
6343 r = 0xFFFD
6344 }
6345 var buf [4]byte
6346 switch {
6347 case r <= 0x7F:
6348 buf[0] = byte(r)
6349 return string(buf[:1])
6350 case r <= 0x7FF:
6351 buf[0] = byte(0xC0 | (r >> 6))
6352 buf[1] = byte(0x80 | (r & 0x3F))
6353 return string(buf[:2])
6354 case r <= 0xFFFF:
6355 buf[0] = byte(0xE0 | (r >> 12))
6356 buf[1] = byte(0x80 | ((r >> 6) & 0x3F))
6357 buf[2] = byte(0x80 | (r & 0x3F))
6358 return string(buf[:3])
6359 default:
6360 buf[0] = byte(0xF0 | (r >> 18))
6361 buf[1] = byte(0x80 | ((r >> 12) & 0x3F))
6362 buf[2] = byte(0x80 | ((r >> 6) & 0x3F))
6363 buf[3] = byte(0x80 | (r & 0x3F))
6364 return string(buf[:4])
6365 }
6366 }
6367
6368 func scanExportPragmas(src []byte) map[string]string {
6369 result := map[string]string{}
6370 exportPrefix := []byte("//export ")
6371 funcPrefix := []byte("func ")
6372 commentPrefix := []byte("//")
6373 pendingExport := ""
6374 i := 0
6375 for i < len(src) {
6376 nlIdx := bytes.IndexByte(src[i:], '\n')
6377 var line []byte
6378 var lineEnd int32
6379 if nlIdx < 0 {
6380 line = src[i:]
6381 lineEnd = len(src)
6382 } else {
6383 line = src[i : i+nlIdx]
6384 lineEnd = i + nlIdx + 1
6385 }
6386 trimmed := bytes.TrimSpace(line)
6387 if len(pendingExport) > 0 {
6388 if len(trimmed) == 0 || bytes.HasPrefix(trimmed, commentPrefix) {
6389 i = lineEnd
6390 continue
6391 }
6392 if bytes.HasPrefix(trimmed, funcPrefix) {
6393 rest := trimmed[5:]
6394 paren := bytes.IndexByte(rest, '(')
6395 if paren > 0 {
6396 funcName := string(bytes.TrimSpace(rest[:paren]))
6397 result[funcName] = pendingExport
6398 }
6399 }
6400 pendingExport = ""
6401 } else if bytes.HasPrefix(trimmed, exportPrefix) {
6402 pendingExport = string(bytes.TrimSpace(trimmed[9:]))
6403 }
6404 i = lineEnd
6405 }
6406 return result
6407 }
6408
6409 func typeCheckPkg(src []byte, name string) (*TCPackage, *File) {
6410 initUniverse()
6411 shortName := name
6412 for i := len(name) - 1; i >= 0; i-- {
6413 if name[i] == '/' {
6414 shortName = name[i+1:]
6415 break
6416 }
6417 }
6418 pkg := newTCPackageWithUniverse(name, shortName)
6419 scope := pkg.Scope()
6420
6421 src = rewriteSliceMakeLiterals(src)
6422 src = rewriteChanMakeLiterals(src)
6423 src = stripDuplicatePackageClauses(src)
6424
6425 if len(src) == 0 {
6426 return nil, nil
6427 }
6428
6429 parseErrors = nil
6430 constValMap = nil
6431 errh := func(err error) {
6432 parseErrors = append(parseErrors, err.Error())
6433 }
6434 tcPkgSrc = src
6435 compileExportMap = scanExportPragmas(src)
6436 file, _ := ParseBytes(NewFileBase(name|".mx"), src, errh, nil, 0)
6437 if file == nil {
6438 return nil, nil
6439 }
6440 for _, d := range file.DeclList {
6441 switch d := d.(type) {
6442 case *ImportDecl:
6443 if d.Path == nil {
6444 continue
6445 }
6446 path := d.Path.Value
6447 if len(path) >= 2 && path[0] == '"' {
6448 path = path[1 : len(path)-1]
6449 }
6450 ensureImportRegistry()
6451 imported := importRegistry[path]
6452 if imported == nil {
6453 continue
6454 }
6455 if path == "unsafe" && imported.Scope().Lookup("Pointer") == nil {
6456 imported.Scope().Insert(NewTypeName(imported, "Pointer", Typ[UnsafePointer]))
6457 }
6458 localName := imported.Name()
6459 if d.LocalPkgName != nil {
6460 localName = d.LocalPkgName.Value
6461 }
6462 scope.Insert(NewPkgName(pkg, localName, imported))
6463 case *VarDecl:
6464 for _, n := range d.NameList {
6465 scope.Insert(NewTCVar(pkg, n.Value, nil))
6466 }
6467 case *FuncDecl:
6468 if d.Recv == nil && d.Name.Value != "init" {
6469 scope.Insert(NewTCFunc(pkg, d.Name.Value, nil))
6470 }
6471 case *TypeDecl:
6472 scope.Insert(NewTypeName(pkg, d.Name.Value, nil))
6473 case *ConstDecl:
6474 for _, n := range d.NameList {
6475 scope.Insert(NewTCConst(pkg, n.Value, nil, nil))
6476 }
6477 }
6478 }
6479
6480 var curConstGroup *Group
6481 var prevConstValues Expr
6482 var prevConstType Expr
6483 iotaVal := int32(-1)
6484 for _, d := range file.DeclList {
6485 if td, ok := d.(*TypeDecl); ok {
6486 obj := scope.Lookup(td.Name.Value)
6487 if obj != nil {
6488 if tn, ok2 := obj.(*TypeName); ok2 {
6489 NewNamed(tn, nil)
6490 }
6491 }
6492 }
6493 }
6494 for _, d := range file.DeclList {
6495 if cd, ok := d.(*ConstDecl); ok {
6496 if cd.Group == nil || cd.Group != curConstGroup {
6497 curConstGroup = cd.Group
6498 iotaVal = int32(0)
6499 prevConstValues = nil
6500 prevConstType = nil
6501 } else {
6502 iotaVal++
6503 }
6504 valExpr := cd.Values
6505 typeExpr := cd.Type
6506 if valExpr == nil {
6507 valExpr = prevConstValues
6508 }
6509 if typeExpr == nil && cd.Type == nil {
6510 typeExpr = prevConstType
6511 }
6512 if cd.Values != nil {
6513 prevConstValues = cd.Values
6514 }
6515 if cd.Type != nil {
6516 prevConstType = cd.Type
6517 }
6518 typ := tcResolveNameInline(typeExpr, scope)
6519 if typ == nil && valExpr != nil {
6520 typ = tcInferTypeFromExpr(valExpr, scope)
6521 }
6522 var val ConstVal
6523 if valExpr != nil {
6524 val = tcEvalConstExpr(valExpr, scope, iotaVal)
6525 }
6526 if typ == nil && val != nil {
6527 typ = untypedTypeOfCV(val)
6528 }
6529 for _, n := range cd.NameList {
6530 if val != nil {
6531 if ci, ok2 := val.(constInt); ok2 {
6532 if constValMap == nil {
6533 constValMap = map[string]int32{}
6534 }
6535 constValMap[n.Value] = ci.v
6536 }
6537 }
6538 obj := scope.Lookup(n.Value)
6539 if obj != nil {
6540 if c, ok := obj.(*TCConst); ok {
6541 c.typ = typ
6542 c.val = val
6543 }
6544 }
6545 }
6546 }
6547 }
6548 for _, d := range file.DeclList {
6549 if td, ok := d.(*TypeDecl); ok {
6550 obj := scope.Lookup(td.Name.Value)
6551 if obj != nil {
6552 if tn, ok2 := obj.(*TypeName); ok2 {
6553 named, ok3 := tn.typ.(*Named)
6554 if ok3 {
6555 typ := tcResolveNameInline(td.Type, scope)
6556 named.SetUnderlying(typ)
6557 }
6558 }
6559 }
6560 }
6561 }
6562 for _, d := range file.DeclList {
6563 switch d := d.(type) {
6564 case *VarDecl:
6565 typ := tcResolveNameInline(d.Type, scope)
6566 if arr, ok := typ.(*Array); ok && arr.Len() < 0 && d.Values != nil {
6567 if cl, ok2 := d.Values.(*CompositeLit); ok2 {
6568 typ = NewArray(arr.Elem(), int32(len(cl.ElemList)))
6569 }
6570 }
6571 if typ == nil && d.Values != nil {
6572 typ = tcInferTypeFromExpr(d.Values, scope)
6573 }
6574 for i, n := range d.NameList {
6575 obj := scope.Lookup(n.Value)
6576 if obj != nil {
6577 if v, ok := obj.(*TCVar); ok {
6578 v.typ = typ
6579 if d.Values != nil {
6580 initExpr := d.Values
6581 if cl, ok2 := d.Values.(*ListExpr); ok2 && i < len(cl.ElemList) {
6582 initExpr = cl.ElemList[i]
6583 }
6584 cv := tcEvalConstExpr(initExpr, scope, -1)
6585 if cv != nil {
6586 v.initVal = cv
6587 }
6588 }
6589 }
6590 }
6591 }
6592 case *FuncDecl:
6593 if d.Recv == nil && d.Name.Value != "init" {
6594 if len(d.TParamList) > 0 {
6595 if genericFuncDecls == nil {
6596 genericFuncDecls = map[string]*FuncDecl{}
6597 }
6598 genericFuncDecls[name+"."+d.Name.Value] = d
6599 if genericPkgScopes == nil {
6600 genericPkgScopes = map[string]*Scope{}
6601 }
6602 genericPkgScopes[name] = pkg.Scope()
6603 continue
6604 }
6605 sig := tcResolveFuncInline(d.Type, scope)
6606 obj := scope.Lookup(d.Name.Value)
6607 if obj != nil {
6608 if fn, ok := obj.(*TCFunc); ok && sig != nil {
6609 fn.typ = sig
6610 }
6611 }
6612 }
6613 }
6614 }
6615 for _, d := range file.DeclList {
6616 if fd, ok := d.(*FuncDecl); ok && fd.Recv != nil {
6617 recvType := tcResolveRecvType(fd.Recv, scope)
6618 if recvType == nil {
6619 continue
6620 }
6621 sig := tcResolveFuncInlineWithRecv(fd.Type, fd.Recv, scope)
6622 fn := NewTCFunc(pkg, fd.Name.Value, sig)
6623 isPtr := false
6624 var named *Named
6625 if pt, ok := recvType.(*Pointer); ok {
6626 if okv, okok := pt.Elem().(*Named); okok {
6627 named = okv
6628 }
6629 isPtr = true
6630 } else {
6631 if okv, okok := recvType.(*Named); okok {
6632 named = okv
6633 }
6634 }
6635 if named != nil {
6636 if isPtr {
6637 fn.hasPtrRecv = true
6638 }
6639 named.AddMethod(fn)
6640 }
6641 }
6642 }
6643
6644 return pkg, file
6645 }
6646
6647 func releasePerPkgState() {
6648 parseErrors = nil
6649 constValMap = nil
6650 compileExportMap = nil
6651 tcPkgSrc = nil
6652 genericFuncDecls = nil
6653 genericPkgScopes = nil
6654 }
6655
6656 func TypeCheckOnly(src []byte, name string) {
6657 pkg, file := typeCheckPkg(src, name)
6658 if pkg != nil && file != nil {
6659 registerCompiledExports(pkg)
6660 }
6661 if pkg != nil {
6662 pkg.Release()
6663 }
6664 if file != nil {
6665 file.DeclList = nil
6666 }
6667 releasePerPkgState()
6668 }
6669
6670 func CompileToIR(src []byte, name string, triple string) string {
6671 pkg, file := typeCheckPkg(src, name)
6672 if file == nil {
6673 out := "; parse error parseErrs=" | simpleItoa(len(parseErrors)) | "\n"
6674 for _, pe := range parseErrors {
6675 out = out | "; " | pe | "\n"
6676 }
6677 releasePerPkgState()
6678 return out
6679 }
6680
6681 prog := NewSSAProgram()
6682 ssaPkg := prog.CreatePackage(pkg, []*File{file}, nil)
6683 emitter := newIREmitter(ssaPkg, triple)
6684 ir := emitter.emit()
6685
6686 if len(ir) > 0 && ir[0] != ';' {
6687 registerCompiledExports(pkg)
6688 }
6689
6690 emitter.releaseAfterEmit()
6691 ssaPkg.release()
6692 prog.release()
6693 if pkg != nil {
6694 pkg.Release()
6695 }
6696 file.DeclList = nil
6697 releasePerPkgState()
6698 return ir
6699 }
6700
6701 func registerCompiledExports(pkg *TCPackage) {
6702 ensureImportRegistry()
6703 path := pkg.Path()
6704 regPkg := NewTCPackage(path, pkg.Name())
6705 for _, name := range pkg.Scope().Names() {
6706 if len(name) == 0 || name[0] < 'A' || name[0] > 'Z' {
6707 continue
6708 }
6709 obj := pkg.Scope().Lookup(name)
6710 if obj != nil {
6711 regPkg.Scope().Insert(obj)
6712 }
6713 }
6714 importRegistry[path] = regPkg
6715 }
6716
6717 func tcInferTypeFromExpr(e Expr, scope *Scope) Type {
6718 switch e := e.(type) {
6719 case *BasicLit:
6720 switch e.Kind {
6721 case StringLit:
6722 return Typ[TCString]
6723 case IntLit:
6724 return Typ[Int32]
6725 case FloatLit:
6726 return Typ[Float64]
6727 }
6728 case *Name:
6729 if e.Value == "true" || e.Value == "false" {
6730 return Typ[Bool]
6731 }
6732 return tcResolveNameInline(e, scope)
6733 case *CallExpr:
6734 return tcResolveNameInline(e.Fun, scope)
6735 case *CompositeLit:
6736 t := tcResolveNameInline(e.Type, scope)
6737 if arr, ok := t.(*Array); ok && arr.Len() < 0 {
6738 return NewArray(arr.Elem(), int32(len(e.ElemList)))
6739 }
6740 return t
6741 case *Operation:
6742 if e.Y == nil && e.Op == And {
6743 return NewPointer(tcInferTypeFromExpr(e.X, scope))
6744 }
6745 }
6746 return nil
6747 }
6748
6749 var constValMap map[string]int32
6750 var tcPkgSrc []byte
6751
6752 func resolveArrayLenFromSrc(p Pos, cmap map[string]int32) int32 {
6753 line := p.Line()
6754 col := p.Col()
6755 if line == 0 || col == 0 || tcPkgSrc == nil {
6756 return -1
6757 }
6758 off := 0
6759 curLine := uint32(1)
6760 for off < len(tcPkgSrc) && curLine < line {
6761 if tcPkgSrc[off] == '\n' {
6762 curLine++
6763 }
6764 off++
6765 }
6766 off += int32(col) - 1
6767 if off >= len(tcPkgSrc) || tcPkgSrc[off] != '[' {
6768 return -1
6769 }
6770 off++
6771 for off < len(tcPkgSrc) && tcPkgSrc[off] == ' ' {
6772 off++
6773 }
6774 start := off
6775 for off < len(tcPkgSrc) {
6776 c := tcPkgSrc[off]
6777 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' {
6778 off++
6779 } else {
6780 break
6781 }
6782 }
6783 if off == start {
6784 return -1
6785 }
6786 name := string(tcPkgSrc[start:off])
6787 if v, ok := cmap[name]; ok {
6788 if off < len(tcPkgSrc) && tcPkgSrc[off] == '+' {
6789 off++
6790 for off < len(tcPkgSrc) && tcPkgSrc[off] == ' ' {
6791 off++
6792 }
6793 numStart := off
6794 for off < len(tcPkgSrc) && tcPkgSrc[off] >= '0' && tcPkgSrc[off] <= '9' {
6795 off++
6796 }
6797 if off > numStart {
6798 addend := int32(0)
6799 for i := numStart; i < off; i++ {
6800 addend = addend*10 + int32(tcPkgSrc[i]-'0')
6801 }
6802 return v + addend
6803 }
6804 }
6805 return v
6806 }
6807 n := int32(0)
6808 isNum := true
6809 for i := start; i < off; i++ {
6810 c := tcPkgSrc[i]
6811 if c >= '0' && c <= '9' {
6812 n = n*10 + int32(c-'0')
6813 } else {
6814 isNum = false
6815 break
6816 }
6817 }
6818 if isNum && off > start {
6819 return n
6820 }
6821 return -1
6822 }
6823
6824 func resolveArrayLenFromConstMap(e Expr, cmap map[string]int32) int32 {
6825 line := e.Pos().Line()
6826 col := e.Pos().Col()
6827 if line == 0 || col == 0 || tcPkgSrc == nil {
6828 return -1
6829 }
6830 curLine := uint32(1)
6831 off := 0
6832 for off < len(tcPkgSrc) && curLine < line {
6833 if tcPkgSrc[off] == '\n' {
6834 curLine++
6835 }
6836 off++
6837 }
6838 off += int32(col) - 1
6839 if off >= len(tcPkgSrc) {
6840 return -1
6841 }
6842 start := off
6843 for off < len(tcPkgSrc) {
6844 c := tcPkgSrc[off]
6845 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' {
6846 off++
6847 } else {
6848 break
6849 }
6850 }
6851 if off == start {
6852 return -1
6853 }
6854 name := string(tcPkgSrc[start:off])
6855 if v, ok := cmap[name]; ok {
6856 return v
6857 }
6858 return -1
6859 }
6860
6861 func tcEvalConstExpr(e Expr, scope *Scope, iotaVal int32) ConstVal {
6862 if e == nil {
6863 return nil
6864 }
6865 switch e := e.(type) {
6866 case *BasicLit:
6867 return evalBasicLitLocal(e)
6868 case *Name:
6869 if e.Value == "iota" && iotaVal >= 0 {
6870 return constInt{iotaVal}
6871 }
6872 if scope != nil {
6873 _, obj := scope.LookupParent(e.Value)
6874 if c, ok := obj.(*TCConst); ok && c.val != nil {
6875 return c.val
6876 }
6877 }
6878 if constValMap != nil {
6879 if v, ok := constValMap[e.Value]; ok {
6880 return constInt{v}
6881 }
6882 }
6883 case *Operation:
6884 if e.Y == nil {
6885 xr := tcEvalConstExpr(e.X, scope, iotaVal)
6886 if xr == nil {
6887 return nil
6888 }
6889 return evalUnaryLocal(e.Op, xr)
6890 }
6891 xr := tcEvalConstExpr(e.X, scope, iotaVal)
6892 yr := tcEvalConstExpr(e.Y, scope, iotaVal)
6893 if xr == nil || yr == nil {
6894 return nil
6895 }
6896 return evalBinaryLocal(e.Op, xr, yr)
6897 case *ParenExpr:
6898 return tcEvalConstExpr(e.X, scope, iotaVal)
6899 case *CallExpr:
6900 if id, ok := e.Fun.(*Name); ok && id.Value == "len" && len(e.ArgList) == 1 {
6901 if lit, ok2 := e.ArgList[0].(*BasicLit); ok2 && lit.Kind == StringLit {
6902 lv := evalBasicLitLocal(lit)
6903 if cs, ok3 := lv.(constStr); ok3 {
6904 return constInt{int32(len(cs.s))}
6905 }
6906 }
6907 av := tcEvalConstExpr(e.ArgList[0], scope, iotaVal)
6908 if cs, ok2 := av.(constStr); ok2 {
6909 return constInt{int32(len(cs.s))}
6910 }
6911 }
6912 if sel, ok := e.Fun.(*SelectorExpr); ok {
6913 if pkg, ok2 := sel.X.(*Name); ok2 && pkg.Value == "unsafe" {
6914 switch sel.Sel.Value {
6915 case "Sizeof", "Alignof", "Offsetof":
6916 return constInt{8}
6917 }
6918 }
6919 }
6920 if len(e.ArgList) != 1 {
6921 return nil
6922 }
6923 inner := tcEvalConstExpr(e.ArgList[0], scope, iotaVal)
6924 if inner == nil {
6925 return nil
6926 }
6927 targetType := tcResolveNameInline(e.Fun, scope)
6928 if targetType == nil {
6929 return inner
6930 }
6931 return convertConstLocal(inner, targetType)
6932 case *SelectorExpr:
6933 pkgName, ok := e.X.(*Name)
6934 if !ok {
6935 return nil
6936 }
6937 var imported *TCPackage
6938 if scope != nil {
6939 _, obj := scope.LookupParent(pkgName.Value)
6940 if pn, ok2 := obj.(*PkgName); ok2 && pn.imported != nil {
6941 imported = pn.imported
6942 }
6943 }
6944 if imported == nil {
6945 ensureImportRegistry()
6946 imported = importRegistry[pkgName.Value]
6947 }
6948 if imported == nil {
6949 return nil
6950 }
6951 member := imported.Scope().Lookup(e.Sel.Value)
6952 if member == nil {
6953 return nil
6954 }
6955 if k, ok := member.(*TCConst); ok && k.val != nil {
6956 return k.val
6957 }
6958 return nil
6959 }
6960 return nil
6961 }
6962
6963 func tcResolveNameInline(e Expr, scope *Scope) Type {
6964 if e == nil {
6965 return nil
6966 }
6967 switch e := e.(type) {
6968 case *Name:
6969 var obj Object
6970 if scope != nil {
6971 _, obj = scope.LookupParent(e.Value)
6972 } else {
6973 _, obj = Universe.LookupParent(e.Value)
6974 }
6975 if obj != nil {
6976 if tn, ok := obj.(*TypeName); ok {
6977 return tn.typ
6978 }
6979 }
6980 case *SelectorExpr:
6981 pkgName, ok := e.X.(*Name)
6982 if ok && scope != nil {
6983 _, pkgObj := scope.LookupParent(pkgName.Value)
6984 if pn, ok2 := pkgObj.(*PkgName); ok2 && pn.imported != nil {
6985 typeObj := pn.imported.scope.Lookup(e.Sel.Value)
6986 if typeObj != nil {
6987 if tn, ok3 := typeObj.(*TypeName); ok3 {
6988 return tn.typ
6989 }
6990 }
6991 }
6992 }
6993 // Fallback: check importRegistry directly for external package types
6994 if pkgName, ok := e.X.(*Name); ok {
6995 var irKeys []string
6996 for k := range importRegistry {
6997 irKeys = append(irKeys, k)
6998 }
6999 for i := 1; i < len(irKeys); i++ {
7000 for j := i; j > 0 && irKeys[j] < irKeys[j-1]; j-- {
7001 irKeys[j], irKeys[j-1] = irKeys[j-1], irKeys[j]
7002 }
7003 }
7004 for _, k := range irKeys {
7005 pkg := importRegistry[k]
7006 if pkg.Name() == pkgName.Value {
7007 typeObj := pkg.Scope().Lookup(e.Sel.Value)
7008 if typeObj != nil {
7009 if tn, ok2 := typeObj.(*TypeName); ok2 {
7010 return tn.typ
7011 }
7012 }
7013 break
7014 }
7015 }
7016 }
7017 case *Operation:
7018 if e.Y == nil && e.Op == Mul {
7019 base := tcResolveNameInline(e.X, scope)
7020 if base == nil {
7021 base = Typ[Int8]
7022 }
7023 return NewPointer(base)
7024 }
7025 case *SliceType:
7026 elem := tcResolveNameInline(e.Elem, scope)
7027 if elem != nil {
7028 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
7029 return Typ[TCString]
7030 }
7031 return NewSlice(elem)
7032 }
7033 case *ArrayType:
7034 elem := tcResolveNameInline(e.Elem, scope)
7035 if elem != nil {
7036 n := int32(-1)
7037 if lit, ok := e.Len.(*BasicLit); ok {
7038 n = irParseInt64(lit.Value)
7039 } else if e.Len != nil {
7040 cv := tcEvalConstExpr(e.Len, scope, -1)
7041 if cv != nil {
7042 if ci, ok := cv.(constInt); ok {
7043 n = ci.v
7044 }
7045 }
7046 if n == -1 && constValMap != nil {
7047 n = resolveArrayLenFromSrc(e.pos, constValMap)
7048 }
7049 }
7050 return NewArray(elem, n)
7051 }
7052 case *MapType:
7053 key := tcResolveNameInline(e.Key, scope)
7054 val := tcResolveNameInline(e.Value, scope)
7055 if key != nil && val != nil {
7056 return NewTCMap(key, val)
7057 }
7058 case *StructType:
7059 var fields []*TCVar
7060 var tags []string
7061 for i, field := range e.FieldList {
7062 typ := tcResolveNameInline(field.Type, scope)
7063 fname := ""
7064 if field.Name != nil {
7065 fname = field.Name.Value
7066 } else {
7067 fname = typeBaseName(typ)
7068 }
7069 fields = append(fields, NewTCField(nil, fname, typ, field.Name == nil))
7070 tag := ""
7071 if i < len(e.TagList) && e.TagList[i] != nil {
7072 tag = e.TagList[i].Value
7073 }
7074 tags = append(tags, tag)
7075 }
7076 return NewTCStruct(fields, tags)
7077 case *FuncType:
7078 return tcResolveFuncInline(e, scope)
7079 case *InterfaceType:
7080 return tcResolveInterfaceInline(e, scope)
7081 case *DotsType:
7082 elem := tcResolveNameInline(e.Elem, scope)
7083 if elem != nil {
7084 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
7085 return Typ[TCString]
7086 }
7087 return NewSlice(elem)
7088 }
7089 }
7090 return nil
7091 }
7092
7093 func tcResolveInterfaceInline(e *InterfaceType, scope *Scope) *TCInterface {
7094 var methods []*IfaceMethod
7095 for _, f := range e.MethodList {
7096 if f.Name == nil {
7097 continue
7098 }
7099 ft, ok := f.Type.(*FuncType)
7100 if !ok {
7101 continue
7102 }
7103 sig := tcResolveFuncInline(ft, scope)
7104 if sig != nil {
7105 methods = append(methods, NewTCIfaceMethod(f.Name.Value, sig))
7106 }
7107 }
7108 iface := NewTCInterface(methods, nil)
7109 iface.Complete()
7110 return iface
7111 }
7112
7113 func stripDuplicatePackageClauses(src []byte) []byte {
7114 found := false
7115 var out []byte
7116 i := 0
7117 for i < len(src) {
7118 nlIdx := bytes.IndexByte(src[i:], '\n')
7119 var line []byte
7120 var lineEnd int32
7121 if nlIdx < 0 {
7122 line = src[i:]
7123 lineEnd = len(src)
7124 } else {
7125 line = src[i : i+nlIdx]
7126 lineEnd = i + nlIdx + 1
7127 }
7128 trimmed := bytes.TrimSpace(line)
7129 if bytes.HasPrefix(trimmed, "package ") {
7130 if found {
7131 if out == nil {
7132 out = []byte{:0:len(src)}
7133 out = append(out, src[:i]...)
7134 }
7135 for k := 0; k < len(line); k++ {
7136 out = append(out, ' ')
7137 }
7138 if nlIdx >= 0 {
7139 out = append(out, '\n')
7140 }
7141 i = lineEnd
7142 continue
7143 }
7144 found = true
7145 }
7146 if out != nil {
7147 out = append(out, src[i:lineEnd]...)
7148 }
7149 i = lineEnd
7150 }
7151 if out == nil {
7152 return src
7153 }
7154 return out
7155 }
7156
7157 func rewriteSliceMakeLiterals(src []byte) []byte {
7158 var out []byte
7159 i := 0
7160 for i < len(src) {
7161 start := bytes.Index(src[i:], []byte("{:"))
7162 if start < 0 {
7163 out = append(out, src[i:]...)
7164 break
7165 }
7166 start = start + i
7167 lbrack := findSliceTypeStart(src, start)
7168 if lbrack < 0 {
7169 out = append(out, src[i:start+2]...)
7170 i = start + 2
7171 continue
7172 }
7173 close := findMatchingBrace(src, start)
7174 if close < 0 {
7175 out = append(out, src[i:start+2]...)
7176 i = start + 2
7177 continue
7178 }
7179 inner := src[start+2 : close]
7180 colonIdx := bytes.IndexByte(inner, ':')
7181 typeText := src[lbrack:start]
7182 out = append(out, src[i:lbrack]...)
7183 if colonIdx < 0 {
7184 out = append(out, "make("...)
7185 out = append(out, typeText...)
7186 out = append(out, ", "...)
7187 out = append(out, bytes.TrimSpace(inner)...)
7188 out = append(out, ')')
7189 } else {
7190 lenExpr := bytes.TrimSpace(inner[:colonIdx])
7191 capExpr := bytes.TrimSpace(inner[colonIdx+1:])
7192 out = append(out, "make("...)
7193 out = append(out, typeText...)
7194 out = append(out, ", "...)
7195 out = append(out, lenExpr...)
7196 out = append(out, ", "...)
7197 out = append(out, capExpr...)
7198 out = append(out, ')')
7199 }
7200 i = close + 1
7201 }
7202 if out == nil {
7203 return src
7204 }
7205 return out
7206 }
7207
7208 func findSliceTypeStart(src []byte, braceIdx int32) int32 {
7209 j := braceIdx - 1
7210 for j >= 0 && (src[j] == ' ' || src[j] == '\t' || src[j] == '\n') {
7211 j--
7212 }
7213 if j < 0 {
7214 return -1
7215 }
7216 depth := 0
7217 parenDepth := 0
7218 candidate := -1
7219 for j >= 0 {
7220 ch := src[j]
7221 if ch == ')' {
7222 parenDepth++
7223 } else if ch == '(' {
7224 parenDepth--
7225 } else if parenDepth > 0 {
7226 j--
7227 continue
7228 }
7229 if ch == ']' {
7230 depth++
7231 } else if ch == '[' {
7232 depth--
7233 if depth == 0 {
7234 candidate = j
7235 }
7236 } else if depth == 0 && parenDepth == 0 {
7237 if candidate >= 0 {
7238 return candidate
7239 }
7240 if ch == ' ' || ch == '\t' || ch == '\n' || ch == '*' || ch == '(' || ch == ')' {
7241 j--
7242 continue
7243 }
7244 if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '.' {
7245 j--
7246 continue
7247 }
7248 return -1
7249 }
7250 j--
7251 }
7252 if candidate >= 0 {
7253 return candidate
7254 }
7255 return -1
7256 }
7257
7258 func findMatchingBrace(src []byte, openIdx int32) int32 {
7259 depth := 1
7260 for i := openIdx + 1; i < len(src); i++ {
7261 if src[i] == '{' {
7262 depth++
7263 } else if src[i] == '}' {
7264 depth--
7265 if depth == 0 {
7266 return i
7267 }
7268 }
7269 }
7270 return -1
7271 }
7272
7273 func rewriteChanMakeLiterals(src []byte) []byte {
7274 chanKw := []byte("chan ")
7275 var out []byte
7276 i := 0
7277 for i < len(src) {
7278 idx := bytes.Index(src[i:], chanKw)
7279 if idx < 0 {
7280 if out != nil {
7281 out = append(out, src[i:]...)
7282 }
7283 break
7284 }
7285 idx = idx + i
7286 j := idx + 5
7287 for j < len(src) && (src[j] == ' ' || src[j] == '\t') {
7288 j++
7289 }
7290 if j >= len(src) {
7291 if out != nil {
7292 out = append(out, src[i:]...)
7293 }
7294 break
7295 }
7296 if src[j] == '<' && j+1 < len(src) && src[j+1] == '-' {
7297 if out != nil {
7298 out = append(out, src[i:j+2]...)
7299 }
7300 i = j + 2
7301 continue
7302 }
7303 for j < len(src) && (src[j] != '{' && src[j] != '\n' && src[j] != ';' && src[j] != '(' && src[j] != ')') {
7304 if src[j] == ' ' || src[j] == '\t' {
7305 break
7306 }
7307 j++
7308 }
7309 if j >= len(src) || src[j] != '{' {
7310 if out == nil {
7311 i = idx + 4
7312 } else {
7313 out = append(out, src[i:idx+4]...)
7314 i = idx + 4
7315 }
7316 continue
7317 }
7318 braceOpen := j
7319 close := findMatchingBrace(src, braceOpen)
7320 if close < 0 {
7321 if out == nil {
7322 i = idx + 4
7323 } else {
7324 out = append(out, src[i:idx+4]...)
7325 i = idx + 4
7326 }
7327 continue
7328 }
7329 inner := bytes.TrimSpace(src[braceOpen+1 : close])
7330 chanType := src[idx : braceOpen]
7331 for len(chanType) > 0 && (chanType[len(chanType)-1] == ' ' || chanType[len(chanType)-1] == '\t') {
7332 chanType = chanType[:len(chanType)-1]
7333 }
7334 if out == nil {
7335 out = []byte{:0:len(src)}
7336 out = append(out, src[:idx]...)
7337 } else {
7338 out = append(out, src[i:idx]...)
7339 }
7340 if len(inner) == 0 {
7341 out = append(out, "make("...)
7342 out = append(out, chanType...)
7343 out = append(out, ')')
7344 } else {
7345 out = append(out, "make("...)
7346 out = append(out, chanType...)
7347 out = append(out, ", "...)
7348 out = append(out, inner...)
7349 out = append(out, ')')
7350 }
7351 i = close + 1
7352 }
7353 if out == nil {
7354 return src
7355 }
7356 return out
7357 }
7358
7359 func tcResolveRecvType(recv *Field, scope *Scope) Type {
7360 if recv == nil {
7361 return nil
7362 }
7363 return tcResolveNameInline(recv.Type, scope)
7364 }
7365
7366 func tcResolveFuncInlineWithRecv(ft *FuncType, recv *Field, scope *Scope) *Signature {
7367 if ft == nil {
7368 return nil
7369 }
7370 var recvVar *TCVar
7371 if recv != nil {
7372 recvTyp := tcResolveNameInline(recv.Type, scope)
7373 recvName := ""
7374 if recv.Name != nil {
7375 recvName = recv.Name.Value
7376 }
7377 recvVar = NewTCVar(nil, recvName, recvTyp)
7378 }
7379 params := tcResolveFieldList(ft.ParamList, scope)
7380 results := tcResolveFieldList(ft.ResultList, scope)
7381 variadic := false
7382 if len(ft.ParamList) > 0 {
7383 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
7384 variadic = true
7385 }
7386 }
7387 return NewSignature(recvVar, params, results, variadic)
7388 }
7389
7390 func tcResolveFieldList(fields []*Field, scope *Scope) *Tuple {
7391 if len(fields) == 0 {
7392 return nil
7393 }
7394 var vars []*TCVar
7395 for _, f := range fields {
7396 typ := tcResolveNameInline(f.Type, scope)
7397 pname := ""
7398 if f.Name != nil {
7399 pname = f.Name.Value
7400 }
7401 vars = append(vars, NewTCVar(nil, pname, typ))
7402 }
7403 return NewTuple(vars...)
7404 }
7405
7406 func tcResolveFuncInline(ft *FuncType, scope *Scope) *Signature {
7407 if ft == nil {
7408 return nil
7409 }
7410 var params []*TCVar
7411 for _, p := range ft.ParamList {
7412 typ := tcResolveNameInline(p.Type, scope)
7413 pname := ""
7414 if p.Name != nil {
7415 pname = p.Name.Value
7416 }
7417 params = append(params, NewTCVar(nil, pname, typ))
7418 }
7419 var results []*TCVar
7420 for _, r := range ft.ResultList {
7421 typ := tcResolveNameInline(r.Type, scope)
7422 rname := ""
7423 if r.Name != nil {
7424 rname = r.Name.Value
7425 }
7426 results = append(results, NewTCVar(nil, rname, typ))
7427 }
7428 variadic := false
7429 if len(ft.ParamList) > 0 {
7430 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
7431 variadic = true
7432 }
7433 }
7434 var pTuple *Tuple
7435 if len(params) > 0 {
7436 pTuple = NewTuple(params...)
7437 }
7438 var rTuple *Tuple
7439 if len(results) > 0 {
7440 rTuple = NewTuple(results...)
7441 }
7442 return NewSignature(nil, pTuple, rTuple, variadic)
7443 }
7444
7445 func (e *irEmitter) instrOperands(instr SSAInstruction) []SSAValue {
7446 switch i := instr.(type) {
7447 case *SSAStore:
7448 return []SSAValue{i.Addr, i.Val}
7449 case *SSAUnOp:
7450 return []SSAValue{i.X}
7451 case *SSABinOp:
7452 return []SSAValue{i.X, i.Y}
7453 case *SSACall:
7454 out := []SSAValue{i.Call.Value}
7455 for _, a := range i.Call.Args {
7456 out = append(out, a)
7457 }
7458 return out
7459 case *SSAFieldAddr:
7460 return []SSAValue{i.X}
7461 case *SSAIndexAddr:
7462 return []SSAValue{i.X, i.Index}
7463 case *SSAExtract:
7464 return []SSAValue{i.Tuple}
7465 case *SSAPhi:
7466 return i.Edges
7467 case *SSAReturn:
7468 var out []SSAValue
7469 for _, r := range i.Results {
7470 out = append(out, r)
7471 }
7472 return out
7473 case *SSAIf:
7474 return []SSAValue{i.Cond}
7475 case *SSAConvert:
7476 return []SSAValue{i.X}
7477 case *SSAChangeType:
7478 return []SSAValue{i.X}
7479 case *SSAMakeInterface:
7480 return []SSAValue{i.X}
7481 case *SSATypeAssert:
7482 return []SSAValue{i.X}
7483 case *SSASlice:
7484 out := []SSAValue{i.X}
7485 if i.Low != nil { out = append(out, i.Low) }
7486 if i.High != nil { out = append(out, i.High) }
7487 if i.Max != nil { out = append(out, i.Max) }
7488 return out
7489 case *SSAMapUpdate:
7490 return []SSAValue{i.Map, i.Key, i.Value}
7491 case *SSALookup:
7492 return []SSAValue{i.X, i.Index}
7493 case *SSARange:
7494 return []SSAValue{i.X}
7495 case *SSANext:
7496 return []SSAValue{i.Iter}
7497 case *SSASend:
7498 return []SSAValue{i.Chan, i.X}
7499 case *SSAMakeSlice:
7500 out := []SSAValue{i.Len}
7501 if i.Cap != nil { out = append(out, i.Cap) }
7502 if i.Data != nil { out = append(out, i.Data) }
7503 return out
7504 }
7505 return nil
7506 }
7507
7508 func simpleItoa(n int32) string {
7509 if n == 0 {
7510 return "0"
7511 }
7512 neg := n < 0
7513 if neg {
7514 n = -n
7515 }
7516 buf := []byte{:0:20}
7517 for n > 0 {
7518 buf = append(buf, byte('0'+n%10))
7519 n /= 10
7520 }
7521 if neg {
7522 buf = append(buf, '-')
7523 }
7524 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
7525 buf[i], buf[j] = buf[j], buf[i]
7526 }
7527 return string(buf)
7528 }
7529
7530