ir_emit.mx raw

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