ir_emit.mx raw

   1  package main
   2  
   3  import (
   4  	"bytes"
   5  	"go/constant"
   6  	"go/token"
   7  )
   8  
   9  type irEmitter struct {
  10  	buf        []byte
  11  	triple     string
  12  	ptrBits    int
  13  	pkg        *SSAPackage
  14  	valName    map[SSAValue]string
  15  	nextReg    int
  16  	extDecls   map[string]string
  17  	extGlobals map[string]string
  18  	strConst   []string
  19  	strMap     map[string]int
  20  	curFunc    *SSAFunction
  21  	typeIDs    map[string]bool
  22  	allocTypes map[SSAValue]string
  23  	hoisted    map[SSAValue]bool
  24  }
  25  
  26  func newIREmitter(pkg *SSAPackage, triple string) *irEmitter {
  27  	ptrBits := 64
  28  	if len(triple) >= 4 && triple[:4] == "wasm" {
  29  		ptrBits = 32
  30  	}
  31  	return &irEmitter{
  32  		buf:      []byte{:0:4096},
  33  		triple:   triple,
  34  		ptrBits:  ptrBits,
  35  		pkg:      pkg,
  36  		valName:  map[SSAValue]string{},
  37  		extDecls:   map[string]string{},
  38  		extGlobals: map[string]string{},
  39  		strMap:     map[string]int{},
  40  		allocTypes: map[SSAValue]string{},
  41  	}
  42  }
  43  
  44  func (e *irEmitter) dataLayout() string {
  45  	if len(e.triple) >= 6 && e.triple[:6] == "x86_64" {
  46  		return "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
  47  	}
  48  	if len(e.triple) >= 7 && e.triple[:7] == "aarch64" {
  49  		return "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
  50  	}
  51  	if len(e.triple) >= 6 && e.triple[:6] == "wasm32" {
  52  		return "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
  53  	}
  54  	if len(e.triple) >= 3 && e.triple[:3] == "arm" {
  55  		return "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
  56  	}
  57  	return ""
  58  }
  59  
  60  func (e *irEmitter) w(s string) {
  61  	e.buf = append(e.buf, s...)
  62  }
  63  
  64  func (e *irEmitter) regName(v SSAValue) string {
  65  	if n, ok := e.valName[v]; ok {
  66  		return n
  67  	}
  68  	name := v.SSAName()
  69  	if name == "" {
  70  		e.nextReg++
  71  		name = "r" | irItoa(e.nextReg)
  72  	}
  73  	n := "%" | name
  74  	e.valName[v] = n
  75  	return n
  76  }
  77  
  78  func (e *irEmitter) llvmType(t Type) string {
  79  	if t == nil {
  80  		return "void"
  81  	}
  82  	u := safeUnderlying(t)
  83  	if u == nil {
  84  		if _, ok := t.(*Slice); ok {
  85  			return e.sliceType()
  86  		}
  87  		if n, ok := t.(*Named); ok {
  88  			_ = n
  89  			return "ptr"
  90  		}
  91  		return "ptr"
  92  	}
  93  	t = u
  94  	switch t := t.(type) {
  95  	case *Basic:
  96  		return e.llvmBasicType(t)
  97  	case *Pointer:
  98  		return "ptr"
  99  	case *Slice:
 100  		return e.sliceType()
 101  	case *Array:
 102  		n := t.Len()
 103  		elem := e.llvmType(t.Elem())
 104  		return "[" | irItoa(int(n)) | " x " | elem | "]"
 105  	case *TCStruct:
 106  		return e.llvmStructType(t)
 107  	case *Signature:
 108  		return "{ptr, ptr}"
 109  	case *TCMap:
 110  		return "ptr"
 111  	case *TCChan:
 112  		return "ptr"
 113  	case *TCInterface:
 114  		return e.ifaceType()
 115  	case *Tuple:
 116  		if t.Len() == 0 {
 117  			return "void"
 118  		}
 119  		if t.Len() == 1 {
 120  			return e.llvmType(t.At(0).Type())
 121  		}
 122  		s := "{"
 123  		for i := 0; i < t.Len(); i++ {
 124  			if i > 0 {
 125  				s = s | ", "
 126  			}
 127  			ft := e.llvmType(t.At(i).Type())
 128  			if ft == "void" {
 129  				ft = "ptr"
 130  			}
 131  			s = s | ft
 132  		}
 133  		return s | "}"
 134  	}
 135  	return "i8"
 136  }
 137  
 138  func (e *irEmitter) llvmBasicType(t *Basic) string {
 139  	switch t.Kind() {
 140  	case Bool:
 141  		return "i1"
 142  	case Int8, Uint8:
 143  		return "i8"
 144  	case Int16, Uint16:
 145  		return "i16"
 146  	case Int32, Uint32:
 147  		return "i32"
 148  	case Int64, Uint64:
 149  		return "i64"
 150  	case Float32:
 151  		return "float"
 152  	case Float64:
 153  		return "double"
 154  	case TCString:
 155  		return e.sliceType()
 156  	case UnsafePointer:
 157  		return "ptr"
 158  	case UntypedBool:
 159  		return "i1"
 160  	case UntypedInt, UntypedRune:
 161  		return "i32"
 162  	case UntypedFloat:
 163  		return "double"
 164  	case UntypedString:
 165  		return e.sliceType()
 166  	}
 167  	return "i32"
 168  }
 169  
 170  func (e *irEmitter) ptrType() string {
 171  	return "ptr"
 172  }
 173  
 174  func (e *irEmitter) intptrType() string {
 175  	if e.ptrBits == 32 {
 176  		return "i32"
 177  	}
 178  	return "i64"
 179  }
 180  
 181  func (e *irEmitter) sliceType() string {
 182  	ipt := e.intptrType()
 183  	return "{ptr, " | ipt | ", " | ipt | "}"
 184  }
 185  
 186  func (e *irEmitter) ifaceType() string {
 187  	return "{ptr, ptr}"
 188  }
 189  
 190  func (e *irEmitter) llvmStructType(t *TCStruct) string {
 191  	s := "{"
 192  	for i := 0; i < t.NumFields(); i++ {
 193  		if i > 0 {
 194  			s = s | ", "
 195  		}
 196  		ft := e.llvmType(t.Field(i).Type())
 197  		if ft == "void" {
 198  			ft = "ptr"
 199  		}
 200  		s = s | ft
 201  	}
 202  	return s | "}"
 203  }
 204  
 205  func (e *irEmitter) declareRuntime(name, retType, params string) {
 206  	e.extDecls[name] = retType | " @" | name | "(" | params | ")"
 207  }
 208  
 209  func (e *irEmitter) declareExternalGlobal(g *SSAGlobal) {
 210  	if g.pkg == nil || g.pkg == e.pkg {
 211  		return
 212  	}
 213  	name := e.globalName(g)
 214  	if _, ok := e.extGlobals[name]; ok {
 215  		return
 216  	}
 217  	typ := e.llvmType(g.typ)
 218  	if p, ok := safeUnderlying(g.typ).(*Pointer); ok {
 219  		typ = e.llvmType(p.Elem())
 220  	}
 221  	e.extGlobals[name] = typ
 222  }
 223  
 224  func (e *irEmitter) declareExternalFunc(fn *SSAFunction) {
 225  	sym := e.funcSymbol(fn)
 226  	if _, ok := e.extDecls[sym]; ok {
 227  		return
 228  	}
 229  	retType := e.funcRetType(fn)
 230  	params := ""
 231  	if fn.Signature != nil && fn.Signature.Params() != nil {
 232  		for i := 0; i < fn.Signature.Params().Len(); i++ {
 233  			if i > 0 {
 234  				params = params | ", "
 235  			}
 236  			params = params | e.llvmType(fn.Signature.Params().At(i).Type())
 237  		}
 238  	}
 239  	if params != "" {
 240  		params = params | ", "
 241  	}
 242  	params = params | "ptr"
 243  	e.extDecls[sym] = retType | " " | sym | "(" | params | ")"
 244  }
 245  
 246  func (e *irEmitter) addStringConst(s string) int {
 247  	if idx, ok := e.strMap[s]; ok {
 248  		return idx
 249  	}
 250  	idx := len(e.strConst)
 251  	e.strConst = append(e.strConst, s)
 252  	e.strMap[s] = idx
 253  	return idx
 254  }
 255  
 256  func (e *irEmitter) strConstGlobal(idx int) string {
 257  	return "@.str." | irItoa(idx)
 258  }
 259  
 260  func irEscapeString(s string) string {
 261  	var buf []byte
 262  	for i := 0; i < len(s); i++ {
 263  		c := s[i]
 264  		if c >= 32 && c < 127 && c != '\\' && c != '"' {
 265  			buf = append(buf, c)
 266  		} else {
 267  			buf = append(buf, '\\')
 268  			buf = append(buf, "0123456789ABCDEF"[c>>4])
 269  			buf = append(buf, "0123456789ABCDEF"[c&0xf])
 270  		}
 271  	}
 272  	return string(buf)
 273  }
 274  
 275  func (e *irEmitter) emit() string {
 276  	dl := e.dataLayout()
 277  	if dl != "" {
 278  		e.w("target datalayout = \"")
 279  		e.w(dl)
 280  		e.w("\"\n")
 281  	}
 282  	e.w("target triple = \"")
 283  	e.w(e.triple)
 284  	e.w("\"\n\n")
 285  
 286  	for _, member := range e.pkgMembersSorted() {
 287  		switch m := member.(type) {
 288  		case *SSAGlobal:
 289  			if m.name != "_" {
 290  				e.emitGlobal(m)
 291  			}
 292  		}
 293  	}
 294  
 295  	for _, member := range e.pkgMembersSorted() {
 296  		switch m := member.(type) {
 297  		case *SSAFunction:
 298  			e.emitFunction(m)
 299  			e.emitAnonFuncs(m)
 300  		}
 301  	}
 302  
 303  	e.emitInitFunction()
 304  
 305  	for i, s := range e.strConst {
 306  		e.w(e.strConstGlobal(i))
 307  		e.w(" = private constant [")
 308  		e.w(irItoa(len(s)))
 309  		e.w(" x i8] c\"")
 310  		e.w(irEscapeString(s))
 311  		e.w("\"\n")
 312  	}
 313  
 314  	for name := range e.typeIDs {
 315  		e.w("@")
 316  		e.w(name)
 317  		e.w(" = private constant i8 0\n")
 318  	}
 319  
 320  	if len(e.extDecls) > 0 {
 321  		e.w("\n")
 322  		for _, decl := range e.extDecls {
 323  			e.w("declare ")
 324  			e.w(decl)
 325  			e.w("\n")
 326  		}
 327  	}
 328  
 329  	if len(e.extGlobals) > 0 {
 330  		e.w("\n")
 331  		for name, typ := range e.extGlobals {
 332  			e.w(name)
 333  			e.w(" = external global ")
 334  			e.w(typ)
 335  			e.w("\n")
 336  		}
 337  	}
 338  
 339  	return string(e.buf)
 340  }
 341  
 342  func (e *irEmitter) pkgMembersSorted() []SSAMember {
 343  	var members []SSAMember
 344  	for _, m := range e.pkg.Members {
 345  		members = append(members, m)
 346  	}
 347  	for i := 1; i < len(members); i++ {
 348  		for j := i; j > 0 && members[j].MemberName() < members[j-1].MemberName(); j-- {
 349  			members[j], members[j-1] = members[j-1], members[j]
 350  		}
 351  	}
 352  	return members
 353  }
 354  
 355  func (e *irEmitter) emitGlobal(g *SSAGlobal) {
 356  	name := e.globalName(g)
 357  	typ := e.llvmType(g.typ)
 358  	if p, ok := safeUnderlying(g.typ).(*Pointer); ok {
 359  		typ = e.llvmType(p.Elem())
 360  	}
 361  	e.w(name)
 362  	e.w(" = global ")
 363  	e.w(typ)
 364  	e.w(" zeroinitializer\n")
 365  }
 366  
 367  func (e *irEmitter) globalName(g *SSAGlobal) string {
 368  	pkg := e.pkg.Pkg.Path()
 369  	if g.pkg != nil {
 370  		pkg = g.pkg.Pkg.Path()
 371  	}
 372  	return irGlobalSymbol(pkg, g.name)
 373  }
 374  
 375  func irNeedsQuote(s string) bool {
 376  	for i := 0; i < len(s); i++ {
 377  		c := s[i]
 378  		if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '$' {
 379  			continue
 380  		}
 381  		return true
 382  	}
 383  	return false
 384  }
 385  
 386  func irGlobalSymbol(pkg, name string) string {
 387  	sym := pkg | "." | name
 388  	if irNeedsQuote(sym) {
 389  		return "@\"" | sym | "\""
 390  	}
 391  	return "@" | sym
 392  }
 393  
 394  func (e *irEmitter) funcSymbol(f *SSAFunction) string {
 395  	pkg := e.pkg.Pkg.Path()
 396  	if f.Pkg != nil {
 397  		pkg = f.Pkg.Pkg.Path()
 398  	}
 399  	return irGlobalSymbol(pkg, f.name)
 400  }
 401  
 402  func (e *irEmitter) isPkgFunc(f *SSAFunction) bool {
 403  	if f.Pkg == e.pkg {
 404  		return true
 405  	}
 406  	if f.parent != nil {
 407  		return e.isPkgFunc(f.parent)
 408  	}
 409  	return false
 410  }
 411  
 412  func (e *irEmitter) emitAnonFuncs(f *SSAFunction) {
 413  	for _, af := range f.AnonFuncs {
 414  		e.emitFunction(af)
 415  		e.emitAnonFuncs(af)
 416  	}
 417  }
 418  
 419  func (e *irEmitter) emitInitFunction() {
 420  	pkgPath := e.pkg.Pkg.Path()
 421  	hasInit := false
 422  	for _, m := range e.pkg.Members {
 423  		if fn, ok := m.(*SSAFunction); ok && fn.name == "init" {
 424  			hasInit = true
 425  			break
 426  		}
 427  	}
 428  	if hasInit {
 429  		return
 430  	}
 431  	e.w("\ndefine void @")
 432  	e.w(pkgPath)
 433  	e.w(".init(ptr %context) {\nentry:\n  ret void\n}\n")
 434  }
 435  
 436  func (e *irEmitter) emitFunction(f *SSAFunction) {
 437  	e.w("; [emit] " | f.name | "\n")
 438  	if len(f.Blocks) == 0 {
 439  		e.emitFuncDecl(f)
 440  		return
 441  	}
 442  	e.curFunc = f
 443  	e.nextReg = 0
 444  	e.valName = map[SSAValue]string{}
 445  
 446  	for i, p := range f.Params {
 447  		pname := p.SSAName()
 448  		if pname == "" {
 449  			pname = "p" | irItoa(i)
 450  		}
 451  		e.valName[p] = "%" | pname
 452  	}
 453  
 454  	e.w("\ndefine ")
 455  	e.w(e.funcRetType(f))
 456  	e.w(" ")
 457  	e.w(e.funcSymbol(f))
 458  	e.w("(")
 459  	for i, p := range f.Params {
 460  		if i > 0 {
 461  			e.w(", ")
 462  		}
 463  		e.w(e.llvmType(p.SSAType()))
 464  		e.w(" ")
 465  		e.w(e.regName(p))
 466  	}
 467  	if len(f.Params) > 0 {
 468  		e.w(", ")
 469  	}
 470  	ctxName := "context"
 471  	for _, p := range f.Params {
 472  		if p.SSAName() == "context" {
 473  			ctxName = "context.1"
 474  			break
 475  		}
 476  	}
 477  	e.w("ptr %")
 478  	e.w(ctxName)
 479  	e.w(") {\n")
 480  
 481  	// Pre-scan: set allocTypes, detect cross-block alloca references
 482  	allocBlock := map[SSAValue]int{}
 483  	for _, b := range f.Blocks {
 484  		for _, instr := range b.Instrs {
 485  			if n, ok := instr.(*SSANext); ok {
 486  				if ri, ok2 := n.Iter.(*SSARange); ok2 {
 487  					if arr, ok3 := safeUnderlying(ri.X.SSAType()).(*Array); ok3 {
 488  						elemType := e.llvmType(arr.Elem())
 489  						e.allocTypes[n] = "{i1, i32, " | elemType | "}"
 490  					}
 491  				}
 492  			}
 493  			if c, ok := instr.(*SSACall); ok {
 494  				if b2, ok2 := c.Call.Value.(*SSABuiltin); ok2 && b2.SSAName() == "recover" {
 495  					e.allocTypes[c] = e.ifaceType()
 496  				}
 497  			}
 498  			if a, ok := instr.(*SSAAlloc); ok {
 499  				allocBlock[a] = b.Index
 500  			}
 501  		}
 502  	}
 503  	hoistAllocs := map[SSAValue]bool{}
 504  	for _, b := range f.Blocks {
 505  		for _, instr := range b.Instrs {
 506  			refs := e.instrOperands(instr)
 507  			for _, ref := range refs {
 508  				if ab, ok := allocBlock[ref]; ok && ab != 0 && ab != b.Index {
 509  					hoistAllocs[ref] = true
 510  				}
 511  			}
 512  		}
 513  	}
 514  	e.hoisted = hoistAllocs
 515  
 516  	for _, b := range f.Blocks {
 517  		if b.Index == 0 {
 518  			e.w("entry:\n")
 519  			for v := range hoistAllocs {
 520  				if a, ok := v.(*SSAAlloc); ok {
 521  					e.emitAlloc(a)
 522  				}
 523  			}
 524  			if len(e.curFunc.FreeVars) > 0 {
 525  				e.emitFreeVarUnpack(e.curFunc)
 526  			}
 527  			for _, instr := range b.Instrs {
 528  				e.emitInstr(instr)
 529  			}
 530  		} else {
 531  			e.emitBlock(b)
 532  		}
 533  	}
 534  	e.hoisted = nil
 535  
 536  	e.w("}\n")
 537  }
 538  
 539  func (e *irEmitter) emitFuncDecl(f *SSAFunction) {
 540  	e.w("\ndeclare ")
 541  	e.w(e.funcRetType(f))
 542  	e.w(" ")
 543  	e.w(e.funcSymbol(f))
 544  	e.w("(")
 545  	if f.Signature != nil && f.Signature.Params() != nil {
 546  		for i := 0; i < f.Signature.Params().Len(); i++ {
 547  			if i > 0 {
 548  				e.w(", ")
 549  			}
 550  			e.w(e.llvmType(f.Signature.Params().At(i).Type()))
 551  		}
 552  		if f.Signature.Params().Len() > 0 {
 553  			e.w(", ")
 554  		}
 555  	}
 556  	e.w("ptr")
 557  	e.w(")\n")
 558  }
 559  
 560  func (e *irEmitter) funcRetType(f *SSAFunction) string {
 561  	if f.Signature == nil || f.Signature.Results() == nil || f.Signature.Results().Len() == 0 {
 562  		return "void"
 563  	}
 564  	if f.Signature.Results().Len() == 1 {
 565  		return e.llvmType(f.Signature.Results().At(0).Type())
 566  	}
 567  	s := "{"
 568  	for i := 0; i < f.Signature.Results().Len(); i++ {
 569  		if i > 0 {
 570  			s = s | ", "
 571  		}
 572  		s = s | e.llvmType(f.Signature.Results().At(i).Type())
 573  	}
 574  	return s | "}"
 575  }
 576  
 577  func (e *irEmitter) emitBlock(b *SSABasicBlock) {
 578  	label := "b" | irItoa(b.Index)
 579  	if b.Index == 0 {
 580  		label = "entry"
 581  	}
 582  	e.w(label)
 583  	e.w(":\n")
 584  
 585  	if b.Index == 0 && len(e.curFunc.FreeVars) > 0 {
 586  		e.emitFreeVarUnpack(e.curFunc)
 587  	}
 588  
 589  	for _, instr := range b.Instrs {
 590  		e.emitInstr(instr)
 591  	}
 592  }
 593  
 594  func (e *irEmitter) blockLabel(b *SSABasicBlock) string {
 595  	if b.Index == 0 {
 596  		return "%entry"
 597  	}
 598  	return "%b" | irItoa(b.Index)
 599  }
 600  
 601  func (e *irEmitter) emitInstr(instr SSAInstruction) {
 602  	switch i := instr.(type) {
 603  	case *SSAAlloc:
 604  		if e.hoisted != nil && e.hoisted[i] {
 605  			break
 606  		}
 607  		e.emitAlloc(i)
 608  	case *SSAStore:
 609  		e.emitStore(i)
 610  	case *SSABinOp:
 611  		e.emitBinOp(i)
 612  	case *SSAUnOp:
 613  		e.emitUnOp(i)
 614  	case *SSACall:
 615  		e.emitCall(i)
 616  	case *SSAPhi:
 617  		e.emitPhi(i)
 618  	case *SSAReturn:
 619  		e.emitReturn(i)
 620  	case *SSAJump:
 621  		e.emitJump(i)
 622  	case *SSAIf:
 623  		e.emitIf(i)
 624  	case *SSAConvert:
 625  		e.emitConvert(i)
 626  	case *SSAChangeType:
 627  		e.emitChangeType(i)
 628  	case *SSAFieldAddr:
 629  		e.emitFieldAddr(i)
 630  	case *SSAIndexAddr:
 631  		e.emitIndexAddr(i)
 632  	case *SSAExtract:
 633  		e.emitExtract(i)
 634  	case *SSAMakeSlice:
 635  		e.emitMakeSlice(i)
 636  	case *SSASlice:
 637  		e.emitSliceOp(i)
 638  	case *SSAMakeInterface:
 639  		e.emitMakeInterface(i)
 640  	case *SSAInvoke:
 641  		e.emitInvoke(i)
 642  	case *SSATypeAssert:
 643  		e.emitTypeAssert(i)
 644  	case *SSAMakeMap:
 645  		e.emitMakeMap(i)
 646  	case *SSAMapUpdate:
 647  		e.emitMapUpdate(i)
 648  	case *SSALookup:
 649  		e.emitLookup(i)
 650  	case *SSAMakeClosure:
 651  		e.emitMakeClosure(i)
 652  	case *SSAPanic:
 653  		e.emitPanic(i)
 654  	case *SSARunDefers:
 655  		e.w("  ; rundefers\n")
 656  	case *SSADefer:
 657  		e.w("  ; defer\n")
 658  	case *SSASend:
 659  		e.w("  ; send\n")
 660  	case *SSAGo:
 661  		e.w("  ; go\n")
 662  	case *SSASelect:
 663  		e.w("  ; select\n")
 664  	case *SSARange:
 665  		e.emitRange(i)
 666  	case *SSANext:
 667  		e.emitNext(i)
 668  	case *SSAMakeChan:
 669  		e.w("  ; makechan\n")
 670  	}
 671  }
 672  
 673  func (e *irEmitter) emitAlloc(a *SSAAlloc) {
 674  	reg := e.regName(a)
 675  	elemType := e.llvmType(a.SSAType())
 676  	nilElem := false
 677  	if p, ok := safeUnderlying(a.SSAType()).(*Pointer); ok {
 678  		if p.Elem() != nil {
 679  			elemType = e.llvmType(p.Elem())
 680  		} else {
 681  			nilElem = true
 682  		}
 683  	}
 684  	if elemType == "void" || (elemType == "ptr" && nilElem) {
 685  		inferred := e.inferAllocTypeFromStores(a)
 686  		if inferred != "ptr" || elemType == "void" {
 687  			elemType = inferred
 688  		}
 689  		e.allocTypes[a] = elemType
 690  	} else {
 691  		override := e.inferAllocTypeFromStores(a)
 692  		if override != "ptr" && override != elemType {
 693  			bothScalar := len(elemType) > 0 && elemType[0] == 'i' && len(override) > 0 && override[0] == 'i'
 694  			if !bothScalar {
 695  				elemType = override
 696  				e.allocTypes[a] = elemType
 697  			}
 698  		}
 699  	}
 700  	if a.Heap {
 701  		ipt := e.intptrType()
 702  		e.nextReg++
 703  		sz := "%ha" | irItoa(e.nextReg)
 704  		e.w("  ") ; e.w(sz)
 705  		e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
 706  		e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
 707  		e.w("  ") ; e.w(reg)
 708  		e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
 709  		e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
 710  		e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
 711  	} else {
 712  		e.w("  ")
 713  		e.w(reg)
 714  		e.w(" = alloca ")
 715  		e.w(elemType)
 716  		e.w("\n")
 717  	}
 718  }
 719  
 720  func (e *irEmitter) inferAllocTypeFromStores(a *SSAAlloc) string {
 721  	for _, b := range e.curFunc.Blocks {
 722  		for _, instr := range b.Instrs {
 723  			if s, ok := instr.(*SSAStore); ok && s.Addr == a {
 724  				// Check allocTypes override first
 725  				if at, ok2 := e.allocTypes[s.Val]; ok2 && at != "ptr" && at != "void" {
 726  					return at
 727  				}
 728  				vt := e.llvmType(s.Val.SSAType())
 729  				if vt != "void" && vt != "" {
 730  					return vt
 731  				}
 732  				// Check if stored value is an append builtin call (result is always a slice)
 733  				if call, ok := s.Val.(*SSACall); ok {
 734  					if b, ok2 := call.Call.Value.(*SSABuiltin); ok2 && b.SSAName() == "append" {
 735  						return e.sliceType()
 736  					}
 737  				}
 738  			}
 739  		}
 740  	}
 741  	return "ptr"
 742  }
 743  
 744  func (e *irEmitter) emitStore(s *SSAStore) {
 745  	valType := e.llvmType(s.Val.SSAType())
 746  	val := e.operand(s.Val)
 747  	if at, ok := e.allocTypes[s.Val]; ok && at != valType {
 748  		bothScalar := len(valType) > 0 && valType[0] == 'i' && len(at) > 0 && at[0] == 'i'
 749  		if !bothScalar {
 750  			valType = at
 751  			if val == "null" && valType != "ptr" {
 752  				val = "zeroinitializer"
 753  			}
 754  		}
 755  	}
 756  	// If value type is still generic ptr but the address has a known alloc type, use that
 757  	if valType == "ptr" || valType == "void" {
 758  		if at, ok := e.allocTypes[s.Addr]; ok && at != "ptr" && at != "void" {
 759  			valType = at
 760  			if val == "null" && valType != "ptr" {
 761  				val = "zeroinitializer"
 762  			}
 763  		}
 764  	}
 765  	if valType == "void" {
 766  		if p, ok := safeUnderlying(s.Addr.SSAType()).(*Pointer); ok {
 767  			valType = e.llvmType(p.Elem())
 768  		}
 769  		if valType == "void" {
 770  			valType = "ptr"
 771  		}
 772  		if val == "null" && valType != "ptr" {
 773  			val = "zeroinitializer"
 774  		}
 775  	}
 776  	addr := e.operand(s.Addr)
 777  	e.w("  store ")
 778  	e.w(valType)
 779  	e.w(" ")
 780  	e.w(val)
 781  	e.w(", ptr ")
 782  	e.w(addr)
 783  	e.w("\n")
 784  }
 785  
 786  func (e *irEmitter) emitZeroReg(reg string, typ Type) {
 787  	rt := e.llvmType(typ)
 788  	if rt == "void" || rt == "" {
 789  		rt = "i32"
 790  	}
 791  	if rt == "ptr" {
 792  		e.w("  ") ; e.w(reg) ; e.w(" = inttoptr i64 0 to ptr\n")
 793  	} else if rt == "i1" {
 794  		e.w("  ") ; e.w(reg) ; e.w(" = add i1 false, false\n")
 795  	} else if e.intBits(rt) > 0 {
 796  		e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(rt) ; e.w(" 0, 0\n")
 797  	} else {
 798  		e.w("  ") ; e.w(reg) ; e.w(" = add i32 0, 0\n")
 799  	}
 800  }
 801  
 802  func (e *irEmitter) emitBinOp(b *SSABinOp) {
 803  	if b.X == nil || b.X.SSAType() == nil {
 804  		e.emitZeroReg(e.regName(b), b.SSAType())
 805  		return
 806  	}
 807  	reg := e.regName(b)
 808  	lt := e.llvmType(b.X.SSAType())
 809  	if lt == "void" && b.Y != nil {
 810  		lt = e.llvmType(b.Y.SSAType())
 811  	}
 812  	if at, ok := e.allocTypes[b.X]; ok && at != "ptr" && at != "void" && at != lt {
 813  		lt = at
 814  	}
 815  	lv := e.operand(b.X)
 816  	rv := e.operand(b.Y)
 817  	if (b.Op == OpAdd || b.Op == OpOr) && b.X.SSAType() != nil {
 818  		if sl, ok := safeUnderlying(b.X.SSAType()).(*Slice); ok {
 819  			e.emitSliceConcat(reg, sl, lv, rv)
 820  			return
 821  		}
 822  		if e.isStringLike(b.X.SSAType()) {
 823  			e.emitSliceConcat(reg, NewSlice(Typ[Uint8]), lv, rv)
 824  			return
 825  		}
 826  	}
 827  	if b.X.SSAType() != nil && e.isStringLike(b.X.SSAType()) {
 828  		isActuallyIface := false
 829  		if at, ok := e.allocTypes[b.X]; ok && at == e.ifaceType() {
 830  			isActuallyIface = true
 831  		}
 832  		if !isActuallyIface {
 833  			e.emitStringCompare(reg, b.Op, lv, rv)
 834  			return
 835  		}
 836  	}
 837  	if (b.Op == OpEql || b.Op == OpNeq) && (rv == "null" || rv == "zeroinitializer" || lv == "null" || lv == "zeroinitializer") && b.X.SSAType() != nil {
 838  		u := safeUnderlying(b.X.SSAType())
 839  		_, isIface := u.(*TCInterface)
 840  		_, isSlice := u.(*Slice)
 841  		_, isSig := u.(*Signature)
 842  		_, isPtr := u.(*Pointer)
 843  		if !isIface && !isSlice && !isSig && !isPtr && u == nil && (lt == "{ptr, ptr}" || lt == "{ptr, i64}") {
 844  			isIface = true
 845  		}
 846  		if isIface || isSlice || isSig || e.isStringLike(b.X.SSAType()) {
 847  			e.nextReg++
 848  			extReg := "%ne" | irItoa(e.nextReg)
 849  			aggVal := lv
 850  			if lv == "null" || lv == "zeroinitializer" {
 851  				aggVal = rv
 852  			}
 853  			e.w("  ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(aggVal) ; e.w(", 0\n")
 854  			cmpOp := "icmp eq"
 855  			if b.Op == OpNeq {
 856  				cmpOp = "icmp ne"
 857  			}
 858  			e.w("  ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", null\n")
 859  			return
 860  		}
 861  		if isPtr {
 862  			cmpOp := "icmp eq"
 863  			if b.Op == OpNeq {
 864  				cmpOp = "icmp ne"
 865  			}
 866  			ptrVal := lv
 867  			if lv == "null" || lv == "zeroinitializer" {
 868  				ptrVal = rv
 869  			}
 870  			e.w("  ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(ptrVal) ; e.w(", null\n")
 871  			return
 872  		}
 873  	}
 874  	if (b.Op == OpEql || b.Op == OpNeq) && b.X.SSAType() != nil {
 875  		if st, ok := safeUnderlying(b.X.SSAType()).(*TCStruct); ok {
 876  			e.emitStructCompare(reg, b.Op, st, lt, lv, rv)
 877  			return
 878  		}
 879  		u2 := safeUnderlying(b.X.SSAType())
 880  		_, isSig2 := u2.(*Signature)
 881  		_, isIfce2 := u2.(*TCInterface)
 882  		if !isSig2 && !isIfce2 && u2 == nil && lt == "{ptr, ptr}" {
 883  			isIfce2 = true
 884  		}
 885  		if isSig2 || isIfce2 {
 886  			rt2 := "ptr"
 887  			if b.Y != nil && b.Y.SSAType() != nil {
 888  				rt2 = e.llvmType(b.Y.SSAType())
 889  			}
 890  			if lt == "{ptr, ptr}" && rt2 == "ptr" {
 891  				e.nextReg++
 892  				extReg := "%fc" | irItoa(e.nextReg)
 893  				e.w("  ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 0\n")
 894  				cmpOp := "icmp eq"
 895  				if b.Op == OpNeq { cmpOp = "icmp ne" }
 896  				e.w("  ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", ") ; e.w(rv) ; e.w("\n")
 897  				return
 898  			}
 899  			if lt == "ptr" && rt2 == "{ptr, ptr}" {
 900  				e.nextReg++
 901  				extReg := "%fc" | irItoa(e.nextReg)
 902  				e.w("  ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 0\n")
 903  				cmpOp := "icmp eq"
 904  				if b.Op == OpNeq { cmpOp = "icmp ne" }
 905  				e.w("  ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(lv) ; e.w(", ") ; e.w(extReg) ; e.w("\n")
 906  				return
 907  			}
 908  			e.nextReg++
 909  			pA := "%fc" | irItoa(e.nextReg)
 910  			e.nextReg++
 911  			pB := "%fc" | irItoa(e.nextReg)
 912  			e.nextReg++
 913  			qA := "%fc" | irItoa(e.nextReg)
 914  			e.nextReg++
 915  			qB := "%fc" | irItoa(e.nextReg)
 916  			e.nextReg++
 917  			cA := "%fc" | irItoa(e.nextReg)
 918  			e.nextReg++
 919  			cB := "%fc" | irItoa(e.nextReg)
 920  			e.w("  ") ; e.w(pA) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 0\n")
 921  			e.w("  ") ; e.w(pB) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 0\n")
 922  			e.w("  ") ; e.w(qA) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 1\n")
 923  			e.w("  ") ; e.w(qB) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 1\n")
 924  			cmpOp := "icmp eq"
 925  			combOp := "and"
 926  			if b.Op == OpNeq {
 927  				cmpOp = "icmp ne"
 928  				combOp = "or"
 929  			}
 930  			e.w("  ") ; e.w(cA) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(pA) ; e.w(", ") ; e.w(pB) ; e.w("\n")
 931  			e.w("  ") ; e.w(cB) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(qA) ; e.w(", ") ; e.w(qB) ; e.w("\n")
 932  			e.w("  ") ; e.w(reg) ; e.w(" = ") ; e.w(combOp) ; e.w(" i1 ") ; e.w(cA) ; e.w(", ") ; e.w(cB) ; e.w("\n")
 933  			return
 934  		}
 935  	}
 936  	if b.Op == OpAndNot {
 937  		e.nextReg++
 938  		notReg := "%an" | irItoa(e.nextReg)
 939  		allOnes := "-1"
 940  		e.w("  ") ; e.w(notReg) ; e.w(" = xor ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(allOnes) ; e.w("\n")
 941  		e.w("  ") ; e.w(reg) ; e.w(" = and ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(notReg) ; e.w("\n")
 942  		return
 943  	}
 944  	if b.Y == nil || b.Y.SSAType() == nil {
 945  		e.emitZeroReg(e.regName(b), b.SSAType())
 946  		return
 947  	}
 948  	rt := e.llvmType(b.Y.SSAType())
 949  	if lt != rt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
 950  		resType := e.llvmType(b.SSAType())
 951  		if e.intBits(resType) > 0 {
 952  			if lt != resType {
 953  				lv = e.coerceInt(lv, lt, resType)
 954  				lt = resType
 955  			}
 956  			if rt != resType {
 957  				rv = e.coerceInt(rv, rt, resType)
 958  			}
 959  		} else if e.intBits(lt) > e.intBits(rt) {
 960  			rv = e.coerceInt(rv, rt, lt)
 961  		} else {
 962  			lv = e.coerceInt(lv, lt, rt)
 963  			lt = rt
 964  		}
 965  	}
 966  	op := e.llvmBinOp(b.Op, b.X.SSAType())
 967  	if op == "" {
 968  		e.w("  ; unsupported binop\n")
 969  		return
 970  	}
 971  	e.w("  ")
 972  	e.w(reg)
 973  	e.w(" = ")
 974  	e.w(op)
 975  	e.w(" ")
 976  	e.w(lt)
 977  	e.w(" ")
 978  	e.w(lv)
 979  	e.w(", ")
 980  	e.w(rv)
 981  	e.w("\n")
 982  }
 983  
 984  func (e *irEmitter) emitSliceConcat(reg string, sl *Slice, lv, rv string) {
 985  	ipt := e.intptrType()
 986  	sty := "{ptr, " | ipt | ", " | ipt | "}"
 987  	elemType := e.llvmType(sl.Elem())
 988  	p := func(prefix string) string {
 989  		e.nextReg++
 990  		return "%" | prefix | irItoa(e.nextReg)
 991  	}
 992  	xPtr := p("cc")
 993  	e.w("  ") ; e.w(xPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 0\n")
 994  	xLen := p("cc")
 995  	e.w("  ") ; e.w(xLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 1\n")
 996  	yPtr := p("cc")
 997  	e.w("  ") ; e.w(yPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 0\n")
 998  	yLen := p("cc")
 999  	e.w("  ") ; e.w(yLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 1\n")
1000  	elemSz := p("cc")
1001  	e.w("  ") ; e.w(elemSz)
1002  	e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1003  	e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1004  	retTy := "{ptr, " | ipt | ", " | ipt | "}"
1005  	result := p("cc")
1006  	e.w("  ") ; e.w(result)
1007  	e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
1008  	e.w(xPtr) ; e.w(", ptr ") ; e.w(yPtr)
1009  	e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
1010  	e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
1011  	e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(yLen)
1012  	e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
1013  	e.w(")\n")
1014  	newPtr := p("cc")
1015  	e.w("  ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
1016  	newLen := p("cc")
1017  	e.w("  ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
1018  	newCap := p("cc")
1019  	e.w("  ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
1020  	s1 := p("cc")
1021  	e.w("  ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
1022  	s2 := p("cc")
1023  	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")
1024  	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")
1025  	e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
1026  }
1027  
1028  func (e *irEmitter) emitStringCompare(reg string, op SSAOp, lv, rv string) {
1029  	ipt := e.intptrType()
1030  	sty := "{ptr, " | ipt | ", " | ipt | "}"
1031  	if lv == "null" { lv = "zeroinitializer" }
1032  	if rv == "null" { rv = "zeroinitializer" }
1033  	switch op {
1034  	case OpEql:
1035  		e.w("  ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringEqual(")
1036  		e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
1037  		e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
1038  	case OpNeq:
1039  		p := func() string {
1040  			e.nextReg++
1041  			return "%sc" | irItoa(e.nextReg)
1042  		}
1043  		tmp := p()
1044  		e.w("  ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringEqual(")
1045  		e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
1046  		e.w("  ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
1047  		e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
1048  	case OpLss:
1049  		e.w("  ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
1050  		e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
1051  		e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
1052  	case OpGtr:
1053  		e.w("  ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
1054  		e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(")\n")
1055  		e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
1056  	case OpLeq:
1057  		p := func() string {
1058  			e.nextReg++
1059  			return "%sc" | irItoa(e.nextReg)
1060  		}
1061  		tmp := p()
1062  		e.w("  ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
1063  		e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(")\n")
1064  		e.w("  ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
1065  		e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
1066  	case OpGeq:
1067  		p := func() string {
1068  			e.nextReg++
1069  			return "%sc" | irItoa(e.nextReg)
1070  		}
1071  		tmp := p()
1072  		e.w("  ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
1073  		e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
1074  		e.w("  ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
1075  		e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
1076  	default:
1077  		e.w("  ; unsupported string binop\n")
1078  	}
1079  }
1080  
1081  func (e *irEmitter) emitStructCompare(reg string, op SSAOp, st *TCStruct, lt, lv, rv string) {
1082  	p := func(prefix string) string {
1083  		e.nextReg++
1084  		return "%" | prefix | irItoa(e.nextReg)
1085  	}
1086  	n := st.NumFields()
1087  	if n == 0 {
1088  		if op == OpEql {
1089  			e.valName[nil] = "true"
1090  			e.w("  ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
1091  		} else {
1092  			e.w("  ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
1093  		}
1094  		return
1095  	}
1096  	var lastCmp string
1097  	for i := 0; i < n; i++ {
1098  		ft := e.llvmType(st.Field(i).Type())
1099  		lf := p("sf")
1100  		rf := p("sf")
1101  		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")
1102  		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")
1103  		cmp := p("sf")
1104  		if e.isStringLike(st.Field(i).Type()) {
1105  			sty := e.sliceType()
1106  			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")
1107  			e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
1108  		} else {
1109  			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")
1110  		}
1111  		if i == 0 {
1112  			lastCmp = cmp
1113  		} else {
1114  			acc := p("sf")
1115  			e.w("  ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
1116  			lastCmp = acc
1117  		}
1118  	}
1119  	if op == OpNeq {
1120  		e.w("  ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
1121  	} else if n == 1 {
1122  		e.w("  ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
1123  	} else {
1124  		e.w("  ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
1125  	}
1126  }
1127  
1128  func (e *irEmitter) llvmBinOp(op SSAOp, typ Type) string {
1129  	isFloat := false
1130  	isSigned := true
1131  	if typ != nil {
1132  		if b, ok := safeUnderlying(typ).(*Basic); ok {
1133  			if b.Info()&IsFloat != 0 {
1134  				isFloat = true
1135  			}
1136  			if b.Info()&IsUnsigned != 0 {
1137  				isSigned = false
1138  			}
1139  		}
1140  	}
1141  	if isFloat {
1142  		switch op {
1143  		case OpAdd:
1144  			return "fadd"
1145  		case OpSub:
1146  			return "fsub"
1147  		case OpMul:
1148  			return "fmul"
1149  		case OpQuo:
1150  			return "fdiv"
1151  		case OpEql:
1152  			return "fcmp oeq"
1153  		case OpNeq:
1154  			return "fcmp une"
1155  		case OpLss:
1156  			return "fcmp olt"
1157  		case OpLeq:
1158  			return "fcmp ole"
1159  		case OpGtr:
1160  			return "fcmp ogt"
1161  		case OpGeq:
1162  			return "fcmp oge"
1163  		}
1164  		return ""
1165  	}
1166  	switch op {
1167  	case OpAdd:
1168  		return "add"
1169  	case OpSub:
1170  		return "sub"
1171  	case OpMul:
1172  		return "mul"
1173  	case OpQuo:
1174  		if isSigned {
1175  			return "sdiv"
1176  		}
1177  		return "udiv"
1178  	case OpRem:
1179  		if isSigned {
1180  			return "srem"
1181  		}
1182  		return "urem"
1183  	case OpAnd:
1184  		return "and"
1185  	case OpOr:
1186  		return "or"
1187  	case OpLand:
1188  		return "and"
1189  	case OpLor:
1190  		return "or"
1191  	case OpXor:
1192  		return "xor"
1193  	case OpShl:
1194  		return "shl"
1195  	case OpShr:
1196  		if isSigned {
1197  			return "ashr"
1198  		}
1199  		return "lshr"
1200  	case OpAndNot:
1201  		return ""
1202  	case OpEql:
1203  		return "icmp eq"
1204  	case OpNeq:
1205  		return "icmp ne"
1206  	case OpLss:
1207  		if isSigned {
1208  			return "icmp slt"
1209  		}
1210  		return "icmp ult"
1211  	case OpLeq:
1212  		if isSigned {
1213  			return "icmp sle"
1214  		}
1215  		return "icmp ule"
1216  	case OpGtr:
1217  		if isSigned {
1218  			return "icmp sgt"
1219  		}
1220  		return "icmp ugt"
1221  	case OpGeq:
1222  		if isSigned {
1223  			return "icmp sge"
1224  		}
1225  		return "icmp uge"
1226  	}
1227  	return ""
1228  }
1229  
1230  func (e *irEmitter) emitUnOp(u *SSAUnOp) {
1231  	reg := e.regName(u)
1232  	if u.Op == OpMul {
1233  		loadType := e.llvmType(u.SSAType())
1234  		if loadType == "void" {
1235  			if at, ok := e.allocTypes[u.X]; ok {
1236  				loadType = at
1237  			} else if a, ok := u.X.(*SSAAlloc); ok {
1238  				loadType = e.inferAllocTypeFromStores(a)
1239  			} else {
1240  				loadType = "ptr"
1241  			}
1242  			e.allocTypes[u] = loadType
1243  		} else if at, ok := e.allocTypes[u.X]; ok && at != "ptr" && at != "void" && at != loadType {
1244  			bothScalar := len(loadType) > 0 && loadType[0] == 'i' && len(at) > 0 && at[0] == 'i'
1245  			if !bothScalar {
1246  				loadType = at
1247  				e.allocTypes[u] = loadType
1248  			}
1249  		}
1250  		addr := e.operand(u.X)
1251  		e.w("  ")
1252  		e.w(reg)
1253  		e.w(" = load ")
1254  		e.w(loadType)
1255  		e.w(", ptr ")
1256  		e.w(addr)
1257  		e.w("\n")
1258  		return
1259  	}
1260  	valType := e.llvmType(u.X.SSAType())
1261  	val := e.operand(u.X)
1262  	switch u.Op {
1263  	case OpSub:
1264  		isFloat := false
1265  		if b, ok := safeUnderlying(u.X.SSAType()).(*Basic); ok {
1266  			isFloat = b.Info()&IsFloat != 0
1267  		}
1268  		e.w("  ")
1269  		e.w(reg)
1270  		if isFloat {
1271  			e.w(" = fneg ")
1272  		} else {
1273  			e.w(" = sub ")
1274  			e.w(valType)
1275  			e.w(" 0, ")
1276  			val = val
1277  			e.w(val)
1278  			e.w("\n")
1279  			return
1280  		}
1281  		e.w(valType)
1282  		e.w(" ")
1283  		e.w(val)
1284  		e.w("\n")
1285  	case OpNot:
1286  		e.w("  ")
1287  		e.w(reg)
1288  		e.w(" = xor ")
1289  		e.w(valType)
1290  		e.w(" ")
1291  		e.w(val)
1292  		e.w(", -1\n")
1293  	case OpXor:
1294  		e.w("  ")
1295  		e.w(reg)
1296  		e.w(" = xor ")
1297  		e.w(valType)
1298  		e.w(" ")
1299  		e.w(val)
1300  		e.w(", -1\n")
1301  	default:
1302  		e.w("  ; unsupported unop\n")
1303  	}
1304  }
1305  
1306  func (e *irEmitter) callArgType(arg SSAValue, sig *Signature, i int) string {
1307  	if at, ok := e.allocTypes[arg]; ok {
1308  		return at
1309  	}
1310  	t := e.llvmType(arg.SSAType())
1311  	if t != "void" {
1312  		return t
1313  	}
1314  	if sig != nil && sig.Params() != nil && i < sig.Params().Len() {
1315  		return e.llvmType(sig.Params().At(i).Type())
1316  	}
1317  	return "ptr"
1318  }
1319  
1320  func (e *irEmitter) callSig(c *SSACall) *Signature {
1321  	if fn, ok := c.Call.Value.(*SSAFunction); ok && fn.Signature != nil {
1322  		return fn.Signature
1323  	}
1324  	if sig, ok := safeUnderlying(c.Call.Value.SSAType()).(*Signature); ok {
1325  		return sig
1326  	}
1327  	return nil
1328  }
1329  
1330  func (e *irEmitter) emitCall(c *SSACall) {
1331  	if b, ok := c.Call.Value.(*SSABuiltin); ok {
1332  		e.emitBuiltinCall(c, b)
1333  		return
1334  	}
1335  	reg := e.regName(c)
1336  	retType := e.llvmType(c.SSAType())
1337  	isVoid := retType == "void"
1338  	sig := e.callSig(c)
1339  
1340  	if fn, ok := c.Call.Value.(*SSAFunction); ok {
1341  		if !e.isPkgFunc(fn) {
1342  			e.declareExternalFunc(fn)
1343  		}
1344  		e.w("  ")
1345  		if !isVoid {
1346  			e.w(reg) ; e.w(" = ")
1347  		}
1348  		e.w("call ") ; e.w(retType) ; e.w(" ")
1349  		e.w(e.funcSymbol(fn))
1350  		e.w("(")
1351  		for i, arg := range c.Call.Args {
1352  			if i > 0 { e.w(", ") }
1353  			at := e.callArgType(arg, sig, i)
1354  			av := e.operand(arg)
1355  			if av == "null" && at != "ptr" {
1356  				av = "zeroinitializer"
1357  			}
1358  			e.w(at) ; e.w(" ") ; e.w(av)
1359  		}
1360  		if len(c.Call.Args) > 0 { e.w(", ") }
1361  		e.w("ptr null")
1362  		e.w(")\n")
1363  		return
1364  	}
1365  
1366  	p := func(prefix string) string {
1367  		e.nextReg++
1368  		return "%" | prefix | irItoa(e.nextReg)
1369  	}
1370  	funcVal := e.operand(c.Call.Value)
1371  	funcPtr := p("fp")
1372  	ctx := p("ctx")
1373  	e.w("  ") ; e.w(funcPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(funcVal) ; e.w(", 1\n")
1374  	e.w("  ") ; e.w(ctx) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(funcVal) ; e.w(", 0\n")
1375  	e.w("  ")
1376  	if !isVoid {
1377  		e.w(reg) ; e.w(" = ")
1378  	}
1379  	e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(funcPtr) ; e.w("(")
1380  	for i, arg := range c.Call.Args {
1381  		if i > 0 { e.w(", ") }
1382  		at := e.callArgType(arg, sig, i)
1383  		av := e.operand(arg)
1384  		if av == "null" && at != "ptr" {
1385  			av = "zeroinitializer"
1386  		}
1387  		e.w(at) ; e.w(" ") ; e.w(av)
1388  	}
1389  	if len(c.Call.Args) > 0 { e.w(", ") }
1390  	e.w("ptr ") ; e.w(ctx)
1391  	e.w(")\n")
1392  }
1393  
1394  func (e *irEmitter) emitBuiltinCall(c *SSACall, b *SSABuiltin) {
1395  	reg := e.regName(c)
1396  	name := b.SSAName()
1397  	ipt := e.intptrType()
1398  	sty := e.sliceType()
1399  	switch name {
1400  	case "len":
1401  		if len(c.Call.Args) == 1 {
1402  			arg := e.operand(c.Call.Args[0])
1403  			u := safeUnderlying(c.Call.Args[0].SSAType())
1404  			if u == nil { u = c.Call.Args[0].SSAType() }
1405  			if arr, ok := u.(*Array); ok {
1406  				retType := e.llvmType(c.SSAType())
1407  				e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int(arr.Len()))) ; e.w(", 0\n")
1408  				_ = arg
1409  				return
1410  			}
1411  			_, isSlice := u.(*Slice)
1412  			_, isMap := u.(*TCMap)
1413  			isStr := e.isStringLike(c.Call.Args[0].SSAType())
1414  			if !isSlice && !isMap && !isStr {
1415  				isSlice = true
1416  			}
1417  			if isMap {
1418  				retType := e.llvmType(c.SSAType())
1419  				e.nextReg++
1420  				tmp := "%bl" | irItoa(e.nextReg)
1421  				e.w("  ") ; e.w(tmp) ; e.w(" = call ") ; e.w(ipt) ; e.w(" @runtime.hashmapLen(ptr ") ; e.w(arg) ; e.w(")\n")
1422  				if retType != ipt {
1423  					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")
1424  				} else {
1425  					e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(", 0\n")
1426  				}
1427  				e.declareRuntime("runtime.hashmapLen", ipt, "ptr")
1428  				return
1429  			}
1430  			if isSlice || isStr {
1431  				retType := e.llvmType(c.SSAType())
1432  				if retType != ipt {
1433  					e.nextReg++
1434  					tmp := "%bl" | irItoa(e.nextReg)
1435  					e.w("  ") ; e.w(tmp) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 1\n")
1436  					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")
1437  				} else {
1438  					e.w("  ") ; e.w(reg) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 1\n")
1439  				}
1440  				return
1441  			}
1442  		}
1443  	case "cap":
1444  		if len(c.Call.Args) == 1 {
1445  			arg := e.operand(c.Call.Args[0])
1446  			uc := safeUnderlying(c.Call.Args[0].SSAType())
1447  			if uc == nil { uc = c.Call.Args[0].SSAType() }
1448  			if arr, ok := uc.(*Array); ok {
1449  				retType := e.llvmType(c.SSAType())
1450  				e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int(arr.Len()))) ; e.w(", 0\n")
1451  				_ = arg
1452  				return
1453  			}
1454  			_, isSlice := uc.(*Slice)
1455  			isStr := e.isStringLike(c.Call.Args[0].SSAType())
1456  			if isSlice || isStr {
1457  				retType := e.llvmType(c.SSAType())
1458  				if retType != ipt {
1459  					e.nextReg++
1460  					tmp := "%bl" | irItoa(e.nextReg)
1461  					e.w("  ") ; e.w(tmp) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 2\n")
1462  					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")
1463  				} else {
1464  					e.w("  ") ; e.w(reg) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 2\n")
1465  				}
1466  				return
1467  			}
1468  		}
1469  	case "append":
1470  		if len(c.Call.Args) > 2 {
1471  			src := e.operand(c.Call.Args[0])
1472  			elemType := "i8"
1473  			if sl, ok := safeUnderlying(c.Call.Args[0].SSAType()).(*Slice); ok {
1474  				elemType = e.llvmType(sl.Elem())
1475  			}
1476  			if elemType == "i8" || elemType == "void" {
1477  				for j := 1; j < len(c.Call.Args); j++ {
1478  					et := e.llvmType(c.Call.Args[j].SSAType())
1479  					if et != "void" && et != "" && et != "i8" {
1480  						elemType = et
1481  						break
1482  					}
1483  				}
1484  			}
1485  			nElems := len(c.Call.Args) - 1
1486  			p := func(prefix string) string {
1487  				e.nextReg++
1488  				return "%" | prefix | irItoa(e.nextReg)
1489  			}
1490  			arrAlloca := p("ap")
1491  			arrTy := "[" | irItoa(nElems) | " x " | elemType | "]"
1492  			e.w("  ") ; e.w(arrAlloca) ; e.w(" = alloca ") ; e.w(arrTy) ; e.w("\n")
1493  			for j := 1; j < len(c.Call.Args); j++ {
1494  				elemVal := e.operand(c.Call.Args[j])
1495  				gep := p("ap")
1496  				e.w("  ") ; e.w(gep) ; e.w(" = getelementptr inbounds ") ; e.w(arrTy)
1497  				e.w(", ptr ") ; e.w(arrAlloca) ; e.w(", i32 0, i32 ") ; e.w(irItoa(j-1)) ; e.w("\n")
1498  				e.w("  store ") ; e.w(elemType) ; e.w(" ") ; e.w(elemVal) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
1499  			}
1500  			srcBuf := p("ap")
1501  			e.w("  ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
1502  			srcLen := p("ap")
1503  			e.w("  ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
1504  			srcCap := p("ap")
1505  			e.w("  ") ; e.w(srcCap) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 2\n")
1506  			elemSz := p("ap")
1507  			e.w("  ") ; e.w(elemSz)
1508  			e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1509  			e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1510  			retTy := "{ptr, " | ipt | ", " | ipt | "}"
1511  			result := p("ap")
1512  			e.w("  ") ; e.w(result)
1513  			e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
1514  			e.w(srcBuf) ; e.w(", ptr ") ; e.w(arrAlloca)
1515  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcLen)
1516  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcCap)
1517  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(irItoa(nElems))
1518  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
1519  			e.w(")\n")
1520  			newPtr := p("ap")
1521  			e.w("  ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
1522  			newLen := p("ap")
1523  			e.w("  ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
1524  			newCap := p("ap")
1525  			e.w("  ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
1526  			s1 := p("ap")
1527  			e.w("  ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
1528  			s2 := p("ap")
1529  			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")
1530  			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")
1531  			e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
1532  			return
1533  		}
1534  		if len(c.Call.Args) == 2 {
1535  			src := e.operand(c.Call.Args[0])
1536  			elems := e.operand(c.Call.Args[1])
1537  			elemType := "i8"
1538  			if sl, ok := safeUnderlying(c.Call.Args[0].SSAType()).(*Slice); ok {
1539  				elemType = e.llvmType(sl.Elem())
1540  			}
1541  			if elemType == "i8" || elemType == "void" {
1542  				et := e.llvmType(c.Call.Args[1].SSAType())
1543  				if et != "void" && et != "" && et != "i8" {
1544  					elemType = et
1545  				}
1546  			}
1547  			p := func(prefix string) string {
1548  				e.nextReg++
1549  				return "%" | prefix | irItoa(e.nextReg)
1550  			}
1551  			srcBuf := p("ap")
1552  			e.w("  ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
1553  			srcLen := p("ap")
1554  			e.w("  ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
1555  			srcCap := p("ap")
1556  			e.w("  ") ; e.w(srcCap) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 2\n")
1557  			var elemsBuf, elemsLen string
1558  			_, arg1IsSlice := safeUnderlying(c.Call.Args[1].SSAType()).(*Slice)
1559  			if !arg1IsSlice {
1560  				if b, ok := safeUnderlying(c.Call.Args[1].SSAType()).(*Basic); ok && b.Info()&IsString != 0 {
1561  					arg1IsSlice = true
1562  				}
1563  			}
1564  			if arg1IsSlice {
1565  				elemsBuf = p("ap")
1566  				e.w("  ") ; e.w(elemsBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(elems) ; e.w(", 0\n")
1567  				elemsLen = p("ap")
1568  				e.w("  ") ; e.w(elemsLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(elems) ; e.w(", 1\n")
1569  			} else {
1570  				alloca := p("ap")
1571  				e.w("  ") ; e.w(alloca) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
1572  				e.w("  store ") ; e.w(elemType) ; e.w(" ") ; e.w(elems) ; e.w(", ptr ") ; e.w(alloca) ; e.w("\n")
1573  				elemsBuf = alloca
1574  				elemsLen = "1"
1575  			}
1576  			elemSz := p("ap")
1577  			e.w("  ") ; e.w(elemSz)
1578  			e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1579  			e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1580  			retTy := "{ptr, " | ipt | ", " | ipt | "}"
1581  			result := p("ap")
1582  			e.w("  ") ; e.w(result)
1583  			e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
1584  			e.w(srcBuf) ; e.w(", ptr ") ; e.w(elemsBuf)
1585  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcLen)
1586  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcCap)
1587  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemsLen)
1588  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
1589  			e.w(")\n")
1590  			newPtr := p("ap")
1591  			e.w("  ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
1592  			newLen := p("ap")
1593  			e.w("  ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
1594  			newCap := p("ap")
1595  			e.w("  ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
1596  			s1 := p("ap")
1597  			e.w("  ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
1598  			s2 := p("ap")
1599  			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")
1600  			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")
1601  			e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
1602  			return
1603  		}
1604  	case "copy":
1605  		if len(c.Call.Args) == 2 {
1606  			dst := e.operand(c.Call.Args[0])
1607  			src := e.operand(c.Call.Args[1])
1608  			elemType := "i8"
1609  			if sl, ok := safeUnderlying(c.Call.Args[0].SSAType()).(*Slice); ok {
1610  				elemType = e.llvmType(sl.Elem())
1611  			}
1612  			p := func(prefix string) string {
1613  				e.nextReg++
1614  				return "%" | prefix | irItoa(e.nextReg)
1615  			}
1616  			dstBuf := p("cp")
1617  			e.w("  ") ; e.w(dstBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(dst) ; e.w(", 0\n")
1618  			dstLen := p("cp")
1619  			e.w("  ") ; e.w(dstLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(dst) ; e.w(", 1\n")
1620  			srcBuf := p("cp")
1621  			e.w("  ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
1622  			srcLen := p("cp")
1623  			e.w("  ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
1624  			elemSz := p("cp")
1625  			e.w("  ") ; e.w(elemSz)
1626  			e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
1627  			e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
1628  			callReg := p("cp")
1629  			e.w("  ") ; e.w(callReg)
1630  			e.w(" = call ") ; e.w(ipt) ; e.w(" @runtime.sliceCopy(ptr ")
1631  			e.w(dstBuf) ; e.w(", ptr ") ; e.w(srcBuf)
1632  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(dstLen)
1633  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(srcLen)
1634  			e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
1635  			e.w(")\n")
1636  			retType := e.llvmType(c.SSAType())
1637  			if retType != ipt {
1638  				e.w("  ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(callReg) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
1639  			} else {
1640  				e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(callReg) ; e.w(", 0\n")
1641  			}
1642  			e.declareRuntime("runtime.sliceCopy", ipt, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt)
1643  			return
1644  		}
1645  	case "print", "println":
1646  		e.w("  call void @runtime.printlock()\n")
1647  		for i, arg := range c.Call.Args {
1648  			if i > 0 && name == "println" {
1649  				e.w("  call void @runtime.printspace()\n")
1650  			}
1651  			av := e.operand(arg)
1652  			at := arg.SSAType()
1653  			e.emitPrintArg(av, at)
1654  		}
1655  		if name == "println" {
1656  			e.w("  call void @runtime.printnl()\n")
1657  			e.declareRuntime("runtime.printnl", "void", "")
1658  		}
1659  		e.w("  call void @runtime.printunlock()\n")
1660  		e.declareRuntime("runtime.printlock", "void", "")
1661  		e.declareRuntime("runtime.printunlock", "void", "")
1662  		if name == "println" && len(c.Call.Args) > 1 {
1663  			e.declareRuntime("runtime.printspace", "void", "")
1664  		}
1665  		return
1666  	case "delete":
1667  		if len(c.Call.Args) == 2 {
1668  			mapVal := e.operand(c.Call.Args[0])
1669  			keyVal := e.operand(c.Call.Args[1])
1670  			mt, _ := safeUnderlying(c.Call.Args[0].SSAType()).(*TCMap)
1671  			keyType := "i32"
1672  			if mt != nil {
1673  				keyType = e.llvmType(mt.Key())
1674  			}
1675  			p := func(prefix string) string {
1676  				e.nextReg++
1677  				return "%" | prefix | irItoa(e.nextReg)
1678  			}
1679  			keyAlloca := p("dl")
1680  			e.w("  ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
1681  			e.w("  store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
1682  			e.w("  call void @runtime.hashmapBinaryDelete(ptr ") ; e.w(mapVal)
1683  			e.w(", ptr ") ; e.w(keyAlloca) ; e.w(")\n")
1684  			e.declareRuntime("runtime.hashmapBinaryDelete", "void", "ptr, ptr")
1685  			return
1686  		}
1687  	case "close":
1688  		if len(c.Call.Args) == 1 {
1689  			e.w("  call void @runtime.chanClose(ptr ")
1690  			e.w(e.operand(c.Call.Args[0]))
1691  			e.w(")\n")
1692  			return
1693  		}
1694  	case "min", "max":
1695  		if len(c.Call.Args) >= 2 {
1696  			retType := e.llvmType(c.SSAType())
1697  			if retType == "" || retType == "void" {
1698  				retType = "i32"
1699  			}
1700  			a := e.operand(c.Call.Args[0])
1701  			b2 := e.operand(c.Call.Args[1])
1702  			cmpOp := "slt"
1703  			if name == "max" {
1704  				cmpOp = "sgt"
1705  			}
1706  			u := safeUnderlying(c.SSAType())
1707  			if bb, ok := u.(*Basic); ok && bb.Info()&IsUnsigned != 0 {
1708  				cmpOp = "ult"
1709  				if name == "max" {
1710  					cmpOp = "ugt"
1711  				}
1712  			}
1713  			e.nextReg++
1714  			cmpReg := "%mm" | irItoa(e.nextReg)
1715  			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")
1716  			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")
1717  			return
1718  		}
1719  	}
1720  	e.w("  ; unhandled builtin: ")
1721  	e.w(name)
1722  	e.w("\n")
1723  	retType := e.llvmType(c.SSAType())
1724  	if name == "recover" {
1725  		retType = e.ifaceType()
1726  	}
1727  	if retType != "void" && retType != "" {
1728  		if retType == "ptr" || e.intBits(retType) > 0 || retType == "i1" {
1729  			e.emitZeroReg(reg, c.SSAType())
1730  		} else {
1731  			// Aggregate type: use alloca to get zeroinitializer
1732  			e.nextReg++
1733  			tmp := "%ub" | irItoa(e.nextReg)
1734  			e.w("  ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
1735  			e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
1736  			e.allocTypes[c] = retType
1737  		}
1738  	}
1739  }
1740  
1741  func (e *irEmitter) emitPrintArg(val string, t Type) {
1742  	if t == nil {
1743  		return
1744  	}
1745  	sty := e.sliceType()
1746  	switch u := safeUnderlying(t).(type) {
1747  	case *Basic:
1748  		switch {
1749  		case u.Info()&IsString != 0:
1750  			e.w("  call void @runtime.printstring(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1751  			e.declareRuntime("runtime.printstring", "void", sty)
1752  		case u.Kind() == Bool || u.Kind() == UntypedBool:
1753  			e.w("  call void @runtime.printbool(i1 ") ; e.w(val) ; e.w(")\n")
1754  			e.declareRuntime("runtime.printbool", "void", "i1")
1755  		case u.Kind() == Float32:
1756  			e.w("  call void @runtime.printfloat32(float ") ; e.w(val) ; e.w(")\n")
1757  			e.declareRuntime("runtime.printfloat32", "void", "float")
1758  		case u.Kind() == Float64 || u.Kind() == UntypedFloat:
1759  			e.w("  call void @runtime.printfloat64(double ") ; e.w(val) ; e.w(")\n")
1760  			e.declareRuntime("runtime.printfloat64", "void", "double")
1761  		case u.Info()&IsUnsigned != 0:
1762  			lt := e.llvmType(t)
1763  			fname := "runtime.printuint" | lt[1:]
1764  			e.w("  call void @") ; e.w(fname) ; e.w("(") ; e.w(lt) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1765  			e.declareRuntime(fname, "void", lt)
1766  		case u.Info()&IsInteger != 0:
1767  			lt := e.llvmType(t)
1768  			fname := "runtime.printint" | lt[1:]
1769  			e.w("  call void @") ; e.w(fname) ; e.w("(") ; e.w(lt) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1770  			e.declareRuntime(fname, "void", lt)
1771  		}
1772  	case *Pointer:
1773  		ipt := e.intptrType()
1774  		e.nextReg++
1775  		tmp := "%pr" | irItoa(e.nextReg)
1776  		e.w("  ") ; e.w(tmp) ; e.w(" = ptrtoint ptr ") ; e.w(val) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
1777  		e.w("  call void @runtime.printptr(") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(")\n")
1778  		e.declareRuntime("runtime.printptr", "void", ipt)
1779  	case *Slice:
1780  		if b, ok := u.Elem().(*Basic); ok && (b.Kind() == Uint8 || b.Kind() == Int8) {
1781  			e.w("  call void @runtime.printbytes(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1782  			e.declareRuntime("runtime.printbytes", "void", sty)
1783  		} else {
1784  			e.w("  call void @runtime.printstring(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
1785  			e.declareRuntime("runtime.printstring", "void", sty)
1786  		}
1787  	case *TCMap:
1788  		e.w("  call void @runtime.printmap(ptr ") ; e.w(val) ; e.w(")\n")
1789  		e.declareRuntime("runtime.printmap", "void", "ptr")
1790  	}
1791  }
1792  
1793  func (e *irEmitter) emitPhi(p *SSAPhi) {
1794  	reg := e.regName(p)
1795  	typ := e.llvmType(p.SSAType())
1796  	e.w("  ")
1797  	e.w(reg)
1798  	e.w(" = phi ")
1799  	e.w(typ)
1800  	e.w(" ")
1801  	blk := p.InstrBlock()
1802  	for i, edge := range p.Edges {
1803  		if i > 0 {
1804  			e.w(", ")
1805  		}
1806  		e.w("[")
1807  		e.w(e.operand(edge))
1808  		e.w(", ")
1809  		if i < len(blk.Preds) {
1810  			e.w(e.blockLabel(blk.Preds[i]))
1811  		} else {
1812  			e.w("%unknown")
1813  		}
1814  		e.w("]")
1815  	}
1816  	e.w("\n")
1817  }
1818  
1819  func (e *irEmitter) coerceInt(valReg string, fromType string, toType string) string {
1820  	if fromType == toType {
1821  		return valReg
1822  	}
1823  	fromBits := e.intBits(fromType)
1824  	toBits := e.intBits(toType)
1825  	if fromBits == 0 || toBits == 0 {
1826  		return valReg
1827  	}
1828  	e.nextReg++
1829  	r := "%rc" | irItoa(e.nextReg)
1830  	if fromBits > toBits {
1831  		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")
1832  	} else {
1833  		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")
1834  	}
1835  	return r
1836  }
1837  
1838  func (e *irEmitter) intBits(ty string) int32 {
1839  	switch ty {
1840  	case "i1":
1841  		return 1
1842  	case "i8":
1843  		return 8
1844  	case "i16":
1845  		return 16
1846  	case "i32":
1847  		return 32
1848  	case "i64":
1849  		return 64
1850  	}
1851  	return 0
1852  }
1853  
1854  func (e *irEmitter) emitReturn(r *SSAReturn) {
1855  	if len(r.Results) == 0 {
1856  		rt := e.funcRetType(e.curFunc)
1857  		if rt == "void" {
1858  			e.w("  ret void\n")
1859  		} else {
1860  			e.w("  unreachable\n")
1861  		}
1862  		return
1863  	}
1864  	sig := e.curFunc.Signature
1865  	if len(r.Results) == 1 {
1866  		typ := e.llvmType(r.Results[0].SSAType())
1867  		val := e.operand(r.Results[0])
1868  		expectType := typ
1869  		if sig != nil && sig.Results() != nil && sig.Results().Len() == 1 {
1870  			expectType = e.llvmType(sig.Results().At(0).Type())
1871  		}
1872  		if val == "null" && expectType != "ptr" {
1873  			val = "zeroinitializer"
1874  		} else {
1875  			val = e.coerceInt(val, typ, expectType)
1876  		}
1877  		if typ != expectType && val != "zeroinitializer" {
1878  			if expectType == "ptr" && e.intBits(typ) > 0 {
1879  				e.nextReg++
1880  				r := "%rc" | irItoa(e.nextReg)
1881  				e.w("  ") ; e.w(r) ; e.w(" = inttoptr ") ; e.w(typ) ; e.w(" ") ; e.w(val) ; e.w(" to ptr\n")
1882  				val = r
1883  				typ = "ptr"
1884  			} else if typ == "ptr" && e.intBits(expectType) > 0 {
1885  				e.nextReg++
1886  				r := "%rc" | irItoa(e.nextReg)
1887  				e.w("  ") ; e.w(r) ; e.w(" = ptrtoint ptr ") ; e.w(val) ; e.w(" to ") ; e.w(expectType) ; e.w("\n")
1888  				val = r
1889  				typ = expectType
1890  			}
1891  			if typ != expectType {
1892  				val = "zeroinitializer"
1893  			}
1894  		}
1895  		e.w("  ret ")
1896  		e.w(expectType)
1897  		e.w(" ")
1898  		e.w(val)
1899  		e.w("\n")
1900  		return
1901  	}
1902  	var expectTypes []string
1903  	if sig != nil && sig.Results() != nil {
1904  		for i := 0; i < sig.Results().Len(); i++ {
1905  			expectTypes = append(expectTypes, e.llvmType(sig.Results().At(i).Type()))
1906  		}
1907  	}
1908  	retType := "{"
1909  	for i, res := range r.Results {
1910  		if i > 0 {
1911  			retType = retType | ", "
1912  		}
1913  		if i < len(expectTypes) {
1914  			retType = retType | expectTypes[i]
1915  		} else {
1916  			retType = retType | e.llvmType(res.SSAType())
1917  		}
1918  	}
1919  	retType = retType | "}"
1920  	prev := "undef"
1921  	for i, res := range r.Results {
1922  		valType := e.llvmType(res.SSAType())
1923  		valOp := e.operand(res)
1924  		elemType := valType
1925  		if i < len(expectTypes) {
1926  			elemType = expectTypes[i]
1927  			if valOp == "null" && elemType != "ptr" {
1928  				valOp = "zeroinitializer"
1929  			} else {
1930  				valOp = e.coerceInt(valOp, valType, elemType)
1931  			}
1932  		}
1933  		e.nextReg++
1934  		cur := "%rv" | irItoa(e.nextReg)
1935  		e.w("  ")
1936  		e.w(cur)
1937  		e.w(" = insertvalue ")
1938  		e.w(retType)
1939  		e.w(" ")
1940  		e.w(prev)
1941  		e.w(", ")
1942  		e.w(elemType)
1943  		e.w(" ")
1944  		e.w(valOp)
1945  		e.w(", ")
1946  		e.w(irItoa(i))
1947  		e.w("\n")
1948  		prev = cur
1949  	}
1950  	e.w("  ret ")
1951  	e.w(retType)
1952  	e.w(" ")
1953  	e.w(prev)
1954  	e.w("\n")
1955  }
1956  
1957  func (e *irEmitter) emitJump(j *SSAJump) {
1958  	blk := j.InstrBlock()
1959  	if len(blk.Succs) > 0 {
1960  		e.w("  br label ")
1961  		e.w(e.blockLabel(blk.Succs[0]))
1962  		e.w("\n")
1963  	}
1964  }
1965  
1966  func isComparisonOp(op SSAOp) bool {
1967  	return op == OpEql || op == OpNeq || op == OpLss || op == OpLeq || op == OpGtr || op == OpGeq
1968  }
1969  
1970  func (e *irEmitter) emitIf(i *SSAIf) {
1971  	blk := i.InstrBlock()
1972  	cond := e.operand(i.Cond)
1973  	condType := e.llvmType(i.Cond.SSAType())
1974  	if at, ok := e.allocTypes[i.Cond]; ok {
1975  		condType = at
1976  	}
1977  	if bop, ok := i.Cond.(*SSABinOp); ok && isComparisonOp(bop.Op) {
1978  		condType = "i1"
1979  	}
1980  	if condType != "i1" && condType != "" && condType != "void" {
1981  		e.nextReg++
1982  		truncReg := "%ift" | irItoa(e.nextReg)
1983  		e.w("  ") ; e.w(truncReg) ; e.w(" = trunc ") ; e.w(condType) ; e.w(" ") ; e.w(cond) ; e.w(" to i1\n")
1984  		cond = truncReg
1985  	}
1986  	if len(blk.Succs) >= 2 {
1987  		e.w("  br i1 ")
1988  		e.w(cond)
1989  		e.w(", label ")
1990  		e.w(e.blockLabel(blk.Succs[0]))
1991  		e.w(", label ")
1992  		e.w(e.blockLabel(blk.Succs[1]))
1993  		e.w("\n")
1994  	}
1995  }
1996  
1997  func (e *irEmitter) emitConvert(c *SSAConvert) {
1998  	reg := e.regName(c)
1999  	srcType := e.llvmType(c.X.SSAType())
2000  	dstType := e.llvmType(c.SSAType())
2001  	val := e.operand(c.X)
2002  
2003  	if srcType == "void" || c.X.SSAType() == nil {
2004  		if dstType == "ptr" {
2005  			e.valName[c] = "null"
2006  		} else {
2007  			e.valName[c] = "zeroinitializer"
2008  		}
2009  		return
2010  	}
2011  
2012  	if srcType == dstType {
2013  		e.valName[c] = e.operand(c.X)
2014  		return
2015  	}
2016  
2017  	op := e.conversionOp(c.X.SSAType(), c.SSAType())
2018  	if op == "ptrtoint" && e.intBits(dstType) == 0 {
2019  		if dstType == e.ifaceType() {
2020  			e.w("  ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} zeroinitializer, ptr ") ; e.w(val) ; e.w(", 1\n")
2021  		} else {
2022  			e.valName[c] = "zeroinitializer"
2023  		}
2024  		return
2025  	}
2026  	if op == "inttoptr" && e.intBits(srcType) == 0 {
2027  		if srcType == e.ifaceType() {
2028  			e.nextReg++
2029  			r := "%cv" | irItoa(e.nextReg)
2030  			e.w("  ") ; e.w(r) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
2031  			e.valName[c] = r
2032  		} else {
2033  			e.valName[c] = "null"
2034  		}
2035  		return
2036  	}
2037  	e.w("  ")
2038  	e.w(reg)
2039  	e.w(" = ")
2040  	e.w(op)
2041  	e.w(" ")
2042  	e.w(srcType)
2043  	e.w(" ")
2044  	e.w(val)
2045  	e.w(" to ")
2046  	e.w(dstType)
2047  	e.w("\n")
2048  }
2049  
2050  func (e *irEmitter) conversionOp(from, to Type) string {
2051  	fromBits := e.typeBits(from)
2052  	toBits := e.typeBits(to)
2053  
2054  	fromFloat := false
2055  	toFloat := false
2056  	fromSigned := true
2057  	if b, ok := safeUnderlying(from).(*Basic); ok {
2058  		fromFloat = b.Info()&IsFloat != 0
2059  		if b.Info()&IsUnsigned != 0 {
2060  			fromSigned = false
2061  		}
2062  	}
2063  	if b, ok := safeUnderlying(to).(*Basic); ok {
2064  		toFloat = b.Info()&IsFloat != 0
2065  	}
2066  
2067  	if fromFloat && toFloat {
2068  		if fromBits < toBits {
2069  			return "fpext"
2070  		}
2071  		return "fptrunc"
2072  	}
2073  	if fromFloat && !toFloat {
2074  		if fromSigned {
2075  			return "fptosi"
2076  		}
2077  		return "fptoui"
2078  	}
2079  	if !fromFloat && toFloat {
2080  		if fromSigned {
2081  			return "sitofp"
2082  		}
2083  		return "uitofp"
2084  	}
2085  
2086  	_, fromPtr := safeUnderlying(from).(*Pointer)
2087  	_, toPtr := safeUnderlying(to).(*Pointer)
2088  	if fromPtr && !toPtr {
2089  		return "ptrtoint"
2090  	}
2091  	if !fromPtr && toPtr {
2092  		return "inttoptr"
2093  	}
2094  
2095  	if fromBits < toBits {
2096  		if fromSigned {
2097  			return "sext"
2098  		}
2099  		return "zext"
2100  	}
2101  	if fromBits > toBits {
2102  		return "trunc"
2103  	}
2104  	return "bitcast"
2105  }
2106  
2107  func (e *irEmitter) typeBits(t Type) int {
2108  	if t == nil {
2109  		return 0
2110  	}
2111  	switch t := safeUnderlying(t).(type) {
2112  	case *Basic:
2113  		switch t.Kind() {
2114  		case Bool:
2115  			return 1
2116  		case Int8, Uint8:
2117  			return 8
2118  		case Int16, Uint16:
2119  			return 16
2120  		case Int32, Uint32:
2121  			return 32
2122  		case Int64, Uint64:
2123  			return 64
2124  		case Float32:
2125  			return 32
2126  		case Float64:
2127  			return 64
2128  		case UntypedInt, UntypedRune:
2129  			return 32
2130  		case UntypedFloat:
2131  			return 64
2132  		case UnsafePointer:
2133  			return e.ptrBits
2134  		}
2135  	case *Pointer:
2136  		return e.ptrBits
2137  	}
2138  	return 0
2139  }
2140  
2141  func (e *irEmitter) emitChangeType(c *SSAChangeType) {
2142  	srcType := e.llvmType(c.X.SSAType())
2143  	dstType := e.llvmType(c.SSAType())
2144  	if at, ok := e.allocTypes[c.X]; ok && at != "ptr" && at != "void" {
2145  		srcType = at
2146  	}
2147  	if srcType == dstType || (srcType == "ptr" && dstType == "ptr") {
2148  		e.valName[c] = e.operand(c.X)
2149  		return
2150  	}
2151  	reg := e.regName(c)
2152  	val := e.operand(c.X)
2153  	e.nextReg++
2154  	tmp := "%ct" | irItoa(e.nextReg)
2155  	e.w("  ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(dstType) ; e.w("\n")
2156  	e.w("  store ") ; e.w(srcType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
2157  	e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(dstType) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
2158  }
2159  
2160  func (e *irEmitter) emitFieldAddr(f *SSAFieldAddr) {
2161  	reg := e.regName(f)
2162  	baseType := e.llvmType(f.X.SSAType())
2163  	if p, ok := safeUnderlying(f.X.SSAType()).(*Pointer); ok && p.Elem() != nil {
2164  		elem := p.Elem()
2165  		if p2, ok2 := safeUnderlying(elem).(*Pointer); ok2 && p2.Elem() != nil {
2166  			baseType = e.llvmType(p2.Elem())
2167  		} else {
2168  			baseType = e.llvmType(elem)
2169  		}
2170  	}
2171  	if at, ok := e.allocTypes[f.X]; ok && at != "ptr" && at != "void" {
2172  		baseType = at
2173  	}
2174  	base := e.operand(f.X)
2175  	// If X is a load (struct by value), use the load's source alloca instead
2176  	if uop, ok := f.X.(*SSAUnOp); ok {
2177  		addrType := e.llvmType(uop.X.SSAType())
2178  		useSource := false
2179  		if p, ok2 := safeUnderlying(uop.X.SSAType()).(*Pointer); ok2 && p.Elem() != nil {
2180  			elem := p.Elem()
2181  			if p2, ok3 := safeUnderlying(elem).(*Pointer); ok3 && p2.Elem() != nil {
2182  				// **Struct: load indirection, don't replace base
2183  				baseType = e.llvmType(p2.Elem())
2184  			} else {
2185  				// *Struct: source is struct storage, safe to GEP directly
2186  				baseType = e.llvmType(elem)
2187  				useSource = true
2188  			}
2189  		}
2190  		if useSource && addrType == "ptr" && baseType != "ptr" && baseType != "void" {
2191  			base = e.operand(uop.X)
2192  		}
2193  	}
2194  	if baseType == "ptr" || baseType == "void" {
2195  		e.w("  ") ; e.w(reg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(base)
2196  		e.w(", i32 0\n")
2197  		return
2198  	}
2199  	e.w("  ")
2200  	e.w(reg)
2201  	e.w(" = getelementptr inbounds ")
2202  	e.w(baseType)
2203  	e.w(", ptr ")
2204  	e.w(base)
2205  	e.w(", i32 0, i32 ")
2206  	e.w(irItoa(f.Field))
2207  	e.w("\n")
2208  }
2209  
2210  func (e *irEmitter) emitIndexAddr(idx *SSAIndexAddr) {
2211  	reg := e.regName(idx)
2212  	elemType := e.llvmType(idx.SSAType())
2213  	if p, ok := safeUnderlying(idx.SSAType()).(*Pointer); ok {
2214  		elemType = e.llvmType(p.Elem())
2215  	}
2216  	base := e.operand(idx.X)
2217  	index := e.operand(idx.Index)
2218  	_, isSlice := safeUnderlying(idx.X.SSAType()).(*Slice)
2219  	if !isSlice {
2220  		if b, ok := safeUnderlying(idx.X.SSAType()).(*Basic); ok && b.Info()&IsString != 0 {
2221  			isSlice = true
2222  		}
2223  	}
2224  	if isSlice {
2225  		e.nextReg++
2226  		dataPtr := "%sp" | irItoa(e.nextReg)
2227  		e.w("  ")
2228  		e.w(dataPtr)
2229  		e.w(" = extractvalue ")
2230  		e.w(e.sliceType())
2231  		e.w(" ")
2232  		e.w(base)
2233  		e.w(", 0\n")
2234  		e.w("  ")
2235  		e.w(reg)
2236  		e.w(" = getelementptr inbounds ")
2237  		e.w(elemType)
2238  		e.w(", ptr ")
2239  		e.w(dataPtr)
2240  		e.w(", ")
2241  		e.w(e.llvmType(idx.Index.SSAType()))
2242  		e.w(" ")
2243  		e.w(index)
2244  		e.w("\n")
2245  		return
2246  	}
2247  	_, isArray := safeUnderlying(idx.X.SSAType()).(*Array)
2248  	if isArray {
2249  		e.nextReg++
2250  		arrPtr := "%ai" | irItoa(e.nextReg)
2251  		arrType := e.llvmType(idx.X.SSAType())
2252  		e.w("  ") ; e.w(arrPtr) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
2253  		e.w("  store ") ; e.w(arrType) ; e.w(" ") ; e.w(base) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w("\n")
2254  		e.w("  ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
2255  		e.w(arrType) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w(", i32 0, ")
2256  		e.w(e.llvmType(idx.Index.SSAType())) ; e.w(" ") ; e.w(index) ; e.w("\n")
2257  		return
2258  	}
2259  	e.w("  ")
2260  	e.w(reg)
2261  	e.w(" = getelementptr inbounds ")
2262  	e.w(elemType)
2263  	e.w(", ptr ")
2264  	e.w(base)
2265  	e.w(", ")
2266  	e.w(e.llvmType(idx.Index.SSAType()))
2267  	e.w(" ")
2268  	e.w(index)
2269  	e.w("\n")
2270  }
2271  
2272  func (e *irEmitter) emitExtract(ex *SSAExtract) {
2273  	reg := e.regName(ex)
2274  	tupType := e.llvmType(ex.Tuple.SSAType())
2275  	if at, ok := e.allocTypes[ex.Tuple]; ok {
2276  		tupType = at
2277  	}
2278  	val := e.operand(ex.Tuple)
2279  	// Track extracted element type for downstream alloc/store consistency
2280  	extractedType := extractTupleField(tupType, ex.Index)
2281  	if extractedType != "" {
2282  		ssaType := e.llvmType(ex.SSAType())
2283  		if extractedType != ssaType {
2284  			e.allocTypes[ex] = extractedType
2285  		}
2286  	}
2287  	if tupType == "ptr" || tupType == "void" {
2288  		elemType := e.llvmType(ex.SSAType())
2289  		if elemType == "void" { elemType = "ptr" }
2290  		e.nextReg++
2291  		castReg := "%ev" | irItoa(e.nextReg)
2292  		e.w("  ") ; e.w(castReg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(val) ; e.w(", i32 0\n")
2293  		e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(castReg) ; e.w("\n")
2294  		e.allocTypes[ex] = elemType
2295  		return
2296  	}
2297  	e.w("  ")
2298  	e.w(reg)
2299  	e.w(" = extractvalue ")
2300  	e.w(tupType)
2301  	e.w(" ")
2302  	e.w(val)
2303  	e.w(", ")
2304  	e.w(irItoa(ex.Index))
2305  	e.w("\n")
2306  }
2307  
2308  func extractTupleField(tupType string, index int) string {
2309  	if len(tupType) < 3 || tupType[0] != '{' {
2310  		return ""
2311  	}
2312  	inner := tupType[1 : len(tupType)-1]
2313  	depth := 0
2314  	field := 0
2315  	start := 0
2316  	for i := 0; i < len(inner); i++ {
2317  		c := inner[i]
2318  		if c == '{' {
2319  			depth++
2320  		} else if c == '}' {
2321  			depth--
2322  		} else if c == ',' && depth == 0 {
2323  			if field == index {
2324  				s := inner[start:i]
2325  				for len(s) > 0 && s[0] == ' ' { s = s[1:] }
2326  				for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] }
2327  				return s
2328  			}
2329  			field++
2330  			start = i + 1
2331  		}
2332  	}
2333  	if field == index {
2334  		s := inner[start:]
2335  		for len(s) > 0 && s[0] == ' ' { s = s[1:] }
2336  		for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] }
2337  		return s
2338  	}
2339  	return ""
2340  }
2341  
2342  func (e *irEmitter) sextToIpt(val SSAValue, op string) string {
2343  	ipt := e.intptrType()
2344  	if val == nil {
2345  		return op
2346  	}
2347  	valType := e.llvmType(val.SSAType())
2348  	if valType == ipt {
2349  		return op
2350  	}
2351  	e.nextReg++
2352  	ext := "%sx" | irItoa(e.nextReg)
2353  	e.w("  ") ; e.w(ext) ; e.w(" = sext ") ; e.w(valType) ; e.w(" ") ; e.w(op) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
2354  	return ext
2355  }
2356  
2357  func (e *irEmitter) emitMakeSlice(m *SSAMakeSlice) {
2358  	reg := e.regName(m)
2359  	ipt := e.intptrType()
2360  	sty := e.sliceType()
2361  	lenOp := e.sextToIpt(m.Len, e.operand(m.Len))
2362  	capOp := lenOp
2363  	if m.Cap != nil {
2364  		capOp = e.sextToIpt(m.Cap, e.operand(m.Cap))
2365  	}
2366  	var dataPtr string
2367  	if m.Data != nil {
2368  		dataPtr = e.operand(m.Data)
2369  	} else {
2370  		elemType := "i8"
2371  		if sl, ok := safeUnderlying(m.SSAType()).(*Slice); ok {
2372  			elemType = e.llvmType(sl.Elem())
2373  		}
2374  		e.nextReg++
2375  		elemSz := "%ms" | irItoa(e.nextReg)
2376  		e.w("  ")
2377  		e.w(elemSz)
2378  		e.w(" = ptrtoint ptr getelementptr (")
2379  		e.w(elemType)
2380  		e.w(", ptr null, i32 1) to ")
2381  		e.w(ipt)
2382  		e.w("\n")
2383  		e.nextReg++
2384  		allocSz := "%ms" | irItoa(e.nextReg)
2385  		e.w("  ")
2386  		e.w(allocSz)
2387  		e.w(" = mul ")
2388  		e.w(ipt)
2389  		e.w(" ")
2390  		e.w(elemSz)
2391  		e.w(", ")
2392  		e.w(capOp)
2393  		e.w("\n")
2394  		e.nextReg++
2395  		dataPtr = "%ms" | irItoa(e.nextReg)
2396  		e.w("  ")
2397  		e.w(dataPtr)
2398  		e.w(" = call ptr @runtime.alloc(")
2399  		e.w(ipt)
2400  		e.w(" ")
2401  		e.w(allocSz)
2402  		e.w(", ptr null, ptr undef)\n")
2403  		e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
2404  	}
2405  	e.nextReg++
2406  	s1 := "%ms" | irItoa(e.nextReg)
2407  	e.w("  ")
2408  	e.w(s1)
2409  	e.w(" = insertvalue ")
2410  	e.w(sty)
2411  	e.w(" undef, ptr ")
2412  	e.w(dataPtr)
2413  	e.w(", 0\n")
2414  	e.nextReg++
2415  	s2 := "%ms" | irItoa(e.nextReg)
2416  	e.w("  ")
2417  	e.w(s2)
2418  	e.w(" = insertvalue ")
2419  	e.w(sty)
2420  	e.w(" ")
2421  	e.w(s1)
2422  	e.w(", ")
2423  	e.w(ipt)
2424  	e.w(" ")
2425  	e.w(lenOp)
2426  	e.w(", 1\n")
2427  	e.w("  ")
2428  	e.w(reg)
2429  	e.w(" = insertvalue ")
2430  	e.w(sty)
2431  	e.w(" ")
2432  	e.w(s2)
2433  	e.w(", ")
2434  	e.w(ipt)
2435  	e.w(" ")
2436  	e.w(capOp)
2437  	e.w(", 2\n")
2438  }
2439  
2440  func (e *irEmitter) emitSliceOp(s *SSASlice) {
2441  	reg := e.regName(s)
2442  	ipt := e.intptrType()
2443  	sty := e.sliceType()
2444  	src := e.operand(s.X)
2445  	var oldPtr, oldLen, oldCap string
2446  	if arr, ok := safeUnderlying(s.X.SSAType()).(*Array); ok {
2447  		arrType := e.llvmType(s.X.SSAType())
2448  		e.nextReg++
2449  		tmp := "%sl" | irItoa(e.nextReg)
2450  		e.w("  ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
2451  		e.w("  store ") ; e.w(arrType) ; e.w(" ") ; e.w(src) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
2452  		oldPtr = tmp
2453  		oldLen = irItoa64(arr.Len())
2454  		oldCap = oldLen
2455  	} else {
2456  		e.nextReg++
2457  		oldPtr = "%sl" | irItoa(e.nextReg)
2458  		e.w("  ")
2459  		e.w(oldPtr)
2460  		e.w(" = extractvalue ")
2461  		e.w(sty)
2462  		e.w(" ")
2463  		e.w(src)
2464  		e.w(", 0\n")
2465  		e.nextReg++
2466  		oldLen = "%sl" | irItoa(e.nextReg)
2467  		e.w("  ")
2468  		e.w(oldLen)
2469  		e.w(" = extractvalue ")
2470  		e.w(sty)
2471  		e.w(" ")
2472  		e.w(src)
2473  		e.w(", 1\n")
2474  		e.nextReg++
2475  		oldCap = "%sl" | irItoa(e.nextReg)
2476  		e.w("  ")
2477  		e.w(oldCap)
2478  		e.w(" = extractvalue ")
2479  		e.w(sty)
2480  		e.w(" ")
2481  		e.w(src)
2482  		e.w(", 2\n")
2483  	}
2484  	toIpt := func(val SSAValue, operandStr string) string {
2485  		if val == nil {
2486  			return operandStr
2487  		}
2488  		valType := e.llvmType(val.SSAType())
2489  		if valType == ipt {
2490  			return operandStr
2491  		}
2492  		e.nextReg++
2493  		ext := "%sl" | irItoa(e.nextReg)
2494  		e.w("  ") ; e.w(ext) ; e.w(" = sext ") ; e.w(valType) ; e.w(" ") ; e.w(operandStr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
2495  		return ext
2496  	}
2497  	low := "0"
2498  	if s.Low != nil {
2499  		low = toIpt(s.Low, e.operand(s.Low))
2500  	}
2501  	high := oldLen
2502  	if s.High != nil {
2503  		high = toIpt(s.High, e.operand(s.High))
2504  	}
2505  	maxCap := oldCap
2506  	if s.Max != nil {
2507  		maxCap = toIpt(s.Max, e.operand(s.Max))
2508  	}
2509  	elemType := "i8"
2510  	if sl, ok := safeUnderlying(s.X.SSAType()).(*Slice); ok {
2511  		elemType = e.llvmType(sl.Elem())
2512  	} else if ar, ok := safeUnderlying(s.X.SSAType()).(*Array); ok {
2513  		elemType = e.llvmType(ar.Elem())
2514  	}
2515  	e.nextReg++
2516  	newPtr := "%sl" | irItoa(e.nextReg)
2517  	e.w("  ")
2518  	e.w(newPtr)
2519  	e.w(" = getelementptr inbounds ")
2520  	e.w(elemType)
2521  	e.w(", ptr ")
2522  	e.w(oldPtr)
2523  	e.w(", ")
2524  	e.w(ipt)
2525  	e.w(" ")
2526  	e.w(low)
2527  	e.w("\n")
2528  	e.nextReg++
2529  	newLen := "%sl" | irItoa(e.nextReg)
2530  	e.w("  ")
2531  	e.w(newLen)
2532  	e.w(" = sub ")
2533  	e.w(ipt)
2534  	e.w(" ")
2535  	e.w(high)
2536  	e.w(", ")
2537  	e.w(low)
2538  	e.w("\n")
2539  	e.nextReg++
2540  	newCap := "%sl" | irItoa(e.nextReg)
2541  	e.w("  ")
2542  	e.w(newCap)
2543  	e.w(" = sub ")
2544  	e.w(ipt)
2545  	e.w(" ")
2546  	e.w(maxCap)
2547  	e.w(", ")
2548  	e.w(low)
2549  	e.w("\n")
2550  	e.nextReg++
2551  	s1 := "%sl" | irItoa(e.nextReg)
2552  	e.w("  ")
2553  	e.w(s1)
2554  	e.w(" = insertvalue ")
2555  	e.w(sty)
2556  	e.w(" undef, ptr ")
2557  	e.w(newPtr)
2558  	e.w(", 0\n")
2559  	e.nextReg++
2560  	s2 := "%sl" | irItoa(e.nextReg)
2561  	e.w("  ")
2562  	e.w(s2)
2563  	e.w(" = insertvalue ")
2564  	e.w(sty)
2565  	e.w(" ")
2566  	e.w(s1)
2567  	e.w(", ")
2568  	e.w(ipt)
2569  	e.w(" ")
2570  	e.w(newLen)
2571  	e.w(", 1\n")
2572  	e.w("  ")
2573  	e.w(reg)
2574  	e.w(" = insertvalue ")
2575  	e.w(sty)
2576  	e.w(" ")
2577  	e.w(s2)
2578  	e.w(", ")
2579  	e.w(ipt)
2580  	e.w(" ")
2581  	e.w(newCap)
2582  	e.w(", 2\n")
2583  }
2584  
2585  func (e *irEmitter) emitMakeInterface(m *SSAMakeInterface) {
2586  	reg := e.regName(m)
2587  	val := e.operand(m.X)
2588  	valType := e.llvmType(m.X.SSAType())
2589  	if at, ok := e.allocTypes[m.X]; ok && at != "ptr" && at != "void" {
2590  		valType = at
2591  	}
2592  	p := func(prefix string) string {
2593  		e.nextReg++
2594  		return "%" | prefix | irItoa(e.nextReg)
2595  	}
2596  	if valType == e.ifaceType() {
2597  		tp := p("mi")
2598  		e.w("  ") ; e.w(tp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 0\n")
2599  		dp := p("mi")
2600  		e.w("  ") ; e.w(dp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
2601  		t1 := p("mi")
2602  		e.w("  ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(tp) ; e.w(", 0\n")
2603  		e.w("  ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(dp) ; e.w(", 1\n")
2604  		return
2605  	}
2606  	var valPtr string
2607  	if valType == "ptr" {
2608  		valPtr = val
2609  	} else {
2610  		valPtr = p("mi")
2611  		e.w("  ") ; e.w(valPtr) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
2612  		e.w("  store ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2613  	}
2614  	typeid := e.typeIDGlobal(m.X.SSAType())
2615  	t1 := p("mi")
2616  	e.w("  ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(typeid) ; e.w(", 0\n")
2617  	e.w("  ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1) ; e.w(", ptr ") ; e.w(valPtr) ; e.w(", 1\n")
2618  }
2619  
2620  func (e *irEmitter) typeIDGlobal(t Type) string {
2621  	name := e.typeIDName(t)
2622  	if e.typeIDs == nil {
2623  		e.typeIDs = map[string]bool{}
2624  	}
2625  	if !e.typeIDs[name] {
2626  		e.typeIDs[name] = true
2627  	}
2628  	return "@" | name
2629  }
2630  
2631  func (e *irEmitter) typeIDName(t Type) string {
2632  	pkg := e.pkg.Pkg.Path()
2633  	if named, ok := t.(*Named); ok && named.Obj() != nil {
2634  		return pkg | ".typeid." | named.Obj().Name()
2635  	}
2636  	if p, ok := t.(*Pointer); ok {
2637  		if named, ok := p.Elem().(*Named); ok && named.Obj() != nil {
2638  			return pkg | ".typeid.ptr." | named.Obj().Name()
2639  		}
2640  	}
2641  	raw := e.llvmType(t)
2642  	safe := []byte{:len(raw)}
2643  	safe = safe[:0]
2644  	for i := 0; i < len(raw); i++ {
2645  		c := raw[i]
2646  		if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '.' {
2647  			safe = append(safe, c)
2648  		} else if c == '{' || c == '}' || c == ',' || c == ' ' || c == '*' {
2649  			safe = append(safe, '_')
2650  		}
2651  	}
2652  	return pkg | ".typeid." | string(safe)
2653  }
2654  
2655  func (e *irEmitter) findIfaceImpls(methodName string) []ifaceImpl {
2656  	var impls []ifaceImpl
2657  	for mname, m := range e.pkg.Members {
2658  		fn, ok := m.(*SSAFunction)
2659  		if !ok {
2660  			continue
2661  		}
2662  		dotIdx := -1
2663  		for i := 0; i < len(mname); i++ {
2664  			if mname[i] == '.' {
2665  				dotIdx = i
2666  				break
2667  			}
2668  		}
2669  		if dotIdx < 0 {
2670  			continue
2671  		}
2672  		if mname[dotIdx+1:] != methodName {
2673  			continue
2674  		}
2675  		tname := mname[:dotIdx]
2676  		obj := e.pkg.Pkg.Scope().Lookup(tname)
2677  		if obj == nil {
2678  			continue
2679  		}
2680  		tn, ok2 := obj.(*TypeName)
2681  		if !ok2 || tn.Type() == nil {
2682  			continue
2683  		}
2684  		isPtrRecv := fn.object != nil && fn.object.HasPtrRecv()
2685  		impls = append(impls, ifaceImpl{fn: fn, recvType: tn.Type(), ptrRecv: isPtrRecv})
2686  	}
2687  	return impls
2688  }
2689  
2690  type ifaceImpl struct {
2691  	fn       *SSAFunction
2692  	recvType Type
2693  	ptrRecv  bool
2694  }
2695  
2696  func (e *irEmitter) emitInvoke(inv *SSAInvoke) {
2697  	reg := e.regName(inv)
2698  	ifaceVal := e.operand(inv.X)
2699  	retType := e.llvmType(inv.SSAType())
2700  	isVoid := retType == "void"
2701  	p := func(prefix string) string {
2702  		e.nextReg++
2703  		return "%" | prefix | irItoa(e.nextReg)
2704  	}
2705  	tidPtr := p("tid")
2706  	e.w("  ") ; e.w(tidPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(ifaceVal) ; e.w(", 0\n")
2707  	valPtr := p("vp")
2708  	e.w("  ") ; e.w(valPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(ifaceVal) ; e.w(", 1\n")
2709  
2710  	impls := e.findIfaceImpls(inv.MethodName)
2711  
2712  	if len(impls) == 0 {
2713  		e.w("  ; invoke: no implementations for ") ; e.w(inv.MethodName) ; e.w("\n")
2714  		if !isVoid {
2715  			e.nextReg++
2716  			zp := "%zp" | irItoa(e.nextReg)
2717  			e.w("  ") ; e.w(zp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
2718  			e.w("  store ") ; e.w(retType) ; e.w(" zeroinitializer, ptr ") ; e.w(zp) ; e.w("\n")
2719  			e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(zp) ; e.w("\n")
2720  		}
2721  		return
2722  	}
2723  
2724  	if len(impls) == 1 {
2725  		impl := impls[0]
2726  		var recvLLVM, recv string
2727  		if impl.ptrRecv {
2728  			recvLLVM = "ptr"
2729  			recv = valPtr
2730  		} else {
2731  			recvLLVM = e.llvmType(impl.recvType)
2732  			if recvLLVM == "ptr" {
2733  				recv = valPtr
2734  			} else {
2735  				recv = p("ld")
2736  				e.w("  ") ; e.w(recv) ; e.w(" = load ") ; e.w(recvLLVM) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2737  			}
2738  		}
2739  		e.w("  ")
2740  		if !isVoid {
2741  			e.w(reg) ; e.w(" = ")
2742  		}
2743  		e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(e.funcSymbol(impl.fn)) ; e.w("(")
2744  		e.w(recvLLVM) ; e.w(" ") ; e.w(recv)
2745  		for i, arg := range inv.Args {
2746  			argT := e.llvmType(arg.SSAType())
2747  			if argT == "void" {
2748  				argT = "ptr"
2749  			}
2750  			e.w(", ") ; e.w(argT) ; e.w(" ") ; e.w(e.operand(arg))
2751  			_ = i
2752  		}
2753  		e.w(", ptr null)\n")
2754  		return
2755  	}
2756  
2757  	baseID := e.nextReg
2758  	mergeLabel := "invoke.merge" | irItoa(baseID)
2759  	var checkLabels []string
2760  	var caseLabels []string
2761  	var callRegs []string
2762  	for i := range impls {
2763  		checkLabels = append(checkLabels, "invoke.check" | irItoa(baseID) | "." | irItoa(i))
2764  		caseLabels = append(caseLabels, "invoke.case" | irItoa(baseID) | "." | irItoa(i))
2765  		if !isVoid {
2766  			callRegs = append(callRegs, p("cr"))
2767  		}
2768  	}
2769  	defaultLabel := "invoke.default" | irItoa(baseID)
2770  
2771  	e.w("  br label %") ; e.w(checkLabels[0]) ; e.w("\n")
2772  
2773  	for i, impl := range impls {
2774  		nextCheck := defaultLabel
2775  		if i < len(impls)-1 {
2776  			nextCheck = checkLabels[i+1]
2777  		}
2778  		e.w(checkLabels[i]) ; e.w(":\n")
2779  		tidGlobal := e.typeIDGlobal(impl.recvType)
2780  		cmpReg := p("cmp")
2781  		e.w("  ") ; e.w(cmpReg) ; e.w(" = icmp eq ptr ") ; e.w(tidPtr) ; e.w(", ") ; e.w(tidGlobal) ; e.w("\n")
2782  		e.w("  br i1 ") ; e.w(cmpReg) ; e.w(", label %") ; e.w(caseLabels[i]) ; e.w(", label %") ; e.w(nextCheck) ; e.w("\n")
2783  
2784  		e.w(caseLabels[i]) ; e.w(":\n")
2785  		var recvLLVM, recv string
2786  		if impl.ptrRecv {
2787  			recvLLVM = "ptr"
2788  			recv = valPtr
2789  		} else {
2790  			recvLLVM = e.llvmType(impl.recvType)
2791  			if recvLLVM == "ptr" {
2792  				recv = valPtr
2793  			} else {
2794  				recv = p("ld")
2795  				e.w("  ") ; e.w(recv) ; e.w(" = load ") ; e.w(recvLLVM) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2796  			}
2797  		}
2798  		e.w("  ")
2799  		if !isVoid {
2800  			e.w(callRegs[i]) ; e.w(" = ")
2801  		}
2802  		e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(e.funcSymbol(impl.fn)) ; e.w("(")
2803  		e.w(recvLLVM) ; e.w(" ") ; e.w(recv)
2804  		for ii, arg := range inv.Args {
2805  			argT := e.llvmType(arg.SSAType())
2806  			if argT == "void" {
2807  				argT = "ptr"
2808  			}
2809  			e.w(", ") ; e.w(argT) ; e.w(" ") ; e.w(e.operand(arg))
2810  			_ = ii
2811  		}
2812  		e.w(", ptr null)\n")
2813  		e.w("  br label %") ; e.w(mergeLabel) ; e.w("\n")
2814  	}
2815  
2816  	e.w(defaultLabel) ; e.w(":\n")
2817  	e.w("  unreachable\n")
2818  
2819  	e.w(mergeLabel) ; e.w(":\n")
2820  	if !isVoid {
2821  		e.w("  ") ; e.w(reg) ; e.w(" = phi ") ; e.w(retType) ; e.w(" ")
2822  		for i := range impls {
2823  			if i > 0 { e.w(", ") }
2824  			e.w("[ ") ; e.w(callRegs[i]) ; e.w(", %") ; e.w(caseLabels[i]) ; e.w(" ]")
2825  		}
2826  		e.w("\n")
2827  	}
2828  }
2829  
2830  func (e *irEmitter) emitTypeAssert(t *SSATypeAssert) {
2831  	reg := e.regName(t)
2832  	val := e.operand(t.X)
2833  	assertedType := e.llvmType(t.AssertedType)
2834  	voidAssert := assertedType == "void"
2835  	if voidAssert {
2836  		assertedType = "ptr"
2837  	}
2838  	p := func(prefix string) string {
2839  		e.nextReg++
2840  		return "%" | prefix | irItoa(e.nextReg)
2841  	}
2842  	// Check if input is already a concrete ptr (not an interface {ptr, ptr})
2843  	inputType := e.llvmType(t.X.SSAType())
2844  	if at, ok := e.allocTypes[t.X]; ok {
2845  		inputType = at
2846  	}
2847  	var valPtr, typePtr string
2848  	if inputType == "ptr" {
2849  		valPtr = val
2850  		typePtr = "null"
2851  	} else {
2852  		valPtr = p("ta")
2853  		e.w("  ") ; e.w(valPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 1\n")
2854  		typePtr = p("ta")
2855  		e.w("  ") ; e.w(typePtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(val) ; e.w(", 0\n")
2856  	}
2857  	if t.CommaOk {
2858  		tidGlobal := e.typeIDGlobal(t.AssertedType)
2859  		ok := p("ta")
2860  		e.w("  ") ; e.w(ok) ; e.w(" = icmp eq ptr ") ; e.w(typePtr) ; e.w(", ") ; e.w(tidGlobal) ; e.w("\n")
2861  		loaded := p("ta")
2862  		e.w("  ") ; e.w(loaded) ; e.w(" = load ") ; e.w(assertedType) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2863  		tupType := "{" | assertedType | ", i1}"
2864  		t1 := p("ta")
2865  		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")
2866  		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")
2867  		if voidAssert {
2868  			e.allocTypes[t] = tupType
2869  		}
2870  	} else {
2871  		e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(assertedType) ; e.w(", ptr ") ; e.w(valPtr) ; e.w("\n")
2872  		if voidAssert {
2873  			e.allocTypes[t] = assertedType
2874  		}
2875  	}
2876  }
2877  
2878  func (e *irEmitter) emitMakeMap(m *SSAMakeMap) {
2879  	reg := e.regName(m)
2880  	ipt := e.intptrType()
2881  	mt, _ := safeUnderlying(m.SSAType()).(*TCMap)
2882  	keyType := "i32"
2883  	valType := "i32"
2884  	alg := "0"
2885  	if mt != nil {
2886  		keyType = e.llvmType(mt.Key())
2887  		valType = e.llvmType(mt.Elem())
2888  		if e.isStringLike(mt.Key()) {
2889  			alg = "1"
2890  		}
2891  	}
2892  	p := func(prefix string) string {
2893  		e.nextReg++
2894  		return "%" | prefix | irItoa(e.nextReg)
2895  	}
2896  	keySz := p("mm")
2897  	e.w("  ") ; e.w(keySz) ; e.w(" = ptrtoint ptr getelementptr (")
2898  	e.w(keyType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
2899  	valSz := p("mm")
2900  	e.w("  ") ; e.w(valSz) ; e.w(" = ptrtoint ptr getelementptr (")
2901  	e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
2902  	hint := "8"
2903  	if m.Reserve != nil {
2904  		hint = e.operand(m.Reserve)
2905  	}
2906  	e.w("  ") ; e.w(reg) ; e.w(" = call ptr @runtime.hashmapMake(")
2907  	e.w(ipt) ; e.w(" ") ; e.w(keySz) ; e.w(", ")
2908  	e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(", ")
2909  	e.w(ipt) ; e.w(" ") ; e.w(hint) ; e.w(", i8 ") ; e.w(alg) ; e.w(")\n")
2910  	e.declareRuntime("runtime.hashmapMake", "ptr", ipt | ", " | ipt | ", " | ipt | ", i8")
2911  }
2912  
2913  func (e *irEmitter) emitMapUpdate(m *SSAMapUpdate) {
2914  	mapVal := e.operand(m.Map)
2915  	keyVal := e.operand(m.Key)
2916  	valVal := e.operand(m.Value)
2917  	mapType := m.Map.SSAType()
2918  	if pt, ok := safeUnderlying(mapType).(*Pointer); ok {
2919  		mapType = pt.Elem()
2920  	}
2921  	mt, _ := safeUnderlying(mapType).(*TCMap)
2922  	keyType := "i32"
2923  	valType := "i32"
2924  	if mt != nil {
2925  		keyType = e.llvmType(mt.Key())
2926  		valType = e.llvmType(mt.Elem())
2927  	}
2928  	p := func(prefix string) string {
2929  		e.nextReg++
2930  		return "%" | prefix | irItoa(e.nextReg)
2931  	}
2932  	if keyVal == "null" && keyType != "ptr" { keyVal = "zeroinitializer" }
2933  	if valVal == "null" && valType != "ptr" { valVal = "zeroinitializer" }
2934  	keyAlloca := p("mu")
2935  	e.w("  ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
2936  	e.w("  store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
2937  	valAlloca := p("mu")
2938  	e.w("  ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
2939  	e.w("  store ") ; e.w(valType) ; e.w(" ") ; e.w(valVal) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
2940  	if mt != nil && e.isStringLike(mt.Key()) {
2941  		e.w("  call void @runtime.hashmapContentSet(ptr ") ; e.w(mapVal)
2942  		e.w(", ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal)
2943  		e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
2944  		e.declareRuntime("runtime.hashmapContentSet", "void", "ptr, " | keyType | ", ptr")
2945  	} else {
2946  		e.w("  call void @runtime.hashmapBinarySet(ptr ") ; e.w(mapVal)
2947  		e.w(", ptr ") ; e.w(keyAlloca)
2948  		e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
2949  		e.declareRuntime("runtime.hashmapBinarySet", "void", "ptr, ptr, ptr")
2950  	}
2951  }
2952  
2953  func (e *irEmitter) emitLookup(l *SSALookup) {
2954  	reg := e.regName(l)
2955  	ipt := e.intptrType()
2956  	mapVal := e.operand(l.X)
2957  	keyVal := e.operand(l.Index)
2958  	mt, _ := safeUnderlying(l.X.SSAType()).(*TCMap)
2959  	keyType := "i32"
2960  	valType := "i32"
2961  	if mt != nil {
2962  		keyType = e.llvmType(mt.Key())
2963  		valType = e.llvmType(mt.Elem())
2964  	}
2965  	p := func(prefix string) string {
2966  		e.nextReg++
2967  		return "%" | prefix | irItoa(e.nextReg)
2968  	}
2969  	valAlloca := p("ml")
2970  	e.w("  ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
2971  	valSz := p("ml")
2972  	e.w("  ") ; e.w(valSz) ; e.w(" = ptrtoint ptr getelementptr (")
2973  	e.w(valType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
2974  	if mt != nil && e.isStringLike(mt.Key()) {
2975  		okReg := p("ml")
2976  		e.w("  ") ; e.w(okReg) ; e.w(" = call i1 @runtime.hashmapContentGet(ptr ") ; e.w(mapVal)
2977  		e.w(", ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal)
2978  		e.w(", ptr ") ; e.w(valAlloca)
2979  		e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(")\n")
2980  		e.declareRuntime("runtime.hashmapContentGet", "i1", "ptr, " | keyType | ", ptr, " | ipt)
2981  		if l.CommaOk {
2982  			loaded := p("ml")
2983  			e.w("  ") ; e.w(loaded) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
2984  			tupType := "{" | valType | ", i1}"
2985  			t1 := p("ml")
2986  			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")
2987  			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")
2988  		} else {
2989  			e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
2990  		}
2991  	} else {
2992  		keyAlloca := p("ml")
2993  		e.w("  ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
2994  		e.w("  store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
2995  		okReg := p("ml")
2996  		e.w("  ") ; e.w(okReg) ; e.w(" = call i1 @runtime.hashmapBinaryGet(ptr ") ; e.w(mapVal)
2997  		e.w(", ptr ") ; e.w(keyAlloca)
2998  		e.w(", ptr ") ; e.w(valAlloca)
2999  		e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(valSz) ; e.w(")\n")
3000  		e.declareRuntime("runtime.hashmapBinaryGet", "i1", "ptr, ptr, ptr, " | ipt)
3001  		if l.CommaOk {
3002  			loaded := p("ml")
3003  			e.w("  ") ; e.w(loaded) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
3004  			tupType := "{" | valType | ", i1}"
3005  			t1 := p("ml")
3006  			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")
3007  			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")
3008  		} else {
3009  			e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
3010  		}
3011  	}
3012  }
3013  
3014  func (e *irEmitter) isStringLike(t Type) bool {
3015  	if t == nil {
3016  		return false
3017  	}
3018  	if b, ok := safeUnderlying(t).(*Basic); ok {
3019  		return b.Info()&IsString != 0
3020  	}
3021  	return false
3022  }
3023  
3024  func (e *irEmitter) emitMakeClosure(m *SSAMakeClosure) {
3025  	reg := e.regName(m)
3026  	fn, _ := m.Fn.(*SSAFunction)
3027  	p := func(prefix string) string {
3028  		e.nextReg++
3029  		return "%" | prefix | irItoa(e.nextReg)
3030  	}
3031  	ipt := e.intptrType()
3032  
3033  	if len(m.Bindings) == 0 {
3034  		t1 := p("mc")
3035  		e.w("  ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr null, 0\n")
3036  		e.w("  ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1)
3037  		e.w(", ptr ") ; e.w(e.funcSymbol(fn)) ; e.w(", 1\n")
3038  		return
3039  	}
3040  
3041  	ctxType := e.closureContextType(m.Bindings)
3042  	ctxSz := p("mc")
3043  	e.w("  ") ; e.w(ctxSz) ; e.w(" = ptrtoint ptr getelementptr (")
3044  	e.w(ctxType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
3045  	ctxPtr := p("mc")
3046  	e.w("  ") ; e.w(ctxPtr) ; e.w(" = call ptr @runtime.alloc(")
3047  	e.w(ipt) ; e.w(" ") ; e.w(ctxSz) ; e.w(", ptr null, ptr undef)\n")
3048  	e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
3049  
3050  	for i, b := range m.Bindings {
3051  		bval := e.operand(b)
3052  		btype := e.llvmType(b.SSAType())
3053  		gep := p("mc")
3054  		e.w("  ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(ctxType) ; e.w(", ptr ")
3055  		e.w(ctxPtr) ; e.w(", i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
3056  		e.w("  store ") ; e.w(btype) ; e.w(" ") ; e.w(bval) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
3057  	}
3058  
3059  	t1 := p("mc")
3060  	e.w("  ") ; e.w(t1) ; e.w(" = insertvalue {ptr, ptr} undef, ptr ") ; e.w(ctxPtr) ; e.w(", 0\n")
3061  	e.w("  ") ; e.w(reg) ; e.w(" = insertvalue {ptr, ptr} ") ; e.w(t1)
3062  	e.w(", ptr ") ; e.w(e.funcSymbol(fn)) ; e.w(", 1\n")
3063  }
3064  
3065  func (e *irEmitter) closureContextType(bindings []SSAValue) string {
3066  	s := "{"
3067  	for i, b := range bindings {
3068  		if i > 0 {
3069  			s = s | ", "
3070  		}
3071  		s = s | e.llvmType(b.SSAType())
3072  	}
3073  	return s | "}"
3074  }
3075  
3076  func (e *irEmitter) emitFreeVarUnpack(f *SSAFunction) {
3077  	ctxTypes := []string{:len(f.FreeVars)}
3078  	for i, fv := range f.FreeVars {
3079  		ctxTypes[i] = e.llvmType(fv.SSAType())
3080  	}
3081  	ctxType := "{"
3082  	for i, t := range ctxTypes {
3083  		if i > 0 {
3084  			ctxType = ctxType | ", "
3085  		}
3086  		ctxType = ctxType | t
3087  	}
3088  	ctxType = ctxType | "}"
3089  
3090  	for i, fv := range f.FreeVars {
3091  		fvName := e.regName(fv)
3092  		e.nextReg++
3093  		gep := "%fv" | irItoa(e.nextReg)
3094  		e.w("  ") ; e.w(gep) ; e.w(" = getelementptr ") ; e.w(ctxType)
3095  		e.w(", ptr %context, i32 0, i32 ") ; e.w(irItoa(i)) ; e.w("\n")
3096  		e.w("  ") ; e.w(fvName) ; e.w(" = load ") ; e.w(ctxTypes[i])
3097  		e.w(", ptr ") ; e.w(gep) ; e.w("\n")
3098  	}
3099  }
3100  
3101  func (e *irEmitter) emitPanic(p *SSAPanic) {
3102  	e.w("  call void @runtime._panic(ptr null)\n")
3103  	e.w("  unreachable\n")
3104  	e.declareRuntime("runtime._panic", "void", "ptr")
3105  }
3106  
3107  func (e *irEmitter) emitRange(r *SSARange) {
3108  	reg := e.regName(r)
3109  	if _, ok := safeUnderlying(r.X.SSAType()).(*TCMap); ok {
3110  		e.w("  ") ; e.w(reg) ; e.w(" = alloca [48 x i8]\n")
3111  		e.w("  call void @llvm.memset.p0.i64(ptr ") ; e.w(reg) ; e.w(", i8 0, i64 48, i1 false)\n")
3112  		e.declareRuntime("llvm.memset.p0.i64", "void", "ptr, i8, i64, i1")
3113  		return
3114  	}
3115  	ipt := e.intptrType()
3116  	e.w("  ") ; e.w(reg) ; e.w(" = alloca ") ; e.w(ipt) ; e.w("\n")
3117  	e.w("  store ") ; e.w(ipt) ; e.w(" 0, ptr ") ; e.w(reg) ; e.w("\n")
3118  }
3119  
3120  func (e *irEmitter) emitNext(n *SSANext) {
3121  	reg := e.regName(n)
3122  	rangeInstr := n.Iter.(*SSARange)
3123  	iterPtr := e.regName(rangeInstr)
3124  	collVal := e.operand(rangeInstr.X)
3125  	p := func(prefix string) string {
3126  		e.nextReg++
3127  		return "%" | prefix | irItoa(e.nextReg)
3128  	}
3129  	if mt, ok := safeUnderlying(rangeInstr.X.SSAType()).(*TCMap); ok {
3130  		e.emitNextMap(reg, iterPtr, collVal, mt, n, p)
3131  		return
3132  	}
3133  	if arr, ok := safeUnderlying(rangeInstr.X.SSAType()).(*Array); ok {
3134  		e.emitNextArray(reg, iterPtr, collVal, arr, n, p)
3135  		return
3136  	}
3137  	collLLVM := e.llvmType(rangeInstr.X.SSAType())
3138  	if len(collLLVM) > 0 && collLLVM[0] == 'i' {
3139  		tupType := e.llvmType(n.SSAType())
3140  		if at, ok := e.allocTypes[n]; ok {
3141  			tupType = at
3142  		}
3143  		e.w("  ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" zeroinitializer, i1 false, 0\n")
3144  		return
3145  	}
3146  	e.emitNextSlice(reg, iterPtr, collVal, rangeInstr, n, p)
3147  }
3148  
3149  func (e *irEmitter) emitNextSlice(reg, iterPtr, collVal string, rangeInstr *SSARange, n *SSANext, p func(string) string) {
3150  	ipt := e.intptrType()
3151  	sty := e.sliceType()
3152  	idx := p("rn")
3153  	e.w("  ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
3154  	slLen := p("rn")
3155  	e.w("  ") ; e.w(slLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(collVal) ; e.w(", 1\n")
3156  	ok := p("rn")
3157  	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")
3158  	key := p("rn")
3159  	e.w("  ") ; e.w(key) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(" to i32\n")
3160  	dataPtr := p("rn")
3161  	e.w("  ") ; e.w(dataPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(collVal) ; e.w(", 0\n")
3162  	elemType := "i32"
3163  	if sl, ok2 := safeUnderlying(rangeInstr.X.SSAType()).(*Slice); ok2 {
3164  		elemType = e.llvmType(sl.Elem())
3165  	}
3166  	eptr := p("rn")
3167  	e.w("  ") ; e.w(eptr) ; e.w(" = getelementptr ") ; e.w(elemType)
3168  	e.w(", ptr ") ; e.w(dataPtr) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
3169  	fallback := p("rn")
3170  	e.w("  ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
3171  	safePtr := p("rn")
3172  	e.w("  ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
3173  	e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
3174  	elem := p("rn")
3175  	e.w("  ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
3176  	inc := p("rn")
3177  	e.w("  ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
3178  	newCnt := p("rn")
3179  	e.w("  ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
3180  	e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
3181  	e.w("  store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
3182  	tupType := e.llvmType(n.SSAType())
3183  	t1 := p("rn")
3184  	e.w("  ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
3185  	t2 := p("rn")
3186  	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")
3187  	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")
3188  }
3189  
3190  func (e *irEmitter) emitNextArray(reg, iterPtr, collVal string, arr *Array, n *SSANext, p func(string) string) {
3191  	ipt := e.intptrType()
3192  	arrLen := arr.Len()
3193  	elemType := e.llvmType(arr.Elem())
3194  	arrType := "[" | irItoa(int(arrLen)) | " x " | elemType | "]"
3195  	idx := p("rn")
3196  	e.w("  ") ; e.w(idx) ; e.w(" = load ") ; e.w(ipt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
3197  	ok := p("rn")
3198  	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")
3199  	key := p("rn")
3200  	e.w("  ") ; e.w(key) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(" to i32\n")
3201  	// Store array to memory to get element pointer via GEP
3202  	arrAlloca := p("rn")
3203  	e.w("  ") ; e.w(arrAlloca) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
3204  	e.w("  store ") ; e.w(arrType) ; e.w(" ") ; e.w(collVal) ; e.w(", ptr ") ; e.w(arrAlloca) ; e.w("\n")
3205  	eptr := p("rn")
3206  	e.w("  ") ; e.w(eptr) ; e.w(" = getelementptr inbounds ") ; e.w(arrType)
3207  	e.w(", ptr ") ; e.w(arrAlloca) ; e.w(", i32 0, ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
3208  	fallback := p("rn")
3209  	e.w("  ") ; e.w(fallback) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
3210  	safePtr := p("rn")
3211  	e.w("  ") ; e.w(safePtr) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ptr ") ; e.w(eptr)
3212  	e.w(", ptr ") ; e.w(fallback) ; e.w("\n")
3213  	elem := p("rn")
3214  	e.w("  ") ; e.w(elem) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(safePtr) ; e.w("\n")
3215  	inc := p("rn")
3216  	e.w("  ") ; e.w(inc) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w(", 1\n")
3217  	newCnt := p("rn")
3218  	e.w("  ") ; e.w(newCnt) ; e.w(" = select i1 ") ; e.w(ok) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(inc)
3219  	e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(idx) ; e.w("\n")
3220  	e.w("  store ") ; e.w(ipt) ; e.w(" ") ; e.w(newCnt) ; e.w(", ptr ") ; e.w(iterPtr) ; e.w("\n")
3221  	tupType := "{i1, i32, " | elemType | "}"
3222  	e.allocTypes[n] = tupType
3223  	t1 := p("rn")
3224  	e.w("  ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
3225  	t2 := p("rn")
3226  	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")
3227  	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")
3228  }
3229  
3230  func (e *irEmitter) emitNextMap(reg, iterPtr, collVal string, mt *TCMap, n *SSANext, p func(string) string) {
3231  	keyType := e.llvmType(mt.Key())
3232  	valType := e.llvmType(mt.Elem())
3233  	keyAlloca := p("mn")
3234  	e.w("  ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
3235  	valAlloca := p("mn")
3236  	e.w("  ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(valType) ; e.w("\n")
3237  	ok := p("mn")
3238  	e.w("  ") ; e.w(ok) ; e.w(" = call i1 @runtime.hashmapNext(ptr ") ; e.w(collVal)
3239  	e.w(", ptr ") ; e.w(iterPtr)
3240  	e.w(", ptr ") ; e.w(keyAlloca)
3241  	e.w(", ptr ") ; e.w(valAlloca) ; e.w(")\n")
3242  	key := p("mn")
3243  	e.w("  ") ; e.w(key) ; e.w(" = load ") ; e.w(keyType) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
3244  	val := p("mn")
3245  	e.w("  ") ; e.w(val) ; e.w(" = load ") ; e.w(valType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
3246  	tupType := e.llvmType(n.SSAType())
3247  	t1 := p("mn")
3248  	e.w("  ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupType) ; e.w(" undef, i1 ") ; e.w(ok) ; e.w(", 0\n")
3249  	t2 := p("mn")
3250  	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")
3251  	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")
3252  	e.declareRuntime("runtime.hashmapNext", "i1", "ptr, ptr, ptr, ptr")
3253  }
3254  
3255  func (e *irEmitter) operand(v SSAValue) string {
3256  	if v == nil {
3257  		return "zeroinitializer"
3258  	}
3259  	if c, ok := v.(*SSAConst); ok {
3260  		return e.constOperand(c)
3261  	}
3262  	if b, ok := v.(*SSABuiltin); ok {
3263  		return "@runtime." | b.SSAName()
3264  	}
3265  	if f, ok := v.(*SSAFunction); ok {
3266  		return "{ ptr null, ptr " | e.funcSymbol(f) | " }"
3267  	}
3268  	if g, ok := v.(*SSAGlobal); ok {
3269  		e.declareExternalGlobal(g)
3270  		return e.globalName(g)
3271  	}
3272  	return e.regName(v)
3273  }
3274  
3275  func (e *irEmitter) constOperand(c *SSAConst) string {
3276  	if c.val == nil {
3277  		if c.typ == nil {
3278  			return "null"
3279  		}
3280  		typ := e.llvmType(c.typ)
3281  		if typ == "ptr" {
3282  			return "null"
3283  		}
3284  		if typ == "i1" {
3285  			return "false"
3286  		}
3287  		return "zeroinitializer"
3288  	}
3289  	b := underlyingBasic(c.typ)
3290  	if b != nil {
3291  		switch b.kind {
3292  		case Bool, UntypedBool:
3293  			s := c.val.String()
3294  			if s == "true" {
3295  				return "true"
3296  			}
3297  			return "false"
3298  		case Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64,
3299  			UntypedInt, UntypedRune:
3300  			return c.val.String()
3301  		case Float32, Float64, UntypedFloat:
3302  			return c.val.String()
3303  		case TCString, UntypedString:
3304  			cv, ok := c.val.(constant.Value)
3305  			if !ok {
3306  				return "zeroinitializer"
3307  			}
3308  			s := constant.StringVal(cv)
3309  			if len(s) == 0 {
3310  				return "zeroinitializer"
3311  			}
3312  			idx := e.addStringConst(s)
3313  			ipt := e.intptrType()
3314  			slen := irItoa64(int64(len(s)))
3315  			return "{ ptr " | e.strConstGlobal(idx) | ", " | ipt | " " | slen | ", " | ipt | " " | slen | " }"
3316  		}
3317  	}
3318  	if c.typ == nil {
3319  		return c.val.String()
3320  	}
3321  	return "zeroinitializer"
3322  }
3323  
3324  func underlyingBasic(t Type) *Basic {
3325  	if t == nil {
3326  		return nil
3327  	}
3328  	u := safeUnderlying(t)
3329  	if u == nil {
3330  		return nil
3331  	}
3332  	b, ok := u.(*Basic)
3333  	if !ok {
3334  		return nil
3335  	}
3336  	return b
3337  }
3338  
3339  func newTCPackageWithUniverse(path, name string) *TCPackage {
3340  	return &TCPackage{
3341  		path:  path,
3342  		name:  name,
3343  		scope: NewScope(Universe),
3344  	}
3345  }
3346  
3347  func irItoa(n int) string {
3348  	if n == 0 {
3349  		return "0"
3350  	}
3351  	neg := n < 0
3352  	if neg {
3353  		n = -n
3354  	}
3355  	buf := []byte{:0:20}
3356  	for n > 0 {
3357  		buf = append(buf, byte('0'+n%10))
3358  		n /= 10
3359  	}
3360  	if neg {
3361  		buf = append(buf, '-')
3362  	}
3363  	for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
3364  		buf[i], buf[j] = buf[j], buf[i]
3365  	}
3366  	return string(buf)
3367  }
3368  
3369  func irItoa64(n int64) string {
3370  	if n == 0 {
3371  		return "0"
3372  	}
3373  	neg := n < 0
3374  	if neg {
3375  		n = -n
3376  	}
3377  	buf := []byte{:0:20}
3378  	for n > 0 {
3379  		buf = append(buf, byte('0'+n%10))
3380  		n /= 10
3381  	}
3382  	if neg {
3383  		buf = append(buf, '-')
3384  	}
3385  	for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
3386  		buf[i], buf[j] = buf[j], buf[i]
3387  	}
3388  	return string(buf)
3389  }
3390  
3391  func irFtoa(f float64) string {
3392  	return "0.0"
3393  }
3394  
3395  func irParseInt64(s string) int64 {
3396  	var n int64
3397  	for i := 0; i < len(s); i++ {
3398  		c := s[i]
3399  		if c < '0' || c > '9' {
3400  			break
3401  		}
3402  		n = n*10 + int64(c-'0')
3403  	}
3404  	return n
3405  }
3406  
3407  func CompileToIR(src []byte, name string, triple string) string {
3408  	initUniverse()
3409  	prog := NewSSAProgram()
3410  	pkg := newTCPackageWithUniverse(name, name)
3411  	scope := pkg.Scope()
3412  
3413  	src = rewriteSliceMakeLiterals(src)
3414  	src = stripDuplicatePackageClauses(src)
3415  
3416  	var parseErrors []string
3417  	errh := func(err error) {
3418  		parseErrors = append(parseErrors, err.Error())
3419  	}
3420  	r := bytes.NewReader(src)
3421  	file, err := Parse(NewFileBase(name|".mx"), r, errh, nil, 0)
3422  	if err != nil || file == nil {
3423  		msg := "; parse error"
3424  		for _, e := range parseErrors {
3425  			msg = msg | ": " | e
3426  		}
3427  		return msg | "\n"
3428  	}
3429  
3430  	for _, d := range file.DeclList {
3431  		switch d := d.(type) {
3432  		case *ImportDecl:
3433  			if d.Path == nil {
3434  				continue
3435  			}
3436  			path := d.Path.Value
3437  			if len(path) >= 2 && path[0] == '"' {
3438  				path = path[1 : len(path)-1]
3439  			}
3440  			ensureImportRegistry()
3441  			imported := importRegistry[path]
3442  			if imported == nil {
3443  				continue
3444  			}
3445  			if path == "unsafe" && imported.Scope().Lookup("Pointer") == nil {
3446  				imported.Scope().Insert(NewTypeName(imported, "Pointer", Typ[UnsafePointer]))
3447  			}
3448  			localName := imported.Name()
3449  			if d.LocalPkgName != nil {
3450  				localName = d.LocalPkgName.Value
3451  			}
3452  			scope.Insert(NewPkgName(pkg, localName, imported))
3453  		case *VarDecl:
3454  			for _, n := range d.NameList {
3455  				scope.Insert(NewTCVar(pkg, n.Value, nil))
3456  			}
3457  		case *FuncDecl:
3458  			if d.Recv == nil && d.Name.Value != "init" {
3459  				scope.Insert(NewTCFunc(pkg, d.Name.Value, nil))
3460  			}
3461  		case *TypeDecl:
3462  			scope.Insert(NewTypeName(pkg, d.Name.Value, nil))
3463  		case *ConstDecl:
3464  			for _, n := range d.NameList {
3465  				scope.Insert(NewTCConst(pkg, n.Value, nil, nil))
3466  			}
3467  		}
3468  	}
3469  
3470  	var curConstGroup *Group
3471  	var prevConstValues Expr
3472  	var prevConstType Expr
3473  	iotaVal := int64(-1)
3474  
3475  	for _, d := range file.DeclList {
3476  		if td, ok := d.(*TypeDecl); ok {
3477  			obj := scope.Lookup(td.Name.Value)
3478  			if obj != nil {
3479  				if tn, ok2 := obj.(*TypeName); ok2 {
3480  					NewNamed(tn, nil)
3481  				}
3482  			}
3483  		}
3484  	}
3485  	for _, d := range file.DeclList {
3486  		if td, ok := d.(*TypeDecl); ok {
3487  			obj := scope.Lookup(td.Name.Value)
3488  			if obj != nil {
3489  				if tn, ok2 := obj.(*TypeName); ok2 {
3490  					named, ok3 := tn.typ.(*Named)
3491  					if ok3 {
3492  						typ := tcResolveNameInline(td.Type, scope)
3493  						named.SetUnderlying(typ)
3494  					}
3495  				}
3496  			}
3497  		}
3498  	}
3499  
3500  	for _, d := range file.DeclList {
3501  		switch d := d.(type) {
3502  		case *VarDecl:
3503  			typ := tcResolveNameInline(d.Type, scope)
3504  			if arr, ok := typ.(*Array); ok && arr.Len() < 0 && d.Values != nil {
3505  				if cl, ok2 := d.Values.(*CompositeLit); ok2 {
3506  					typ = NewArray(arr.Elem(), int64(len(cl.ElemList)))
3507  				}
3508  			}
3509  			if typ == nil && d.Values != nil {
3510  				typ = tcInferTypeFromExpr(d.Values, scope)
3511  			}
3512  			for _, n := range d.NameList {
3513  				obj := scope.Lookup(n.Value)
3514  				if obj != nil {
3515  					if v, ok := obj.(*TCVar); ok {
3516  						v.typ = typ
3517  					}
3518  				}
3519  			}
3520  		case *FuncDecl:
3521  			if d.Recv == nil && d.Name.Value != "init" {
3522  				sig := tcResolveFuncInline(d.Type, scope)
3523  				obj := scope.Lookup(d.Name.Value)
3524  				if obj != nil {
3525  					if fn, ok := obj.(*TCFunc); ok && sig != nil {
3526  						fn.typ = sig
3527  					}
3528  				}
3529  			}
3530  		case *ConstDecl:
3531  			if d.Group == nil || d.Group != curConstGroup {
3532  				curConstGroup = d.Group
3533  				iotaVal = 0
3534  				prevConstValues = nil
3535  				prevConstType = nil
3536  			} else {
3537  				iotaVal++
3538  			}
3539  			valExpr := d.Values
3540  			typeExpr := d.Type
3541  			if valExpr == nil {
3542  				valExpr = prevConstValues
3543  			}
3544  			if typeExpr == nil && d.Type == nil {
3545  				typeExpr = prevConstType
3546  			}
3547  			if d.Values != nil {
3548  				prevConstValues = d.Values
3549  			}
3550  			if d.Type != nil {
3551  				prevConstType = d.Type
3552  			}
3553  			typ := tcResolveNameInline(typeExpr, scope)
3554  			if typ == nil && valExpr != nil {
3555  				typ = tcInferTypeFromExpr(valExpr, scope)
3556  			}
3557  			var val ConstVal
3558  			if valExpr != nil {
3559  				val = tcEvalConstExpr(valExpr, scope, iotaVal)
3560  			}
3561  			if typ == nil && val != nil {
3562  				typ = Typ[UntypedInt]
3563  			}
3564  			for _, n := range d.NameList {
3565  				obj := scope.Lookup(n.Value)
3566  				if obj != nil {
3567  					if c, ok := obj.(*TCConst); ok {
3568  						c.typ = typ
3569  						c.val = val
3570  					}
3571  				}
3572  			}
3573  		}
3574  	}
3575  	for _, d := range file.DeclList {
3576  		if fd, ok := d.(*FuncDecl); ok && fd.Recv != nil {
3577  			recvType := tcResolveRecvType(fd.Recv, scope)
3578  			if recvType == nil {
3579  				continue
3580  			}
3581  			sig := tcResolveFuncInlineWithRecv(fd.Type, fd.Recv, scope)
3582  			fn := NewTCFunc(pkg, fd.Name.Value, sig)
3583  			isPtr := false
3584  			var named *Named
3585  			if pt, ok := recvType.(*Pointer); ok {
3586  				named, _ = pt.Elem().(*Named)
3587  				isPtr = true
3588  			} else {
3589  				named, _ = recvType.(*Named)
3590  			}
3591  			if named != nil {
3592  				if isPtr {
3593  					fn.hasPtrRecv = true
3594  				}
3595  				named.AddMethod(fn)
3596  			}
3597  		}
3598  	}
3599  
3600  	ssaPkg := prog.CreatePackage(pkg, []*File{file}, nil)
3601  	emitter := newIREmitter(ssaPkg, triple)
3602  	return emitter.emit()
3603  }
3604  
3605  func tcInferTypeFromExpr(e Expr, scope *Scope) Type {
3606  	switch e := e.(type) {
3607  	case *BasicLit:
3608  		switch e.Kind {
3609  		case StringLit:
3610  			return Typ[TCString]
3611  		case IntLit:
3612  			return Typ[Int32]
3613  		case FloatLit:
3614  			return Typ[Float64]
3615  		}
3616  	case *Name:
3617  		if e.Value == "true" || e.Value == "false" {
3618  			return Typ[Bool]
3619  		}
3620  		return tcResolveNameInline(e, scope)
3621  	case *CallExpr:
3622  		return tcResolveNameInline(e.Fun, scope)
3623  	case *CompositeLit:
3624  		t := tcResolveNameInline(e.Type, scope)
3625  		if arr, ok := t.(*Array); ok && arr.Len() < 0 {
3626  			return NewArray(arr.Elem(), int64(len(e.ElemList)))
3627  		}
3628  		return t
3629  	case *Operation:
3630  		if e.Y == nil && e.Op == And {
3631  			return NewPointer(tcInferTypeFromExpr(e.X, scope))
3632  		}
3633  	}
3634  	return nil
3635  }
3636  
3637  func tcEvalConstExpr(e Expr, scope *Scope, iotaVal int64) ConstVal {
3638  	if e == nil {
3639  		return nil
3640  	}
3641  	switch e := e.(type) {
3642  	case *BasicLit:
3643  		return evalBasicLit(e)
3644  	case *Name:
3645  		if e.Value == "iota" && iotaVal >= 0 {
3646  			return constant.MakeInt64(iotaVal)
3647  		}
3648  		if scope != nil {
3649  			_, obj := scope.LookupParent(e.Value)
3650  			if c, ok := obj.(*TCConst); ok && c.val != nil {
3651  				return c.val
3652  			}
3653  		}
3654  	case *Operation:
3655  		if e.Y == nil {
3656  			return tcEvalConstExpr(e.X, scope, iotaVal)
3657  		}
3658  		xr := tcEvalConstExpr(e.X, scope, iotaVal)
3659  		yr := tcEvalConstExpr(e.Y, scope, iotaVal)
3660  		if xr == nil || yr == nil {
3661  			return nil
3662  		}
3663  		xv, _ := xr.(constant.Value)
3664  		yv, _ := yr.(constant.Value)
3665  		if xv == nil || yv == nil {
3666  			return nil
3667  		}
3668  		switch e.Op {
3669  		case Add:
3670  			return constant.BinaryOp(xv, token.ADD, yv)
3671  		case Sub:
3672  			return constant.BinaryOp(xv, token.SUB, yv)
3673  		case Mul:
3674  			return constant.BinaryOp(xv, token.MUL, yv)
3675  		case Div:
3676  			return constant.BinaryOp(xv, token.QUO, yv)
3677  		case Shl:
3678  			shift, _ := constant.Uint64Val(yv)
3679  			return constant.Shift(xv, token.SHL, uint(shift))
3680  		case Shr:
3681  			shift, _ := constant.Uint64Val(yv)
3682  			return constant.Shift(xv, token.SHR, uint(shift))
3683  		case Or:
3684  			return constant.BinaryOp(xv, token.OR, yv)
3685  		case And:
3686  			return constant.BinaryOp(xv, token.AND, yv)
3687  		case Xor:
3688  			return constant.BinaryOp(xv, token.XOR, yv)
3689  		}
3690  	case *ParenExpr:
3691  		return tcEvalConstExpr(e.X, scope, iotaVal)
3692  	}
3693  	return nil
3694  }
3695  
3696  func tcResolveNameInline(e Expr, scope *Scope) Type {
3697  	if e == nil {
3698  		return nil
3699  	}
3700  	switch e := e.(type) {
3701  	case *Name:
3702  		var obj Object
3703  		if scope != nil {
3704  			_, obj = scope.LookupParent(e.Value)
3705  		} else {
3706  			_, obj = Universe.LookupParent(e.Value)
3707  		}
3708  		if obj != nil {
3709  			if tn, ok := obj.(*TypeName); ok {
3710  				return tn.typ
3711  			}
3712  		}
3713  	case *SelectorExpr:
3714  		pkgName, ok := e.X.(*Name)
3715  		if ok && scope != nil {
3716  			_, pkgObj := scope.LookupParent(pkgName.Value)
3717  			if pn, ok2 := pkgObj.(*PkgName); ok2 && pn.imported != nil {
3718  				typeObj := pn.imported.scope.Lookup(e.Sel.Value)
3719  				if typeObj != nil {
3720  					if tn, ok3 := typeObj.(*TypeName); ok3 {
3721  						return tn.typ
3722  					}
3723  				}
3724  			}
3725  		}
3726  		// Fallback: check importRegistry directly for external package types
3727  		if pkgName, ok := e.X.(*Name); ok {
3728  			for _, pkg := range importRegistry {
3729  				if pkg.Name() == pkgName.Value {
3730  					typeObj := pkg.Scope().Lookup(e.Sel.Value)
3731  					if typeObj != nil {
3732  						if tn, ok2 := typeObj.(*TypeName); ok2 {
3733  							return tn.typ
3734  						}
3735  					}
3736  					break
3737  				}
3738  			}
3739  		}
3740  	case *Operation:
3741  		if e.Y == nil && e.Op == Mul {
3742  			base := tcResolveNameInline(e.X, scope)
3743  			if base == nil {
3744  				base = Typ[Int8]
3745  			}
3746  			return NewPointer(base)
3747  		}
3748  	case *SliceType:
3749  		elem := tcResolveNameInline(e.Elem, scope)
3750  		if elem != nil {
3751  			if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3752  				return Typ[TCString]
3753  			}
3754  			return NewSlice(elem)
3755  		}
3756  	case *ArrayType:
3757  		elem := tcResolveNameInline(e.Elem, scope)
3758  		if elem != nil {
3759  			n := int64(-1)
3760  			if lit, ok := e.Len.(*BasicLit); ok {
3761  				n = irParseInt64(lit.Value)
3762  			} else if e.Len != nil {
3763  				cv := tcEvalConstExpr(e.Len, scope, -1)
3764  				if cv != nil {
3765  					if gv, ok := cv.(constant.Value); ok {
3766  						if iv, ok2 := constant.Int64Val(gv); ok2 {
3767  							n = iv
3768  						}
3769  					}
3770  				}
3771  			}
3772  			return NewArray(elem, n)
3773  		}
3774  	case *MapType:
3775  		key := tcResolveNameInline(e.Key, scope)
3776  		val := tcResolveNameInline(e.Value, scope)
3777  		if key != nil && val != nil {
3778  			return NewTCMap(key, val)
3779  		}
3780  	case *StructType:
3781  		var fields []*TCVar
3782  		var tags []string
3783  		for i, field := range e.FieldList {
3784  			typ := tcResolveNameInline(field.Type, scope)
3785  			fname := ""
3786  			if field.Name != nil {
3787  				fname = field.Name.Value
3788  			}
3789  			fields = append(fields, NewTCField(nil, fname, typ, field.Name == nil))
3790  			tag := ""
3791  			if i < len(e.TagList) && e.TagList[i] != nil {
3792  				tag = e.TagList[i].Value
3793  			}
3794  			tags = append(tags, tag)
3795  		}
3796  		return NewTCStruct(fields, tags)
3797  	case *FuncType:
3798  		return tcResolveFuncInline(e, scope)
3799  	case *InterfaceType:
3800  		return tcResolveInterfaceInline(e, scope)
3801  	case *DotsType:
3802  		elem := tcResolveNameInline(e.Elem, scope)
3803  		if elem != nil {
3804  			if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3805  				return Typ[TCString]
3806  			}
3807  			return NewSlice(elem)
3808  		}
3809  	}
3810  	return nil
3811  }
3812  
3813  func tcResolveInterfaceInline(e *InterfaceType, scope *Scope) *TCInterface {
3814  	var methods []*IfaceMethod
3815  	for _, f := range e.MethodList {
3816  		if f.Name == nil {
3817  			continue
3818  		}
3819  		ft, ok := f.Type.(*FuncType)
3820  		if !ok {
3821  			continue
3822  		}
3823  		sig := tcResolveFuncInline(ft, scope)
3824  		if sig != nil {
3825  			methods = append(methods, NewTCIfaceMethod(f.Name.Value, sig))
3826  		}
3827  	}
3828  	iface := NewTCInterface(methods, nil)
3829  	iface.Complete()
3830  	return iface
3831  }
3832  
3833  func stripDuplicatePackageClauses(src []byte) []byte {
3834  	found := false
3835  	var out []byte
3836  	i := 0
3837  	for i < len(src) {
3838  		nlIdx := bytes.IndexByte(src[i:], '\n')
3839  		var line []byte
3840  		var lineEnd int
3841  		if nlIdx < 0 {
3842  			line = src[i:]
3843  			lineEnd = len(src)
3844  		} else {
3845  			line = src[i : i+nlIdx]
3846  			lineEnd = i + nlIdx + 1
3847  		}
3848  		trimmed := bytes.TrimSpace(line)
3849  		if bytes.HasPrefix(trimmed, "package ") {
3850  			if found {
3851  				if out == nil {
3852  					out = []byte{:0:len(src)}
3853  					out = append(out, src[:i]...)
3854  				}
3855  				for k := 0; k < len(line); k++ {
3856  					out = append(out, ' ')
3857  				}
3858  				if nlIdx >= 0 {
3859  					out = append(out, '\n')
3860  				}
3861  				i = lineEnd
3862  				continue
3863  			}
3864  			found = true
3865  		}
3866  		if out != nil {
3867  			out = append(out, src[i:lineEnd]...)
3868  		}
3869  		i = lineEnd
3870  	}
3871  	if out == nil {
3872  		return src
3873  	}
3874  	return out
3875  }
3876  
3877  func rewriteSliceMakeLiterals(src []byte) []byte {
3878  	var out []byte
3879  	i := 0
3880  	for i < len(src) {
3881  		start := bytes.Index(src[i:], []byte("{:"))
3882  		if start < 0 {
3883  			out = append(out, src[i:]...)
3884  			break
3885  		}
3886  		start = start + i
3887  		lbrack := findSliceTypeStart(src, start)
3888  		if lbrack < 0 {
3889  			out = append(out, src[i:start+2]...)
3890  			i = start + 2
3891  			continue
3892  		}
3893  		close := findMatchingBrace(src, start)
3894  		if close < 0 {
3895  			out = append(out, src[i:start+2]...)
3896  			i = start + 2
3897  			continue
3898  		}
3899  		inner := src[start+2 : close]
3900  		colonIdx := bytes.IndexByte(inner, ':')
3901  		typeText := src[lbrack:start]
3902  		out = append(out, src[i:lbrack]...)
3903  		if colonIdx < 0 {
3904  			out = append(out, "make("...)
3905  			out = append(out, typeText...)
3906  			out = append(out, ", "...)
3907  			out = append(out, bytes.TrimSpace(inner)...)
3908  			out = append(out, ')')
3909  		} else {
3910  			lenExpr := bytes.TrimSpace(inner[:colonIdx])
3911  			capExpr := bytes.TrimSpace(inner[colonIdx+1:])
3912  			out = append(out, "make("...)
3913  			out = append(out, typeText...)
3914  			out = append(out, ", "...)
3915  			out = append(out, lenExpr...)
3916  			out = append(out, ", "...)
3917  			out = append(out, capExpr...)
3918  			out = append(out, ')')
3919  		}
3920  		i = close + 1
3921  	}
3922  	if out == nil {
3923  		return src
3924  	}
3925  	return out
3926  }
3927  
3928  func findSliceTypeStart(src []byte, braceIdx int) int {
3929  	j := braceIdx - 1
3930  	for j >= 0 && (src[j] == ' ' || src[j] == '\t' || src[j] == '\n') {
3931  		j--
3932  	}
3933  	if j < 0 {
3934  		return -1
3935  	}
3936  	depth := 0
3937  	parenDepth := 0
3938  	for j >= 0 {
3939  		ch := src[j]
3940  		if ch == ')' {
3941  			parenDepth++
3942  		} else if ch == '(' {
3943  			parenDepth--
3944  		} else if parenDepth > 0 {
3945  			j--
3946  			continue
3947  		}
3948  		if ch == ']' {
3949  			depth++
3950  		} else if ch == '[' {
3951  			depth--
3952  			if depth == 0 {
3953  				return j
3954  			}
3955  		} else if depth == 0 && parenDepth == 0 {
3956  			if ch == ' ' || ch == '\t' || ch == '\n' || ch == '*' || ch == '(' || ch == ')' {
3957  				j--
3958  				continue
3959  			}
3960  			if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '.' {
3961  				j--
3962  				continue
3963  			}
3964  			return -1
3965  		}
3966  		j--
3967  	}
3968  	return -1
3969  }
3970  
3971  func findMatchingBrace(src []byte, openIdx int) int {
3972  	depth := 1
3973  	for i := openIdx + 1; i < len(src); i++ {
3974  		if src[i] == '{' {
3975  			depth++
3976  		} else if src[i] == '}' {
3977  			depth--
3978  			if depth == 0 {
3979  				return i
3980  			}
3981  		}
3982  	}
3983  	return -1
3984  }
3985  
3986  func tcResolveRecvType(recv *Field, scope *Scope) Type {
3987  	if recv == nil {
3988  		return nil
3989  	}
3990  	return tcResolveNameInline(recv.Type, scope)
3991  }
3992  
3993  func tcResolveFuncInlineWithRecv(ft *FuncType, recv *Field, scope *Scope) *Signature {
3994  	if ft == nil {
3995  		return nil
3996  	}
3997  	var recvVar *TCVar
3998  	if recv != nil {
3999  		recvTyp := tcResolveNameInline(recv.Type, scope)
4000  		recvName := ""
4001  		if recv.Name != nil {
4002  			recvName = recv.Name.Value
4003  		}
4004  		recvVar = NewTCVar(nil, recvName, recvTyp)
4005  	}
4006  	params := tcResolveFieldList(ft.ParamList, scope)
4007  	results := tcResolveFieldList(ft.ResultList, scope)
4008  	variadic := false
4009  	if len(ft.ParamList) > 0 {
4010  		if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
4011  			variadic = true
4012  		}
4013  	}
4014  	return NewSignature(recvVar, params, results, variadic)
4015  }
4016  
4017  func tcResolveFieldList(fields []*Field, scope *Scope) *Tuple {
4018  	if len(fields) == 0 {
4019  		return nil
4020  	}
4021  	var vars []*TCVar
4022  	for _, f := range fields {
4023  		typ := tcResolveNameInline(f.Type, scope)
4024  		pname := ""
4025  		if f.Name != nil {
4026  			pname = f.Name.Value
4027  		}
4028  		vars = append(vars, NewTCVar(nil, pname, typ))
4029  	}
4030  	return NewTuple(vars...)
4031  }
4032  
4033  func tcResolveFuncInline(ft *FuncType, scope *Scope) *Signature {
4034  	if ft == nil {
4035  		return nil
4036  	}
4037  	var params []*TCVar
4038  	for _, p := range ft.ParamList {
4039  		typ := tcResolveNameInline(p.Type, scope)
4040  		pname := ""
4041  		if p.Name != nil {
4042  			pname = p.Name.Value
4043  		}
4044  		params = append(params, NewTCVar(nil, pname, typ))
4045  	}
4046  	var results []*TCVar
4047  	for _, r := range ft.ResultList {
4048  		typ := tcResolveNameInline(r.Type, scope)
4049  		rname := ""
4050  		if r.Name != nil {
4051  			rname = r.Name.Value
4052  		}
4053  		results = append(results, NewTCVar(nil, rname, typ))
4054  	}
4055  	variadic := false
4056  	if len(ft.ParamList) > 0 {
4057  		if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
4058  			variadic = true
4059  		}
4060  	}
4061  	var pTuple *Tuple
4062  	if len(params) > 0 {
4063  		pTuple = NewTuple(params...)
4064  	}
4065  	var rTuple *Tuple
4066  	if len(results) > 0 {
4067  		rTuple = NewTuple(results...)
4068  	}
4069  	return NewSignature(nil, pTuple, rTuple, variadic)
4070  }
4071  
4072  func (e *irEmitter) instrOperands(instr SSAInstruction) []SSAValue {
4073  	switch i := instr.(type) {
4074  	case *SSAStore:
4075  		return []SSAValue{i.Addr, i.Val}
4076  	case *SSAUnOp:
4077  		return []SSAValue{i.X}
4078  	case *SSABinOp:
4079  		return []SSAValue{i.X, i.Y}
4080  	case *SSACall:
4081  		out := []SSAValue{i.Call.Value}
4082  		for _, a := range i.Call.Args {
4083  			out = append(out, a)
4084  		}
4085  		return out
4086  	case *SSAFieldAddr:
4087  		return []SSAValue{i.X}
4088  	case *SSAIndexAddr:
4089  		return []SSAValue{i.X, i.Index}
4090  	case *SSAExtract:
4091  		return []SSAValue{i.Tuple}
4092  	case *SSAPhi:
4093  		return i.Edges
4094  	case *SSAReturn:
4095  		var out []SSAValue
4096  		for _, r := range i.Results {
4097  			out = append(out, r)
4098  		}
4099  		return out
4100  	case *SSAIf:
4101  		return []SSAValue{i.Cond}
4102  	case *SSAConvert:
4103  		return []SSAValue{i.X}
4104  	case *SSAChangeType:
4105  		return []SSAValue{i.X}
4106  	case *SSAMakeInterface:
4107  		return []SSAValue{i.X}
4108  	case *SSATypeAssert:
4109  		return []SSAValue{i.X}
4110  	case *SSASlice:
4111  		out := []SSAValue{i.X}
4112  		if i.Low != nil { out = append(out, i.Low) }
4113  		if i.High != nil { out = append(out, i.High) }
4114  		if i.Max != nil { out = append(out, i.Max) }
4115  		return out
4116  	case *SSAMapUpdate:
4117  		return []SSAValue{i.Map, i.Key, i.Value}
4118  	case *SSALookup:
4119  		return []SSAValue{i.X, i.Index}
4120  	case *SSARange:
4121  		return []SSAValue{i.X}
4122  	case *SSANext:
4123  		return []SSAValue{i.Iter}
4124  	case *SSASend:
4125  		return []SSAValue{i.Chan, i.X}
4126  	case *SSAMakeSlice:
4127  		out := []SSAValue{i.Len}
4128  		if i.Cap != nil { out = append(out, i.Cap) }
4129  		if i.Data != nil { out = append(out, i.Data) }
4130  		return out
4131  	}
4132  	return nil
4133  }
4134  
4135