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