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