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