ir_emit.mx raw

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