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