globals.mx raw
1 package emit
2
3 import (
4 "math"
5 "git.smesh.lol/moxie/pkg/ssa"
6 "git.smesh.lol/moxie/pkg/types"
7 )
8
9 func (e *irEmitter) declareRuntime(name, retType, params string) {
10 e.extDecls[name] = retType | " @" | name | "(" | params | ")"
11 }
12
13 func (e *irEmitter) declareExternalGlobal(g *ssa.SSAGlobal) {
14 if g.MemberPkg() == nil || g.MemberPkg() == e.pkg {
15 return
16 }
17 name := e.globalName(g)
18 if _, ok := e.extGlobals[name]; ok {
19 return
20 }
21 typ := e.llvmType(g.SSAType())
22 if p, ok := types.SafeUnderlying(g.SSAType()).(*types.Pointer); ok {
23 typ = e.llvmType(p.Elem())
24 }
25 e.extGlobals[name] = typ
26 }
27
28 func (e *irEmitter) declareExternalFunc(fn *ssa.SSAFunction) {
29 if len(fn.Blocks) > 0 {
30 return
31 }
32 sym := e.funcSymbol(fn)
33 if _, ok := e.extDecls[sym]; ok {
34 return
35 }
36 retType := e.funcRetType(fn)
37 params := ""
38 hasRecv := fn.Signature != nil && fn.Signature.Recv() != nil
39 if hasRecv {
40 params = "ptr"
41 }
42 if fn.Signature != nil && fn.Signature.Params() != nil {
43 for i := 0; i < fn.Signature.Params().Len(); i++ {
44 if params != "" {
45 params = params | ", "
46 }
47 params = params | e.llvmType(fn.Signature.Params().At(i).Type())
48 }
49 }
50 if !fn.IsExternC() {
51 if params != "" {
52 params = params | ", "
53 }
54 params = params | "ptr"
55 }
56 e.extDecls[sym] = retType | " " | sym | "(" | params | ")"
57 }
58
59 func (e *irEmitter) addStringConst(s string) int32 {
60 if idx, ok := e.strMap[s]; ok {
61 return idx
62 }
63 idx := len(e.strConst)
64 e.strConst = append(e.strConst, s)
65 e.strMap[s] = idx
66 return idx
67 }
68
69 func (e *irEmitter) strConstGlobal(idx int32) string {
70 return "@.str." | irItoa(idx)
71 }
72
73 func irEscapeString(s string) string {
74 var buf []byte
75 for i := 0; i < len(s); i++ {
76 c := s[i]
77 if c >= 32 && c < 127 && c != '\\' && c != '"' {
78 buf = append(buf, c)
79 } else {
80 buf = append(buf, '\\')
81 buf = append(buf, "0123456789ABCDEF"[c>>4])
82 buf = append(buf, "0123456789ABCDEF"[c&0xf])
83 }
84 }
85 return string(buf)
86 }
87
88 func (e *irEmitter) emit() string {
89 dl := e.dataLayout()
90 if dl != "" {
91 e.w("target datalayout = \"")
92 e.w(dl)
93 e.w("\"\n")
94 }
95 e.w("target triple = \"")
96 e.w(e.triple)
97 e.w("\"\n\n")
98
99 e.globalTypes = map[string]string{}
100 e.globalDeclTypes = map[string]string{}
101 sortedM := e.pkgMembersSorted()
102 for _, member := range sortedM {
103 fn, ok := member.(*ssa.SSAFunction)
104 if !ok { continue }
105 for _, b := range fn.Blocks {
106 for _, instr := range b.Instrs {
107 if s, ok2 := instr.(*ssa.SSAStore); ok2 && s.Addr != nil && s.Val != nil {
108 if g, ok3 := s.Addr.(*ssa.SSAGlobal); ok3 {
109 vt := e.llvmType(s.Val.SSAType())
110 if vt != "ptr" && vt != "void" && vt != "i1" && vt != "" {
111 name := e.globalName(g)
112 gt := ""
113 if p, ok4 := types.SafeUnderlying(g.SSAType()).(*types.Pointer); ok4 {
114 gt = e.llvmType(p.Elem())
115 }
116 if gt != "" && gt != "ptr" && gt != "i8" && gt[0] == '{' && vt[0] != '{' {
117 vt = gt
118 }
119 e.globalTypes[name] = vt
120 }
121 }
122 }
123 }
124 }
125 e.loadToGlobal = nil
126 e.loadToGlobal = map[string]*ssa.SSAGlobal{}
127 for _, b := range fn.Blocks {
128 for _, instr := range b.Instrs {
129 load, ok2 := instr.(*ssa.SSAUnOp)
130 if !ok2 || load.Op != ssa.OpMul { continue }
131 g, ok3 := load.X.(*ssa.SSAGlobal)
132 if !ok3 { continue }
133 e.loadToGlobal[load.SSAName()] = g
134 }
135 }
136 for _, b := range fn.Blocks {
137 for _, instr := range b.Instrs {
138 if ret, ok2 := instr.(*ssa.SSAReturn); ok2 {
139 if fn.Signature == nil { continue }
140 rets := fn.Signature.Results()
141 if rets == nil || rets.Len() == 0 { continue }
142 for i, res := range ret.Results {
143 if i >= rets.Len() { break }
144 if g, ok3 := e.loadToGlobal[res.SSAName()]; ok3 {
145 rt := rets.At(i)
146 if rt == nil { continue }
147 expectType := e.llvmType(rt.Type())
148 if expectType != "ptr" && expectType != "void" && expectType != "i1" && expectType != "" {
149 name := e.globalName(g)
150 if _, exists := e.globalTypes[name]; !exists {
151 e.globalTypes[name] = expectType
152 }
153 }
154 }
155 }
156 }
157 call, ok2 := instr.(*ssa.SSACall)
158 if !ok2 { continue }
159 callee := call.Call.Value
160 if callee == nil { continue }
161 var sig *types.Signature
162 if cfn, ok3 := callee.(*ssa.SSAFunction); ok3 && cfn.Signature != nil {
163 sig = cfn.Signature
164 } else {
165 ct := callee.SSAType()
166 if ct != nil {
167 if okv, okok := types.SafeUnderlying(ct).(*types.Signature); okok {
168 sig = okv
169 }
170 }
171 }
172 if sig == nil { continue }
173 params := sig.Params()
174 if params == nil || params.Len() == 0 { continue }
175 recvOff := 0
176 if sig.Recv() != nil {
177 recvOff = 1
178 }
179 for i, arg := range call.Call.Args {
180 if arg == nil { continue }
181 sigIdx := i - recvOff
182 if sigIdx < 0 || sigIdx >= params.Len() { continue }
183 pt := params.At(sigIdx)
184 if pt == nil { continue }
185 g, found := e.loadToGlobal[arg.SSAName()]
186 if !found { continue }
187 expectType := e.llvmType(pt.Type())
188 name := e.globalName(g)
189 if expectType != "void" && expectType != "i1" && expectType != "" {
190 if _, exists := e.globalTypes[name]; !exists {
191 e.globalTypes[name] = expectType
192 }
193 }
194 }
195 }
196 }
197 for _, b := range fn.Blocks {
198 for _, instr := range b.Instrs {
199 if rng, ok2 := instr.(*ssa.SSARange); ok2 && rng.X != nil {
200 if g, ok3 := e.loadToGlobal[rng.X.SSAName()]; ok3 {
201 name := e.globalName(g)
202 if _, exists := e.globalTypes[name]; !exists {
203 e.globalTypes[name] = "ptr"
204 }
205 }
206 }
207 if mu, ok2 := instr.(*ssa.SSAMapUpdate); ok2 && mu.Map != nil {
208 if g, ok3 := e.loadToGlobal[mu.Map.SSAName()]; ok3 {
209 name := e.globalName(g)
210 if _, exists := e.globalTypes[name]; !exists {
211 e.globalTypes[name] = "ptr"
212 }
213 }
214 }
215 if lu, ok2 := instr.(*ssa.SSALookup); ok2 && lu.X != nil {
216 if g, ok3 := e.loadToGlobal[lu.X.SSAName()]; ok3 {
217 name := e.globalName(g)
218 if _, exists := e.globalTypes[name]; !exists {
219 e.globalTypes[name] = "ptr"
220 }
221 }
222 }
223 bop, ok2 := instr.(*ssa.SSABinOp)
224 if !ok2 { continue }
225 if bop.X == nil || bop.Y == nil { continue }
226 gx, xIsGlobal := e.loadToGlobal[bop.X.SSAName()]
227 gy, yIsGlobal := e.loadToGlobal[bop.Y.SSAName()]
228 if xIsGlobal {
229 yt := e.llvmType(bop.Y.SSAType())
230 if yt != "ptr" && yt != "void" && yt != "i1" && yt != "" {
231 name := e.globalName(gx)
232 if _, exists := e.globalTypes[name]; !exists {
233 e.globalTypes[name] = yt
234 }
235 }
236 }
237 if yIsGlobal {
238 xt := e.llvmType(bop.X.SSAType())
239 if xt != "ptr" && xt != "void" && xt != "i1" && xt != "" {
240 name := e.globalName(gy)
241 if _, exists := e.globalTypes[name]; !exists {
242 e.globalTypes[name] = xt
243 }
244 }
245 }
246 }
247 }
248 }
249
250 for _, member := range e.pkgMembersSorted() {
251 switch m := member.(type) {
252 case *ssa.SSAGlobal:
253 if m.MemberName() != "_" {
254 e.emitGlobal(m)
255 }
256 }
257 }
258 for _, member := range e.pkgMembersSorted() {
259 switch m := member.(type) {
260 case *ssa.SSAFunction:
261 e.emitFunction(m)
262 e.emitAnonFuncs(m)
263 m.Blocks = nil
264 m.Locals = nil
265 m.Params = nil
266 m.FreeVars = nil
267 m.NamedResults = nil
268 m.vars = nil
269 }
270 }
271 e.emitLibMain()
272
273 for i, s := range e.strConst {
274 e.w(e.strConstGlobal(i))
275 e.w(" = private constant [")
276 e.w(irItoa(len(s)))
277 e.w(" x i8] c\"")
278 e.w(irEscapeString(s))
279 e.w("\"\n")
280 }
281
282 var tidKeys []string
283 for name := range e.typeIDs {
284 tidKeys = append(tidKeys, name)
285 }
286 for i := 1; i < len(tidKeys); i++ {
287 for j := i; j > 0 && tidKeys[j] < tidKeys[j-1]; j-- {
288 tidKeys[j], tidKeys[j-1] = tidKeys[j-1], tidKeys[j]
289 }
290 }
291 for _, name := range tidKeys {
292 if hasPrefix(name, "reflect/types.type:") {
293 quoted := "\"" | name | "\""
294 if e.extTypeIDs != nil {
295 if _, dup := e.extTypeIDs[quoted]; dup {
296 continue
297 }
298 }
299 e.w("@\"")
300 e.w(name)
301 e.w("\" = linkonce_odr hidden global i8 0\n")
302 } else {
303 e.w("@\"")
304 e.w(name)
305 e.w("\" = private constant i32 0\n")
306 }
307 }
308
309 if len(e.extDecls) > 0 {
310 e.w("\n")
311 var edKeys []string
312 for k := range e.extDecls {
313 edKeys = append(edKeys, k)
314 }
315 for i := 1; i < len(edKeys); i++ {
316 for j := i; j > 0 && edKeys[j] < edKeys[j-1]; j-- {
317 edKeys[j], edKeys[j-1] = edKeys[j-1], edKeys[j]
318 }
319 }
320 for _, k := range edKeys {
321 decl := e.extDecls[k]
322 if decl == "" {
323 continue
324 }
325 localName := k
326 if len(localName) > 0 && localName[0] == '@' {
327 localName = localName[1:]
328 }
329 if len(localName) > 1 && localName[0] == '"' && localName[len(localName)-1] == '"' {
330 localName = localName[1 : len(localName)-1]
331 }
332 pkgPrefix := e.pkg.Pkg.Path() | "."
333 if hasPrefix(localName, pkgPrefix) {
334 memberName := localName[len(pkgPrefix):]
335 if _, ok := e.pkg.Members[memberName]; ok {
336 continue
337 }
338 }
339 e.w("declare ")
340 e.w(decl)
341 e.w("\n")
342 }
343 }
344
345 if len(e.extGlobals) > 0 {
346 e.w("\n")
347 var egKeys []string
348 for name := range e.extGlobals {
349 egKeys = append(egKeys, name)
350 }
351 for i := 1; i < len(egKeys); i++ {
352 for j := i; j > 0 && egKeys[j] < egKeys[j-1]; j-- {
353 egKeys[j], egKeys[j-1] = egKeys[j-1], egKeys[j]
354 }
355 }
356 for _, name := range egKeys {
357 e.w(name)
358 e.w(" = external global ")
359 e.w(e.extGlobals[name])
360 e.w("\n")
361 }
362 }
363
364 if len(e.extTypeIDs) > 0 {
365 e.w("\n")
366 for _, tid := range sortedKeys(e.extTypeIDs) {
367 e.w("@") ; e.w(tid) ; e.w(" = linkonce_odr hidden global i8 0\n")
368 }
369 }
370
371 return string(e.buf)
372 }
373
374 func (e *irEmitter) releaseAfterEmit() {
375 e.buf = nil
376 e.valName = nil
377 e.extDecls = nil
378 e.extGlobals = nil
379 e.strMap = nil
380 e.strConst = nil
381 e.typeIDs = nil
382 e.extTypeIDs = nil
383 e.localTypeIDs = nil
384 e.allocTypes = nil
385 e.regTypes = nil
386 e.hoisted = nil
387 e.blockExitLabel = nil
388 e.nameUsed = nil
389 e.missingStores = nil
390 e.globalTypes = nil
391 e.globalDeclTypes = nil
392 e.sortedMembers = nil
393 e.loadToGlobal = nil
394 e.allocBlock = nil
395 e.storedTo = nil
396 e.usedAs = nil
397 e.scopeAllocs = nil
398 e.instrScope = nil
399 e.pkg = nil
400 e.curFunc = nil
401 }
402
403 func (e *irEmitter) pkgMembersSorted() []ssa.SSAMember {
404 if e.sortedMembers != nil {
405 return e.sortedMembers
406 }
407 var members []ssa.SSAMember
408 for _, m := range e.pkg.Members {
409 members = append(members, m)
410 }
411 for i := 1; i < len(members); i++ {
412 for j := i; j > 0 && members[j].MemberName() < members[j-1].MemberName(); j-- {
413 members[j], members[j-1] = members[j-1], members[j]
414 }
415 }
416 e.sortedMembers = members
417 return members
418 }
419
420 func (e *irEmitter) inferGlobalTypeFromLoads(g *ssa.SSAGlobal) string {
421 gname := g.SSAName()
422 for _, member := range e.pkgMembersSorted() {
423 fn, ok := member.(*ssa.SSAFunction)
424 if !ok { continue }
425 for _, b := range fn.Blocks {
426 for _, instr := range b.Instrs {
427 if load, ok2 := instr.(*ssa.SSAUnOp); ok2 && load.Op == ssa.OpMul {
428 if lg, ok3 := load.X.(*ssa.SSAGlobal); ok3 && lg.SSAName() == gname {
429 lt := e.llvmType(load.SSAType())
430 if lt != "void" && lt != "i8" && lt != "ptr" {
431 return lt
432 }
433 }
434 }
435 }
436 }
437 }
438 return ""
439 }
440
441 func (e *irEmitter) resolveGlobalDeclType(g *ssa.SSAGlobal) string {
442 name := e.globalName(g)
443 if dt, ok := e.globalDeclTypes[name]; ok {
444 return dt
445 }
446 typ := e.llvmType(g.SSAType())
447 gtu := types.SafeUnderlying(g.SSAType())
448 elemNil := false
449 if p, ok := gtu.(*types.Pointer); ok {
450 pElem := p.Elem()
451 if pElem == nil {
452 elemNil = true
453 } else {
454 typ = e.llvmType(pElem)
455 }
456 }
457 if !elemNil && (typ == "ptr" || typ == "i8") {
458 if gt, ok := e.globalTypes[name]; ok && gt != "ptr" && gt != "void" && gt != "" {
459 typ = gt
460 }
461 }
462 if typ == "void" {
463 typ = "i1"
464 }
465 e.globalDeclTypes[name] = typ
466 return typ
467 }
468
469 func (e *irEmitter) emitGlobal(g *ssa.SSAGlobal) {
470 name := e.globalName(g)
471 typ := e.resolveGlobalDeclType(g)
472 e.w(name)
473 e.w(" = global ")
474 e.w(typ)
475 e.w(" zeroinitializer\n")
476 }
477
478 func (e *irEmitter) globalName(g *ssa.SSAGlobal) string {
479 pkg := e.pkg.Pkg.Path()
480 if g.MemberPkg() != nil {
481 pkg = g.MemberPkg().Pkg.Path()
482 }
483 return irGlobalSymbol(pkg, g.MemberName())
484 }
485
486 func irNeedsQuote(s string) bool {
487 for i := 0; i < len(s); i++ {
488 c := s[i]
489 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '$' {
490 continue
491 }
492 return true
493 }
494 return false
495 }
496
497 func irGlobalSymbol(pkg, name string) string {
498 return IrGlobalSymbol(pkg, name)
499 }
500
501 func IrGlobalSymbol(pkg, name string) string {
502 sym := pkg | "." | name
503 if irNeedsQuote(sym) {
504 return "@\"" | sym | "\""
505 }
506 return "@" | sym
507 }
508
509 func (e *irEmitter) funcSymbol(f *ssa.SSAFunction) string {
510 if f.ExternalSymbol() != "" {
511 sym := f.ExternalSymbol()
512 if irNeedsQuote(sym) {
513 return "@\"" | sym | "\""
514 }
515 return "@" | sym
516 }
517 pkg := e.pkg.Pkg.Path()
518 if f.Pkg != nil {
519 pkg = f.Pkg.Pkg.Path()
520 }
521 return irGlobalSymbol(pkg, f.SSAName())
522 }
523
524 func (e *irEmitter) isPkgFunc(f *ssa.SSAFunction) bool {
525 if f.Pkg == e.pkg {
526 return true
527 }
528 if f.SSAParent() != nil {
529 return e.isPkgFunc(f.SSAParent())
530 }
531 return false
532 }
533
534 func (e *irEmitter) emitAnonFuncs(f *ssa.SSAFunction) {
535 for _, af := range f.AnonFuncs {
536 e.emitFunction(af)
537 e.emitAnonFuncs(af)
538 af.Blocks = nil
539 af.Locals = nil
540 af.Params = nil
541 af.FreeVars = nil
542 af.NamedResults = nil
543 af.vars = nil
544 }
545 f.AnonFuncs = nil
546 }
547
548 func (e *irEmitter) emitLibMain() {
549 pkgPath := e.pkg.Pkg.Path()
550 if pkgPath == "main" {
551 return
552 }
553 hasMain := false
554 for _, m := range e.pkg.Members {
555 if fn, ok := m.(*ssa.SSAFunction); ok && fn.SSAName() == "main" {
556 hasMain = true
557 break
558 }
559 }
560 if hasMain {
561 return
562 }
563 sym := irGlobalSymbol(pkgPath, "main")
564 e.w("\ndefine hidden void ")
565 e.w(sym)
566 e.w("(ptr %context) {\nentry:\n ret void\n}\n")
567 }
568
569 func (e *irEmitter) asmAlias(linkName string) string {
570 switch linkName {
571 case "math.archLog":
572 return "math.log"
573 case "math.archExp":
574 return "math.exp"
575 case "math.archExp2":
576 return "math.exp2"
577 case "math.archFloor":
578 return "math.floor"
579 case "math.archCeil":
580 return "math.ceil"
581 case "math.archTrunc":
582 return "math.trunc"
583 case "math.archHypot":
584 return "math.hypot"
585 case "math.archMax":
586 return "math.max"
587 case "math.archMin":
588 return "math.min"
589 case "math.archModf":
590 return "math.modf"
591 case "crypto/md5.block":
592 return "crypto/md5.blockGeneric"
593 case "crypto/sha1.block":
594 return "crypto/sha1.blockGeneric"
595 case "crypto/sha1.blockAMD64":
596 return "crypto/sha1.blockGeneric"
597 case "crypto/sha256.block":
598 return "crypto/sha256.blockGeneric"
599 case "crypto/sha512.blockAMD64":
600 return "crypto/sha512.blockGeneric"
601 }
602 return ""
603 }
604