iface.mx raw
1 package emit
2
3 import (
4 "git.smesh.lol/moxie/pkg/syntax"
5 "git.smesh.lol/moxie/pkg/ssa"
6 "git.smesh.lol/moxie/pkg/token"
7 "git.smesh.lol/moxie/pkg/types"
8 )
9
10 func (e *irEmitter) isScalarType(t string) bool {
11 return t == "i1" || t == "i8" || t == "i16" || t == "i32" || t == "i64" || t == "float" || t == "double"
12 }
13
14 func (e *irEmitter) fitsInPtr(t string) bool {
15 if !e.isScalarType(t) { return false }
16 if e.ptrBits == 32 && (t == "i64" || t == "double") { return false }
17 return true
18 }
19
20 func (e *irEmitter) emitMakeInterface(m *ssa.SSAMakeInterface) {
21 reg := e.regName(m)
22 val := e.operand(m.X)
23 valType := e.llvmType(m.X.SSAType())
24 if _, isAlloc := m.X.(*ssa.SSAAlloc); !isAlloc {
25 if at, ok := e.allocTypes[m.X]; ok && at != "ptr" && at != "void" {
26 valType = at
27 }
28 }
29 if valType == e.ifaceType() {
30 tp := e.nextReg2("mi")
31 e.w(" ") ; e.w(tp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 0\n")
32 dp := e.nextReg2("mi")
33 e.w(" ") ; e.w(dp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
34 t1 := e.nextReg2("mi")
35 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(tp) ; e.w(", 0\n")
36 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(dp) ; e.w(", 1\n")
37 return
38 }
39 var valPtr string
40 if valType == "void" {
41 valPtr = "null"
42 } else if valType == "ptr" {
43 valPtr = val
44 } else if e.fitsInPtr(valType) {
45 ipt := e.intptrType()
46 ext := ""
47 if valType == ipt {
48 ext = val
49 } else if valType == "i1" || valType == "i8" || valType == "i16" || valType == "i32" {
50 ext = e.nextReg2("mi")
51 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")
52 } else if valType == "i64" {
53 ext = val
54 } else if valType == "float" {
55 ftmp := e.nextReg2("mi")
56 e.w(" ") ; e.w(ftmp) ; e.w(" = bitcast float ") ; e.w(val) ; e.w(" to i32\n")
57 if ipt == "i32" {
58 ext = ftmp
59 } else {
60 ext = e.nextReg2("mi")
61 e.w(" ") ; e.w(ext) ; e.w(" = zext i32 ") ; e.w(ftmp) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
62 }
63 } else if valType == "double" {
64 dval := val
65 if isConstOperand(val) {
66 dval = e.nextReg2("mi")
67 e.w(" ") ; e.w(dval) ; e.w(" = fadd double 0.0, ") ; e.w(ensureTokenFloatLit(val)) ; e.w("\n")
68 }
69 ext = e.nextReg2("mi")
70 e.w(" ") ; e.w(ext) ; e.w(" = bitcast double ") ; e.w(dval) ; e.w(" to i64\n")
71 } else {
72 ext = val
73 }
74 valPtr = e.nextReg2("mi")
75 e.w(" ") ; e.w(valPtr) ; e.w(" = inttoptr ") ; e.w(ipt) ; e.w(" ") ; e.w(ext) ; e.w(" to ptr\n")
76 } else {
77 ipt := e.intptrType()
78 sz := e.nextReg2("ha")
79 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")
80 valPtr = e.nextReg2("mi")
81 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")
82 e.w(" store ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
83 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
84 e.scopeTrackAlloc(valPtr)
85 }
86 typeid := e.typeIDGlobal(m.X.SSAType())
87 t1 := e.nextReg2("mi")
88 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(typeid) ; e.w(", 0\n")
89 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(valPtr) ; e.w(", 1\n")
90 }
91
92 func (e *irEmitter) typeIDGlobal(t syntax.Type) string {
93 name := e.reflectTypeName(t)
94 if e.typeIDs == nil {
95 e.typeIDs = map[string]int32{}
96 }
97 if _, ok := e.typeIDs[name]; !ok {
98 e.typeIDNext++
99 e.typeIDs[name] = e.typeIDNext
100 }
101 return "@\"" | name | "\""
102 }
103
104 func (e *irEmitter) reflectTypeName(t syntax.Type) string {
105 if b, ok := t.(*types.Basic); ok {
106 switch b.Kind() {
107 case types.Bool, types.UntypedBool:
108 return "reflect/types.type:basic:bool"
109 case types.Int8:
110 return "reflect/types.type:basic:int8"
111 case types.Int16:
112 return "reflect/types.type:basic:int16"
113 case types.Int32, types.UntypedInt, types.UntypedRune:
114 return "reflect/types.type:basic:int32"
115 case types.Int64:
116 return "reflect/types.type:basic:int64"
117 case types.Uint8:
118 return "reflect/types.type:basic:uint8"
119 case types.Uint16:
120 return "reflect/types.type:basic:uint16"
121 case types.Uint32:
122 return "reflect/types.type:basic:uint32"
123 case types.Uint64:
124 return "reflect/types.type:basic:uint64"
125 case types.Float32:
126 return "reflect/types.type:basic:float32"
127 case types.Float64, types.UntypedFloat:
128 return "reflect/types.type:basic:float64"
129 case types.TCString, types.UntypedString:
130 return "reflect/types.type:basic:bytes"
131 case types.UnsafePointer:
132 return "reflect/types.type:basic:uintptr"
133 }
134 }
135 if named, ok := t.(*types.Named); ok && named.Obj() != nil {
136 pkg := ""
137 if named.Obj().Pkg() != nil {
138 pkg = named.Obj().Pkg().Path()
139 }
140 if pkg == "" {
141 pkg = e.pkg.Pkg.Path()
142 }
143 result := "reflect/types.type:named:" | pkg | "." | named.Obj().Name()
144 if pkg == e.pkg.Pkg.Path() {
145 if e.localTypeIDs == nil {
146 e.localTypeIDs = map[string]bool{}
147 }
148 e.localTypeIDs["\"" | result | "\""] = true
149 }
150 return result
151 }
152 if p, ok := t.(*types.Pointer); ok {
153 inner := e.reflectTypeName(p.Elem())
154 if hasPrefix(inner, "reflect/types.type:") {
155 result := "reflect/types.type:pointer:" | inner[len("reflect/types.type:"):]
156 quoted := "\"" | result | "\""
157 if e.localTypeIDs != nil && e.localTypeIDs["\"" | inner | "\""] {
158 e.localTypeIDs[quoted] = true
159 }
160 return result
161 }
162 return inner | ".ptr"
163 }
164 if _, ok := t.(*types.TCInterface); ok {
165 result := "reflect/types.type:interface:{}"
166 if e.localTypeIDs == nil {
167 e.localTypeIDs = map[string]bool{}
168 }
169 e.localTypeIDs["\"" | result | "\""] = true
170 return result
171 }
172 if sl, ok := t.(*types.Slice); ok {
173 elem := sl.Elem()
174 if b, ok := types.SafeUnderlying(elem).(*types.Basic); ok && b.Kind() == Uint8 {
175 return "reflect/types.type:basic:bytes"
176 }
177 inner := e.reflectTypeName(elem)
178 if hasPrefix(inner, "reflect/types.type:") {
179 result := "reflect/types.type:slice:" | inner[len("reflect/types.type:"):]
180 if e.localTypeIDs == nil {
181 e.localTypeIDs = map[string]bool{}
182 }
183 e.localTypeIDs["\"" | result | "\""] = true
184 return result
185 }
186 return inner | ".slice"
187 }
188 pkg := e.pkg.Pkg.Path()
189 return pkg | ".typeid.unknown"
190 }
191
192 func (e *irEmitter) findIfaceImpls(methodName string) []ifaceImpl {
193 var impls []ifaceImpl
194 hasType := map[string]bool{}
195 var memberKeys []string
196 for mname := range e.pkg.Members {
197 memberKeys = append(memberKeys, mname)
198 }
199 for i := 1; i < len(memberKeys); i++ {
200 for j := i; j > 0 && memberKeys[j] < memberKeys[j-1]; j-- {
201 memberKeys[j], memberKeys[j-1] = memberKeys[j-1], memberKeys[j]
202 }
203 }
204 for _, mname := range memberKeys {
205 m := e.pkg.Members[mname]
206 fn, ok := m.(*ssa.SSAFunction)
207 if !ok {
208 continue
209 }
210 dotIdx := -1
211 for i := 0; i < len(mname); i++ {
212 if mname[i] == '.' {
213 dotIdx = i
214 break
215 }
216 }
217 if dotIdx < 0 {
218 continue
219 }
220 if mname[dotIdx+1:] != methodName {
221 continue
222 }
223 tname := mname[:dotIdx]
224 looked := e.pkg.Pkg.Scope().Lookup(tname)
225 if looked == nil {
226 continue
227 }
228 tn, ok2 := looked.(*types.TypeName)
229 if !ok2 || tn.Type() == nil {
230 continue
231 }
232 isPtrRecv := fn.object != nil && fn.object.HasPtrRecv()
233 recvT := tn.Type()
234 if isPtrRecv {
235 recvT = types.NewPointer(recvT)
236 }
237 impls = append(impls, ifaceImpl{fn: fn, recvType: recvT, ptrRecv: isPtrRecv})
238 hasType[tname] = true
239 }
240 scopeNames := e.pkg.Pkg.Scope().Names()
241 for sni := 0; sni < len(scopeNames); sni++ {
242 sname := scopeNames[sni]
243 tn2, ok4 := e.pkg.Pkg.Scope().Lookup(sname).(*types.TypeName)
244 if !ok4 || tn2.Type() == nil {
245 continue
246 }
247 if hasType[sname] {
248 continue
249 }
250 chain, fn, embedT := e.findEmbedMethod(tn2.Type(), methodName, 0)
251 if fn != nil {
252 isPtrRecv := fn.object != nil && fn.object.HasPtrRecv()
253 impls = append(impls, ifaceImpl{
254 fn: fn,
255 recvType: types.NewPointer(tn2.Type()),
256 ptrRecv: isPtrRecv,
257 embedField: chain[0],
258 embedType: embedT,
259 embedChain: chain,
260 })
261 hasType[sname] = true
262 }
263 }
264 var regKeys []string
265 for pkgPath := range ImportRegistry {
266 regKeys = append(regKeys, pkgPath)
267 }
268 for i := 1; i < len(regKeys); i++ {
269 for j := i; j > 0 && regKeys[j] < regKeys[j-1]; j-- {
270 regKeys[j], regKeys[j-1] = regKeys[j-1], regKeys[j]
271 }
272 }
273 for _, pkgPath := range regKeys {
274 ipkg := ImportRegistry[pkgPath]
275 if ipkg == nil {
276 continue
277 }
278 names := ipkg.Scope().Names()
279 for ni := 0; ni < len(names); ni++ {
280 tname := names[ni]
281 tn3, ok7 := ipkg.Scope().Lookup(tname).(*types.TypeName)
282 if !ok7 || tn3.Type() == nil {
283 continue
284 }
285 named3, ok8 := tn3.Type().(*types.Named)
286 if !ok8 {
287 continue
288 }
289 for mi := 0; mi < named3.NumMethods(); mi++ {
290 m := named3.Method(mi)
291 if m.Name() != methodName {
292 continue
293 }
294 isPR := m.HasPtrRecv()
295 sym := pkgPath | "." | tname | "." | methodName
296 tid := ""
297 if isPR {
298 tid = "reflect/types.type:pointer:named:" | pkgPath | "." | tname
299 } else {
300 tid = "reflect/types.type:named:" | pkgPath | "." | tname
301 }
302 impls = append(impls, ifaceImpl{
303 recvType: tn3.Type(),
304 ptrRecv: isPR,
305 extSymbol: sym,
306 extTypeID: tid,
307 })
308 }
309 }
310 }
311 for i := 1; i < len(impls); i++ {
312 for j := i; j > 0 && impls[j].recvType.String() < impls[j-1].recvType.String(); j-- {
313 impls[j], impls[j-1] = impls[j-1], impls[j]
314 }
315 }
316 return impls
317 }
318
319 func (e *irEmitter) findEmbedMethod(t syntax.Type, methodName string, depth int32) ([]int32, *ssa.SSAFunction, syntax.Type) {
320 if depth > 5 {
321 return nil, nil, nil
322 }
323 st, ok := types.SafeUnderlying(t).(*types.TCStruct)
324 if !ok || st == nil {
325 return nil, nil, nil
326 }
327 for fi := 0; fi < st.NumFields(); fi++ {
328 f := st.Field(fi)
329 if !f.Anonymous() {
330 continue
331 }
332 embedType := f.Type()
333 embedName := ""
334 if en, ok2 := embedType.(*types.Named); ok2 && en.Obj() != nil {
335 embedName = en.Obj().Name()
336 }
337 if embedName == "" {
338 continue
339 }
340 embedMName := embedName | "." | methodName
341 if fn, ok2 := e.pkg.Members[embedMName].(*ssa.SSAFunction); ok2 {
342 return []int32{fi}, fn, embedType
343 }
344 sub, fn, embedT := e.findEmbedMethod(embedType, methodName, depth+1)
345 if fn != nil {
346 return append([]int32{fi}, sub...), fn, embedT
347 }
348 }
349 return nil, nil, nil
350 }
351
352 type ifaceImpl struct {
353 fn *ssa.SSAFunction
354 recvType syntax.Type
355 ptrRecv bool
356 embedField int32
357 embedType syntax.Type
358 embedChain []int32
359 extSymbol string
360 extTypeID string
361 }
362
363 func (e *irEmitter) implFuncSym(impl ifaceImpl) string {
364 if impl.extSymbol != "" {
365 if irNeedsQuote(impl.extSymbol) {
366 return "@\"" | impl.extSymbol | "\""
367 }
368 return "@" | impl.extSymbol
369 }
370 return e.funcSymbol(impl.fn)
371 }
372
373 func (e *irEmitter) declareExtInvoke(impl ifaceImpl, inv *ssa.SSAInvoke) {
374 if impl.extSymbol == "" {
375 return
376 }
377 sym := e.implFuncSym(impl)
378 if _, ok := e.extDecls[sym]; ok {
379 return
380 }
381 retType := e.llvmType(inv.SSAType())
382 params := "ptr"
383 for _, arg := range inv.Args {
384 argT := e.llvmType(arg.SSAType())
385 if argT == "void" || argT == "" {
386 argT = "ptr"
387 }
388 flat := flattenTypeStr(argT)
389 if flat == "" {
390 flat = "ptr"
391 }
392 params = params | ", " | flat
393 }
394 params = params | ", ptr"
395 e.extDecls[sym] = retType | " " | sym | "(" | params | ")"
396 }
397
398 func flattenTypeStr(t string) string {
399 if len(t) == 0 || t[0] != '{' {
400 return t
401 }
402 result := ""
403 depth := 0
404 start := 1
405 for i := 1; i < len(t)-1; i++ {
406 if t[i] == '{' {
407 depth++
408 } else if t[i] == '}' {
409 depth--
410 } else if t[i] == ',' && depth == 0 {
411 f := trimSpaces(t[start:i])
412 if f != "" {
413 sub := flattenTypeStr(f)
414 if result != "" {
415 result = result | ", " | sub
416 } else {
417 result = sub
418 }
419 }
420 start = i + 1
421 }
422 }
423 f := trimSpaces(t[start : len(t)-1])
424 if f != "" {
425 sub := flattenTypeStr(f)
426 if result != "" {
427 result = result | ", " | sub
428 } else {
429 result = sub
430 }
431 }
432 return result
433 }
434
435 func trimSpaces(s string) string {
436 for len(s) > 0 && s[0] == ' ' {
437 s = s[1:]
438 }
439 for len(s) > 0 && s[len(s)-1] == ' ' {
440 s = s[:len(s)-1]
441 }
442 return s
443 }
444
445 func (e *irEmitter) emitExtInvokeCall(reg, retType, funcSym, recvLLVM, recv string, inv *ssa.SSAInvoke, isVoid bool) {
446 extracts := ""
447 callArgs := recvLLVM | " " | recv
448 for _, arg := range inv.Args {
449 argT := e.llvmType(arg.SSAType())
450 if argT == "void" {
451 argT = "ptr"
452 }
453 argVal := e.operand(arg)
454 if len(argT) > 0 && argT[0] == '{' {
455 depth := 0
456 start := 1
457 fi := 0
458 for i := 1; i < len(argT)-1; i++ {
459 if argT[i] == '{' {
460 depth++
461 } else if argT[i] == '}' {
462 depth--
463 } else if argT[i] == ',' && depth == 0 {
464 ft := trimSpaces(argT[start:i])
465 if ft != "" {
466 e.nextReg++
467 ex := "%ef" | irItoa(e.nextReg)
468 extracts = extracts | " " | ex | " = extractvalue " | argT | " " | argVal | ", " | irItoa(fi) | "\n"
469 callArgs = callArgs | ", " | ft | " " | ex
470 fi++
471 }
472 start = i + 1
473 }
474 }
475 ft := trimSpaces(argT[start : len(argT)-1])
476 if ft != "" {
477 e.nextReg++
478 ex := "%ef" | irItoa(e.nextReg)
479 extracts = extracts | " " | ex | " = extractvalue " | argT | " " | argVal | ", " | irItoa(fi) | "\n"
480 callArgs = callArgs | ", " | ft | " " | ex
481 }
482 } else {
483 callArgs = callArgs | ", " | argT | " " | argVal
484 }
485 }
486 callArgs = callArgs | ", ptr null"
487 e.w(extracts)
488 e.w(" ")
489 if !isVoid {
490 e.w(reg) ; e.w(" = ")
491 }
492 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(funcSym) ; e.w("(")
493 e.w(callArgs)
494 e.w(")\n")
495 }
496
497 func (e *irEmitter) implTypeID(impl ifaceImpl) string {
498 if impl.extTypeID != "" {
499 if e.extTypeIDs == nil {
500 e.extTypeIDs = map[string]bool{}
501 }
502 quoted := "\"" | impl.extTypeID | "\""
503 e.extTypeIDs[quoted] = true
504 return "@" | quoted
505 }
506 return e.typeIDGlobal(impl.recvType)
507 }
508
509 func (e *irEmitter) emitEmbedChainGEP(impl ifaceImpl, valPtr string) string {
510 chain := impl.embedChain
511 if len(chain) == 0 {
512 chain = []int32{impl.embedField}
513 }
514 outerType := impl.recvType
515 if pt, ok := outerType.(*types.Pointer); ok {
516 outerType = pt.Elem()
517 }
518 cur := valPtr
519 curType := outerType
520 for _, idx := range chain {
521 outerLLVM := e.llvmType(curType)
522 gep := e.nextReg2("eg")
523 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr inbounds ") ; e.w(outerLLVM)
524 e.w(", ptr ") ; e.w(cur) ; e.w(", i32 0, i32 ") ; e.w(irItoa(idx)) ; e.w("\n")
525 cur = gep
526 st, ok := types.SafeUnderlying(curType).(*types.TCStruct)
527 if ok && st != nil && idx < st.NumFields() {
528 curType = st.Field(idx).Type()
529 }
530 }
531 return cur
532 }
533
534 type invokeArg struct {
535 typ string
536 val string
537 }
538
539 func (e *irEmitter) prepareInvokeArgs(inv *ssa.SSAInvoke, impl ifaceImpl) []invokeArg {
540 var sig *types.Signature
541 if impl.fn != nil {
542 sig = impl.fn.Signature
543 }
544 var result []invokeArg
545 for i, arg := range inv.Args {
546 argT := e.llvmType(arg.SSAType())
547 if at, ok := e.allocTypes[arg]; ok && at != "ptr" && at != "void" {
548 argT = at
549 }
550 argV := e.operand(arg)
551 if sig != nil && sig.Params() != nil && i < sig.Params().Len() {
552 pt := e.llvmType(sig.Params().At(i).Type())
553 if pt != "void" && pt != "ptr" && pt != "" && argT != "void" && pt != argT && len(pt) > len(argT) {
554 e.nextReg++
555 tmp := "%icast" | irItoa(e.nextReg)
556 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(pt) ; e.w("\n")
557 e.w(" store ") ; e.w(pt) ; e.w(" zeroinitializer, ptr ") ; e.w(tmp) ; e.w("\n")
558 e.w(" store ") ; e.w(argT) ; e.w(" ") ; e.w(argV) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
559 e.nextReg++
560 loaded := "%icld" | irItoa(e.nextReg)
561 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(pt) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
562 argT = pt
563 argV = loaded
564 }
565 }
566 if argT == "void" {
567 argT = "ptr"
568 }
569 result = append(result, invokeArg{typ: argT, val: argV})
570 }
571 return result
572 }
573
574 func (e *irEmitter) emitInvokeArgs(args []invokeArg) {
575 for _, a := range args {
576 e.w(", ") ; e.w(a.typ) ; e.w(" ") ; e.w(a.val)
577 }
578 }
579
580 func (e *irEmitter) emitInvoke(inv *ssa.SSAInvoke) {
581 reg := e.regName(inv)
582 ifaceVal := e.operand(inv.X)
583 retType := e.llvmType(inv.SSAType())
584 isVoid := retType == "void"
585 tidPtr := e.nextReg2("tid")
586 e.w(" ") ; e.w(tidPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(ifaceVal) ; e.w(", 0\n")
587 valPtr := e.nextReg2("vp")
588 e.w(" ") ; e.w(valPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(ifaceVal) ; e.w(", 1\n")
589
590 impls := e.findIfaceImpls(inv.MethodName)
591 for _, impl := range impls {
592 e.declareExtInvoke(impl, inv)
593 }
594
595 if len(impls) == 0 {
596 e.w(" ; invoke: no implementations for ") ; e.w(inv.MethodName) ; e.w("\n")
597 if !isVoid {
598 e.nextReg++
599 zp := "%zp" | irItoa(e.nextReg)
600 e.w(" ") ; e.w(zp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
601 e.w(" store ") ; e.w(retType) ; e.w(" zeroinitializer, ptr ") ; e.w(zp) ; e.w("\n")
602 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(zp) ; e.w("\n")
603 }
604 return
605 }
606
607 if len(impls) == 1 {
608 impl := impls[0]
609 callRecv := valPtr
610 if impl.embedType != nil {
611 callRecv = e.emitEmbedChainGEP(impl, valPtr)
612 }
613 var recvLLVM, recv string
614 if impl.ptrRecv {
615 recvLLVM = "ptr"
616 recv = callRecv
617 } else {
618 if impl.embedType != nil {
619 recvLLVM = e.llvmType(impl.embedType)
620 } else {
621 recvType := impl.recvType
622 if pt, ok := recvType.(*types.Pointer); ok {
623 recvType = pt.Elem()
624 }
625 recvLLVM = e.llvmType(recvType)
626 }
627 if recvLLVM == "ptr" {
628 recv = callRecv
629 } else if e.fitsInPtr(recvLLVM) {
630 recv = e.extractScalarFromIface(callRecv, recvLLVM)
631 } else {
632 recv = e.nextReg2("ld")
633 e.w(" ") ; e.w(recv) ; e.w(" = load ") ; e.w(recvLLVM) ; e.w(", ptr ") ; e.w(callRecv) ; e.w("\n")
634 }
635 }
636 if impl.extSymbol != "" {
637 e.emitExtInvokeCall(reg, retType, e.implFuncSym(impl), recvLLVM, recv, inv, isVoid)
638 } else {
639 e.w(" ")
640 prepArgs := e.prepareInvokeArgs(inv, impl)
641 if !isVoid {
642 e.w(reg) ; e.w(" = ")
643 }
644 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(e.implFuncSym(impl)) ; e.w("(")
645 e.w(recvLLVM) ; e.w(" ") ; e.w(recv)
646 e.emitInvokeArgs(prepArgs)
647 e.w(", ptr null)\n")
648 }
649 return
650 }
651
652 baseID := e.nextReg
653 mergeLabel := "invoke.merge" | irItoa(baseID)
654 var checkLabels []string
655 var caseLabels []string
656 var callRegs []string
657 for i := range impls {
658 checkLabels = append(checkLabels, "invoke.check" | irItoa(baseID) | "." | irItoa(i))
659 caseLabels = append(caseLabels, "invoke.case" | irItoa(baseID) | "." | irItoa(i))
660 if !isVoid {
661 callRegs = append(callRegs, e.nextReg2("cr"))
662 }
663 }
664 defaultLabel := "invoke.default" | irItoa(baseID)
665
666 e.w(" br label %") ; e.w(checkLabels[0]) ; e.w("\n")
667
668 for i, impl := range impls {
669 nextCheck := defaultLabel
670 if i < len(impls)-1 {
671 nextCheck = checkLabels[i+1]
672 }
673 e.w(checkLabels[i]) ; e.w(":\n")
674 tidGlobal := e.implTypeID(impl)
675 cmpReg := e.nextReg2("cmp")
676 e.w(" ") ; e.w(cmpReg) ; e.w(" = icmp eq ptr ") ; e.w(tidPtr) ; e.w(", ") ; e.w(tidGlobal) ; e.w("\n")
677 e.w(" br i1 ") ; e.w(cmpReg) ; e.w(", label %") ; e.w(caseLabels[i]) ; e.w(", label %") ; e.w(nextCheck) ; e.w("\n")
678
679 e.w(caseLabels[i]) ; e.w(":\n")
680 var recvLLVM, recv string
681 callRecv := valPtr
682 if impl.embedType != nil {
683 callRecv = e.emitEmbedChainGEP(impl, valPtr)
684 }
685 if impl.ptrRecv {
686 recvLLVM = "ptr"
687 recv = callRecv
688 } else {
689 if impl.embedType != nil {
690 recvLLVM = e.llvmType(impl.embedType)
691 } else {
692 recvType := impl.recvType
693 if pt, ok := recvType.(*types.Pointer); ok {
694 recvType = pt.Elem()
695 }
696 recvLLVM = e.llvmType(recvType)
697 }
698 if recvLLVM == "ptr" {
699 recv = callRecv
700 } else if e.fitsInPtr(recvLLVM) {
701 recv = e.extractScalarFromIface(callRecv, recvLLVM)
702 } else {
703 recv = e.nextReg2("ld")
704 e.w(" ") ; e.w(recv) ; e.w(" = load ") ; e.w(recvLLVM) ; e.w(", ptr ") ; e.w(callRecv) ; e.w("\n")
705 }
706 }
707 if impl.extSymbol != "" {
708 creg := ""
709 if !isVoid {
710 creg = callRegs[i]
711 }
712 e.emitExtInvokeCall(creg, retType, e.implFuncSym(impl), recvLLVM, recv, inv, isVoid)
713 } else {
714 prepArgs := e.prepareInvokeArgs(inv, impl)
715 e.w(" ")
716 if !isVoid {
717 e.w(callRegs[i]) ; e.w(" = ")
718 }
719 e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(e.implFuncSym(impl)) ; e.w("(")
720 e.w(recvLLVM) ; e.w(" ") ; e.w(recv)
721 e.emitInvokeArgs(prepArgs)
722 e.w(", ptr null)\n")
723 }
724 e.w(" br label %") ; e.w(mergeLabel) ; e.w("\n")
725 }
726
727 e.w(defaultLabel) ; e.w(":\n")
728 e.w(" unreachable\n")
729
730 e.w(mergeLabel) ; e.w(":\n")
731 if blk := inv.InstrBlock(); blk != nil {
732 e.blockExitLabel[blk.Index] = "%" | mergeLabel
733 }
734 if !isVoid {
735 e.w(" ") ; e.w(reg) ; e.w(" = phi ") ; e.w(retType) ; e.w(" ")
736 for i := range impls {
737 if i > 0 { e.w(", ") }
738 e.w("[ ") ; e.w(callRegs[i]) ; e.w(", %") ; e.w(caseLabels[i]) ; e.w(" ]")
739 }
740 e.w("\n")
741 }
742 }
743
744 func (e *irEmitter) emitTypeAssert(t *ssa.SSATypeAssert) {
745 reg := e.regName(t)
746 val := e.operand(t.X)
747 assertedType := e.llvmType(t.AssertedType)
748 voidAssert := assertedType == "void"
749 if voidAssert {
750 assertedType = "ptr"
751 }
752 // Check if input is already a concrete ptr (not an interface {ptr, ptr})
753 inputType := e.llvmType(t.X.SSAType())
754 if at, ok := e.allocTypes[t.X]; ok {
755 inputType = at
756 }
757 var valPtr, typePtr string
758 if inputType == "ptr" {
759 valPtr = val
760 typePtr = "null"
761 } else {
762 valPtr = e.nextReg2("ta")
763 e.w(" ") ; e.w(valPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
764 typePtr = e.nextReg2("ta")
765 e.w(" ") ; e.w(typePtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 0\n")
766 }
767 if t.CommaOk {
768 tidGlobal := e.typeIDGlobal(t.AssertedType)
769 ok := e.nextReg2("ta")
770 e.w(" ") ; e.w(ok) ; e.w(" = icmp eq ptr ") ; e.w(typePtr) ; e.w(", ") ; e.w(tidGlobal) ; e.w("\n")
771 var loaded string
772 if assertedType == "ptr" {
773 loaded = e.nextReg2("ta")
774 e.w(" ") ; e.w(loaded) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(valPtr) ; e.w(", ptr null\n")
775 } else if e.fitsInPtr(assertedType) {
776 loaded = e.extractScalarFromIface(valPtr, assertedType)
777 } else {
778 nonnull := e.nextReg2("ta")
779 e.w(" ") ; e.w(nonnull) ; e.w(" = icmp ne ptr ") ; e.w(valPtr) ; e.w(", null\n")
780 e.nextReg++
781 safeLabel := "ta.safe" | irItoa(e.nextReg)
782 e.nextReg++
783 zeroLabel := "ta.zero" | irItoa(e.nextReg)
784 e.nextReg++
785 mergeLabel := "ta.merge" | irItoa(e.nextReg)
786 e.w(" br i1 ") ; e.w(nonnull) ; e.w(", label %") ; e.w(safeLabel) ; e.w(", label %") ; e.w(zeroLabel) ; e.w("\n")
787 e.w(safeLabel) ; e.w(":\n")
788 realLoad := e.nextReg2("ta")
789 e.w(" ") ; e.w(realLoad) ; e.w(" = load ") ; e.w(assertedType) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
790 e.w(" br label %") ; e.w(mergeLabel) ; e.w("\n")
791 e.w(zeroLabel) ; e.w(":\n")
792 e.w(" br label %") ; e.w(mergeLabel) ; e.w("\n")
793 e.w(mergeLabel) ; e.w(":\n")
794 loaded = e.nextReg2("ta")
795 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")
796 if blk := t.InstrBlock(); blk != nil {
797 e.blockExitLabel[blk.Index] = "%" | mergeLabel
798 }
799 }
800 tupType := "{" | assertedType | ", i1}"
801 t1 := e.nextReg2("ta")
802 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")
803 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")
804 if voidAssert {
805 e.allocTypes[t] = tupType
806 }
807 } else {
808 if assertedType == "ptr" {
809 e.w(" ") ; e.w(reg) ; e.w(" = select i1 true, ptr ") ; e.w(valPtr) ; e.w(", ptr null\n")
810 } else if e.fitsInPtr(assertedType) {
811 extracted := e.extractScalarFromIface(valPtr, assertedType)
812 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(assertedType) ; e.w(" ") ; e.w(extracted) ; e.w(", 0\n")
813 } else {
814 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(assertedType) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
815 }
816 if voidAssert {
817 e.allocTypes[t] = assertedType
818 }
819 }
820 }
821
822 func (e *irEmitter) extractScalarFromIface(valPtr string, assertedType string) string {
823 ipt := e.intptrType()
824 raw := e.nextReg2("ta")
825 e.w(" ") ; e.w(raw) ; e.w(" = ptrtoint ptr ") ; e.w(valPtr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
826 if assertedType == ipt {
827 return raw
828 }
829 if assertedType == "i1" || assertedType == "i8" || assertedType == "i16" || assertedType == "i32" {
830 tr := e.nextReg2("ta")
831 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")
832 return tr
833 }
834 if assertedType == "float" {
835 trDst := e.nextReg2("ta")
836 src := e.emitIntCast(trDst, ipt, raw, "i32")
837 bc := e.nextReg2("ta")
838 e.w(" ") ; e.w(bc) ; e.w(" = bitcast i32 ") ; e.w(src) ; e.w(" to float\n")
839 return bc
840 }
841 if assertedType == "double" {
842 bc := e.nextReg2("ta")
843 e.w(" ") ; e.w(bc) ; e.w(" = bitcast ") ; e.w(ipt) ; e.w(" ") ; e.w(raw) ; e.w(" to double\n")
844 return bc
845 }
846 return raw
847 }
848
849 func (e *irEmitter) emitMakeMap(m *ssa.SSAMakeMap) {
850 reg := e.regName(m)
851 ipt := e.intptrType()
852 var mt *types.TCMap
853 if okv, okok := types.SafeUnderlying(m.SSAType()).(*types.TCMap); okok {
854 mt = okv
855 }
856 keyType := "i32"
857 valType := "i32"
858 alg := "0"
859 if mt != nil {
860 keyType = e.llvmType(mt.Key())
861 valType = e.llvmType(mt.Elem())
862 if e.isStringLike(mt.Key()) {
863 alg = "1"
864 }
865 }
866 keySz := e.nextReg2("mm")
867 e.w(" ") ; e.w(keySz) ; e.w(" = ptrtoint ptr getelementptr (")
868 e.w(keyType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
869 valSz := e.nextReg2("mm")
870 e.w(" ") ; e.w(valSz) ; e.w(" = ptrtoint ptr getelementptr (")
871 e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
872 hint := "8"
873 if m.Reserve != nil {
874 hint = e.operand(m.Reserve)
875 }
876 e.w(" ") ; e.w(reg) ; e.w(" = call ptr @runtime.hashmapMake(")
877 e.w(ipt) ; e.w(" ") ; e.w(keySz) ; e.w(", ")
878 e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(", ")
879 e.w(ipt) ; e.w(" ") ; e.w(hint) ; e.w(", i8 ") ; e.w(alg) ; e.w(")\n")
880 e.declareRuntime("runtime.hashmapMake", "ptr", ipt | ", " | ipt | ", " | ipt | ", i8")
881 e.scopeTrackAlloc(reg)
882 }
883
884 func (e *irEmitter) emitMapUpdate(m *ssa.SSAMapUpdate) {
885 mapVal := e.operand(m.Map)
886 keyVal := e.operand(m.Key)
887 valVal := e.operand(m.Value)
888 mapType := m.Map.SSAType()
889 if pt, ok := types.SafeUnderlying(mapType).(*types.Pointer); ok {
890 mapType = pt.Elem()
891 }
892 var mt *types.TCMap
893 if okv, okok := types.SafeUnderlying(mapType).(*types.TCMap); okok {
894 mt = okv
895 }
896 keyType := "i32"
897 valType := "i32"
898 if mt != nil {
899 keyType = e.llvmType(mt.Key())
900 valType = e.llvmType(mt.Elem())
901 }
902 if keyVal == "null" && keyType != "ptr" { keyVal = "zeroinitializer" }
903 if valVal == "null" && valType != "ptr" { valVal = "zeroinitializer" }
904 keyAlloca := e.nextReg2("mu")
905 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
906 e.w(" store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
907 valAlloca := e.nextReg2("mu")
908 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
909 actualValType := e.llvmType(m.Value.SSAType())
910 resolved := e.resolvedType(m.Value, actualValType)
911 if resolved != actualValType {
912 actualValType = resolved
913 }
914 if actualValType != valType && valType == "{ptr, ptr}" && actualValType == "ptr" {
915 e.w(" store {ptr, ptr} zeroinitializer, ptr ") ; e.w(valAlloca) ; e.w("\n")
916 vfld := e.nextReg2("mu")
917 e.w(" ") ; e.w(vfld) ; e.w(" = getelementptr inbounds {ptr, ptr}, ptr ") ; e.w(valAlloca) ; e.w(", i32 0, i32 1\n")
918 e.w(" store ptr ") ; e.w(valVal) ; e.w(", ptr ") ; e.w(vfld) ; e.w("\n")
919 } else {
920 e.w(" store ") ; e.w(valType) ; e.w(" ") ; e.w(valVal) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
921 }
922 if mt != nil && e.isStringLike(mt.Key()) {
923 sty := e.sliceType()
924 ipt := e.intptrType()
925 kd := e.nextReg2("mu")
926 kl := e.nextReg2("mu")
927 kc := e.nextReg2("mu")
928 e.w(" ") ; e.w(kd) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(keyVal) ; e.w(", 0\n")
929 e.w(" ") ; e.w(kl) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(keyVal) ; e.w(", 1\n")
930 e.w(" ") ; e.w(kc) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(keyVal) ; e.w(", 2\n")
931 e.w(" call void @runtime.hashmapContentSet(ptr ") ; e.w(mapVal)
932 e.w(", ptr ") ; e.w(kd)
933 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(kl)
934 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(kc)
935 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
936 e.declareRuntime("runtime.hashmapContentSet", "void", "ptr, ptr, " | ipt | ", " | ipt | ", ptr")
937 } else {
938 e.w(" call void @runtime.hashmapBinarySet(ptr ") ; e.w(mapVal)
939 e.w(", ptr ") ; e.w(keyAlloca)
940 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
941 e.declareRuntime("runtime.hashmapBinarySet", "void", "ptr, ptr, ptr")
942 }
943 }
944
945 func (e *irEmitter) emitLookup(l *ssa.SSALookup) {
946 reg := e.regName(l)
947 ipt := e.intptrType()
948 mapVal := e.operand(l.X)
949 keyVal := e.operand(l.Index)
950 var mt *types.TCMap
951 if okv, okok := types.SafeUnderlying(l.X.SSAType()).(*types.TCMap); okok {
952 mt = okv
953 }
954 keyType := "i32"
955 valType := "i32"
956 if mt != nil {
957 keyType = e.llvmType(mt.Key())
958 valType = e.llvmType(mt.Elem())
959 }
960 valAlloca := e.nextReg2("ml")
961 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
962 valSz := e.nextReg2("ml")
963 e.w(" ") ; e.w(valSz) ; e.w(" = ptrtoint ptr getelementptr (")
964 e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
965 if mt != nil && e.isStringLike(mt.Key()) {
966 sty := e.sliceType()
967 kd := e.nextReg2("ml")
968 kl := e.nextReg2("ml")
969 kc := e.nextReg2("ml")
970 e.w(" ") ; e.w(kd) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(keyVal) ; e.w(", 0\n")
971 e.w(" ") ; e.w(kl) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(keyVal) ; e.w(", 1\n")
972 e.w(" ") ; e.w(kc) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(keyVal) ; e.w(", 2\n")
973 okReg := e.nextReg2("ml")
974 e.w(" ") ; e.w(okReg) ; e.w(" = call i1 @runtime.hashmapContentGet(ptr ") ; e.w(mapVal)
975 e.w(", ptr ") ; e.w(kd)
976 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(kl)
977 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(kc)
978 e.w(", ptr ") ; e.w(valAlloca)
979 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(")\n")
980 e.declareRuntime("runtime.hashmapContentGet", "i1", "ptr, ptr, " | ipt | ", " | ipt | ", ptr, " | ipt)
981 if l.CommaOk {
982 loaded := e.nextReg2("ml")
983 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
984 tupType := "{" | valType | ", i1}"
985 t1 := e.nextReg2("ml")
986 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")
987 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")
988 } else {
989 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
990 }
991 } else {
992 keyAlloca := e.nextReg2("ml")
993 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
994 e.w(" store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
995 okReg := e.nextReg2("ml")
996 e.w(" ") ; e.w(okReg) ; e.w(" = call i1 @runtime.hashmapBinaryGet(ptr ") ; e.w(mapVal)
997 e.w(", ptr ") ; e.w(keyAlloca)
998 e.w(", ptr ") ; e.w(valAlloca)
999 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(")\n")
1000 e.declareRuntime("runtime.hashmapBinaryGet", "i1", "ptr, ptr, ptr, " | ipt)
1001 if l.CommaOk {
1002 loaded := e.nextReg2("ml")
1003 e.w(" ") ; e.w(loaded) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
1004 tupType := "{" | valType | ", i1}"
1005 t1 := e.nextReg2("ml")
1006 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")
1007 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")
1008 } else {
1009 e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
1010 }
1011 }
1012 }
1013
1014 func (e *irEmitter) isStringLike(t syntax.Type) bool {
1015 if t == nil {
1016 return false
1017 }
1018 if b, ok := types.SafeUnderlying(t).(*types.Basic); ok {
1019 return b.Info()&types.IsString != 0
1020 }
1021 return false
1022 }
1023
1024 func (e *irEmitter) emitMakeClosure(m *ssa.SSAMakeClosure) {
1025 reg := e.regName(m)
1026 var fn *ssa.SSAFunction
1027 if okv, okok := m.Fn.(*ssa.SSAFunction); okok {
1028 fn = okv
1029 }
1030 ipt := e.intptrType()
1031
1032 if len(m.Bindings) == 0 {
1033 t1 := e.nextReg2("mc")
1034 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr null, 0\n")
1035 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1)
1036 e.w(", ptr ") ; e.w(e.funcSymbol(fn)) ; e.w(", 1\n")
1037 e.declareExternalFunc(fn)
1038 return
1039 }
1040
1041 ctxType := e.closureContextType(m.Bindings)
1042 ctxSz := e.nextReg2("mc")
1043 e.w(" ") ; e.w(ctxSz) ; e.w(" = ptrtoint ptr getelementptr (")
1044 e.w(ctxType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1045 ctxPtr := e.nextReg2("mc")
1046 e.w(" ") ; e.w(ctxPtr) ; e.w(" = call ptr @runtime.alloc(")
1047 e.w(ipt) ; e.w(" ") ; e.w(ctxSz) ; e.w(", ptr null, ptr undef)\n")
1048 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
1049 e.scopeTrackAlloc(ctxPtr)
1050
1051 for i, b := range m.Bindings {
1052 bval := e.operand(b)
1053 bt := e.closureBindingType(b)
1054 gep := e.nextReg2("mc")
1055 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(ctxType) ; e.w(", ptr ")
1056 e.w(ctxPtr) ; e.w(", i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
1057 e.w(" store ") ; e.w(bt) ; e.w(" ") ; e.w(bval) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
1058 _ = b
1059 }
1060
1061 t1 := e.nextReg2("mc")
1062 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(ctxPtr) ; e.w(", 0\n")
1063 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1)
1064 e.w(", ptr ") ; e.w(e.funcSymbol(fn)) ; e.w(", 1\n")
1065 e.declareExternalFunc(fn)
1066 }
1067
1068 func (e *irEmitter) closureBindingType(b ssa.SSAValue) string {
1069 return "ptr"
1070 }
1071
1072 func (e *irEmitter) closureContextType(bindings []ssa.SSAValue) string {
1073 s := "{"
1074 for i, b := range bindings {
1075 if i > 0 {
1076 s = s | ", "
1077 }
1078 s = s | e.closureBindingType(b)
1079 }
1080 return s | "}"
1081 }
1082
1083 func (e *irEmitter) freeVarType(fv *ssa.SSAFreeVar) string {
1084 return "ptr"
1085 }
1086
1087 func (e *irEmitter) emitFreeVarUnpack(f *ssa.SSAFunction) {
1088 ctxName := "context"
1089 for _, p := range f.Params {
1090 if p.SSAName() == "context" {
1091 ctxName = "context.1"
1092 break
1093 }
1094 }
1095 ctxType := "{"
1096 for i, fv := range f.FreeVars {
1097 if i > 0 {
1098 ctxType = ctxType | ", "
1099 }
1100 ctxType = ctxType | e.freeVarType(fv)
1101 }
1102 ctxType = ctxType | "}"
1103
1104 for i, fv := range f.FreeVars {
1105 fvName := e.regName(fv)
1106 e.nextReg++
1107 gep := "%fv" | irItoa(e.nextReg)
1108 e.w(" ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(ctxType)
1109 e.w(", ptr %") ; e.w(ctxName) ; e.w(", i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
1110 e.w(" ") ; e.w(fvName) ; e.w(" = load ptr, ptr ") ; e.w(gep) ; e.w("\n")
1111 }
1112 }
1113
1114 func (e *irEmitter) emitPanic(p *ssa.SSAPanic) {
1115 if c, ok := p.X.(*ssa.SSAConst); ok && e.isStringLike(c.SSAType()) {
1116 arg := e.operand(c)
1117 sty := e.sliceType()
1118 e.w(" call void @runtime._panicstr(") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(")\n")
1119 e.declareRuntime("runtime._panicstr", "void", sty)
1120 e.w(" unreachable\n")
1121 return
1122 }
1123 e.w(" call void @runtime._panic(ptr null)\n")
1124 e.declareRuntime("runtime._panic", "void", "ptr")
1125 e.w(" unreachable\n")
1126 }
1127
1128 func (e *irEmitter) emitRange(r *ssa.SSARange) {
1129 reg := e.regName(r)
1130 if _, ok := types.SafeUnderlying(r.X.SSAType()).(*types.TCMap); ok {
1131 e.w(" ") ; e.w(reg) ; e.w(" = alloca [48 x i8]\n")
1132 e.w(" call void @llvm.memset.p0.i64(ptr ") ; e.w(reg) ; e.w(", i8 0, i64 48, i1 false)\n")
1133 e.declareRuntime("llvm.memset.p0.i64", "void", "ptr, i8, i64, i1")
1134 return
1135 }
1136 ipt := e.intptrType()
1137 e.w(" ") ; e.w(reg) ; e.w(" = alloca ") ; e.w(ipt) ; e.w("\n")
1138 e.w(" store ") ; e.w(ipt) ; e.w(" 0, ptr ") ; e.w(reg) ; e.w("\n")
1139 }
1140
1141 func (e *irEmitter) emitNext(n *ssa.SSANext) {
1142 reg := e.regName(n)
1143 rangeInstr := n.Iter.(*ssa.SSARange)
1144 iterPtr := e.regName(rangeInstr)
1145 collVal := e.operand(rangeInstr.X)
1146 if mt, ok := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.TCMap); ok {
1147 e.emitNextMap(reg, iterPtr, collVal, mt, n)
1148 return
1149 }
1150 if arr, ok := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.Array); ok {
1151 e.emitNextArray(reg, iterPtr, collVal, arr, n)
1152 return
1153 }
1154 if p, ok := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.Pointer); ok && p.Elem() != nil {
1155 if arr, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 {
1156 e.emitNextPtrArray(reg, iterPtr, collVal, arr, n)
1157 return
1158 }
1159 }
1160 collLLVM := e.llvmType(rangeInstr.X.SSAType())
1161 if len(collLLVM) > 0 && collLLVM[0] == 'i' {
1162 tupType := e.llvmType(n.SSAType())
1163 if at, ok := e.allocTypes[n]; ok {
1164 tupType = at
1165 }
1166 e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" zeroinitializer, i1 false, 0\n")
1167 return
1168 }
1169 e.emitNextSlice(reg, iterPtr, collVal, rangeInstr, n)
1170 }
1171
1172 func (e *irEmitter) emitNextSlice(reg, iterPtr, collVal string, rangeInstr *ssa.SSARange, n *ssa.SSANext) {
1173 ipt := e.intptrType()
1174 sty := e.sliceType()
1175 idx := e.nextReg2("rn")
1176 e.w(" ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
1177 slLen := e.nextReg2("rn")
1178 e.w(" ") ; e.w(slLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(collVal) ; e.w(", 1\n")
1179 ok := e.nextReg2("rn")
1180 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")
1181 keyDst := e.nextReg2("rn")
1182 key := e.emitIntCast(keyDst, ipt, idx, "i32")
1183 dataPtr := e.nextReg2("rn")
1184 e.w(" ") ; e.w(dataPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(collVal) ; e.w(", 0\n")
1185 elemType := "i32"
1186 elemResolved := false
1187 xType := rangeInstr.X.SSAType()
1188 if sl, ok2 := types.SafeUnderlying(xType).(*types.Slice); ok2 {
1189 elemType = e.llvmType(sl.Elem())
1190 elemResolved = true
1191 } else if xType != nil {
1192 switch t := xType.(type) {
1193 case *types.Slice:
1194 elemType = e.llvmType(t.Elem())
1195 elemResolved = true
1196 case *types.Basic:
1197 elemType = "i8"
1198 elemResolved = true
1199 case *types.Named:
1200 if sl2, ok3 := t.Underlying().(*types.Slice); ok3 {
1201 elemType = e.llvmType(sl2.Elem())
1202 elemResolved = true
1203 } else if e.isStringLike(t) {
1204 elemType = "i8"
1205 elemResolved = true
1206 }
1207 }
1208 }
1209 if !elemResolved && elemType == "i32" {
1210 if tup, ok2 := n.SSAType().(*types.Tuple); ok2 && tup.Len() >= 3 {
1211 vt := tup.At(2).Type()
1212 if vt != nil {
1213 vlt := e.llvmType(vt)
1214 if vlt != "void" {
1215 elemType = vlt
1216 elemResolved = true
1217 }
1218 }
1219 }
1220 }
1221 if !elemResolved && elemType == "i32" && sty == e.sliceType() {
1222 elemType = "i8"
1223 }
1224 eptr := e.nextReg2("rn")
1225 e.w(" ") ; e.w(eptr) ; e.w(" = getelementptr ") ; e.w(elemType)
1226 e.w(", ptr ") ; e.w(dataPtr) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
1227 fallback := e.nextReg2("rn")
1228 e.w(" ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
1229 e.w(" store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(fallback) ; e.w("\n")
1230 safePtr := e.nextReg2("rn")
1231 e.w(" ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
1232 e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
1233 elem := e.nextReg2("rn")
1234 e.w(" ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
1235 inc := e.nextReg2("rn")
1236 e.w(" ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
1237 newCnt := e.nextReg2("rn")
1238 e.w(" ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
1239 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
1240 e.w(" store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
1241 tupType := "{i1, i32, " | elemType | "}"
1242 e.allocTypes[n] = tupType
1243 t1 := e.nextReg2("rn")
1244 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
1245 t2 := e.nextReg2("rn")
1246 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")
1247 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")
1248 }
1249
1250 func (e *irEmitter) emitNextArray(reg, iterPtr, collVal string, arr *types.Array, n *ssa.SSANext) {
1251 ipt := e.intptrType()
1252 arrLen := arr.Len()
1253 if arrLen < 0 {
1254 rangeInstr := n.Iter.(*ssa.SSARange)
1255 e.emitNextSlice(reg, iterPtr, collVal, rangeInstr, n)
1256 return
1257 }
1258 elemType := e.llvmType(arr.Elem())
1259 arrType := "[" | irItoa(int32(arrLen)) | " x " | elemType | "]"
1260 idx := e.nextReg2("rn")
1261 e.w(" ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
1262 ok := e.nextReg2("rn")
1263 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")
1264 keyDst2 := e.nextReg2("rn")
1265 key := e.emitIntCast(keyDst2, ipt, idx, "i32")
1266 // Store array to memory to get element pointer via GEP
1267 arrAlloca := e.nextReg2("rn")
1268 e.w(" ") ; e.w(arrAlloca) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
1269 e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(collVal) ; e.w(", ptr ") ; e.w(arrAlloca) ; e.w("\n")
1270 eptr := e.nextReg2("rn")
1271 e.w(" ") ; e.w(eptr) ; e.w(" = getelementptr inbounds ") ; e.w(arrType)
1272 e.w(", ptr ") ; e.w(arrAlloca) ; e.w(", i32 0, ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
1273 fallback := e.nextReg2("rn")
1274 e.w(" ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
1275 e.w(" store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(fallback) ; e.w("\n")
1276 safePtr := e.nextReg2("rn")
1277 e.w(" ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
1278 e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
1279 elem := e.nextReg2("rn")
1280 e.w(" ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
1281 inc := e.nextReg2("rn")
1282 e.w(" ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
1283 newCnt := e.nextReg2("rn")
1284 e.w(" ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
1285 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
1286 e.w(" store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
1287 tupType := "{i1, i32, " | elemType | "}"
1288 e.allocTypes[n] = tupType
1289 t1 := e.nextReg2("rn")
1290 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
1291 t2 := e.nextReg2("rn")
1292 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")
1293 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")
1294 }
1295
1296 func (e *irEmitter) emitNextPtrArray(reg, iterPtr, collVal string, arr *types.Array, n *ssa.SSANext) {
1297 ipt := e.intptrType()
1298 arrLen := arr.Len()
1299 elemType := e.llvmType(arr.Elem())
1300 arrType := "[" | irItoa(int32(arrLen)) | " x " | elemType | "]"
1301 idx := e.nextReg2("rn")
1302 e.w(" ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
1303 ok := e.nextReg2("rn")
1304 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")
1305 keyDst := e.nextReg2("rn")
1306 key := e.emitIntCast(keyDst, ipt, idx, "i32")
1307 eptr := e.nextReg2("rn")
1308 e.w(" ") ; e.w(eptr) ; e.w(" = getelementptr inbounds ") ; e.w(arrType)
1309 e.w(", ptr ") ; e.w(collVal) ; e.w(", i32 0, ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
1310 fallback := e.nextReg2("rn")
1311 e.w(" ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
1312 e.w(" store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(fallback) ; e.w("\n")
1313 safePtr := e.nextReg2("rn")
1314 e.w(" ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
1315 e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
1316 elem := e.nextReg2("rn")
1317 e.w(" ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
1318 inc := e.nextReg2("rn")
1319 e.w(" ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
1320 newCnt := e.nextReg2("rn")
1321 e.w(" ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
1322 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
1323 e.w(" store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
1324 tupType := "{i1, i32, " | elemType | "}"
1325 e.allocTypes[n] = tupType
1326 t1 := e.nextReg2("rn")
1327 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
1328 t2 := e.nextReg2("rn")
1329 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")
1330 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")
1331 }
1332
1333 func (e *irEmitter) emitNextMap(reg, iterPtr, collVal string, mt *types.TCMap, n *ssa.SSANext) {
1334 keyType := e.llvmType(mt.Key())
1335 valType := e.llvmType(mt.Elem())
1336 keyAlloca := e.nextReg2("mn")
1337 e.w(" ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
1338 valAlloca := e.nextReg2("mn")
1339 e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
1340 ok := e.nextReg2("mn")
1341 e.w(" ") ; e.w(ok) ; e.w(" = call i1 @runtime.hashmapNext(ptr ") ; e.w(collVal)
1342 e.w(", ptr ") ; e.w(iterPtr)
1343 e.w(", ptr ") ; e.w(keyAlloca)
1344 e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
1345 key := e.nextReg2("mn")
1346 e.w(" ") ; e.w(key) ; e.w(" = load ") ; e.w(keyType) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
1347 val := e.nextReg2("mn")
1348 e.w(" ") ; e.w(val) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
1349 tupType := e.llvmType(n.SSAType())
1350 t1 := e.nextReg2("mn")
1351 e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
1352 t2 := e.nextReg2("mn")
1353 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")
1354 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")
1355 e.declareRuntime("runtime.hashmapNext", "i1", "ptr, ptr, ptr, ptr")
1356 }
1357