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