compiler.go raw

   1  package compiler
   2  
   3  import (
   4  	"debug/dwarf"
   5  	"errors"
   6  	"fmt"
   7  	"go/ast"
   8  	"go/constant"
   9  	"go/token"
  10  	"go/types"
  11  	"math/bits"
  12  	"path"
  13  	"path/filepath"
  14  	"sort"
  15  	"strconv"
  16  	"strings"
  17  
  18  	"moxie/compiler/llvmutil"
  19  	"moxie/loader"
  20  	"moxie/src/moxie"
  21  	"golang.org/x/tools/go/ssa"
  22  	"golang.org/x/tools/go/types/typeutil"
  23  	"tinygo.org/x/go-llvm"
  24  )
  25  
  26  func init() {
  27  	llvm.InitializeAllTargets()
  28  	llvm.InitializeAllTargetMCs()
  29  	llvm.InitializeAllTargetInfos()
  30  	llvm.InitializeAllAsmParsers()
  31  	llvm.InitializeAllAsmPrinters()
  32  }
  33  
  34  // Config is the configuration for the compiler. Most settings should be copied
  35  // directly from compileopts.Config, it recreated here to decouple the compiler
  36  // package a bit and because it makes caching easier.
  37  //
  38  // This struct can be used for caching: if one of the flags here changes the
  39  // code must be recompiled.
  40  type Config struct {
  41  	// Target and output information.
  42  	Triple          string
  43  	CPU             string
  44  	Features        string
  45  	ABI             string
  46  	GOOS            string
  47  	GOARCH          string
  48  	BuildMode       string
  49  	CodeModel       string
  50  	RelocationModel string
  51  	SizeLevel       int
  52  	MoxieVersion    string // for llvm.ident
  53  
  54  	// Various compiler options that determine how code is generated.
  55  	Scheduler          string
  56  	AutomaticStackSize bool
  57  	DefaultStackSize   uint64
  58  	MaxStackAlloc      uint64
  59  	NeedsStackObjects  bool
  60  	Debug              bool // Whether to emit debug information in the LLVM module.
  61  	Nobounds           bool // Whether to skip bounds checks
  62  	PanicStrategy      string
  63  }
  64  
  65  // compilerContext contains function-independent data that should still be
  66  // available while compiling every function. It is not strictly read-only, but
  67  // must not contain function-dependent data such as an IR builder.
  68  type compilerContext struct {
  69  	*Config
  70  	DumpSSA          bool
  71  	mod              llvm.Module
  72  	ctx              llvm.Context
  73  	builder          llvm.Builder // only used for constant operations
  74  	dibuilder        *llvm.DIBuilder
  75  	cu               llvm.Metadata
  76  	difiles          map[string]llvm.Metadata
  77  	ditypes          map[types.Type]llvm.Metadata
  78  	llvmTypes        typeutil.Map
  79  	interfaceTypes   typeutil.Map
  80  	machine          llvm.TargetMachine
  81  	targetData       llvm.TargetData
  82  	intType          llvm.Type
  83  	dataPtrType      llvm.Type // pointer in address space 0
  84  	funcPtrType      llvm.Type // pointer in function address space (1 for AVR, 0 elsewhere)
  85  	funcPtrAddrSpace int
  86  	uintptrType      llvm.Type
  87  	program          *ssa.Program
  88  	diagnostics      []error
  89  	functionInfos    map[*ssa.Function]functionInfo
  90  	astComments      map[string]*ast.CommentGroup
  91  	embedGlobals     map[string][]*loader.EmbedFile
  92  	pkg              *types.Package
  93  	packageDir       string // directory for this package
  94  	runtimePkg       *types.Package
  95  }
  96  
  97  // newCompilerContext returns a new compiler context ready for use, most
  98  // importantly with a newly created LLVM context and module.
  99  func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *Config, dumpSSA bool) *compilerContext {
 100  	c := &compilerContext{
 101  		Config:        config,
 102  		DumpSSA:       dumpSSA,
 103  		difiles:       make(map[string]llvm.Metadata),
 104  		ditypes:       make(map[types.Type]llvm.Metadata),
 105  		machine:       machine,
 106  		targetData:    machine.CreateTargetData(),
 107  		functionInfos: map[*ssa.Function]functionInfo{},
 108  		astComments:   map[string]*ast.CommentGroup{},
 109  	}
 110  
 111  	c.ctx = llvm.NewContext()
 112  	c.builder = c.ctx.NewBuilder()
 113  	c.mod = c.ctx.NewModule(moduleName)
 114  	c.mod.SetTarget(config.Triple)
 115  	c.mod.SetDataLayout(c.targetData.String())
 116  	if c.Debug {
 117  		c.dibuilder = llvm.NewDIBuilder(c.mod)
 118  	}
 119  
 120  	c.uintptrType = c.ctx.IntType(c.targetData.PointerSize() * 8)
 121  	// Moxie: int is always 32 bits on all targets. Slice headers still use
 122  	// uintptr-sized len/cap; trunc/ext happens at the int boundary.
 123  	c.intType = c.ctx.Int32Type()
 124  	c.dataPtrType = llvm.PointerType(c.ctx.Int8Type(), 0)
 125  
 126  	dummyFuncType := llvm.FunctionType(c.ctx.VoidType(), nil, false)
 127  	dummyFunc := llvm.AddFunction(c.mod, "moxie.dummy", dummyFuncType)
 128  	c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace()
 129  	c.funcPtrType = dummyFunc.Type()
 130  	dummyFunc.EraseFromParentAsFunction()
 131  
 132  	return c
 133  }
 134  
 135  // Dispose everything related to the context, _except_ for the IR module (and
 136  // the associated context).
 137  func (c *compilerContext) dispose() {
 138  	c.builder.Dispose()
 139  }
 140  
 141  // builder contains all information relevant to build a single function.
 142  type builder struct {
 143  	*compilerContext
 144  	llvm.Builder
 145  	fn                *ssa.Function
 146  	llvmFnType        llvm.Type
 147  	llvmFn            llvm.Value
 148  	info              functionInfo
 149  	locals            map[ssa.Value]llvm.Value // local variables
 150  	blockInfo         []blockInfo
 151  	currentBlock      *ssa.BasicBlock
 152  	currentBlockInfo  *blockInfo
 153  	tarjanStack       []uint
 154  	tarjanIndex       uint
 155  	phis              []phiNode
 156  	deferPtr          llvm.Value
 157  	deferFrame        llvm.Value
 158  	stackChainAlloca  llvm.Value
 159  	landingpad        llvm.BasicBlock
 160  	difunc            llvm.Metadata
 161  	dilocals          map[*types.Var]llvm.Metadata
 162  	initInlinedAt     llvm.Metadata            // fake inlinedAt position
 163  	initPseudoFuncs   map[string]llvm.Metadata // fake "inlined" functions for proper init debug locations
 164  	allDeferFuncs     []interface{}
 165  	deferFuncs        map[*ssa.Function]int
 166  	deferInvokeFuncs  map[string]int
 167  	deferClosureFuncs map[*ssa.Function]int
 168  	deferExprFuncs    map[ssa.Value]int
 169  	selectRecvBuf     map[*ssa.Select]llvm.Value
 170  	deferBuiltinFuncs map[ssa.Value]deferBuiltin
 171  	runDefersBlock    []llvm.BasicBlock
 172  	afterDefersBlock  []llvm.BasicBlock
 173  }
 174  
 175  func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder {
 176  	fnType, fn := c.getFunction(f)
 177  	return &builder{
 178  		compilerContext: c,
 179  		Builder:         irbuilder,
 180  		fn:              f,
 181  		llvmFnType:      fnType,
 182  		llvmFn:          fn,
 183  		info:            c.getFunctionInfo(f),
 184  		locals:          make(map[ssa.Value]llvm.Value),
 185  		dilocals:        make(map[*types.Var]llvm.Metadata),
 186  	}
 187  }
 188  
 189  type blockInfo struct {
 190  	// entry is the LLVM basic block corresponding to the start of this *ssa.Block.
 191  	entry llvm.BasicBlock
 192  
 193  	// exit is the LLVM basic block corresponding to the end of this *ssa.Block.
 194  	// It will be different than entry if any of the block's instructions contain internal branches.
 195  	exit llvm.BasicBlock
 196  
 197  	// tarjan holds state for applying Tarjan's strongly connected components algorithm to the CFG.
 198  	// This is used by defer.go to determine whether to stack- or heap-allocate defer data.
 199  	tarjan tarjanNode
 200  }
 201  
 202  type deferBuiltin struct {
 203  	callName string
 204  	pos      token.Pos
 205  	argTypes []types.Type
 206  	callback int
 207  }
 208  
 209  type phiNode struct {
 210  	ssa  *ssa.Phi
 211  	llvm llvm.Value
 212  }
 213  
 214  // NewTargetMachine returns a new llvm.TargetMachine based on the passed-in
 215  // configuration. It is used by the compiler and is needed for machine code
 216  // emission.
 217  func NewTargetMachine(config *Config) (llvm.TargetMachine, error) {
 218  	target, err := llvm.GetTargetFromTriple(config.Triple)
 219  	if err != nil {
 220  		return llvm.TargetMachine{}, err
 221  	}
 222  
 223  	var codeModel llvm.CodeModel
 224  	var relocationModel llvm.RelocMode
 225  
 226  	switch config.CodeModel {
 227  	case "default":
 228  		codeModel = llvm.CodeModelDefault
 229  	case "tiny":
 230  		codeModel = llvm.CodeModelTiny
 231  	case "small":
 232  		codeModel = llvm.CodeModelSmall
 233  	case "kernel":
 234  		codeModel = llvm.CodeModelKernel
 235  	case "medium":
 236  		codeModel = llvm.CodeModelMedium
 237  	case "large":
 238  		codeModel = llvm.CodeModelLarge
 239  	}
 240  
 241  	switch config.RelocationModel {
 242  	case "static":
 243  		relocationModel = llvm.RelocStatic
 244  	case "pic":
 245  		relocationModel = llvm.RelocPIC
 246  	case "dynamicnopic":
 247  		relocationModel = llvm.RelocDynamicNoPic
 248  	}
 249  
 250  	machine := target.CreateTargetMachine(config.Triple, config.CPU, config.Features, llvm.CodeGenLevelDefault, relocationModel, codeModel)
 251  	return machine, nil
 252  }
 253  
 254  // Sizes returns a types.Sizes appropriate for the given target machine. It
 255  // includes the correct int size and alignment as is necessary for the Go
 256  // typechecker.
 257  func Sizes(machine llvm.TargetMachine) types.Sizes {
 258  	targetData := machine.CreateTargetData()
 259  	defer targetData.Dispose()
 260  
 261  	// Moxie: int is always 32 bits on all targets.
 262  	intWidth := 32
 263  
 264  	// Construct a complex128 type because that's likely the type with the
 265  	// biggest alignment on most/all ABIs.
 266  	ctx := llvm.NewContext()
 267  	defer ctx.Dispose()
 268  	complex128Type := ctx.StructType([]llvm.Type{ctx.DoubleType(), ctx.DoubleType()}, false)
 269  	return &stdSizes{
 270  		IntSize:  int64(intWidth / 8),
 271  		PtrSize:  int64(targetData.PointerSize()),
 272  		MaxAlign: int64(targetData.ABITypeAlignment(complex128Type)),
 273  	}
 274  }
 275  
 276  // CompilePackage compiles a single package to a LLVM module.
 277  func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, machine llvm.TargetMachine, config *Config, dumpSSA bool) (llvm.Module, []error) {
 278  	c := newCompilerContext(moduleName, machine, config, dumpSSA)
 279  	defer c.dispose()
 280  	c.packageDir = pkg.OriginalDir()
 281  	c.embedGlobals = pkg.EmbedGlobals
 282  	c.pkg = pkg.Pkg
 283  	c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg
 284  	c.program = ssaPkg.Prog
 285  
 286  	// Convert AST to SSA.
 287  	ssaPkg.Build()
 288  
 289  	// Initialize debug information.
 290  	if c.Debug {
 291  		c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{
 292  			Language:  0xb, // DW_LANG_C99 (0xc, off-by-one?)
 293  			File:      "<unknown>",
 294  			Dir:       "",
 295  			Producer:  "Moxie",
 296  			Optimized: true,
 297  		})
 298  	}
 299  
 300  	// Load comments such as //go:extern on globals.
 301  	c.loadASTComments(pkg)
 302  
 303  	// Predeclare the runtime.alloc function, which is used by the wordpack
 304  	// functionality.
 305  	c.getFunction(c.program.ImportedPackage("runtime").Members["alloc"].(*ssa.Function))
 306  	if c.NeedsStackObjects {
 307  		// Predeclare trackPointer, which is used everywhere we use runtime.alloc.
 308  		c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function))
 309  	}
 310  
 311  	// Compile all functions, methods, and global variables in this package.
 312  	irbuilder := c.ctx.NewBuilder()
 313  	defer irbuilder.Dispose()
 314  	c.createPackage(irbuilder, ssaPkg)
 315  
 316  	// see: https://reviews.llvm.org/D18355
 317  	if c.Debug {
 318  		c.mod.AddNamedMetadataOperand("llvm.module.flags",
 319  			c.ctx.MDNode([]llvm.Metadata{
 320  				llvm.ConstInt(c.ctx.Int32Type(), 2, false).ConstantAsMetadata(), // Warning on mismatch
 321  				c.ctx.MDString("Debug Info Version"),
 322  				llvm.ConstInt(c.ctx.Int32Type(), 3, false).ConstantAsMetadata(), // DWARF version
 323  			}),
 324  		)
 325  		c.mod.AddNamedMetadataOperand("llvm.module.flags",
 326  			c.ctx.MDNode([]llvm.Metadata{
 327  				llvm.ConstInt(c.ctx.Int32Type(), 7, false).ConstantAsMetadata(), // Max on mismatch
 328  				c.ctx.MDString("Dwarf Version"),
 329  				llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(),
 330  			}),
 331  		)
 332  		if c.MoxieVersion != "" {
 333  			// It is necessary to set llvm.ident, otherwise debugging on MacOS
 334  			// won't work.
 335  			c.mod.AddNamedMetadataOperand("llvm.ident",
 336  				c.ctx.MDNode(([]llvm.Metadata{
 337  					c.ctx.MDString("Moxie version " + c.MoxieVersion),
 338  				})))
 339  		}
 340  		c.dibuilder.Finalize()
 341  		c.dibuilder.Destroy()
 342  	}
 343  
 344  	// Add the "target-abi" flag, which is necessary on RISC-V otherwise it will
 345  	// pick one that doesn't match the -mabi Clang flag.
 346  	if c.ABI != "" {
 347  		c.mod.AddNamedMetadataOperand("llvm.module.flags",
 348  			c.ctx.MDNode([]llvm.Metadata{
 349  				llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch
 350  				c.ctx.MDString("target-abi"),
 351  				c.ctx.MDString(c.ABI),
 352  			}),
 353  		)
 354  	}
 355  
 356  	return c.mod, c.diagnostics
 357  }
 358  
 359  func (c *compilerContext) getRuntimeType(name string) types.Type {
 360  	return c.runtimePkg.Scope().Lookup(name).(*types.TypeName).Type()
 361  }
 362  
 363  // getLLVMRuntimeType obtains a named type from the runtime package and returns
 364  // it as a LLVM type, creating it if necessary. It is a shorthand for
 365  // getLLVMType(getRuntimeType(name)).
 366  func (c *compilerContext) getLLVMRuntimeType(name string) llvm.Type {
 367  	return c.getLLVMType(c.getRuntimeType(name))
 368  }
 369  
 370  // getLLVMType returns a LLVM type for a Go type. It doesn't recreate already
 371  // created types. This is somewhat important for performance, but especially
 372  // important for named struct types (which should only be created once).
 373  func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
 374  	// Try to load the LLVM type from the cache.
 375  	// Note: *types.Named isn't unique when working with generics.
 376  	// See https://github.com/golang/go/issues/53914
 377  	// This is the reason for using typeutil.Map to lookup LLVM types for Go types.
 378  	ival := c.llvmTypes.At(goType)
 379  	if ival != nil {
 380  		return ival.(llvm.Type)
 381  	}
 382  	// Not already created, so adding this type to the cache.
 383  	llvmType := c.makeLLVMType(goType)
 384  	c.llvmTypes.Set(goType, llvmType)
 385  	return llvmType
 386  }
 387  
 388  // makeLLVMType creates a LLVM type for a Go type. Don't call this, use
 389  // getLLVMType instead.
 390  func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
 391  	switch typ := types.Unalias(goType).(type) {
 392  	case *types.Array:
 393  		elemType := c.getLLVMType(typ.Elem())
 394  		return llvm.ArrayType(elemType, int(typ.Len()))
 395  	case *types.Basic:
 396  		switch typ.Kind() {
 397  		case types.Bool, types.UntypedBool:
 398  			return c.ctx.Int1Type()
 399  		case types.Int8, types.Uint8:
 400  			return c.ctx.Int8Type()
 401  		case types.Int16, types.Uint16:
 402  			return c.ctx.Int16Type()
 403  		case types.Int32, types.Uint32:
 404  			return c.ctx.Int32Type()
 405  		case types.Int, types.Uint:
 406  			return c.intType
 407  		case types.Int64, types.Uint64:
 408  			return c.ctx.Int64Type()
 409  		case types.Float32:
 410  			return c.ctx.FloatType()
 411  		case types.Float64:
 412  			return c.ctx.DoubleType()
 413  		case types.Complex64:
 414  			return c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false)
 415  		case types.Complex128:
 416  			return c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false)
 417  		case types.String, types.UntypedString:
 418  			return c.getLLVMRuntimeType("_string")
 419  		case types.Uintptr:
 420  			return c.uintptrType
 421  		case types.UnsafePointer:
 422  			return c.dataPtrType
 423  		default:
 424  			panic("unknown basic type: " + typ.String())
 425  		}
 426  	case *types.Chan, *types.Map, *types.Pointer:
 427  		return c.dataPtrType // all pointers are the same
 428  	case *types.Interface:
 429  		return c.getLLVMRuntimeType("_interface")
 430  	case *types.Named:
 431  		if st, ok := typ.Underlying().(*types.Struct); ok {
 432  			// Structs are a special case. While other named types are ignored
 433  			// in LLVM IR, named structs are implemented as named structs in
 434  			// LLVM. This is because it is otherwise impossible to create
 435  			// self-referencing types such as linked lists.
 436  			llvmName := typ.String()
 437  			llvmType := c.ctx.StructCreateNamed(llvmName)
 438  			c.llvmTypes.Set(goType, llvmType) // avoid infinite recursion
 439  			underlying := c.getLLVMType(st)
 440  			llvmType.StructSetBody(underlying.StructElementTypes(), false)
 441  			return llvmType
 442  		}
 443  		return c.getLLVMType(typ.Underlying())
 444  	case *types.Signature: // function value
 445  		return c.getFuncType(typ)
 446  	case *types.Slice:
 447  		// Moxie: []byte uses the named _string type (string=[]byte unification).
 448  		if basic, ok := typ.Elem().(*types.Basic); ok && basic.Kind() == types.Byte {
 449  			return c.getLLVMRuntimeType("_string")
 450  		}
 451  		members := []llvm.Type{
 452  			c.dataPtrType,
 453  			c.uintptrType, // len
 454  			c.uintptrType, // cap
 455  		}
 456  		return c.ctx.StructType(members, false)
 457  	case *types.Struct:
 458  		members := make([]llvm.Type, typ.NumFields())
 459  		for i := 0; i < typ.NumFields(); i++ {
 460  			members[i] = c.getLLVMType(typ.Field(i).Type())
 461  		}
 462  		return c.ctx.StructType(members, false)
 463  	case *types.TypeParam:
 464  		return c.getLLVMType(typ.Underlying())
 465  	case *types.Tuple:
 466  		members := make([]llvm.Type, typ.Len())
 467  		for i := 0; i < typ.Len(); i++ {
 468  			members[i] = c.getLLVMType(typ.At(i).Type())
 469  		}
 470  		return c.ctx.StructType(members, false)
 471  	default:
 472  		panic("unknown type: " + goType.String())
 473  	}
 474  }
 475  
 476  // Is this a pointer type of some sort? Can be unsafe.Pointer or any *T pointer.
 477  func isPointer(typ types.Type) bool {
 478  	if _, ok := typ.(*types.Pointer); ok {
 479  		return true
 480  	} else if typ, ok := typ.(*types.Basic); ok && typ.Kind() == types.UnsafePointer {
 481  		return true
 482  	} else {
 483  		return false
 484  	}
 485  }
 486  
 487  // Get the DWARF type for this Go type.
 488  func (c *compilerContext) getDIType(typ types.Type) llvm.Metadata {
 489  	if md, ok := c.ditypes[typ]; ok {
 490  		return md
 491  	}
 492  	md := c.createDIType(typ)
 493  	c.ditypes[typ] = md
 494  	return md
 495  }
 496  
 497  // createDIType creates a new DWARF type. Don't call this function directly,
 498  // call getDIType instead.
 499  func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
 500  	llvmType := c.getLLVMType(typ)
 501  	sizeInBytes := c.targetData.TypeAllocSize(llvmType)
 502  	switch typ := typ.(type) {
 503  	case *types.Alias:
 504  		// Implement types.Alias just like types.Named: by treating them like a
 505  		// C typedef.
 506  		temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
 507  			Tag:         dwarf.TagTypedef,
 508  			SizeInBits:  sizeInBytes * 8,
 509  			AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 510  		})
 511  		c.ditypes[typ] = temporaryMDNode
 512  		md := c.dibuilder.CreateTypedef(llvm.DITypedef{
 513  			Type: c.getDIType(types.Unalias(typ)), // TODO: use typ.Rhs in Go 1.23
 514  			Name: typ.String(),
 515  		})
 516  		temporaryMDNode.ReplaceAllUsesWith(md)
 517  		return md
 518  	case *types.Array:
 519  		return c.dibuilder.CreateArrayType(llvm.DIArrayType{
 520  			SizeInBits:  sizeInBytes * 8,
 521  			AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 522  			ElementType: c.getDIType(typ.Elem()),
 523  			Subscripts: []llvm.DISubrange{
 524  				{
 525  					Lo:    0,
 526  					Count: typ.Len(),
 527  				},
 528  			},
 529  		})
 530  	case *types.Basic:
 531  		var encoding llvm.DwarfTypeEncoding
 532  		if typ.Info()&types.IsBoolean != 0 {
 533  			encoding = llvm.DW_ATE_boolean
 534  		} else if typ.Info()&types.IsFloat != 0 {
 535  			encoding = llvm.DW_ATE_float
 536  		} else if typ.Info()&types.IsComplex != 0 {
 537  			encoding = llvm.DW_ATE_complex_float
 538  		} else if typ.Info()&types.IsUnsigned != 0 {
 539  			encoding = llvm.DW_ATE_unsigned
 540  		} else if typ.Info()&types.IsInteger != 0 {
 541  			encoding = llvm.DW_ATE_signed
 542  		} else if typ.Kind() == types.UnsafePointer {
 543  			return c.dibuilder.CreatePointerType(llvm.DIPointerType{
 544  				Name:         "unsafe.Pointer",
 545  				SizeInBits:   c.targetData.TypeAllocSize(llvmType) * 8,
 546  				AlignInBits:  uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 547  				AddressSpace: 0,
 548  			})
 549  		} else if typ.Info()&types.IsString != 0 {
 550  			return c.dibuilder.CreateStructType(llvm.Metadata{}, llvm.DIStructType{
 551  				Name:        "string",
 552  				SizeInBits:  sizeInBytes * 8,
 553  				AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 554  				Elements: []llvm.Metadata{
 555  					c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 556  						Name:         "ptr",
 557  						SizeInBits:   c.targetData.TypeAllocSize(c.dataPtrType) * 8,
 558  						AlignInBits:  uint32(c.targetData.ABITypeAlignment(c.dataPtrType)) * 8,
 559  						OffsetInBits: 0,
 560  						Type:         c.getDIType(types.NewPointer(types.Typ[types.Byte])),
 561  					}),
 562  					c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 563  						Name:         "len",
 564  						SizeInBits:   c.targetData.TypeAllocSize(c.uintptrType) * 8,
 565  						AlignInBits:  uint32(c.targetData.ABITypeAlignment(c.uintptrType)) * 8,
 566  						OffsetInBits: c.targetData.ElementOffset(llvmType, 1) * 8,
 567  						Type:         c.getDIType(types.Typ[types.Uintptr]),
 568  					}),
 569  					c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 570  						Name:         "cap",
 571  						SizeInBits:   c.targetData.TypeAllocSize(c.uintptrType) * 8,
 572  						AlignInBits:  uint32(c.targetData.ABITypeAlignment(c.uintptrType)) * 8,
 573  						OffsetInBits: c.targetData.ElementOffset(llvmType, 2) * 8,
 574  						Type:         c.getDIType(types.Typ[types.Uintptr]),
 575  					}),
 576  				},
 577  			})
 578  		} else {
 579  			panic("unknown basic type")
 580  		}
 581  		return c.dibuilder.CreateBasicType(llvm.DIBasicType{
 582  			Name:       typ.String(),
 583  			SizeInBits: sizeInBytes * 8,
 584  			Encoding:   encoding,
 585  		})
 586  	case *types.Chan:
 587  		return c.getDIType(types.NewPointer(c.program.ImportedPackage("runtime").Members["channel"].(*ssa.Type).Type()))
 588  	case *types.Interface:
 589  		return c.getDIType(c.program.ImportedPackage("runtime").Members["_interface"].(*ssa.Type).Type())
 590  	case *types.Map:
 591  		return c.getDIType(types.NewPointer(c.program.ImportedPackage("runtime").Members["hashmap"].(*ssa.Type).Type()))
 592  	case *types.Named:
 593  		// Placeholder metadata node, to be replaced afterwards.
 594  		temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
 595  			Tag:         dwarf.TagTypedef,
 596  			SizeInBits:  sizeInBytes * 8,
 597  			AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 598  		})
 599  		c.ditypes[typ] = temporaryMDNode
 600  		md := c.dibuilder.CreateTypedef(llvm.DITypedef{
 601  			Type: c.getDIType(typ.Underlying()),
 602  			Name: typ.String(),
 603  		})
 604  		temporaryMDNode.ReplaceAllUsesWith(md)
 605  		return md
 606  	case *types.Pointer:
 607  		return c.dibuilder.CreatePointerType(llvm.DIPointerType{
 608  			Pointee:      c.getDIType(typ.Elem()),
 609  			SizeInBits:   c.targetData.TypeAllocSize(llvmType) * 8,
 610  			AlignInBits:  uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 611  			AddressSpace: 0,
 612  		})
 613  	case *types.Signature:
 614  		// actually a closure
 615  		fields := llvmType.StructElementTypes()
 616  		return c.dibuilder.CreateStructType(llvm.Metadata{}, llvm.DIStructType{
 617  			SizeInBits:  sizeInBytes * 8,
 618  			AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 619  			Elements: []llvm.Metadata{
 620  				c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 621  					Name:         "context",
 622  					SizeInBits:   c.targetData.TypeAllocSize(fields[1]) * 8,
 623  					AlignInBits:  uint32(c.targetData.ABITypeAlignment(fields[1])) * 8,
 624  					OffsetInBits: 0,
 625  					Type:         c.getDIType(types.Typ[types.UnsafePointer]),
 626  				}),
 627  				c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 628  					Name:         "fn",
 629  					SizeInBits:   c.targetData.TypeAllocSize(fields[0]) * 8,
 630  					AlignInBits:  uint32(c.targetData.ABITypeAlignment(fields[0])) * 8,
 631  					OffsetInBits: c.targetData.ElementOffset(llvmType, 1) * 8,
 632  					Type:         c.getDIType(types.Typ[types.UnsafePointer]),
 633  				}),
 634  			},
 635  		})
 636  	case *types.Slice:
 637  		fields := llvmType.StructElementTypes()
 638  		return c.dibuilder.CreateStructType(llvm.Metadata{}, llvm.DIStructType{
 639  			Name:        typ.String(),
 640  			SizeInBits:  sizeInBytes * 8,
 641  			AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 642  			Elements: []llvm.Metadata{
 643  				c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 644  					Name:         "ptr",
 645  					SizeInBits:   c.targetData.TypeAllocSize(fields[0]) * 8,
 646  					AlignInBits:  uint32(c.targetData.ABITypeAlignment(fields[0])) * 8,
 647  					OffsetInBits: 0,
 648  					Type:         c.getDIType(types.NewPointer(typ.Elem())),
 649  				}),
 650  				c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 651  					Name:         "len",
 652  					SizeInBits:   c.targetData.TypeAllocSize(c.uintptrType) * 8,
 653  					AlignInBits:  uint32(c.targetData.ABITypeAlignment(c.uintptrType)) * 8,
 654  					OffsetInBits: c.targetData.ElementOffset(llvmType, 1) * 8,
 655  					Type:         c.getDIType(types.Typ[types.Uintptr]),
 656  				}),
 657  				c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 658  					Name:         "cap",
 659  					SizeInBits:   c.targetData.TypeAllocSize(c.uintptrType) * 8,
 660  					AlignInBits:  uint32(c.targetData.ABITypeAlignment(c.uintptrType)) * 8,
 661  					OffsetInBits: c.targetData.ElementOffset(llvmType, 2) * 8,
 662  					Type:         c.getDIType(types.Typ[types.Uintptr]),
 663  				}),
 664  			},
 665  		})
 666  	case *types.Struct:
 667  		elements := make([]llvm.Metadata, typ.NumFields())
 668  		for i := range elements {
 669  			field := typ.Field(i)
 670  			fieldType := field.Type()
 671  			llvmField := c.getLLVMType(fieldType)
 672  			elements[i] = c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{
 673  				Name:         field.Name(),
 674  				SizeInBits:   c.targetData.TypeAllocSize(llvmField) * 8,
 675  				AlignInBits:  uint32(c.targetData.ABITypeAlignment(llvmField)) * 8,
 676  				OffsetInBits: c.targetData.ElementOffset(llvmType, i) * 8,
 677  				Type:         c.getDIType(fieldType),
 678  			})
 679  		}
 680  		md := c.dibuilder.CreateStructType(llvm.Metadata{}, llvm.DIStructType{
 681  			SizeInBits:  sizeInBytes * 8,
 682  			AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
 683  			Elements:    elements,
 684  		})
 685  		return md
 686  	case *types.TypeParam:
 687  		return c.getDIType(typ.Underlying())
 688  	default:
 689  		panic("unknown type while generating DWARF debug type: " + typ.String())
 690  	}
 691  }
 692  
 693  // setDebugLocation sets the current debug location for the builder.
 694  func (b *builder) setDebugLocation(pos token.Pos) {
 695  	if pos == token.NoPos {
 696  		// No debug information available for this instruction.
 697  		b.SetCurrentDebugLocation(0, 0, b.difunc, llvm.Metadata{})
 698  		return
 699  	}
 700  
 701  	position := b.program.Fset.Position(pos)
 702  	if b.fn.Synthetic == "package initializer" {
 703  		// Package initializers are treated specially, because while individual
 704  		// Go SSA instructions have file/line/col information, the parent
 705  		// function does not. LLVM doesn't store filename information per
 706  		// instruction, only per function. We work around this difference by
 707  		// creating a fake DIFunction for each Go file and say that the
 708  		// instruction really came from that (fake) function but was inlined in
 709  		// the package initializer function.
 710  		position := b.program.Fset.Position(pos)
 711  		name := filepath.Base(position.Filename)
 712  		difunc, ok := b.initPseudoFuncs[name]
 713  		if !ok {
 714  			diFuncType := b.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
 715  				File: b.getDIFile(position.Filename),
 716  			})
 717  			difunc = b.dibuilder.CreateFunction(b.getDIFile(position.Filename), llvm.DIFunction{
 718  				Name:         b.fn.RelString(nil) + "#" + name,
 719  				File:         b.getDIFile(position.Filename),
 720  				Line:         0,
 721  				Type:         diFuncType,
 722  				LocalToUnit:  true,
 723  				IsDefinition: true,
 724  				ScopeLine:    0,
 725  				Flags:        llvm.FlagPrototyped,
 726  				Optimized:    true,
 727  			})
 728  			b.initPseudoFuncs[name] = difunc
 729  		}
 730  		b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), difunc, b.initInlinedAt)
 731  		return
 732  	}
 733  
 734  	// Regular debug information.
 735  	b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), b.difunc, llvm.Metadata{})
 736  }
 737  
 738  // getLocalVariable returns a debug info entry for a local variable, which may
 739  // either be a parameter or a regular variable. It will create a new metadata
 740  // entry if there isn't one for the variable yet.
 741  func (b *builder) getLocalVariable(variable *types.Var) llvm.Metadata {
 742  	if dilocal, ok := b.dilocals[variable]; ok {
 743  		// DILocalVariable was already created, return it directly.
 744  		return dilocal
 745  	}
 746  
 747  	pos := b.program.Fset.Position(variable.Pos())
 748  
 749  	// Check whether this is a function parameter.
 750  	for i, param := range b.fn.Params {
 751  		if param.Object().(*types.Var) == variable {
 752  			// Yes it is, create it as a function parameter.
 753  			dilocal := b.dibuilder.CreateParameterVariable(b.difunc, llvm.DIParameterVariable{
 754  				Name:           param.Name(),
 755  				File:           b.getDIFile(pos.Filename),
 756  				Line:           pos.Line,
 757  				Type:           b.getDIType(param.Type()),
 758  				AlwaysPreserve: true,
 759  				ArgNo:          i + 1,
 760  			})
 761  			b.dilocals[variable] = dilocal
 762  			return dilocal
 763  		}
 764  	}
 765  
 766  	// No, it's not a parameter. Create a regular (auto) variable.
 767  	dilocal := b.dibuilder.CreateAutoVariable(b.difunc, llvm.DIAutoVariable{
 768  		Name:           variable.Name(),
 769  		File:           b.getDIFile(pos.Filename),
 770  		Line:           pos.Line,
 771  		Type:           b.getDIType(variable.Type()),
 772  		AlwaysPreserve: true,
 773  	})
 774  	b.dilocals[variable] = dilocal
 775  	return dilocal
 776  }
 777  
 778  // attachDebugInfo adds debug info to a function declaration. It returns the
 779  // DISubprogram metadata node.
 780  func (c *compilerContext) attachDebugInfo(f *ssa.Function) llvm.Metadata {
 781  	pos := c.program.Fset.Position(f.Syntax().Pos())
 782  	_, fn := c.getFunction(f)
 783  	return c.attachDebugInfoRaw(f, fn, "", pos.Filename, pos.Line)
 784  }
 785  
 786  // attachDebugInfo adds debug info to a function declaration. It returns the
 787  // DISubprogram metadata node. This method allows some more control over how
 788  // debug info is added to the function.
 789  func (c *compilerContext) attachDebugInfoRaw(f *ssa.Function, llvmFn llvm.Value, suffix, filename string, line int) llvm.Metadata {
 790  	// Debug info for this function.
 791  	params := getParams(f.Signature)
 792  	diparams := make([]llvm.Metadata, 0, len(params))
 793  	for _, param := range params {
 794  		diparams = append(diparams, c.getDIType(param.Type()))
 795  	}
 796  	diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
 797  		File:       c.getDIFile(filename),
 798  		Parameters: diparams,
 799  		Flags:      0, // ?
 800  	})
 801  	difunc := c.dibuilder.CreateFunction(c.getDIFile(filename), llvm.DIFunction{
 802  		Name:         f.RelString(nil) + suffix,
 803  		LinkageName:  c.getFunctionInfo(f).linkName + suffix,
 804  		File:         c.getDIFile(filename),
 805  		Line:         line,
 806  		Type:         diFuncType,
 807  		LocalToUnit:  true,
 808  		IsDefinition: true,
 809  		ScopeLine:    0,
 810  		Flags:        llvm.FlagPrototyped,
 811  		Optimized:    true,
 812  	})
 813  	llvmFn.SetSubprogram(difunc)
 814  	return difunc
 815  }
 816  
 817  // getDIFile returns a DIFile metadata node for the given filename. It tries to
 818  // use one that was already created, otherwise it falls back to creating a new
 819  // one.
 820  func (c *compilerContext) getDIFile(filename string) llvm.Metadata {
 821  	if _, ok := c.difiles[filename]; !ok {
 822  		dir, file := filepath.Split(filename)
 823  		if dir != "" {
 824  			dir = dir[:len(dir)-1]
 825  		}
 826  		c.difiles[filename] = c.dibuilder.CreateFile(file, dir)
 827  	}
 828  	return c.difiles[filename]
 829  }
 830  
 831  // createPackage builds the LLVM IR for all types, methods, and global variables
 832  // in the given package.
 833  func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package) {
 834  	// Sort by position, so that the order of the functions in the IR matches
 835  	// the order of functions in the source file. This is useful for testing,
 836  	// for example.
 837  	var members []string
 838  	for name := range pkg.Members {
 839  		members = append(members, name)
 840  	}
 841  	sort.Slice(members, func(i, j int) bool {
 842  		iPos := pkg.Members[members[i]].Pos()
 843  		jPos := pkg.Members[members[j]].Pos()
 844  		if i == j {
 845  			// Cannot sort by pos, so do it by name.
 846  			return members[i] < members[j]
 847  		}
 848  		return iPos < jPos
 849  	})
 850  
 851  	// Define all functions.
 852  	for _, name := range members {
 853  		member := pkg.Members[name]
 854  		switch member := member.(type) {
 855  		case *ssa.Function:
 856  			if member.TypeParams() != nil {
 857  				// Do not try to build generic (non-instantiated) functions.
 858  				continue
 859  			}
 860  			// Create the function definition.
 861  			b := newBuilder(c, irbuilder, member)
 862  			if _, ok := mathToLLVMMapping[member.RelString(nil)]; ok {
 863  				// The body of this function (if there is one) is ignored and
 864  				// replaced with a LLVM intrinsic call.
 865  				b.defineMathOp()
 866  				continue
 867  			}
 868  			if ok := b.defineMathBitsIntrinsic(); ok {
 869  				// Like a math intrinsic, the body of this function was replaced
 870  				// with a LLVM intrinsic.
 871  				continue
 872  			}
 873  			if member.Blocks == nil {
 874  				// Try to define this as an intrinsic function.
 875  				b.defineIntrinsicFunction()
 876  				// It might not be an intrinsic function but simply an external
 877  				// function (defined via //go:linkname). Leave it undefined in
 878  				// that case.
 879  				continue
 880  			}
 881  			b.createFunction()
 882  		case *ssa.Type:
 883  			if types.IsInterface(member.Type()) {
 884  				// Interfaces don't have concrete methods.
 885  				continue
 886  			}
 887  			if _, isalias := member.Type().(*types.Alias); isalias {
 888  				// Aliases don't need to be redefined, since they just refer to
 889  				// an already existing type whose methods will be defined.
 890  				continue
 891  			}
 892  
 893  			// Named type. We should make sure all methods are created.
 894  			// This includes both functions with pointer receivers and those
 895  			// without.
 896  			methods := getAllMethods(pkg.Prog, member.Type())
 897  			methods = append(methods, getAllMethods(pkg.Prog, types.NewPointer(member.Type()))...)
 898  			for _, method := range methods {
 899  				// Parse this method.
 900  				fn := pkg.Prog.MethodValue(method)
 901  				if fn == nil {
 902  					continue // probably a generic method
 903  				}
 904  				if member.Type().String() != member.String() {
 905  					// This is a member on a type alias. Do not build such a
 906  					// function.
 907  					continue
 908  				}
 909  				if fn.Blocks == nil {
 910  					continue // external function
 911  				}
 912  				if fn.Synthetic != "" && fn.Synthetic != "package initializer" {
 913  					// This function is a kind of wrapper function (created by
 914  					// the ssa package, not appearing in the source code) that
 915  					// is created by the getFunction method as needed.
 916  					// Therefore, don't build it here to avoid "function
 917  					// redeclared" errors.
 918  					continue
 919  				}
 920  				// Create the function definition.
 921  				b := newBuilder(c, irbuilder, fn)
 922  				b.createFunction()
 923  			}
 924  		case *ssa.Global:
 925  			// Global variable.
 926  			info := c.getGlobalInfo(member)
 927  			global := c.getGlobal(member)
 928  			if files, ok := c.embedGlobals[member.Name()]; ok {
 929  				c.createEmbedGlobal(member, global, files)
 930  			} else if !info.extern {
 931  				global.SetInitializer(llvm.ConstNull(global.GlobalValueType()))
 932  				global.SetVisibility(llvm.HiddenVisibility)
 933  				if info.section != "" {
 934  					global.SetSection(info.section)
 935  				}
 936  			}
 937  		}
 938  	}
 939  
 940  	// Add forwarding functions for functions that would otherwise be
 941  	// implemented in assembly.
 942  	for _, name := range members {
 943  		member := pkg.Members[name]
 944  		switch member := member.(type) {
 945  		case *ssa.Function:
 946  			if member.Blocks != nil {
 947  				continue // external function
 948  			}
 949  			info := c.getFunctionInfo(member)
 950  			if aliasName, ok := stdlibAliases[info.linkName]; ok {
 951  				alias := c.mod.NamedFunction(aliasName)
 952  				if alias.IsNil() {
 953  					// Shouldn't happen, but perhaps best to just ignore.
 954  					// The error will be a link error, if there is an error.
 955  					continue
 956  				}
 957  				b := newBuilder(c, irbuilder, member)
 958  				b.createAlias(alias)
 959  			}
 960  		}
 961  	}
 962  }
 963  
 964  // createEmbedGlobal creates an initializer for a //go:embed global variable.
 965  func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Value, files []*loader.EmbedFile) {
 966  	switch typ := member.Type().(*types.Pointer).Elem().Underlying().(type) {
 967  	case *types.Basic:
 968  		// String type.
 969  		if typ.Kind() != types.String {
 970  			// This is checked at the AST level, so should be unreachable.
 971  			panic("expected a string type")
 972  		}
 973  		if len(files) != 1 {
 974  			c.addError(member.Pos(), fmt.Sprintf("//go:embed for a string should be given exactly one file, got %d", len(files)))
 975  			return
 976  		}
 977  		strObj := c.getEmbedFileString(files[0])
 978  		global.SetInitializer(strObj)
 979  		global.SetVisibility(llvm.HiddenVisibility)
 980  
 981  	case *types.Slice:
 982  		if typ.Elem().Underlying().(*types.Basic).Kind() != types.Byte {
 983  			// This is checked at the AST level, so should be unreachable.
 984  			panic("expected a byte slice")
 985  		}
 986  		if len(files) != 1 {
 987  			c.addError(member.Pos(), fmt.Sprintf("//go:embed for a string should be given exactly one file, got %d", len(files)))
 988  			return
 989  		}
 990  		file := files[0]
 991  		bufferValue := c.ctx.ConstString(string(file.Data), false)
 992  		bufferGlobal := llvm.AddGlobal(c.mod, bufferValue.Type(), c.pkg.Path()+"$embedslice")
 993  		bufferGlobal.SetInitializer(bufferValue)
 994  		bufferGlobal.SetLinkage(llvm.InternalLinkage)
 995  		bufferGlobal.SetAlignment(1)
 996  		slicePtr := llvm.ConstInBoundsGEP(bufferValue.Type(), bufferGlobal, []llvm.Value{
 997  			llvm.ConstInt(c.uintptrType, 0, false),
 998  			llvm.ConstInt(c.uintptrType, 0, false),
 999  		})
1000  		sliceLen := llvm.ConstInt(c.uintptrType, file.Size, false)
1001  		sliceObj := llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{slicePtr, sliceLen, sliceLen})
1002  		global.SetInitializer(sliceObj)
1003  		global.SetVisibility(llvm.HiddenVisibility)
1004  
1005  		if c.Debug {
1006  			// Add debug info to the slice backing array.
1007  			position := c.program.Fset.Position(member.Pos())
1008  			diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
1009  				File:        c.getDIFile(position.Filename),
1010  				Line:        position.Line,
1011  				Type:        c.getDIType(types.NewArray(types.Typ[types.Byte], int64(len(file.Data)))),
1012  				LocalToUnit: true,
1013  				Expr:        c.dibuilder.CreateExpression(nil),
1014  			})
1015  			bufferGlobal.AddMetadata(0, diglobal)
1016  		}
1017  
1018  	case *types.Struct:
1019  		// Assume this is an embed.FS struct:
1020  		// https://cs.opensource.google/go/go/+/refs/tags/go1.18.2:src/embed/embed.go;l=148
1021  		// It looks like this:
1022  		//   type FS struct {
1023  		//       files *file
1024  		//   }
1025  
1026  		// Make a slice of the files, as they will appear in the binary. They
1027  		// are sorted in a special way to allow for binary searches, see
1028  		// src/embed/embed.go for details.
1029  		dirset := map[string]struct{}{}
1030  		var allFiles []*loader.EmbedFile
1031  		for _, file := range files {
1032  			allFiles = append(allFiles, file)
1033  			dirname := file.Name
1034  			for {
1035  				dirname, _ = path.Split(path.Clean(dirname))
1036  				if dirname == "" {
1037  					break
1038  				}
1039  				if _, ok := dirset[dirname]; ok {
1040  					break
1041  				}
1042  				dirset[dirname] = struct{}{}
1043  				allFiles = append(allFiles, &loader.EmbedFile{
1044  					Name: dirname,
1045  				})
1046  			}
1047  		}
1048  		sort.Slice(allFiles, func(i, j int) bool {
1049  			dir1, name1 := path.Split(path.Clean(allFiles[i].Name))
1050  			dir2, name2 := path.Split(path.Clean(allFiles[j].Name))
1051  			if dir1 != dir2 {
1052  				return dir1 < dir2
1053  			}
1054  			return name1 < name2
1055  		})
1056  
1057  		// Make the backing array for the []files slice. This is a LLVM global.
1058  		embedFileStructType := typ.Field(0).Type().(*types.Pointer).Elem().(*types.Slice).Elem()
1059  		llvmEmbedFileStructType := c.getLLVMType(embedFileStructType)
1060  		var fileStructs []llvm.Value
1061  		for _, file := range allFiles {
1062  			fileStruct := llvm.ConstNull(llvmEmbedFileStructType)
1063  			name := c.createConst(ssa.NewConst(constant.MakeString(file.Name), types.Typ[types.String]), getPos(member))
1064  			fileStruct = c.builder.CreateInsertValue(fileStruct, name, 0, "") // "name" field
1065  			if file.Hash != "" {
1066  				data := c.getEmbedFileString(file)
1067  				fileStruct = c.builder.CreateInsertValue(fileStruct, data, 1, "") // "data" field
1068  			}
1069  			fileStructs = append(fileStructs, fileStruct)
1070  		}
1071  		sliceDataInitializer := llvm.ConstArray(llvmEmbedFileStructType, fileStructs)
1072  		sliceDataGlobal := llvm.AddGlobal(c.mod, sliceDataInitializer.Type(), c.pkg.Path()+"$embedfsfiles")
1073  		sliceDataGlobal.SetInitializer(sliceDataInitializer)
1074  		sliceDataGlobal.SetLinkage(llvm.InternalLinkage)
1075  		sliceDataGlobal.SetGlobalConstant(true)
1076  		sliceDataGlobal.SetUnnamedAddr(true)
1077  		sliceDataGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceDataInitializer.Type()))
1078  		if c.Debug {
1079  			// Add debug information for code size attribution (among others).
1080  			position := c.program.Fset.Position(member.Pos())
1081  			diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
1082  				File:        c.getDIFile(position.Filename),
1083  				Line:        position.Line,
1084  				Type:        c.getDIType(types.NewArray(embedFileStructType, int64(len(allFiles)))),
1085  				LocalToUnit: true,
1086  				Expr:        c.dibuilder.CreateExpression(nil),
1087  			})
1088  			sliceDataGlobal.AddMetadata(0, diglobal)
1089  		}
1090  
1091  		// Create the slice object itself.
1092  		// Because embed.FS refers to it as *[]embed.file instead of a plain
1093  		// []embed.file, we have to store this as a global.
1094  		slicePtr := llvm.ConstInBoundsGEP(sliceDataInitializer.Type(), sliceDataGlobal, []llvm.Value{
1095  			llvm.ConstInt(c.uintptrType, 0, false),
1096  			llvm.ConstInt(c.uintptrType, 0, false),
1097  		})
1098  		sliceLen := llvm.ConstInt(c.uintptrType, uint64(len(fileStructs)), false)
1099  		sliceInitializer := c.ctx.ConstStruct([]llvm.Value{slicePtr, sliceLen, sliceLen}, false)
1100  		sliceGlobal := llvm.AddGlobal(c.mod, sliceInitializer.Type(), c.pkg.Path()+"$embedfsslice")
1101  		sliceGlobal.SetInitializer(sliceInitializer)
1102  		sliceGlobal.SetLinkage(llvm.InternalLinkage)
1103  		sliceGlobal.SetGlobalConstant(true)
1104  		sliceGlobal.SetUnnamedAddr(true)
1105  		sliceGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceInitializer.Type()))
1106  		if c.Debug {
1107  			position := c.program.Fset.Position(member.Pos())
1108  			diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
1109  				File:        c.getDIFile(position.Filename),
1110  				Line:        position.Line,
1111  				Type:        c.getDIType(types.NewSlice(embedFileStructType)),
1112  				LocalToUnit: true,
1113  				Expr:        c.dibuilder.CreateExpression(nil),
1114  			})
1115  			sliceGlobal.AddMetadata(0, diglobal)
1116  		}
1117  
1118  		// Define the embed.FS struct. It has only one field: the files (as a
1119  		// *[]embed.file).
1120  		globalInitializer := llvm.ConstNull(c.getLLVMType(member.Type().(*types.Pointer).Elem()))
1121  		globalInitializer = c.builder.CreateInsertValue(globalInitializer, sliceGlobal, 0, "")
1122  		global.SetInitializer(globalInitializer)
1123  		global.SetVisibility(llvm.HiddenVisibility)
1124  		global.SetAlignment(c.targetData.ABITypeAlignment(globalInitializer.Type()))
1125  	}
1126  }
1127  
1128  // getEmbedFileString returns the (constant) string object with the contents of
1129  // the given file. This is a llvm.Value of a regular Go string.
1130  func (c *compilerContext) getEmbedFileString(file *loader.EmbedFile) llvm.Value {
1131  	dataGlobalName := "embed/file_" + file.Hash
1132  	dataGlobal := c.mod.NamedGlobal(dataGlobalName)
1133  	dataGlobalType := llvm.ArrayType(c.ctx.Int8Type(), int(file.Size))
1134  	if dataGlobal.IsNil() {
1135  		dataGlobal = llvm.AddGlobal(c.mod, dataGlobalType, dataGlobalName)
1136  	}
1137  	strPtr := llvm.ConstInBoundsGEP(dataGlobalType, dataGlobal, []llvm.Value{
1138  		llvm.ConstInt(c.uintptrType, 0, false),
1139  		llvm.ConstInt(c.uintptrType, 0, false),
1140  	})
1141  	strLen := llvm.ConstInt(c.uintptrType, file.Size, false)
1142  	return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen, strLen})
1143  }
1144  
1145  // Start defining a function so that it can be filled with instructions: load
1146  // parameters, create basic blocks, and set up debug information.
1147  // This is separated out from createFunction() so that it is also usable to
1148  // define compiler intrinsics like the atomic operations in sync/atomic.
1149  func (b *builder) createFunctionStart(intrinsic bool) {
1150  	if b.DumpSSA {
1151  		fmt.Printf("\nfunc %s:\n", b.fn)
1152  	}
1153  	if !b.llvmFn.IsDeclaration() {
1154  		errValue := b.llvmFn.Name() + " redeclared in this program"
1155  		fnPos := getPosition(b.llvmFn)
1156  		if fnPos.IsValid() {
1157  			errValue += "\n\tprevious declaration at " + fnPos.String()
1158  		}
1159  		b.addError(b.fn.Pos(), errValue)
1160  		return
1161  	}
1162  
1163  	b.addStandardDefinedAttributes(b.llvmFn)
1164  	if !b.info.exported {
1165  		// Do not set visibility for local linkage (internal or private).
1166  		// Otherwise a "local linkage requires default visibility"
1167  		// assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236
1168  		// is thrown.
1169  		if b.llvmFn.Linkage() != llvm.InternalLinkage &&
1170  			b.llvmFn.Linkage() != llvm.PrivateLinkage {
1171  			b.llvmFn.SetVisibility(llvm.HiddenVisibility)
1172  		}
1173  		b.llvmFn.SetUnnamedAddr(true)
1174  	}
1175  	if b.info.section != "" {
1176  		b.llvmFn.SetSection(b.info.section)
1177  	}
1178  	if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
1179  		// Set the exported name. This is necessary for WebAssembly because
1180  		// otherwise the function is not exported.
1181  		functionAttr := b.ctx.CreateStringAttribute("wasm-export-name", b.info.linkName)
1182  		b.llvmFn.AddFunctionAttr(functionAttr)
1183  		// Unlike most targets, exported functions are actually visible in
1184  		// WebAssembly (even if it's not called from within the WebAssembly
1185  		// module). But LTO generally optimizes such functions away. Therefore,
1186  		// exported functions must be explicitly marked as used.
1187  		llvmutil.AppendToGlobal(b.mod, "llvm.used", b.llvmFn)
1188  	}
1189  
1190  	// Some functions have a pragma controlling the inlining level.
1191  	switch b.info.inline {
1192  	case inlineHint:
1193  		// Add LLVM inline hint to functions with //go:inline pragma.
1194  		inline := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("inlinehint"), 0)
1195  		b.llvmFn.AddFunctionAttr(inline)
1196  	case inlineNone:
1197  		// Add LLVM attribute to always avoid inlining this function.
1198  		noinline := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("noinline"), 0)
1199  		b.llvmFn.AddFunctionAttr(noinline)
1200  	}
1201  
1202  	if b.info.interrupt {
1203  		// Mark this function as an interrupt.
1204  		// This is necessary on MCUs that don't push caller saved registers when
1205  		// entering an interrupt, such as on AVR.
1206  		if strings.HasPrefix(b.Triple, "avr") {
1207  			b.llvmFn.AddFunctionAttr(b.ctx.CreateStringAttribute("signal", ""))
1208  		} else {
1209  			b.addError(b.fn.Pos(), "//go:interrupt not supported on this architecture")
1210  		}
1211  	}
1212  
1213  	// Add debug info, if needed.
1214  	if b.Debug {
1215  		if b.fn.Synthetic == "package initializer" {
1216  			// Package initializer functions have no debug info. Create some
1217  			// fake debug info to at least have *something*.
1218  			b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", b.packageDir, 0)
1219  		} else if b.fn.Syntax() != nil {
1220  			// Create debug info file if needed.
1221  			b.difunc = b.attachDebugInfo(b.fn)
1222  		}
1223  		b.setDebugLocation(b.fn.Pos())
1224  	}
1225  
1226  	// Pre-create all basic blocks in the function.
1227  	var entryBlock llvm.BasicBlock
1228  	if intrinsic {
1229  		// This function isn't defined in Go SSA. It is probably a compiler
1230  		// intrinsic (like an atomic operation). Create the entry block
1231  		// manually.
1232  		entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry")
1233  		// Intrinsics may create internal branches (e.g. nil checks).
1234  		// They will attempt to access b.currentBlockInfo to update the exit block.
1235  		// Create some fake block info for them to access.
1236  		blockInfo := []blockInfo{
1237  			{
1238  				entry: entryBlock,
1239  				exit:  entryBlock,
1240  			},
1241  		}
1242  		b.blockInfo = blockInfo
1243  		b.currentBlockInfo = &blockInfo[0]
1244  	} else {
1245  		blocks := b.fn.Blocks
1246  		blockInfo := make([]blockInfo, len(blocks))
1247  		for _, block := range b.fn.DomPreorder() {
1248  			info := &blockInfo[block.Index]
1249  			llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
1250  			info.entry = llvmBlock
1251  			info.exit = llvmBlock
1252  		}
1253  		b.blockInfo = blockInfo
1254  		// Normal functions have an entry block.
1255  		entryBlock = blockInfo[0].entry
1256  	}
1257  	b.SetInsertPointAtEnd(entryBlock)
1258  
1259  	if b.fn.Synthetic == "package initializer" {
1260  		b.initPseudoFuncs = make(map[string]llvm.Metadata)
1261  
1262  		// Create a fake 'inlined at' metadata node.
1263  		// See setDebugLocation for details.
1264  		alloca := b.CreateAlloca(b.uintptrType, "")
1265  		b.initInlinedAt = alloca.InstructionDebugLoc()
1266  		alloca.EraseFromParentAsInstruction()
1267  	}
1268  
1269  	// Load function parameters
1270  	llvmParamIndex := 0
1271  	for _, param := range b.fn.Params {
1272  		llvmType := b.getLLVMType(param.Type())
1273  		fields := make([]llvm.Value, 0, 1)
1274  		for _, info := range b.expandFormalParamType(llvmType, param.Name(), param.Type()) {
1275  			param := b.llvmFn.Param(llvmParamIndex)
1276  			param.SetName(info.name)
1277  			fields = append(fields, param)
1278  			llvmParamIndex++
1279  		}
1280  		b.locals[param] = b.collapseFormalParam(llvmType, fields)
1281  
1282  		// Add debug information to this parameter (if available)
1283  		if b.Debug && b.fn.Syntax() != nil {
1284  			dbgParam := b.getLocalVariable(param.Object().(*types.Var))
1285  			loc := b.GetCurrentDebugLocation()
1286  			if len(fields) == 1 {
1287  				expr := b.dibuilder.CreateExpression(nil)
1288  				b.dibuilder.InsertValueAtEnd(fields[0], dbgParam, expr, loc, entryBlock)
1289  			} else {
1290  				fieldOffsets := b.expandFormalParamOffsets(llvmType)
1291  				for i, field := range fields {
1292  					expr := b.dibuilder.CreateExpression([]uint64{
1293  						0x1000,              // DW_OP_LLVM_fragment
1294  						fieldOffsets[i] * 8, // offset in bits
1295  						b.targetData.TypeAllocSize(field.Type()) * 8, // size in bits
1296  					})
1297  					b.dibuilder.InsertValueAtEnd(field, dbgParam, expr, loc, entryBlock)
1298  				}
1299  			}
1300  		}
1301  	}
1302  
1303  	// Load free variables from the context. This is a closure (or bound
1304  	// method).
1305  	var context llvm.Value
1306  	if !b.info.exported {
1307  		context = b.llvmFn.LastParam()
1308  		context.SetName("context")
1309  	}
1310  	if len(b.fn.FreeVars) != 0 {
1311  		// Get a list of all variable types in the context.
1312  		freeVarTypes := make([]llvm.Type, len(b.fn.FreeVars))
1313  		for i, freeVar := range b.fn.FreeVars {
1314  			freeVarTypes[i] = b.getLLVMType(freeVar.Type())
1315  		}
1316  
1317  		// Load each free variable from the context pointer.
1318  		// A free variable is always a pointer when this is a closure, but it
1319  		// can be another type when it is a wrapper for a bound method (these
1320  		// wrappers are generated by the ssa package).
1321  		for i, val := range b.emitPointerUnpack(context, freeVarTypes) {
1322  			b.locals[b.fn.FreeVars[i]] = val
1323  		}
1324  	}
1325  
1326  	if b.fn.Recover != nil {
1327  		// This function has deferred function calls. Set some things up for
1328  		// them.
1329  		b.deferInitFunc()
1330  	}
1331  
1332  	if b.NeedsStackObjects {
1333  		// Create a dummy alloca that will be used in runtime.trackPointer.
1334  		// It is necessary to pass a dummy alloca to runtime.trackPointer
1335  		// because runtime.trackPointer is replaced by an alloca store.
1336  		b.stackChainAlloca = b.CreateAlloca(b.ctx.Int8Type(), "stackalloc")
1337  	}
1338  }
1339  
1340  // createFunction builds the LLVM IR implementation for this function. The
1341  // function must not yet be defined, otherwise this function will create a
1342  // diagnostic.
1343  func (b *builder) createFunction() {
1344  	b.createFunctionStart(false)
1345  
1346  	// Check Moxie language restrictions on user code.
1347  	b.checkMoxieRestrictions()
1348  
1349  	// Fill blocks with instructions.
1350  	for _, block := range b.fn.DomPreorder() {
1351  		if b.DumpSSA {
1352  			fmt.Printf("%d: %s:\n", block.Index, block.Comment)
1353  		}
1354  		b.currentBlock = block
1355  		b.currentBlockInfo = &b.blockInfo[block.Index]
1356  		b.SetInsertPointAtEnd(b.currentBlockInfo.entry)
1357  		for _, instr := range block.Instrs {
1358  			if instr, ok := instr.(*ssa.DebugRef); ok {
1359  				if !b.Debug {
1360  					continue
1361  				}
1362  				object := instr.Object()
1363  				variable, ok := object.(*types.Var)
1364  				if !ok {
1365  					// Not a local variable.
1366  					continue
1367  				}
1368  				if instr.IsAddr {
1369  					// TODO, this may happen for *ssa.Alloc and *ssa.FieldAddr
1370  					// for example.
1371  					continue
1372  				}
1373  				dbgVar := b.getLocalVariable(variable)
1374  				pos := b.program.Fset.Position(instr.Pos())
1375  				b.dibuilder.InsertValueAtEnd(b.getValue(instr.X, getPos(instr)), dbgVar, b.dibuilder.CreateExpression(nil), llvm.DebugLoc{
1376  					Line:  uint(pos.Line),
1377  					Col:   uint(pos.Column),
1378  					Scope: b.difunc,
1379  				}, b.GetInsertBlock())
1380  				continue
1381  			}
1382  			if b.DumpSSA {
1383  				if val, ok := instr.(ssa.Value); ok && val.Name() != "" {
1384  					fmt.Printf("\t%s = %s\n", val.Name(), val.String())
1385  				} else {
1386  					fmt.Printf("\t%s\n", instr.String())
1387  				}
1388  			}
1389  			b.createInstruction(instr)
1390  		}
1391  		if b.fn.Name() == "init" && len(block.Instrs) == 0 {
1392  			b.CreateRetVoid()
1393  		}
1394  	}
1395  
1396  	// The rundefers instruction needs to be created after all defer
1397  	// instructions have been created. Otherwise it won't handle all defer
1398  	// cases.
1399  	for i, bb := range b.runDefersBlock {
1400  		b.SetInsertPointAtEnd(bb)
1401  		b.createRunDefers()
1402  		b.CreateBr(b.afterDefersBlock[i])
1403  	}
1404  
1405  	if b.hasDeferFrame() {
1406  		// Create the landing pad block, where execution continues after a
1407  		// panic.
1408  		b.createLandingPad()
1409  	}
1410  
1411  	// Resolve phi nodes
1412  	for _, phi := range b.phis {
1413  		block := phi.ssa.Block()
1414  		for i, edge := range phi.ssa.Edges {
1415  			llvmVal := b.getValue(edge, getPos(phi.ssa))
1416  			llvmBlock := b.blockInfo[block.Preds[i].Index].exit
1417  			phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
1418  		}
1419  	}
1420  
1421  	if b.NeedsStackObjects {
1422  		// Track phi nodes.
1423  		for _, phi := range b.phis {
1424  			insertPoint := llvm.NextInstruction(phi.llvm)
1425  			for !insertPoint.IsAPHINode().IsNil() {
1426  				insertPoint = llvm.NextInstruction(insertPoint)
1427  			}
1428  			b.SetInsertPointBefore(insertPoint)
1429  			b.trackValue(phi.llvm)
1430  		}
1431  	}
1432  
1433  	// Create anonymous functions (closures etc.).
1434  	for _, sub := range b.fn.AnonFuncs {
1435  		b := newBuilder(b.compilerContext, b.Builder, sub)
1436  		b.llvmFn.SetLinkage(llvm.InternalLinkage)
1437  		b.createFunction()
1438  	}
1439  
1440  	// Create wrapper function that can be called externally.
1441  	if b.info.wasmExport != "" {
1442  		b.createWasmExport()
1443  	}
1444  }
1445  
1446  // posser is an interface that's implemented by both ssa.Value and
1447  // ssa.Instruction. It is implemented by everything that has a Pos() method,
1448  // which is all that getPos() needs.
1449  type posser interface {
1450  	Pos() token.Pos
1451  }
1452  
1453  // getPos returns position information for a ssa.Value or ssa.Instruction.
1454  //
1455  // Not all instructions have position information, especially when they're
1456  // implicit (such as implicit casts or implicit returns at the end of a
1457  // function). In these cases, it makes sense to try a bit harder to guess what
1458  // the position really should be.
1459  func getPos(val posser) token.Pos {
1460  	pos := val.Pos()
1461  	if pos != token.NoPos {
1462  		// Easy: position is known.
1463  		return pos
1464  	}
1465  
1466  	// No position information is known.
1467  	switch val := val.(type) {
1468  	case *ssa.MakeInterface:
1469  		return getPos(val.X)
1470  	case *ssa.MakeClosure:
1471  		return val.Fn.(*ssa.Function).Pos()
1472  	case *ssa.Return:
1473  		syntax := val.Parent().Syntax()
1474  		if syntax != nil {
1475  			// non-synthetic
1476  			return syntax.End()
1477  		}
1478  		return token.NoPos
1479  	case *ssa.FieldAddr:
1480  		return getPos(val.X)
1481  	case *ssa.IndexAddr:
1482  		return getPos(val.X)
1483  	case *ssa.Slice:
1484  		return getPos(val.X)
1485  	case *ssa.Store:
1486  		return getPos(val.Addr)
1487  	case *ssa.Extract:
1488  		return getPos(val.Tuple)
1489  	default:
1490  		// This is reachable, for example with *ssa.Const, *ssa.If, and
1491  		// *ssa.Jump. They might be implemented in some way in the future.
1492  		return token.NoPos
1493  	}
1494  }
1495  
1496  // createInstruction builds the LLVM IR equivalent instructions for the
1497  // particular Go SSA instruction.
1498  func (b *builder) createInstruction(instr ssa.Instruction) {
1499  	if b.Debug {
1500  		b.setDebugLocation(getPos(instr))
1501  	}
1502  
1503  	switch instr := instr.(type) {
1504  	case ssa.Value:
1505  		if value, err := b.createExpr(instr); err != nil {
1506  			// This expression could not be parsed. Add the error to the list
1507  			// of diagnostics and continue with an undef value.
1508  			// The resulting IR will be incorrect (but valid). However,
1509  			// compilation can proceed which is useful because there may be
1510  			// more compilation errors which can then all be shown together to
1511  			// the user.
1512  			b.diagnostics = append(b.diagnostics, err)
1513  			b.locals[instr] = llvm.Undef(b.getLLVMType(instr.Type()))
1514  		} else {
1515  			b.locals[instr] = value
1516  			if len(*instr.Referrers()) != 0 && b.NeedsStackObjects {
1517  				b.trackExpr(instr, value)
1518  			}
1519  		}
1520  	case *ssa.DebugRef:
1521  		// ignore
1522  	case *ssa.Defer:
1523  		b.createDefer(instr)
1524  	case *ssa.Go:
1525  		// Moxie: go keyword banned in user code. Runtime/internal exempt.
1526  		if isUserPackage(b.fn.Pkg) {
1527  			b.addError(instr.Pos(), "moxie: the go keyword is not supported (there are no goroutines)")
1528  		} else {
1529  			b.createGo(instr)
1530  		}
1531  	case *ssa.If:
1532  		cond := b.getValue(instr.Cond, getPos(instr))
1533  		block := instr.Block()
1534  		blockThen := b.blockInfo[block.Succs[0].Index].entry
1535  		blockElse := b.blockInfo[block.Succs[1].Index].entry
1536  		b.CreateCondBr(cond, blockThen, blockElse)
1537  	case *ssa.Jump:
1538  		blockJump := b.blockInfo[instr.Block().Succs[0].Index].entry
1539  		b.CreateBr(blockJump)
1540  	case *ssa.MapUpdate:
1541  		m := b.getValue(instr.Map, getPos(instr))
1542  		key := b.getValue(instr.Key, getPos(instr))
1543  		value := b.getValue(instr.Value, getPos(instr))
1544  		mapType := instr.Map.Type().Underlying().(*types.Map)
1545  		b.createMapUpdate(mapType.Key(), m, key, value, instr.Pos())
1546  	case *ssa.Panic:
1547  		value := b.getValue(instr.X, getPos(instr))
1548  		b.createRuntimeInvoke("_panic", []llvm.Value{value}, "")
1549  		b.CreateUnreachable()
1550  	case *ssa.Return:
1551  		if b.hasDeferFrame() {
1552  			b.createRuntimeCall("destroyDeferFrame", []llvm.Value{b.deferFrame}, "")
1553  		}
1554  		if len(instr.Results) == 0 {
1555  			b.CreateRetVoid()
1556  		} else if len(instr.Results) == 1 {
1557  			b.CreateRet(b.getValue(instr.Results[0], getPos(instr)))
1558  		} else {
1559  			// Multiple return values. Put them all in a struct.
1560  			retVal := llvm.ConstNull(b.llvmFn.GlobalValueType().ReturnType())
1561  			for i, result := range instr.Results {
1562  				val := b.getValue(result, getPos(instr))
1563  				retVal = b.CreateInsertValue(retVal, val, i, "")
1564  			}
1565  			b.CreateRet(retVal)
1566  		}
1567  	case *ssa.RunDefers:
1568  		// Note where we're going to put the rundefers block
1569  		run := b.insertBasicBlock("rundefers.block")
1570  		b.CreateBr(run)
1571  		b.runDefersBlock = append(b.runDefersBlock, run)
1572  
1573  		after := b.insertBasicBlock("rundefers.after")
1574  		b.SetInsertPointAtEnd(after)
1575  		b.afterDefersBlock = append(b.afterDefersBlock, after)
1576  	case *ssa.Send:
1577  		b.createChanSend(instr)
1578  	case *ssa.Store:
1579  		llvmAddr := b.getValue(instr.Addr, getPos(instr))
1580  		llvmVal := b.getValue(instr.Val, getPos(instr))
1581  		b.createNilCheck(instr.Addr, llvmAddr, "store")
1582  		if b.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
1583  			// nothing to store
1584  			return
1585  		}
1586  		b.CreateStore(llvmVal, llvmAddr)
1587  	default:
1588  		b.addError(instr.Pos(), "unknown instruction: "+instr.String())
1589  	}
1590  }
1591  
1592  // createBuiltin lowers a builtin Go function (append, close, delete, etc.) to
1593  // LLVM IR. It uses runtime calls for some builtins.
1594  func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, callName string, pos token.Pos) (llvm.Value, error) {
1595  	switch callName {
1596  	case "append":
1597  		src := argValues[0]
1598  		elems := argValues[1]
1599  		srcBuf := b.CreateExtractValue(src, 0, "append.srcBuf")
1600  		srcLen := b.CreateExtractValue(src, 1, "append.srcLen")
1601  		srcCap := b.CreateExtractValue(src, 2, "append.srcCap")
1602  		elemsBuf := b.CreateExtractValue(elems, 0, "append.elemsBuf")
1603  		elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
1604  		// Moxie: argTypes[0] may be *types.Basic (string) due to string=[]byte.
1605  		var elemType llvm.Type
1606  		switch ut := argTypes[0].Underlying().(type) {
1607  		case *types.Slice:
1608  			elemType = b.getLLVMType(ut.Elem())
1609  		case *types.Basic: // string=[]byte: element is byte
1610  			elemType = b.ctx.Int8Type()
1611  		default:
1612  			panic("append on non-slice type: " + argTypes[0].String())
1613  		}
1614  		elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
1615  		result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize}, "append.new")
1616  		newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
1617  		newLen := b.CreateExtractValue(result, 1, "append.newLen")
1618  		newCap := b.CreateExtractValue(result, 2, "append.newCap")
1619  		newSlice := llvm.Undef(src.Type())
1620  		newSlice = b.CreateInsertValue(newSlice, newPtr, 0, "")
1621  		newSlice = b.CreateInsertValue(newSlice, newLen, 1, "")
1622  		newSlice = b.CreateInsertValue(newSlice, newCap, 2, "")
1623  		return newSlice, nil
1624  	case "cap":
1625  		value := argValues[0]
1626  		var llvmCap llvm.Value
1627  		switch argTypes[0].Underlying().(type) {
1628  		case *types.Chan:
1629  			llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap")
1630  		case *types.Slice:
1631  			llvmCap = b.CreateExtractValue(value, 2, "cap")
1632  		default:
1633  			return llvm.Value{}, b.makeError(pos, "todo: cap: unknown type")
1634  		}
1635  		capSize := b.targetData.TypeAllocSize(llvmCap.Type())
1636  		intSize := b.targetData.TypeAllocSize(b.intType)
1637  		if capSize < intSize {
1638  			llvmCap = b.CreateZExt(llvmCap, b.intType, "cap.int")
1639  		} else if capSize > intSize {
1640  			llvmCap = b.CreateTrunc(llvmCap, b.intType, "cap.int")
1641  		}
1642  		return llvmCap, nil
1643  	case "close":
1644  		b.createChanClose(argValues[0])
1645  		return llvm.Value{}, nil
1646  	case "complex":
1647  		r := argValues[0]
1648  		i := argValues[1]
1649  		t := argTypes[0].Underlying().(*types.Basic)
1650  		var cplx llvm.Value
1651  		switch t.Kind() {
1652  		case types.Float32:
1653  			cplx = llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.FloatType(), b.ctx.FloatType()}, false))
1654  		case types.Float64:
1655  			cplx = llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false))
1656  		default:
1657  			return llvm.Value{}, b.makeError(pos, "unsupported type in complex builtin: "+t.String())
1658  		}
1659  		cplx = b.CreateInsertValue(cplx, r, 0, "")
1660  		cplx = b.CreateInsertValue(cplx, i, 1, "")
1661  		return cplx, nil
1662  	case "clear":
1663  		value := argValues[0]
1664  		switch typ := argTypes[0].Underlying().(type) {
1665  		case *types.Slice:
1666  			elementType := b.getLLVMType(typ.Elem())
1667  			elementSize := b.targetData.TypeAllocSize(elementType)
1668  			elementAlign := b.targetData.ABITypeAlignment(elementType)
1669  
1670  			// The pointer to the data to be cleared.
1671  			llvmBuf := b.CreateExtractValue(value, 0, "buf")
1672  
1673  			// The length (in bytes) to be cleared.
1674  			llvmLen := b.CreateExtractValue(value, 1, "len")
1675  			llvmLen = b.CreateMul(llvmLen, llvm.ConstInt(llvmLen.Type(), elementSize, false), "")
1676  
1677  			// Do the clear operation using the LLVM memset builtin.
1678  			// This is also correct for nil slices: in those cases, len will be
1679  			// 0 which means the memset call is a no-op (according to the LLVM
1680  			// LangRef).
1681  			memset := b.getMemsetFunc()
1682  			call := b.createCall(memset.GlobalValueType(), memset, []llvm.Value{
1683  				llvmBuf, // dest
1684  				llvm.ConstInt(b.ctx.Int8Type(), 0, false), // val
1685  				llvmLen, // len
1686  				llvm.ConstInt(b.ctx.Int1Type(), 0, false), // isVolatile
1687  			}, "")
1688  			call.AddCallSiteAttribute(1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elementAlign)))
1689  
1690  			return llvm.Value{}, nil
1691  		case *types.Map:
1692  			m := argValues[0]
1693  			b.createMapClear(m)
1694  			return llvm.Value{}, nil
1695  		default:
1696  			return llvm.Value{}, b.makeError(pos, "unsupported type in clear builtin: "+typ.String())
1697  		}
1698  	case "copy":
1699  		dst := argValues[0]
1700  		src := argValues[1]
1701  		dstLen := b.CreateExtractValue(dst, 1, "copy.dstLen")
1702  		srcLen := b.CreateExtractValue(src, 1, "copy.srcLen")
1703  		dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray")
1704  		srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray")
1705  		elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
1706  		elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
1707  		return b.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
1708  	case "delete":
1709  		m := argValues[0]
1710  		key := argValues[1]
1711  		return llvm.Value{}, b.createMapDelete(argTypes[1], m, key, pos)
1712  	case "imag":
1713  		cplx := argValues[0]
1714  		return b.CreateExtractValue(cplx, 1, "imag"), nil
1715  	case "len":
1716  		value := argValues[0]
1717  		var llvmLen llvm.Value
1718  		switch argTypes[0].Underlying().(type) {
1719  		case *types.Basic, *types.Slice:
1720  			// string or slice
1721  			llvmLen = b.CreateExtractValue(value, 1, "len")
1722  		case *types.Chan:
1723  			llvmLen = b.createRuntimeCall("chanLen", []llvm.Value{value}, "len")
1724  		case *types.Map:
1725  			llvmLen = b.createRuntimeCall("hashmapLen", []llvm.Value{value}, "len")
1726  		default:
1727  			return llvm.Value{}, b.makeError(pos, "todo: len: unknown type")
1728  		}
1729  		lenSize := b.targetData.TypeAllocSize(llvmLen.Type())
1730  		intSize := b.targetData.TypeAllocSize(b.intType)
1731  		if lenSize < intSize {
1732  			llvmLen = b.CreateZExt(llvmLen, b.intType, "len.int")
1733  		} else if lenSize > intSize {
1734  			llvmLen = b.CreateTrunc(llvmLen, b.intType, "len.int")
1735  		}
1736  		return llvmLen, nil
1737  	case "min", "max":
1738  		// min and max builtins, added in Go 1.21.
1739  		// We can simply reuse the existing binop comparison code, which has all
1740  		// the edge cases figured out already.
1741  		tok := token.LSS
1742  		if callName == "max" {
1743  			tok = token.GTR
1744  		}
1745  		result := argValues[0]
1746  		typ := argTypes[0]
1747  		for _, arg := range argValues[1:] {
1748  			cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
1749  			if err != nil {
1750  				return result, err
1751  			}
1752  			result = b.CreateSelect(cmp, result, arg, "")
1753  		}
1754  		return result, nil
1755  	case "panic":
1756  		// This is rare, but happens in "defer panic()".
1757  		b.createRuntimeInvoke("_panic", argValues, "")
1758  		return llvm.Value{}, nil
1759  	case "print", "println":
1760  		b.createRuntimeCall("printlock", nil, "")
1761  		for i, value := range argValues {
1762  			if i >= 1 && callName == "println" {
1763  				b.createRuntimeCall("printspace", nil, "")
1764  			}
1765  			typ := argTypes[i].Underlying()
1766  			switch typ := typ.(type) {
1767  			case *types.Basic:
1768  				switch typ.Kind() {
1769  				case types.String, types.UntypedString:
1770  					b.createRuntimeCall("printstring", []llvm.Value{value}, "")
1771  				case types.Uintptr:
1772  					b.createRuntimeCall("printptr", []llvm.Value{value}, "")
1773  				case types.UnsafePointer:
1774  					ptrValue := b.CreatePtrToInt(value, b.uintptrType, "")
1775  					b.createRuntimeCall("printptr", []llvm.Value{ptrValue}, "")
1776  				default:
1777  					// runtime.print{int,uint}{8,16,32,64}
1778  					if typ.Info()&types.IsInteger != 0 {
1779  						name := "print"
1780  						if typ.Info()&types.IsUnsigned != 0 {
1781  							name += "uint"
1782  						} else {
1783  							name += "int"
1784  						}
1785  						name += strconv.FormatUint(b.targetData.TypeAllocSize(value.Type())*8, 10)
1786  						b.createRuntimeCall(name, []llvm.Value{value}, "")
1787  					} else if typ.Kind() == types.Bool {
1788  						b.createRuntimeCall("printbool", []llvm.Value{value}, "")
1789  					} else if typ.Kind() == types.Float32 {
1790  						b.createRuntimeCall("printfloat32", []llvm.Value{value}, "")
1791  					} else if typ.Kind() == types.Float64 {
1792  						b.createRuntimeCall("printfloat64", []llvm.Value{value}, "")
1793  					} else if typ.Kind() == types.Complex64 {
1794  						b.createRuntimeCall("printcomplex64", []llvm.Value{value}, "")
1795  					} else if typ.Kind() == types.Complex128 {
1796  						b.createRuntimeCall("printcomplex128", []llvm.Value{value}, "")
1797  					} else {
1798  						return llvm.Value{}, b.makeError(pos, "unknown basic arg type: "+typ.String())
1799  					}
1800  				}
1801  			case *types.Interface:
1802  				b.createRuntimeCall("printitf", []llvm.Value{value}, "")
1803  			case *types.Map:
1804  				b.createRuntimeCall("printmap", []llvm.Value{value}, "")
1805  			case *types.Pointer:
1806  				ptrValue := b.CreatePtrToInt(value, b.uintptrType, "")
1807  				b.createRuntimeCall("printptr", []llvm.Value{ptrValue}, "")
1808  			case *types.Slice:
1809  				// []byte prints as text; other slices print the header.
1810  				if basic, ok := typ.Elem().(*types.Basic); ok && basic.Kind() == types.Byte {
1811  					b.createRuntimeCall("printbytes", []llvm.Value{value}, "")
1812  				} else {
1813  					bufptr := b.CreateExtractValue(value, 0, "")
1814  					buflen := b.CreateExtractValue(value, 1, "")
1815  					bufcap := b.CreateExtractValue(value, 2, "")
1816  					ptrValue := b.CreatePtrToInt(bufptr, b.uintptrType, "")
1817  					b.createRuntimeCall("printslice", []llvm.Value{ptrValue, buflen, bufcap}, "")
1818  				}
1819  			default:
1820  				return llvm.Value{}, b.makeError(pos, "unknown arg type: "+typ.String())
1821  			}
1822  		}
1823  		if callName == "println" {
1824  			b.createRuntimeCall("printnl", nil, "")
1825  		}
1826  		b.createRuntimeCall("printunlock", nil, "")
1827  		return llvm.Value{}, nil // print() or println() returns void
1828  	case "real":
1829  		cplx := argValues[0]
1830  		return b.CreateExtractValue(cplx, 0, "real"), nil
1831  	case "recover":
1832  		useParentFrame := uint64(0)
1833  		if b.hasDeferFrame() {
1834  			// recover() should return the panic value of the parent function,
1835  			// not of the current function.
1836  			useParentFrame = 1
1837  		}
1838  		return b.createRuntimeCall("_recover", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), useParentFrame, false)}, ""), nil
1839  	case "ssa:wrapnilchk":
1840  		// TODO: do an actual nil check?
1841  		return argValues[0], nil
1842  
1843  	// Builtins from the unsafe package.
1844  	case "Add": // unsafe.Add
1845  		// This is basically just a GEP operation.
1846  		// Note: the pointer is always of type *i8.
1847  		ptr := argValues[0]
1848  		len := argValues[1]
1849  		return b.CreateGEP(b.ctx.Int8Type(), ptr, []llvm.Value{len}, ""), nil
1850  	case "Alignof": // unsafe.Alignof
1851  		align := b.targetData.ABITypeAlignment(argValues[0].Type())
1852  		return llvm.ConstInt(b.uintptrType, uint64(align), false), nil
1853  	case "Offsetof": // unsafe.Offsetof
1854  		// This builtin is a bit harder to implement and may need a bit of
1855  		// refactoring to work (it may be easier to implement if we have access
1856  		// to the underlying Go SSA instruction). It is also rarely used: it
1857  		// only applies in generic code and unsafe.Offsetof isn't very commonly
1858  		// used anyway.
1859  		// In other words, postpone it to some other day.
1860  		return llvm.Value{}, b.makeError(pos, "todo: unsafe.Offsetof")
1861  	case "Sizeof": // unsafe.Sizeof
1862  		size := b.targetData.TypeAllocSize(argValues[0].Type())
1863  		return llvm.ConstInt(b.uintptrType, size, false), nil
1864  	case "Slice", "String": // unsafe.Slice, unsafe.String
1865  		// This creates a slice or string from a pointer and a length.
1866  		// Note that the exception mentioned in the documentation (if the
1867  		// pointer and length are nil, the slice is also nil) is trivially
1868  		// already the case.
1869  		ptr := argValues[0]
1870  		len := argValues[1]
1871  		var elementType llvm.Type
1872  		if callName == "Slice" {
1873  			elementType = b.getLLVMType(argTypes[0].Underlying().(*types.Pointer).Elem())
1874  		} else {
1875  			elementType = b.ctx.Int8Type()
1876  		}
1877  		b.createUnsafeSliceStringCheck("unsafe."+callName, ptr, len, elementType, argTypes[1].Underlying().(*types.Basic))
1878  		if len.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
1879  			// Too small, zero-extend len.
1880  			len = b.CreateZExt(len, b.uintptrType, "")
1881  		} else if len.Type().IntTypeWidth() > b.uintptrType.IntTypeWidth() {
1882  			// Too big, truncate len.
1883  			len = b.CreateTrunc(len, b.uintptrType, "")
1884  		}
1885  		if callName == "Slice" {
1886  			// Moxie: detect []byte to use named _string type.
1887  			var sliceType llvm.Type
1888  			if elementType == b.ctx.Int8Type() {
1889  				sliceType = b.getLLVMRuntimeType("_string")
1890  			} else {
1891  				sliceType = b.ctx.StructType([]llvm.Type{
1892  					ptr.Type(),
1893  					b.uintptrType,
1894  					b.uintptrType,
1895  				}, false)
1896  			}
1897  			slice := llvm.Undef(sliceType)
1898  			slice = b.CreateInsertValue(slice, ptr, 0, "")
1899  			slice = b.CreateInsertValue(slice, len, 1, "")
1900  			slice = b.CreateInsertValue(slice, len, 2, "")
1901  			return slice, nil
1902  		} else {
1903  			str := llvm.Undef(b.getLLVMRuntimeType("_string"))
1904  			str = b.CreateInsertValue(str, argValues[0], 0, "")
1905  			str = b.CreateInsertValue(str, len, 1, "")
1906  			str = b.CreateInsertValue(str, len, 2, "") // cap = len for strings
1907  			return str, nil
1908  		}
1909  	case "SliceData", "StringData": // unsafe.SliceData, unsafe.StringData
1910  		return b.CreateExtractValue(argValues[0], 0, "slice.data"), nil
1911  	default:
1912  		return llvm.Value{}, b.makeError(pos, "todo: builtin: "+callName)
1913  	}
1914  }
1915  
1916  // createFunctionCall lowers a Go SSA call instruction (to a simple function,
1917  // closure, function pointer, builtin, method, etc.) to LLVM IR, usually a call
1918  // instruction.
1919  //
1920  // This is also where compiler intrinsics are implemented.
1921  func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) {
1922  	// See if this is an intrinsic function that is handled specially.
1923  	if fn := instr.StaticCallee(); fn != nil {
1924  		// Direct function call, either to a named or anonymous (directly
1925  		// applied) function call. If it is anonymous, it may be a closure.
1926  		name := fn.RelString(nil)
1927  		switch {
1928  		case name == "device.Asm" || name == "device/arm.Asm" || name == "device/arm64.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
1929  			return b.createInlineAsm(instr.Args)
1930  		case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
1931  			return b.createInlineAsmFull(instr)
1932  		case strings.HasPrefix(name, "device/arm.SVCall"):
1933  			return b.emitSVCall(instr.Args, getPos(instr))
1934  		case strings.HasPrefix(name, "device/arm64.SVCall"):
1935  			return b.emitSV64Call(instr.Args, getPos(instr))
1936  		case strings.HasPrefix(name, "(device/riscv.CSR)."):
1937  			return b.emitCSROperation(instr)
1938  		case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
1939  			if b.GOOS != "darwin" {
1940  				return b.createSyscall(instr)
1941  			}
1942  		case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
1943  			return b.createRawSyscallNoError(instr)
1944  		case name == "runtime.supportsRecover":
1945  			supportsRecover := uint64(0)
1946  			if b.supportsRecover() {
1947  				supportsRecover = 1
1948  			}
1949  			return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
1950  		case name == "runtime.panicStrategy":
1951  			panicStrategy := map[string]uint64{
1952  				"print": moxie.PanicStrategyPrint,
1953  				"trap":  moxie.PanicStrategyTrap,
1954  			}[b.Config.PanicStrategy]
1955  			return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
1956  		case name == "runtime/interrupt.New":
1957  			return b.createInterruptGlobal(instr)
1958  		case name == "runtime.exportedFuncPtr":
1959  			_, ptr := b.getFunction(instr.Args[0].(*ssa.Function))
1960  			return b.CreatePtrToInt(ptr, b.uintptrType, ""), nil
1961  		case name == "(*runtime/interrupt.Checkpoint).Save":
1962  			return b.createInterruptCheckpoint(instr.Args[0]), nil
1963  		case name == "internal/abi.FuncPCABI0":
1964  			retval := b.createDarwinFuncPCABI0Call(instr)
1965  			if !retval.IsNil() {
1966  				return retval, nil
1967  			}
1968  		case strings.HasPrefix(fn.Name(), "__moxie_concat"):
1969  			return b.createMoxieConcat(instr), nil
1970  		case strings.HasPrefix(fn.Name(), "__moxie_eq"):
1971  			return b.createMoxieEq(instr), nil
1972  		case strings.HasPrefix(fn.Name(), "__moxie_lt"):
1973  			return b.createMoxieLt(instr), nil
1974  		}
1975  	}
1976  
1977  	var params []llvm.Value
1978  	for _, param := range instr.Args {
1979  		params = append(params, b.getValue(param, getPos(instr)))
1980  	}
1981  
1982  	// Try to call the function directly for trivially static calls.
1983  	var callee, context llvm.Value
1984  	var calleeType llvm.Type
1985  	exported := false
1986  	if fn := instr.StaticCallee(); fn != nil {
1987  		calleeType, callee = b.getFunction(fn)
1988  		info := b.getFunctionInfo(fn)
1989  		if callee.IsNil() {
1990  			return llvm.Value{}, b.makeError(instr.Pos(), "undefined function: "+info.linkName)
1991  		}
1992  		switch value := instr.Value.(type) {
1993  		case *ssa.Function:
1994  			// Regular function call. No context is necessary.
1995  			context = llvm.Undef(b.dataPtrType)
1996  			if info.variadic && len(fn.Params) == 0 {
1997  				// This matches Clang, see: https://godbolt.org/z/Gqv49xKMq
1998  				// Eventually we might be able to eliminate this special case
1999  				// entirely. For details, see:
2000  				// https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521
2001  				calleeType = llvm.FunctionType(callee.GlobalValueType().ReturnType(), nil, false)
2002  			}
2003  		case *ssa.MakeClosure:
2004  			// A call on a func value, but the callee is trivial to find. For
2005  			// example: immediately applied functions.
2006  			funcValue := b.getValue(value, getPos(value))
2007  			context = b.extractFuncContext(funcValue)
2008  		default:
2009  			panic("StaticCallee returned an unexpected value")
2010  		}
2011  		exported = info.exported || strings.HasPrefix(info.linkName, "llvm.")
2012  	} else if call, ok := instr.Value.(*ssa.Builtin); ok {
2013  		if call.Name() == "spawn" {
2014  			return b.createSpawn(instr)
2015  		}
2016  		// Builtin function (append, close, delete, etc.).)
2017  		var argTypes []types.Type
2018  		for _, arg := range instr.Args {
2019  			argTypes = append(argTypes, arg.Type())
2020  		}
2021  		return b.createBuiltin(argTypes, params, call.Name(), instr.Pos())
2022  	} else if instr.IsInvoke() {
2023  		// Interface method call (aka invoke call).
2024  		itf := b.getValue(instr.Value, getPos(instr)) // interface value (runtime._interface)
2025  		typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
2026  		value := b.CreateExtractValue(itf, 1, "invoke.func.value") // receiver
2027  		// Prefix the params with receiver value and suffix with typecode.
2028  		params = append([]llvm.Value{value}, params...)
2029  		params = append(params, typecode)
2030  		callee = b.getInvokeFunction(instr)
2031  		calleeType = callee.GlobalValueType()
2032  		context = llvm.Undef(b.dataPtrType)
2033  	} else {
2034  		// Function pointer.
2035  		value := b.getValue(instr.Value, getPos(instr))
2036  		// This is a func value, which cannot be called directly. We have to
2037  		// extract the function pointer and context first from the func value.
2038  		callee, context = b.decodeFuncValue(value)
2039  		calleeType = b.getLLVMFunctionType(instr.Value.Type().Underlying().(*types.Signature))
2040  		b.createNilCheck(instr.Value, callee, "fpcall")
2041  	}
2042  
2043  	if !exported {
2044  		// This function takes a context parameter.
2045  		// Add it to the end of the parameter list.
2046  		params = append(params, context)
2047  	}
2048  
2049  	return b.createInvoke(calleeType, callee, params, ""), nil
2050  }
2051  
2052  // getValue returns the LLVM value of a constant, function value, global, or
2053  // already processed SSA expression.
2054  func (b *builder) getValue(expr ssa.Value, pos token.Pos) llvm.Value {
2055  	switch expr := expr.(type) {
2056  	case *ssa.Const:
2057  		if pos == token.NoPos {
2058  			// If the position isn't known, at least try to find in which file
2059  			// it is defined.
2060  			file := b.program.Fset.File(b.fn.Pos())
2061  			if file != nil {
2062  				pos = file.Pos(0)
2063  			}
2064  		}
2065  		return b.createConst(expr, pos)
2066  	case *ssa.Function:
2067  		if b.getFunctionInfo(expr).exported {
2068  			b.addError(expr.Pos(), "cannot use an exported function as value: "+expr.String())
2069  			return llvm.Undef(b.getLLVMType(expr.Type()))
2070  		}
2071  		_, fn := b.getFunction(expr)
2072  		return b.createFuncValue(fn, llvm.Undef(b.dataPtrType), expr.Signature)
2073  	case *ssa.Global:
2074  		value := b.getGlobal(expr)
2075  		if value.IsNil() {
2076  			b.addError(expr.Pos(), "global not found: "+expr.RelString(nil))
2077  			return llvm.Undef(b.getLLVMType(expr.Type()))
2078  		}
2079  		return value
2080  	default:
2081  		// other (local) SSA value
2082  		if value, ok := b.locals[expr]; ok {
2083  			return value
2084  		} else {
2085  			// indicates a compiler bug
2086  			panic("SSA value not previously found in function: " + expr.String())
2087  		}
2088  	}
2089  }
2090  
2091  // maxSliceSize determines the maximum size a slice of the given element type
2092  // can be.
2093  func (c *compilerContext) maxSliceSize(elementType llvm.Type) uint64 {
2094  	// Calculate ^uintptr(0), which is the max value that fits in uintptr.
2095  	maxPointerValue := llvm.ConstNot(llvm.ConstInt(c.uintptrType, 0, false)).ZExtValue()
2096  	// Calculate (^uint(0))/2, which is the max value that fits in an int.
2097  	maxIntegerValue := llvm.ConstNot(llvm.ConstInt(c.intType, 0, false)).ZExtValue() / 2
2098  
2099  	// Determine the maximum allowed size for a slice. The biggest possible
2100  	// pointer (starting from 0) would be maxPointerValue*sizeof(elementType) so
2101  	// divide by the element type to get the real maximum size.
2102  	elementSize := c.targetData.TypeAllocSize(elementType)
2103  	if elementSize == 0 {
2104  		elementSize = 1
2105  	}
2106  	maxSize := maxPointerValue / elementSize
2107  
2108  	// len(slice) is an int. Make sure the length remains small enough to fit in
2109  	// an int.
2110  	if maxSize > maxIntegerValue {
2111  		maxSize = maxIntegerValue
2112  	}
2113  
2114  	return maxSize
2115  }
2116  
2117  // createExpr translates a Go SSA expression to LLVM IR. This can be zero, one,
2118  // or multiple LLVM IR instructions and/or runtime calls.
2119  func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
2120  	if _, ok := b.locals[expr]; ok {
2121  		// sanity check
2122  		panic("instruction has already been created: " + expr.String())
2123  	}
2124  
2125  	switch expr := expr.(type) {
2126  	case *ssa.Alloc:
2127  		typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
2128  		size := b.targetData.TypeAllocSize(typ)
2129  		// Move all "large" allocations to the heap.
2130  		if expr.Heap || size > b.MaxStackAlloc {
2131  			// Calculate ^uintptr(0)
2132  			maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
2133  			if size > maxSize {
2134  				// Size would be truncated if truncated to uintptr.
2135  				return llvm.Value{}, b.makeError(expr.Pos(), fmt.Sprintf("value is too big (%v bytes)", size))
2136  			}
2137  			sizeValue := llvm.ConstInt(b.uintptrType, size, false)
2138  			layoutValue := b.createObjectLayout(typ, expr.Pos())
2139  			buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment)
2140  			align := b.targetData.ABITypeAlignment(typ)
2141  			buf.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
2142  			return buf, nil
2143  		} else {
2144  			buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment)
2145  			if b.targetData.TypeAllocSize(typ) != 0 {
2146  				b.CreateStore(llvm.ConstNull(typ), buf) // zero-initialize var
2147  			}
2148  			return buf, nil
2149  		}
2150  	case *ssa.BinOp:
2151  		x := b.getValue(expr.X, getPos(expr))
2152  		y := b.getValue(expr.Y, getPos(expr))
2153  		return b.createBinOp(expr.Op, expr.X.Type(), expr.Y.Type(), x, y, expr.Pos())
2154  	case *ssa.Call:
2155  		return b.createFunctionCall(expr.Common())
2156  	case *ssa.ChangeInterface:
2157  		// Do not change between interface types: always use the underlying
2158  		// (concrete) type in the type number of the interface. Every method
2159  		// call on an interface will do a lookup which method to call.
2160  		// This is different from how the official Go compiler works, because of
2161  		// heap allocation and because it's easier to implement, see:
2162  		// https://research.swtch.com/interfaces
2163  		return b.getValue(expr.X, getPos(expr)), nil
2164  	case *ssa.ChangeType:
2165  		// This instruction changes the type, but the underlying value remains
2166  		// the same. This is often a no-op, but sometimes we have to change the
2167  		// LLVM type as well.
2168  		x := b.getValue(expr.X, getPos(expr))
2169  		llvmType := b.getLLVMType(expr.Type())
2170  		if x.Type() == llvmType {
2171  			// Different Go type but same LLVM type (for example, named int).
2172  			// This is the common case.
2173  			return x, nil
2174  		}
2175  		// Figure out what kind of type we need to cast.
2176  		switch llvmType.TypeKind() {
2177  		case llvm.StructTypeKind:
2178  			// Unfortunately, we can't just bitcast structs. We have to
2179  			// actually create a new struct of the correct type and insert the
2180  			// values from the previous struct in there.
2181  			value := llvm.Undef(llvmType)
2182  			for i := 0; i < llvmType.StructElementTypesCount(); i++ {
2183  				field := b.CreateExtractValue(x, i, "changetype.field")
2184  				value = b.CreateInsertValue(value, field, i, "changetype.struct")
2185  			}
2186  			return value, nil
2187  		default:
2188  			return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String())
2189  		}
2190  	case *ssa.Const:
2191  		panic("const is not an expression")
2192  	case *ssa.Convert:
2193  		x := b.getValue(expr.X, getPos(expr))
2194  		return b.createConvert(expr.X.Type(), expr.Type(), x, expr.Pos())
2195  	case *ssa.Extract:
2196  		if _, ok := expr.Tuple.(*ssa.Select); ok {
2197  			return b.getChanSelectResult(expr), nil
2198  		}
2199  		value := b.getValue(expr.Tuple, getPos(expr))
2200  		return b.CreateExtractValue(value, expr.Index, ""), nil
2201  	case *ssa.Field:
2202  		value := b.getValue(expr.X, getPos(expr))
2203  		result := b.CreateExtractValue(value, expr.Field, "")
2204  		return result, nil
2205  	case *ssa.FieldAddr:
2206  		val := b.getValue(expr.X, getPos(expr))
2207  		// Check for nil pointer before calculating the address, from the spec:
2208  		// > For an operand x of type T, the address operation &x generates a
2209  		// > pointer of type *T to x. [...] If the evaluation of x would cause a
2210  		// > run-time panic, then the evaluation of &x does too.
2211  		b.createNilCheck(expr.X, val, "gep")
2212  		// Do a GEP on the pointer to get the field address.
2213  		indices := []llvm.Value{
2214  			llvm.ConstInt(b.ctx.Int32Type(), 0, false),
2215  			llvm.ConstInt(b.ctx.Int32Type(), uint64(expr.Field), false),
2216  		}
2217  		elementType := b.getLLVMType(expr.X.Type().Underlying().(*types.Pointer).Elem())
2218  		return b.CreateInBoundsGEP(elementType, val, indices, ""), nil
2219  	case *ssa.Function:
2220  		panic("function is not an expression")
2221  	case *ssa.Global:
2222  		panic("global is not an expression")
2223  	case *ssa.Index:
2224  		collection := b.getValue(expr.X, getPos(expr))
2225  		index := b.getValue(expr.Index, getPos(expr))
2226  
2227  		switch xType := expr.X.Type().Underlying().(type) {
2228  		case *types.Basic: // extract byte from string
2229  			// Value type must be a string, which is a basic type.
2230  			if xType.Info()&types.IsString == 0 {
2231  				panic("lookup on non-string?")
2232  			}
2233  
2234  			// Sometimes, the index can be e.g. an uint8 or int8, and we have to
2235  			// correctly extend that type for two reasons:
2236  			//  1. The lookup bounds check expects an index of at least uintptr
2237  			//     size.
2238  			//  2. getelementptr has signed operands, and therefore s[uint8(x)]
2239  			//     can be lowered as s[int8(x)]. That would be a bug.
2240  			index = b.extendInteger(index, expr.Index.Type(), b.uintptrType)
2241  
2242  			// Bounds check.
2243  			length := b.CreateExtractValue(collection, 1, "len")
2244  			b.createLookupBoundsCheck(length, index)
2245  
2246  			// Lookup byte
2247  			buf := b.CreateExtractValue(collection, 0, "")
2248  			bufElemType := b.ctx.Int8Type()
2249  			bufPtr := b.CreateInBoundsGEP(bufElemType, buf, []llvm.Value{index}, "")
2250  			return b.CreateLoad(bufElemType, bufPtr, ""), nil
2251  		case *types.Slice: // Moxie: []byte index (string=[]byte unification)
2252  			if basic, ok := xType.Elem().(*types.Basic); ok && basic.Kind() == types.Byte {
2253  				index = b.extendInteger(index, expr.Index.Type(), b.uintptrType)
2254  				length := b.CreateExtractValue(collection, 1, "len")
2255  				b.createLookupBoundsCheck(length, index)
2256  				buf := b.CreateExtractValue(collection, 0, "")
2257  				bufElemType := b.ctx.Int8Type()
2258  				bufPtr := b.CreateInBoundsGEP(bufElemType, buf, []llvm.Value{index}, "")
2259  				return b.CreateLoad(bufElemType, bufPtr, ""), nil
2260  			}
2261  			panic("unexpected slice type in *ssa.Index")
2262  		case *types.Array: // extract element from array
2263  			// Extend index to at least uintptr size, because getelementptr
2264  			// assumes index is a signed integer.
2265  			index = b.extendInteger(index, expr.Index.Type(), b.uintptrType)
2266  
2267  			// Check bounds.
2268  			arrayLen := llvm.ConstInt(b.uintptrType, uint64(xType.Len()), false)
2269  			b.createLookupBoundsCheck(arrayLen, index)
2270  
2271  			// Can't load directly from array (as index is non-constant), so
2272  			// have to do it using an alloca+gep+load.
2273  			arrayType := collection.Type()
2274  			alloca, allocaSize := b.createTemporaryAlloca(arrayType, "index.alloca")
2275  			b.CreateStore(collection, alloca)
2276  			zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
2277  			ptr := b.CreateInBoundsGEP(arrayType, alloca, []llvm.Value{zero, index}, "index.gep")
2278  			result := b.CreateLoad(arrayType.ElementType(), ptr, "index.load")
2279  			b.emitLifetimeEnd(alloca, allocaSize)
2280  			return result, nil
2281  		default:
2282  			panic("unknown *ssa.Index type")
2283  		}
2284  	case *ssa.IndexAddr:
2285  		val := b.getValue(expr.X, getPos(expr))
2286  		index := b.getValue(expr.Index, getPos(expr))
2287  
2288  		// Get buffer pointer and length
2289  		var bufptr, buflen llvm.Value
2290  		var bufType llvm.Type
2291  		switch ptrTyp := expr.X.Type().Underlying().(type) {
2292  		case *types.Pointer:
2293  			typ := ptrTyp.Elem().Underlying()
2294  			switch typ := typ.(type) {
2295  			case *types.Array:
2296  				bufptr = val
2297  				buflen = llvm.ConstInt(b.uintptrType, uint64(typ.Len()), false)
2298  				bufType = b.getLLVMType(typ)
2299  				// Check for nil pointer before calculating the address, from
2300  				// the spec:
2301  				// > For an operand x of type T, the address operation &x
2302  				// > generates a pointer of type *T to x. [...] If the
2303  				// > evaluation of x would cause a run-time panic, then the
2304  				// > evaluation of &x does too.
2305  				b.createNilCheck(expr.X, bufptr, "gep")
2306  			default:
2307  				return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+typ.String())
2308  			}
2309  		case *types.Slice:
2310  			bufptr = b.CreateExtractValue(val, 0, "indexaddr.ptr")
2311  			buflen = b.CreateExtractValue(val, 1, "indexaddr.len")
2312  			bufType = b.getLLVMType(ptrTyp.Elem())
2313  		case *types.Basic: // Moxie: string=[]byte, addressable indexing
2314  			bufptr = b.CreateExtractValue(val, 0, "indexaddr.ptr")
2315  			buflen = b.CreateExtractValue(val, 1, "indexaddr.len")
2316  			bufType = b.ctx.Int8Type()
2317  		default:
2318  			return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+ptrTyp.String())
2319  		}
2320  
2321  		// Make sure index is at least the size of uintptr because getelementptr
2322  		// assumes index is a signed integer.
2323  		index = b.extendInteger(index, expr.Index.Type(), b.uintptrType)
2324  
2325  		// Bounds check.
2326  		b.createLookupBoundsCheck(buflen, index)
2327  
2328  		switch expr.X.Type().Underlying().(type) {
2329  		case *types.Pointer:
2330  			indices := []llvm.Value{
2331  				llvm.ConstInt(b.ctx.Int32Type(), 0, false),
2332  				index,
2333  			}
2334  			return b.CreateInBoundsGEP(bufType, bufptr, indices, ""), nil
2335  		case *types.Slice:
2336  			return b.CreateInBoundsGEP(bufType, bufptr, []llvm.Value{index}, ""), nil
2337  		case *types.Basic: // Moxie: string=[]byte, addressable
2338  			return b.CreateInBoundsGEP(bufType, bufptr, []llvm.Value{index}, ""), nil
2339  		default:
2340  			panic("unreachable")
2341  		}
2342  	case *ssa.Lookup: // map lookup
2343  		value := b.getValue(expr.X, getPos(expr))
2344  		index := b.getValue(expr.Index, getPos(expr))
2345  		valueType := expr.Type()
2346  		if expr.CommaOk {
2347  			valueType = valueType.(*types.Tuple).At(0).Type()
2348  		}
2349  		return b.createMapLookup(expr.X.Type().Underlying().(*types.Map).Key(), valueType, value, index, expr.CommaOk, expr.Pos())
2350  	case *ssa.MakeChan:
2351  		return b.createMakeChan(expr), nil
2352  	case *ssa.MakeClosure:
2353  		return b.parseMakeClosure(expr)
2354  	case *ssa.MakeInterface:
2355  		val := b.getValue(expr.X, getPos(expr))
2356  		return b.createMakeInterface(val, expr.X.Type(), expr.Pos()), nil
2357  	case *ssa.MakeMap:
2358  		return b.createMakeMap(expr)
2359  	case *ssa.MakeSlice:
2360  		sliceLen := b.getValue(expr.Len, getPos(expr))
2361  		sliceCap := b.getValue(expr.Cap, getPos(expr))
2362  		sliceType := expr.Type().Underlying().(*types.Slice)
2363  		llvmElemType := b.getLLVMType(sliceType.Elem())
2364  		elemSize := b.targetData.TypeAllocSize(llvmElemType)
2365  		elemAlign := b.targetData.ABITypeAlignment(llvmElemType)
2366  		elemSizeValue := llvm.ConstInt(b.uintptrType, elemSize, false)
2367  
2368  		maxSize := b.maxSliceSize(llvmElemType)
2369  		if elemSize > maxSize {
2370  			// This seems to be checked by the typechecker already, but let's
2371  			// check it again just to be sure.
2372  			return llvm.Value{}, b.makeError(expr.Pos(), fmt.Sprintf("slice element type is too big (%v bytes)", elemSize))
2373  		}
2374  
2375  		// Bounds checking.
2376  		lenType := expr.Len.Type().Underlying().(*types.Basic)
2377  		capType := expr.Cap.Type().Underlying().(*types.Basic)
2378  		maxSizeValue := llvm.ConstInt(b.uintptrType, maxSize, false)
2379  		b.createSliceBoundsCheck(maxSizeValue, sliceLen, sliceCap, sliceCap, lenType, capType, capType)
2380  
2381  		// Allocate the backing array.
2382  		sliceCapCast, err := b.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
2383  		if err != nil {
2384  			return llvm.Value{}, err
2385  		}
2386  		sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
2387  		layoutValue := b.createObjectLayout(llvmElemType, expr.Pos())
2388  		slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize, layoutValue}, "makeslice.buf")
2389  		slicePtr.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elemAlign)))
2390  
2391  		// Extend or truncate if necessary. This is safe as we've already done
2392  		// the bounds check.
2393  		sliceLen, err = b.createConvert(expr.Len.Type(), types.Typ[types.Uintptr], sliceLen, expr.Pos())
2394  		if err != nil {
2395  			return llvm.Value{}, err
2396  		}
2397  		sliceCap, err = b.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
2398  		if err != nil {
2399  			return llvm.Value{}, err
2400  		}
2401  
2402  		// Create the slice.
2403  		// Moxie: use getLLVMType to get named type for []byte.
2404  		slice := llvm.Undef(b.getLLVMType(sliceType))
2405  		slice = b.CreateInsertValue(slice, slicePtr, 0, "")
2406  		slice = b.CreateInsertValue(slice, sliceLen, 1, "")
2407  		slice = b.CreateInsertValue(slice, sliceCap, 2, "")
2408  		return slice, nil
2409  	case *ssa.Next:
2410  		rangeVal := expr.Iter.(*ssa.Range).X
2411  		llvmRangeVal := b.getValue(rangeVal, getPos(expr))
2412  		it := b.getValue(expr.Iter, getPos(expr))
2413  		if expr.IsString {
2414  			return b.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
2415  		} else { // map
2416  			return b.createMapIteratorNext(rangeVal, llvmRangeVal, it), nil
2417  		}
2418  	case *ssa.Phi:
2419  		phi := b.CreatePHI(b.getLLVMType(expr.Type()), "")
2420  		b.phis = append(b.phis, phiNode{expr, phi})
2421  		return phi, nil
2422  	case *ssa.Range:
2423  		var iteratorType llvm.Type
2424  		switch typ := expr.X.Type().Underlying().(type) {
2425  		case *types.Basic: // string range (yields runes via UTF-8 decode)
2426  			iteratorType = b.getLLVMRuntimeType("stringIterator")
2427  		case *types.Map:
2428  			iteratorType = b.getLLVMRuntimeType("hashmapIterator")
2429  		default:
2430  			panic("unknown type in range: " + typ.String())
2431  		}
2432  		it, _ := b.createTemporaryAlloca(iteratorType, "range.it")
2433  		b.CreateStore(llvm.ConstNull(iteratorType), it)
2434  		return it, nil
2435  	case *ssa.Select:
2436  		return b.createSelect(expr), nil
2437  	case *ssa.Slice:
2438  		value := b.getValue(expr.X, getPos(expr))
2439  
2440  		var lowType, highType, maxType *types.Basic
2441  		var low, high, max llvm.Value
2442  
2443  		if expr.Low != nil {
2444  			lowType = expr.Low.Type().Underlying().(*types.Basic)
2445  			low = b.getValue(expr.Low, getPos(expr))
2446  			low = b.extendInteger(low, lowType, b.uintptrType)
2447  		} else {
2448  			lowType = types.Typ[types.Uintptr]
2449  			low = llvm.ConstInt(b.uintptrType, 0, false)
2450  		}
2451  
2452  		if expr.High != nil {
2453  			highType = expr.High.Type().Underlying().(*types.Basic)
2454  			high = b.getValue(expr.High, getPos(expr))
2455  			high = b.extendInteger(high, highType, b.uintptrType)
2456  		} else {
2457  			highType = types.Typ[types.Uintptr]
2458  		}
2459  
2460  		if expr.Max != nil {
2461  			maxType = expr.Max.Type().Underlying().(*types.Basic)
2462  			max = b.getValue(expr.Max, getPos(expr))
2463  			max = b.extendInteger(max, maxType, b.uintptrType)
2464  		} else {
2465  			maxType = types.Typ[types.Uintptr]
2466  		}
2467  
2468  		switch typ := expr.X.Type().Underlying().(type) {
2469  		case *types.Pointer: // pointer to array
2470  			// slice an array
2471  			arrayType := typ.Elem().Underlying().(*types.Array)
2472  			length := arrayType.Len()
2473  			llvmLen := llvm.ConstInt(b.uintptrType, uint64(length), false)
2474  			if high.IsNil() {
2475  				high = llvmLen
2476  			}
2477  			if max.IsNil() {
2478  				max = llvmLen
2479  			}
2480  			indices := []llvm.Value{
2481  				llvm.ConstInt(b.ctx.Int32Type(), 0, false),
2482  				low,
2483  			}
2484  
2485  			b.createNilCheck(expr.X, value, "slice")
2486  			b.createSliceBoundsCheck(llvmLen, low, high, max, lowType, highType, maxType)
2487  
2488  			// Truncate ints bigger than uintptr. This is after the bounds
2489  			// check so it's safe.
2490  			if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
2491  				low = b.CreateTrunc(low, b.uintptrType, "")
2492  			}
2493  			if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
2494  				high = b.CreateTrunc(high, b.uintptrType, "")
2495  			}
2496  			if b.targetData.TypeAllocSize(max.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
2497  				max = b.CreateTrunc(max, b.uintptrType, "")
2498  			}
2499  
2500  			sliceLen := b.CreateSub(high, low, "slice.len")
2501  			slicePtr := b.CreateInBoundsGEP(b.getLLVMType(arrayType), value, indices, "slice.ptr")
2502  			sliceCap := b.CreateSub(max, low, "slice.cap")
2503  
2504  			// Moxie: use getLLVMType for correct named type on []byte.
2505  			slice := llvm.Undef(b.getLLVMType(expr.Type()))
2506  			slice = b.CreateInsertValue(slice, slicePtr, 0, "")
2507  			slice = b.CreateInsertValue(slice, sliceLen, 1, "")
2508  			slice = b.CreateInsertValue(slice, sliceCap, 2, "")
2509  			return slice, nil
2510  
2511  		case *types.Slice:
2512  			// slice a slice
2513  			oldPtr := b.CreateExtractValue(value, 0, "")
2514  			oldLen := b.CreateExtractValue(value, 1, "")
2515  			oldCap := b.CreateExtractValue(value, 2, "")
2516  			if high.IsNil() {
2517  				high = oldLen
2518  			}
2519  			if max.IsNil() {
2520  				max = oldCap
2521  			}
2522  
2523  			b.createSliceBoundsCheck(oldCap, low, high, max, lowType, highType, maxType)
2524  
2525  			// Truncate ints bigger than uintptr. This is after the bounds
2526  			// check so it's safe.
2527  			if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
2528  				low = b.CreateTrunc(low, b.uintptrType, "")
2529  			}
2530  			if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
2531  				high = b.CreateTrunc(high, b.uintptrType, "")
2532  			}
2533  			if b.targetData.TypeAllocSize(max.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
2534  				max = b.CreateTrunc(max, b.uintptrType, "")
2535  			}
2536  
2537  			ptrElemType := b.getLLVMType(typ.Elem())
2538  			newPtr := b.CreateInBoundsGEP(ptrElemType, oldPtr, []llvm.Value{low}, "")
2539  			newLen := b.CreateSub(high, low, "")
2540  			newCap := b.CreateSub(max, low, "")
2541  			// Moxie: use getLLVMType to get the correct type (named for []byte).
2542  			slice := llvm.Undef(b.getLLVMType(typ))
2543  			slice = b.CreateInsertValue(slice, newPtr, 0, "")
2544  			slice = b.CreateInsertValue(slice, newLen, 1, "")
2545  			slice = b.CreateInsertValue(slice, newCap, 2, "")
2546  			return slice, nil
2547  
2548  		case *types.Basic:
2549  			if typ.Info()&types.IsString == 0 {
2550  				return llvm.Value{}, b.makeError(expr.Pos(), "unknown slice type: "+typ.String())
2551  			}
2552  			// slice a string
2553  			if expr.Max != nil {
2554  				// This might as well be a panic, as the frontend should have
2555  				// handled this already.
2556  				return llvm.Value{}, b.makeError(expr.Pos(), "slicing a string with a max parameter is not allowed by the spec")
2557  			}
2558  			oldPtr := b.CreateExtractValue(value, 0, "")
2559  			oldLen := b.CreateExtractValue(value, 1, "")
2560  			if high.IsNil() {
2561  				high = oldLen
2562  			}
2563  
2564  			b.createSliceBoundsCheck(oldLen, low, high, high, lowType, highType, maxType)
2565  
2566  			// Truncate ints bigger than uintptr. This is after the bounds
2567  			// check so it's safe.
2568  			if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
2569  				low = b.CreateTrunc(low, b.uintptrType, "")
2570  			}
2571  			if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
2572  				high = b.CreateTrunc(high, b.uintptrType, "")
2573  			}
2574  
2575  			newPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), oldPtr, []llvm.Value{low}, "")
2576  			newLen := b.CreateSub(high, low, "")
2577  			str := llvm.Undef(b.getLLVMRuntimeType("_string"))
2578  			str = b.CreateInsertValue(str, newPtr, 0, "")
2579  			str = b.CreateInsertValue(str, newLen, 1, "")
2580  			str = b.CreateInsertValue(str, newLen, 2, "") // cap = len for string slices
2581  			return str, nil
2582  
2583  		default:
2584  			return llvm.Value{}, b.makeError(expr.Pos(), "unknown slice type: "+typ.String())
2585  		}
2586  	case *ssa.SliceToArrayPointer:
2587  		// Conversion from a slice to an array pointer, as the name clearly
2588  		// says. This requires a runtime check to make sure the slice is at
2589  		// least as big as the array.
2590  		slice := b.getValue(expr.X, getPos(expr))
2591  		sliceLen := b.CreateExtractValue(slice, 1, "")
2592  		arrayLen := expr.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len()
2593  		b.createSliceToArrayPointerCheck(sliceLen, arrayLen)
2594  		ptr := b.CreateExtractValue(slice, 0, "")
2595  		return ptr, nil
2596  	case *ssa.TypeAssert:
2597  		return b.createTypeAssert(expr), nil
2598  	case *ssa.UnOp:
2599  		return b.createUnOp(expr)
2600  	default:
2601  		return llvm.Value{}, b.makeError(expr.Pos(), "todo: unknown expression: "+expr.String())
2602  	}
2603  }
2604  
2605  // createBinOp creates a LLVM binary operation (add, sub, mul, etc) for a Go
2606  // binary operation. This is almost a direct mapping, but there are some subtle
2607  // differences such as the requirement in LLVM IR that both sides must have the
2608  // same type, even for bitshifts. Also, signedness in Go is encoded in the type
2609  // and is encoded in the operation in LLVM IR: this is important for some
2610  // operations such as divide.
2611  func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Value, pos token.Pos) (llvm.Value, error) {
2612  	switch typ := typ.Underlying().(type) {
2613  	case *types.Basic:
2614  		if typ.Info()&types.IsInteger != 0 {
2615  			// Operations on integers
2616  			signed := typ.Info()&types.IsUnsigned == 0
2617  			switch op {
2618  			case token.ADD: // +
2619  				return b.CreateAdd(x, y, ""), nil
2620  			case token.SUB: // -
2621  				return b.CreateSub(x, y, ""), nil
2622  			case token.MUL: // *
2623  				return b.CreateMul(x, y, ""), nil
2624  			case token.QUO, token.REM: // /, %
2625  				// Check for a divide by zero. If y is zero, the Go
2626  				// specification says that a runtime error must be triggered.
2627  				b.createDivideByZeroCheck(y)
2628  
2629  				if signed {
2630  					// Deal with signed division overflow.
2631  					// The LLVM LangRef says:
2632  					//
2633  					//   Overflow also leads to undefined behavior; this is a
2634  					//   rare case, but can occur, for example, by doing a
2635  					//   32-bit division of -2147483648 by -1.
2636  					//
2637  					// The Go specification however says this about division:
2638  					//
2639  					//   The one exception to this rule is that if the dividend
2640  					//   x is the most negative value for the int type of x, the
2641  					//   quotient q = x / -1 is equal to x (and r = 0) due to
2642  					//   two's-complement integer overflow.
2643  					//
2644  					// In other words, in the special case that the lowest
2645  					// possible signed integer is divided by -1, the result of
2646  					// the division is the same as x (the dividend).
2647  					// This is implemented by checking for this condition and
2648  					// changing y to 1 if it occurs, for example for 32-bit
2649  					// ints:
2650  					//
2651  					//   if x == -2147483648 && y == -1 {
2652  					//       y = 1
2653  					//   }
2654  					//
2655  					// Dividing x by 1 obviously returns x, therefore satisfying
2656  					// the Go specification without a branch.
2657  					llvmType := x.Type()
2658  					minusOne := llvm.ConstSub(llvm.ConstInt(llvmType, 0, false), llvm.ConstInt(llvmType, 1, false))
2659  					lowestInteger := llvm.ConstInt(x.Type(), 1<<(llvmType.IntTypeWidth()-1), false)
2660  					yIsMinusOne := b.CreateICmp(llvm.IntEQ, y, minusOne, "")
2661  					xIsLowestInteger := b.CreateICmp(llvm.IntEQ, x, lowestInteger, "")
2662  					hasOverflow := b.CreateAnd(yIsMinusOne, xIsLowestInteger, "")
2663  					y = b.CreateSelect(hasOverflow, llvm.ConstInt(llvmType, 1, true), y, "")
2664  
2665  					if op == token.QUO {
2666  						return b.CreateSDiv(x, y, ""), nil
2667  					} else {
2668  						return b.CreateSRem(x, y, ""), nil
2669  					}
2670  				} else {
2671  					if op == token.QUO {
2672  						return b.CreateUDiv(x, y, ""), nil
2673  					} else {
2674  						return b.CreateURem(x, y, ""), nil
2675  					}
2676  				}
2677  			case token.AND: // &
2678  				return b.CreateAnd(x, y, ""), nil
2679  			case token.OR: // |
2680  				return b.CreateOr(x, y, ""), nil
2681  			case token.XOR: // ^
2682  				return b.CreateXor(x, y, ""), nil
2683  			case token.SHL, token.SHR:
2684  				if ytyp.Underlying().(*types.Basic).Info()&types.IsUnsigned == 0 {
2685  					// Ensure that y is not negative.
2686  					b.createNegativeShiftCheck(y)
2687  				}
2688  
2689  				sizeX := b.targetData.TypeAllocSize(x.Type())
2690  				sizeY := b.targetData.TypeAllocSize(y.Type())
2691  
2692  				// Check if the shift is bigger than the bit-width of the shifted value.
2693  				// This is UB in LLVM, so it needs to be handled separately.
2694  				// The Go spec indirectly defines the result as 0.
2695  				// Negative shifts are handled earlier, so we can treat y as unsigned.
2696  				overshifted := b.CreateICmp(llvm.IntUGE, y, llvm.ConstInt(y.Type(), 8*sizeX, false), "shift.overflow")
2697  
2698  				// Adjust the size of y to match x.
2699  				switch {
2700  				case sizeX > sizeY:
2701  					y = b.CreateZExt(y, x.Type(), "")
2702  				case sizeX < sizeY:
2703  					// If it gets truncated, overshifted will be true and it will not matter.
2704  					y = b.CreateTrunc(y, x.Type(), "")
2705  				}
2706  
2707  				// Create a shift operation.
2708  				var val llvm.Value
2709  				switch op {
2710  				case token.SHL: // <<
2711  					val = b.CreateShl(x, y, "")
2712  				case token.SHR: // >>
2713  					if signed {
2714  						// Arithmetic right shifts work differently, since shifting a negative number right yields -1.
2715  						// Cap the shift input rather than selecting the output.
2716  						y = b.CreateSelect(overshifted, llvm.ConstInt(y.Type(), 8*sizeX-1, false), y, "shift.offset")
2717  						return b.CreateAShr(x, y, ""), nil
2718  					} else {
2719  						val = b.CreateLShr(x, y, "")
2720  					}
2721  				default:
2722  					panic("unreachable")
2723  				}
2724  
2725  				// Select between the shift result and zero depending on whether there was an overshift.
2726  				return b.CreateSelect(overshifted, llvm.ConstInt(val.Type(), 0, false), val, "shift.result"), nil
2727  			case token.EQL: // ==
2728  				return b.CreateICmp(llvm.IntEQ, x, y, ""), nil
2729  			case token.NEQ: // !=
2730  				return b.CreateICmp(llvm.IntNE, x, y, ""), nil
2731  			case token.AND_NOT: // &^
2732  				// Go specific. Calculate "and not" with x & (~y)
2733  				inv := b.CreateNot(y, "") // ~y
2734  				return b.CreateAnd(x, inv, ""), nil
2735  			case token.LSS: // <
2736  				if signed {
2737  					return b.CreateICmp(llvm.IntSLT, x, y, ""), nil
2738  				} else {
2739  					return b.CreateICmp(llvm.IntULT, x, y, ""), nil
2740  				}
2741  			case token.LEQ: // <=
2742  				if signed {
2743  					return b.CreateICmp(llvm.IntSLE, x, y, ""), nil
2744  				} else {
2745  					return b.CreateICmp(llvm.IntULE, x, y, ""), nil
2746  				}
2747  			case token.GTR: // >
2748  				if signed {
2749  					return b.CreateICmp(llvm.IntSGT, x, y, ""), nil
2750  				} else {
2751  					return b.CreateICmp(llvm.IntUGT, x, y, ""), nil
2752  				}
2753  			case token.GEQ: // >=
2754  				if signed {
2755  					return b.CreateICmp(llvm.IntSGE, x, y, ""), nil
2756  				} else {
2757  					return b.CreateICmp(llvm.IntUGE, x, y, ""), nil
2758  				}
2759  			default:
2760  				panic("binop on integer: " + op.String())
2761  			}
2762  		} else if typ.Info()&types.IsFloat != 0 {
2763  			// Operations on floats
2764  			switch op {
2765  			case token.ADD: // +
2766  				return b.CreateFAdd(x, y, ""), nil
2767  			case token.SUB: // -
2768  				return b.CreateFSub(x, y, ""), nil
2769  			case token.MUL: // *
2770  				return b.CreateFMul(x, y, ""), nil
2771  			case token.QUO: // /
2772  				return b.CreateFDiv(x, y, ""), nil
2773  			case token.EQL: // ==
2774  				return b.CreateFCmp(llvm.FloatOEQ, x, y, ""), nil
2775  			case token.NEQ: // !=
2776  				return b.CreateFCmp(llvm.FloatUNE, x, y, ""), nil
2777  			case token.LSS: // <
2778  				return b.CreateFCmp(llvm.FloatOLT, x, y, ""), nil
2779  			case token.LEQ: // <=
2780  				return b.CreateFCmp(llvm.FloatOLE, x, y, ""), nil
2781  			case token.GTR: // >
2782  				return b.CreateFCmp(llvm.FloatOGT, x, y, ""), nil
2783  			case token.GEQ: // >=
2784  				return b.CreateFCmp(llvm.FloatOGE, x, y, ""), nil
2785  			default:
2786  				panic("binop on float: " + op.String())
2787  			}
2788  		} else if typ.Info()&types.IsComplex != 0 {
2789  			r1 := b.CreateExtractValue(x, 0, "r1")
2790  			r2 := b.CreateExtractValue(y, 0, "r2")
2791  			i1 := b.CreateExtractValue(x, 1, "i1")
2792  			i2 := b.CreateExtractValue(y, 1, "i2")
2793  			switch op {
2794  			case token.EQL: // ==
2795  				req := b.CreateFCmp(llvm.FloatOEQ, r1, r2, "")
2796  				ieq := b.CreateFCmp(llvm.FloatOEQ, i1, i2, "")
2797  				return b.CreateAnd(req, ieq, ""), nil
2798  			case token.NEQ: // !=
2799  				req := b.CreateFCmp(llvm.FloatOEQ, r1, r2, "")
2800  				ieq := b.CreateFCmp(llvm.FloatOEQ, i1, i2, "")
2801  				neq := b.CreateAnd(req, ieq, "")
2802  				return b.CreateNot(neq, ""), nil
2803  			case token.ADD, token.SUB:
2804  				var r, i llvm.Value
2805  				switch op {
2806  				case token.ADD:
2807  					r = b.CreateFAdd(r1, r2, "")
2808  					i = b.CreateFAdd(i1, i2, "")
2809  				case token.SUB:
2810  					r = b.CreateFSub(r1, r2, "")
2811  					i = b.CreateFSub(i1, i2, "")
2812  				default:
2813  					panic("unreachable")
2814  				}
2815  				cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{r.Type(), i.Type()}, false))
2816  				cplx = b.CreateInsertValue(cplx, r, 0, "")
2817  				cplx = b.CreateInsertValue(cplx, i, 1, "")
2818  				return cplx, nil
2819  			case token.MUL:
2820  				// Complex multiplication follows the current implementation in
2821  				// the Go compiler, with the difference that complex64
2822  				// components are not first scaled up to float64 for increased
2823  				// precision.
2824  				// https://github.com/golang/go/blob/170b8b4b12be50eeccbcdadb8523fb4fc670ca72/src/cmd/compile/internal/gc/ssa.go#L2089-L2127
2825  				// The implementation is as follows:
2826  				//   r := real(a) * real(b) - imag(a) * imag(b)
2827  				//   i := real(a) * imag(b) + imag(a) * real(b)
2828  				// Note: this does NOT follow the C11 specification (annex G):
2829  				// http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf#page=549
2830  				// See https://github.com/golang/go/issues/29846 for a related
2831  				// discussion.
2832  				r := b.CreateFSub(b.CreateFMul(r1, r2, ""), b.CreateFMul(i1, i2, ""), "")
2833  				i := b.CreateFAdd(b.CreateFMul(r1, i2, ""), b.CreateFMul(i1, r2, ""), "")
2834  				cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{r.Type(), i.Type()}, false))
2835  				cplx = b.CreateInsertValue(cplx, r, 0, "")
2836  				cplx = b.CreateInsertValue(cplx, i, 1, "")
2837  				return cplx, nil
2838  			case token.QUO:
2839  				// Complex division.
2840  				// Do this in a library call because it's too difficult to do
2841  				// inline.
2842  				switch r1.Type().TypeKind() {
2843  				case llvm.FloatTypeKind:
2844  					return b.createRuntimeCall("complex64div", []llvm.Value{x, y}, ""), nil
2845  				case llvm.DoubleTypeKind:
2846  					return b.createRuntimeCall("complex128div", []llvm.Value{x, y}, ""), nil
2847  				default:
2848  					panic("unexpected complex type")
2849  				}
2850  			default:
2851  				panic("binop on complex: " + op.String())
2852  			}
2853  		} else if typ.Info()&types.IsBoolean != 0 {
2854  			// Operations on booleans
2855  			switch op {
2856  			case token.EQL: // ==
2857  				return b.CreateICmp(llvm.IntEQ, x, y, ""), nil
2858  			case token.NEQ: // !=
2859  				return b.CreateICmp(llvm.IntNE, x, y, ""), nil
2860  			default:
2861  				panic("binop on bool: " + op.String())
2862  			}
2863  		} else if typ.Kind() == types.UnsafePointer {
2864  			// Operations on pointers
2865  			switch op {
2866  			case token.EQL: // ==
2867  				return b.CreateICmp(llvm.IntEQ, x, y, ""), nil
2868  			case token.NEQ: // !=
2869  				return b.CreateICmp(llvm.IntNE, x, y, ""), nil
2870  			default:
2871  				panic("binop on pointer: " + op.String())
2872  			}
2873  		} else if typ.Info()&types.IsString != 0 {
2874  			// Operations on strings
2875  			switch op {
2876  			case token.ADD: // +
2877  				return b.createRuntimeCall("stringConcat", []llvm.Value{x, y}, ""), nil
2878  			case token.EQL: // ==
2879  				return b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, ""), nil
2880  			case token.NEQ: // !=
2881  				result := b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, "")
2882  				return b.CreateNot(result, ""), nil
2883  			case token.LSS: // x < y
2884  				return b.createRuntimeCall("stringLess", []llvm.Value{x, y}, ""), nil
2885  			case token.LEQ: // x <= y becomes NOT (y < x)
2886  				result := b.createRuntimeCall("stringLess", []llvm.Value{y, x}, "")
2887  				return b.CreateNot(result, ""), nil
2888  			case token.GTR: // x > y becomes y < x
2889  				return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil
2890  			case token.GEQ: // x >= y becomes NOT (x < y)
2891  				result := b.createRuntimeCall("stringLess", []llvm.Value{x, y}, "")
2892  				return b.CreateNot(result, ""), nil
2893  			default:
2894  				panic("binop on string: " + op.String())
2895  			}
2896  		} else {
2897  			return llvm.Value{}, b.makeError(pos, "todo: unknown basic type in binop: "+typ.String())
2898  		}
2899  	case *types.Signature:
2900  		// Get raw scalars from the function value and compare those.
2901  		// Function values may be implemented in multiple ways, but they all
2902  		// have some way of getting a scalar value identifying the function.
2903  		// This is safe: function pointers are generally not comparable
2904  		// against each other, only against nil. So one of these has to be nil.
2905  		x = b.extractFuncScalar(x)
2906  		y = b.extractFuncScalar(y)
2907  		switch op {
2908  		case token.EQL: // ==
2909  			return b.CreateICmp(llvm.IntEQ, x, y, ""), nil
2910  		case token.NEQ: // !=
2911  			return b.CreateICmp(llvm.IntNE, x, y, ""), nil
2912  		default:
2913  			return llvm.Value{}, b.makeError(pos, "binop on signature: "+op.String())
2914  		}
2915  	case *types.Interface:
2916  		switch op {
2917  		case token.EQL, token.NEQ: // ==, !=
2918  			nilInterface := llvm.ConstNull(x.Type())
2919  			var result llvm.Value
2920  			if x == nilInterface || y == nilInterface {
2921  				// An interface value is compared against nil.
2922  				// This is a very common case and is easy to optimize: simply
2923  				// compare the typecodes (of which one is nil).
2924  				typecodeX := b.CreateExtractValue(x, 0, "")
2925  				typecodeY := b.CreateExtractValue(y, 0, "")
2926  				result = b.CreateICmp(llvm.IntEQ, typecodeX, typecodeY, "")
2927  			} else {
2928  				// Fall back to a full interface comparison.
2929  				result = b.createRuntimeCall("interfaceEqual", []llvm.Value{x, y}, "")
2930  			}
2931  			if op == token.NEQ {
2932  				result = b.CreateNot(result, "")
2933  			}
2934  			return result, nil
2935  		default:
2936  			return llvm.Value{}, b.makeError(pos, "binop on interface: "+op.String())
2937  		}
2938  	case *types.Chan, *types.Map, *types.Pointer:
2939  		// Maps are in general not comparable, but can be compared against nil
2940  		// (which is a nil pointer). This means they can be trivially compared
2941  		// by treating them as a pointer.
2942  		// Channels behave as pointers in that they are equal as long as they
2943  		// are created with the same call to make or if both are nil.
2944  		switch op {
2945  		case token.EQL: // ==
2946  			return b.CreateICmp(llvm.IntEQ, x, y, ""), nil
2947  		case token.NEQ: // !=
2948  			return b.CreateICmp(llvm.IntNE, x, y, ""), nil
2949  		default:
2950  			return llvm.Value{}, b.makeError(pos, "todo: binop on pointer: "+op.String())
2951  		}
2952  	case *types.Slice:
2953  		// Moxie: []byte is the text type (replaces string) and supports
2954  		// full comparison (==, !=, <, <=, >, >=) via runtime string functions.
2955  		// Other slice types only support nil comparison.
2956  		if basic, ok := typ.Elem().(*types.Basic); ok && basic.Kind() == types.Byte {
2957  			switch op {
2958  			case token.ADD: // Moxie: []byte + []byte (exempt packages use + on text)
2959  				return b.createRuntimeCall("stringConcat", []llvm.Value{x, y}, ""), nil
2960  			case token.EQL:
2961  				return b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, ""), nil
2962  			case token.NEQ:
2963  				result := b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, "")
2964  				return b.CreateNot(result, ""), nil
2965  			case token.LSS:
2966  				return b.createRuntimeCall("stringLess", []llvm.Value{x, y}, ""), nil
2967  			case token.LEQ:
2968  				result := b.createRuntimeCall("stringLess", []llvm.Value{y, x}, "")
2969  				return b.CreateNot(result, ""), nil
2970  			case token.GTR:
2971  				return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil
2972  			case token.GEQ:
2973  				result := b.createRuntimeCall("stringLess", []llvm.Value{x, y}, "")
2974  				return b.CreateNot(result, ""), nil
2975  			default:
2976  				return llvm.Value{}, b.makeError(pos, "todo: binop on []byte: "+op.String())
2977  			}
2978  		}
2979  		// Moxie: | on any slice type is concatenation.
2980  		// Uses sliceAppend with cap=len to force fresh allocation.
2981  		if op == token.OR {
2982  			xPtr := b.CreateExtractValue(x, 0, "concat.xPtr")
2983  			xLen := b.CreateExtractValue(x, 1, "concat.xLen")
2984  			yPtr := b.CreateExtractValue(y, 0, "concat.yPtr")
2985  			yLen := b.CreateExtractValue(y, 1, "concat.yLen")
2986  			elemType := b.getLLVMType(typ.Elem())
2987  			elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
2988  			result := b.createRuntimeCall("sliceAppend", []llvm.Value{xPtr, yPtr, xLen, xLen, yLen, elemSize}, "concat.new")
2989  			newPtr := b.CreateExtractValue(result, 0, "concat.ptr")
2990  			newLen := b.CreateExtractValue(result, 1, "concat.len")
2991  			newCap := b.CreateExtractValue(result, 2, "concat.cap")
2992  			newSlice := llvm.Undef(x.Type())
2993  			newSlice = b.CreateInsertValue(newSlice, newPtr, 0, "")
2994  			newSlice = b.CreateInsertValue(newSlice, newLen, 1, "")
2995  			newSlice = b.CreateInsertValue(newSlice, newCap, 2, "")
2996  			return newSlice, nil
2997  		}
2998  		// Moxie: slices of comparable types support == and !=.
2999  		// Compare lengths first, then data byte-by-byte via runtime.
3000  		if op != token.EQL && op != token.NEQ {
3001  			return llvm.Value{}, b.makeError(pos, "todo: binop on slice: "+op.String())
3002  		}
3003  		xPtr := b.CreateExtractValue(x, 0, "")
3004  		xLen := b.CreateExtractValue(x, 1, "")
3005  		yPtr := b.CreateExtractValue(y, 0, "")
3006  		yLen := b.CreateExtractValue(y, 1, "")
3007  		elemSize := b.targetData.TypeAllocSize(b.getLLVMType(typ.Elem()))
3008  		elemSizeVal := llvm.ConstInt(b.uintptrType, elemSize, false)
3009  		result := b.createRuntimeCall("sliceEqual", []llvm.Value{xPtr, yPtr, xLen, yLen, elemSizeVal}, "")
3010  		switch op {
3011  		case token.EQL:
3012  			return result, nil
3013  		case token.NEQ:
3014  			return b.CreateNot(result, ""), nil
3015  		default:
3016  			panic("unreachable")
3017  		}
3018  	case *types.Array:
3019  		// Compare each array element and combine the result. From the spec:
3020  		//     Array values are comparable if values of the array element type
3021  		//     are comparable. Two array values are equal if their corresponding
3022  		//     elements are equal.
3023  		result := llvm.ConstInt(b.ctx.Int1Type(), 1, true)
3024  		for i := 0; i < int(typ.Len()); i++ {
3025  			xField := b.CreateExtractValue(x, i, "")
3026  			yField := b.CreateExtractValue(y, i, "")
3027  			fieldEqual, err := b.createBinOp(token.EQL, typ.Elem(), typ.Elem(), xField, yField, pos)
3028  			if err != nil {
3029  				return llvm.Value{}, err
3030  			}
3031  			result = b.CreateAnd(result, fieldEqual, "")
3032  		}
3033  		switch op {
3034  		case token.EQL: // ==
3035  			return result, nil
3036  		case token.NEQ: // !=
3037  			return b.CreateNot(result, ""), nil
3038  		default:
3039  			return llvm.Value{}, b.makeError(pos, "unknown: binop on struct: "+op.String())
3040  		}
3041  	case *types.Struct:
3042  		// Compare each struct field and combine the result. From the spec:
3043  		//     Struct values are comparable if all their fields are comparable.
3044  		//     Two struct values are equal if their corresponding non-blank
3045  		//     fields are equal.
3046  		result := llvm.ConstInt(b.ctx.Int1Type(), 1, true)
3047  		for i := 0; i < typ.NumFields(); i++ {
3048  			if typ.Field(i).Name() == "_" {
3049  				// skip blank fields
3050  				continue
3051  			}
3052  			fieldType := typ.Field(i).Type()
3053  			xField := b.CreateExtractValue(x, i, "")
3054  			yField := b.CreateExtractValue(y, i, "")
3055  			fieldEqual, err := b.createBinOp(token.EQL, fieldType, fieldType, xField, yField, pos)
3056  			if err != nil {
3057  				return llvm.Value{}, err
3058  			}
3059  			result = b.CreateAnd(result, fieldEqual, "")
3060  		}
3061  		switch op {
3062  		case token.EQL: // ==
3063  			return result, nil
3064  		case token.NEQ: // !=
3065  			return b.CreateNot(result, ""), nil
3066  		default:
3067  			return llvm.Value{}, b.makeError(pos, "unknown: binop on struct: "+op.String())
3068  		}
3069  	default:
3070  		return llvm.Value{}, b.makeError(pos, "todo: binop type: "+typ.String())
3071  	}
3072  }
3073  
3074  // createConst creates a LLVM constant value from a Go constant.
3075  func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value {
3076  	switch typ := expr.Type().Underlying().(type) {
3077  	case *types.Basic:
3078  		llvmType := c.getLLVMType(typ)
3079  		if typ.Info()&types.IsBoolean != 0 {
3080  			n := uint64(0)
3081  			if constant.BoolVal(expr.Value) {
3082  				n = 1
3083  			}
3084  			return llvm.ConstInt(llvmType, n, false)
3085  		} else if typ.Info()&types.IsString != 0 {
3086  			str := constant.StringVal(expr.Value)
3087  			strLen := llvm.ConstInt(c.uintptrType, uint64(len(str)), false)
3088  			var strPtr llvm.Value
3089  			if str != "" {
3090  				objname := c.pkg.Path() + "$string"
3091  				globalType := llvm.ArrayType(c.ctx.Int8Type(), len(str))
3092  				global := llvm.AddGlobal(c.mod, globalType, objname)
3093  				global.SetInitializer(c.ctx.ConstString(str, false))
3094  				global.SetLinkage(llvm.InternalLinkage)
3095  				global.SetGlobalConstant(true)
3096  				global.SetUnnamedAddr(true)
3097  				global.SetAlignment(1)
3098  				if c.Debug {
3099  					// Unfortunately, expr.Pos() is always token.NoPos.
3100  					position := c.program.Fset.Position(pos)
3101  					diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{
3102  						File:        c.getDIFile(position.Filename),
3103  						Line:        position.Line,
3104  						Type:        c.getDIType(types.NewArray(types.Typ[types.Byte], int64(len(str)))),
3105  						LocalToUnit: true,
3106  						Expr:        c.dibuilder.CreateExpression(nil),
3107  					})
3108  					global.AddMetadata(0, diglobal)
3109  				}
3110  				zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
3111  				strPtr = llvm.ConstInBoundsGEP(globalType, global, []llvm.Value{zero, zero})
3112  			} else {
3113  				strPtr = llvm.ConstNull(c.dataPtrType)
3114  			}
3115  			strObj := llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen, strLen})
3116  			return strObj
3117  		} else if typ.Kind() == types.UnsafePointer {
3118  			if !expr.IsNil() {
3119  				value, _ := constant.Uint64Val(constant.ToInt(expr.Value))
3120  				return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, value, false), c.dataPtrType)
3121  			}
3122  			return llvm.ConstNull(c.dataPtrType)
3123  		} else if typ.Info()&types.IsUnsigned != 0 {
3124  			n, _ := constant.Uint64Val(constant.ToInt(expr.Value))
3125  			return llvm.ConstInt(llvmType, n, false)
3126  		} else if typ.Info()&types.IsInteger != 0 { // signed
3127  			n, _ := constant.Int64Val(constant.ToInt(expr.Value))
3128  			return llvm.ConstInt(llvmType, uint64(n), true)
3129  		} else if typ.Info()&types.IsFloat != 0 {
3130  			n, _ := constant.Float64Val(expr.Value)
3131  			return llvm.ConstFloat(llvmType, n)
3132  		} else if typ.Kind() == types.Complex64 {
3133  			r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]), pos)
3134  			i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]), pos)
3135  			cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false))
3136  			cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
3137  			cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
3138  			return cplx
3139  		} else if typ.Kind() == types.Complex128 {
3140  			r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]), pos)
3141  			i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]), pos)
3142  			cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false))
3143  			cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
3144  			cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
3145  			return cplx
3146  		} else {
3147  			panic("unknown constant of basic type: " + expr.String())
3148  		}
3149  	case *types.Chan:
3150  		if expr.Value != nil {
3151  			panic("expected nil chan constant")
3152  		}
3153  		return llvm.ConstNull(c.getLLVMType(expr.Type()))
3154  	case *types.Signature:
3155  		if expr.Value != nil {
3156  			panic("expected nil signature constant")
3157  		}
3158  		return llvm.ConstNull(c.getLLVMType(expr.Type()))
3159  	case *types.Interface:
3160  		if expr.Value != nil {
3161  			panic("expected nil interface constant")
3162  		}
3163  		// Create a generic nil interface with no dynamic type (typecode=0).
3164  		fields := []llvm.Value{
3165  			llvm.ConstInt(c.uintptrType, 0, false),
3166  			llvm.ConstPointerNull(c.dataPtrType),
3167  		}
3168  		return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_interface"), fields)
3169  	case *types.Pointer:
3170  		if expr.Value != nil {
3171  			panic("expected nil pointer constant")
3172  		}
3173  		return llvm.ConstPointerNull(c.getLLVMType(typ))
3174  	case *types.Array:
3175  		if expr.Value != nil {
3176  			panic("expected nil array constant")
3177  		}
3178  		return llvm.ConstNull(c.getLLVMType(expr.Type()))
3179  	case *types.Slice:
3180  		if expr.Value != nil {
3181  			panic("expected nil slice constant")
3182  		}
3183  		// Moxie: use ConstNull with correct type (named for []byte).
3184  		return llvm.ConstNull(c.getLLVMType(expr.Type()))
3185  	case *types.Struct:
3186  		if expr.Value != nil {
3187  			panic("expected nil struct constant")
3188  		}
3189  		return llvm.ConstNull(c.getLLVMType(expr.Type()))
3190  	case *types.Map:
3191  		if !expr.IsNil() {
3192  			// I believe this is not allowed by the Go spec.
3193  			panic("non-nil map constant")
3194  		}
3195  		llvmType := c.getLLVMType(typ)
3196  		return llvm.ConstNull(llvmType)
3197  	default:
3198  		panic("unknown constant: " + expr.String())
3199  	}
3200  }
3201  
3202  // createConvert creates a Go type conversion instruction.
3203  func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, pos token.Pos) (llvm.Value, error) {
3204  	llvmTypeFrom := value.Type()
3205  	llvmTypeTo := b.getLLVMType(typeTo)
3206  
3207  	// Conversion between unsafe.Pointer and uintptr.
3208  	isPtrFrom := isPointer(typeFrom.Underlying())
3209  	isPtrTo := isPointer(typeTo.Underlying())
3210  	if isPtrFrom && !isPtrTo {
3211  		return b.CreatePtrToInt(value, llvmTypeTo, ""), nil
3212  	} else if !isPtrFrom && isPtrTo {
3213  		return b.CreateIntToPtr(value, llvmTypeTo, ""), nil
3214  	}
3215  
3216  	// Conversion between pointers and unsafe.Pointer.
3217  	if isPtrFrom && isPtrTo {
3218  		return value, nil
3219  	}
3220  
3221  	switch typeTo := typeTo.Underlying().(type) {
3222  	case *types.Basic:
3223  		sizeFrom := b.targetData.TypeAllocSize(llvmTypeFrom)
3224  
3225  		if typeTo.Info()&types.IsString != 0 {
3226  			switch typeFrom := typeFrom.Underlying().(type) {
3227  			case *types.Basic:
3228  				// Assume a Unicode code point, as that is the only possible
3229  				// value here.
3230  				// Cast to an i32 value as expected by
3231  				// runtime.stringFromUnicode.
3232  				if sizeFrom > 4 {
3233  					value = b.CreateTrunc(value, b.ctx.Int32Type(), "")
3234  				} else if sizeFrom < 4 && typeTo.Info()&types.IsUnsigned != 0 {
3235  					value = b.CreateZExt(value, b.ctx.Int32Type(), "")
3236  				} else if sizeFrom < 4 {
3237  					value = b.CreateSExt(value, b.ctx.Int32Type(), "")
3238  				}
3239  				return b.createRuntimeCall("stringFromUnicode", []llvm.Value{value}, ""), nil
3240  			case *types.Slice:
3241  				switch typeFrom.Elem().(*types.Basic).Kind() {
3242  				case types.Byte:
3243  					// Moxie: string and []byte have identical 3-word layout.
3244  					// No allocation or copy — just repack fields for LLVM type compatibility.
3245  					ptr := b.CreateExtractValue(value, 0, "")
3246  					ln := b.CreateExtractValue(value, 1, "")
3247  					cp := b.CreateExtractValue(value, 2, "")
3248  					str := llvm.Undef(b.getLLVMRuntimeType("_string"))
3249  					str = b.CreateInsertValue(str, ptr, 0, "")
3250  					str = b.CreateInsertValue(str, ln, 1, "")
3251  					str = b.CreateInsertValue(str, cp, 2, "")
3252  					return str, nil
3253  				case types.Rune:
3254  					return b.createRuntimeCall("stringFromRunes", []llvm.Value{value}, ""), nil
3255  				default:
3256  					return llvm.Value{}, b.makeError(pos, "todo: convert to string: "+typeFrom.String())
3257  				}
3258  			default:
3259  				return llvm.Value{}, b.makeError(pos, "todo: convert to string: "+typeFrom.String())
3260  			}
3261  		}
3262  
3263  		typeFrom := typeFrom.Underlying().(*types.Basic)
3264  		sizeTo := b.targetData.TypeAllocSize(llvmTypeTo)
3265  
3266  		if typeFrom.Info()&types.IsInteger != 0 && typeTo.Info()&types.IsInteger != 0 {
3267  			// Conversion between two integers.
3268  			if sizeFrom > sizeTo {
3269  				return b.CreateTrunc(value, llvmTypeTo, ""), nil
3270  			} else if typeFrom.Info()&types.IsUnsigned != 0 { // if unsigned
3271  				return b.CreateZExt(value, llvmTypeTo, ""), nil
3272  			} else { // if signed
3273  				return b.CreateSExt(value, llvmTypeTo, ""), nil
3274  			}
3275  		}
3276  
3277  		if typeFrom.Info()&types.IsFloat != 0 && typeTo.Info()&types.IsFloat != 0 {
3278  			// Conversion between two floats.
3279  			if sizeFrom > sizeTo {
3280  				return b.CreateFPTrunc(value, llvmTypeTo, ""), nil
3281  			} else if sizeFrom < sizeTo {
3282  				return b.CreateFPExt(value, llvmTypeTo, ""), nil
3283  			} else {
3284  				return value, nil
3285  			}
3286  		}
3287  
3288  		if typeFrom.Info()&types.IsFloat != 0 && typeTo.Info()&types.IsInteger != 0 {
3289  			// Conversion from float to int.
3290  			// Passing an out-of-bounds float to LLVM would cause UB, so that UB is trapped by select instructions.
3291  			// The Go specification says that this should be implementation-defined behavior.
3292  			// This implements saturating behavior, except that NaN is mapped to the minimum value.
3293  			var significandBits int
3294  			switch typeFrom.Kind() {
3295  			case types.Float32:
3296  				significandBits = 23
3297  			case types.Float64:
3298  				significandBits = 52
3299  			}
3300  			if typeTo.Info()&types.IsUnsigned != 0 { // if unsigned
3301  				// Select the maximum value for this unsigned integer type.
3302  				max := ^(^uint64(0) << uint(llvmTypeTo.IntTypeWidth()))
3303  				maxFloat := float64(max)
3304  				if bits.Len64(max) > significandBits {
3305  					// Round the max down to fit within the significand.
3306  					maxFloat = float64(max & (^uint64(0) << uint(bits.Len64(max)-significandBits)))
3307  				}
3308  
3309  				// Check if the value is in-bounds (0 <= value <= max).
3310  				positive := b.CreateFCmp(llvm.FloatOLE, llvm.ConstNull(llvmTypeFrom), value, "positive")
3311  				withinMax := b.CreateFCmp(llvm.FloatOLE, value, llvm.ConstFloat(llvmTypeFrom, maxFloat), "withinmax")
3312  				inBounds := b.CreateAnd(positive, withinMax, "inbounds")
3313  
3314  				// Assuming that the value is out-of-bounds, select a saturated value.
3315  				saturated := b.CreateSelect(positive,
3316  					llvm.ConstInt(llvmTypeTo, max, false), // value > max
3317  					llvm.ConstNull(llvmTypeTo),            // value < 0 (or NaN)
3318  					"saturated",
3319  				)
3320  
3321  				// Do a normal conversion.
3322  				normal := b.CreateFPToUI(value, llvmTypeTo, "normal")
3323  
3324  				return b.CreateSelect(inBounds, normal, saturated, ""), nil
3325  			} else { // if signed
3326  				// Select the minimum value for this signed integer type.
3327  				min := uint64(1) << uint(llvmTypeTo.IntTypeWidth()-1)
3328  				minFloat := -float64(min)
3329  
3330  				// Select the maximum value for this signed integer type.
3331  				max := ^(^uint64(0) << uint(llvmTypeTo.IntTypeWidth()-1))
3332  				maxFloat := float64(max)
3333  				if bits.Len64(max) > significandBits {
3334  					// Round the max down to fit within the significand.
3335  					maxFloat = float64(max & (^uint64(0) << uint(bits.Len64(max)-significandBits)))
3336  				}
3337  
3338  				// Check if the value is in-bounds (min <= value <= max).
3339  				aboveMin := b.CreateFCmp(llvm.FloatOLE, llvm.ConstFloat(llvmTypeFrom, minFloat), value, "abovemin")
3340  				belowMax := b.CreateFCmp(llvm.FloatOLE, value, llvm.ConstFloat(llvmTypeFrom, maxFloat), "belowmax")
3341  				inBounds := b.CreateAnd(aboveMin, belowMax, "inbounds")
3342  
3343  				// Assuming that the value is out-of-bounds, select a saturated value.
3344  				saturated := b.CreateSelect(aboveMin,
3345  					llvm.ConstInt(llvmTypeTo, max, false), // value > max
3346  					llvm.ConstInt(llvmTypeTo, min, false), // value < min
3347  					"saturated",
3348  				)
3349  
3350  				// Map NaN to 0.
3351  				saturated = b.CreateSelect(b.CreateFCmp(llvm.FloatUNO, value, value, "isnan"),
3352  					llvm.ConstNull(llvmTypeTo),
3353  					saturated,
3354  					"remapped",
3355  				)
3356  
3357  				// Do a normal conversion.
3358  				normal := b.CreateFPToSI(value, llvmTypeTo, "normal")
3359  
3360  				return b.CreateSelect(inBounds, normal, saturated, ""), nil
3361  			}
3362  		}
3363  
3364  		if typeFrom.Info()&types.IsInteger != 0 && typeTo.Info()&types.IsFloat != 0 {
3365  			// Conversion from int to float.
3366  			if typeFrom.Info()&types.IsUnsigned != 0 { // if unsigned
3367  				return b.CreateUIToFP(value, llvmTypeTo, ""), nil
3368  			} else { // if signed
3369  				return b.CreateSIToFP(value, llvmTypeTo, ""), nil
3370  			}
3371  		}
3372  
3373  		if typeFrom.Kind() == types.Complex128 && typeTo.Kind() == types.Complex64 {
3374  			// Conversion from complex128 to complex64.
3375  			r := b.CreateExtractValue(value, 0, "real.f64")
3376  			i := b.CreateExtractValue(value, 1, "imag.f64")
3377  			r = b.CreateFPTrunc(r, b.ctx.FloatType(), "real.f32")
3378  			i = b.CreateFPTrunc(i, b.ctx.FloatType(), "imag.f32")
3379  			cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.FloatType(), b.ctx.FloatType()}, false))
3380  			cplx = b.CreateInsertValue(cplx, r, 0, "")
3381  			cplx = b.CreateInsertValue(cplx, i, 1, "")
3382  			return cplx, nil
3383  		}
3384  
3385  		if typeFrom.Kind() == types.Complex64 && typeTo.Kind() == types.Complex128 {
3386  			// Conversion from complex64 to complex128.
3387  			r := b.CreateExtractValue(value, 0, "real.f32")
3388  			i := b.CreateExtractValue(value, 1, "imag.f32")
3389  			r = b.CreateFPExt(r, b.ctx.DoubleType(), "real.f64")
3390  			i = b.CreateFPExt(i, b.ctx.DoubleType(), "imag.f64")
3391  			cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false))
3392  			cplx = b.CreateInsertValue(cplx, r, 0, "")
3393  			cplx = b.CreateInsertValue(cplx, i, 1, "")
3394  			return cplx, nil
3395  		}
3396  
3397  		return llvm.Value{}, b.makeError(pos, "todo: convert: basic non-integer type: "+typeFrom.String()+" -> "+typeTo.String())
3398  
3399  	case *types.Slice:
3400  		// Moxie: allow conversion from string or []byte (string=[]byte).
3401  		if !isStringLike(typeFrom.Underlying()) {
3402  			panic("can only convert from a string/[]byte to a slice")
3403  		}
3404  
3405  		elemType := typeTo.Elem().Underlying().(*types.Basic) // must be byte or rune
3406  		switch elemType.Kind() {
3407  		case types.Byte:
3408  			// Moxie: string and []byte have identical 3-word layout.
3409  			// No allocation or copy — just repack fields for LLVM type compatibility.
3410  			ptr := b.CreateExtractValue(value, 0, "")
3411  			ln := b.CreateExtractValue(value, 1, "")
3412  			cp := b.CreateExtractValue(value, 2, "")
3413  			slice := llvm.Undef(b.getLLVMType(typeTo))
3414  			slice = b.CreateInsertValue(slice, ptr, 0, "")
3415  			slice = b.CreateInsertValue(slice, ln, 1, "")
3416  			slice = b.CreateInsertValue(slice, cp, 2, "")
3417  			return slice, nil
3418  		case types.Rune:
3419  			return b.createRuntimeCall("stringToRunes", []llvm.Value{value}, ""), nil
3420  		default:
3421  			panic("unexpected type in string to slice conversion")
3422  		}
3423  
3424  	default:
3425  		return llvm.Value{}, b.makeError(pos, "todo: convert "+typeTo.String()+" <- "+typeFrom.String())
3426  	}
3427  }
3428  
3429  // createUnOp creates LLVM IR for a given Go unary operation.
3430  // Most unary operators are pretty simple, such as the not and minus operator
3431  // which can all be directly lowered to IR. However, there is also the channel
3432  // receive operator which is handled in the runtime directly.
3433  func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
3434  	x := b.getValue(unop.X, getPos(unop))
3435  	switch unop.Op {
3436  	case token.NOT: // !x
3437  		return b.CreateNot(x, ""), nil
3438  	case token.SUB: // -x
3439  		if typ, ok := unop.X.Type().Underlying().(*types.Basic); ok {
3440  			if typ.Info()&types.IsInteger != 0 {
3441  				return b.CreateSub(llvm.ConstInt(x.Type(), 0, false), x, ""), nil
3442  			} else if typ.Info()&types.IsFloat != 0 {
3443  				return b.CreateFNeg(x, ""), nil
3444  			} else if typ.Info()&types.IsComplex != 0 {
3445  				// Negate both components of the complex number.
3446  				r := b.CreateExtractValue(x, 0, "r")
3447  				i := b.CreateExtractValue(x, 1, "i")
3448  				r = b.CreateFNeg(r, "")
3449  				i = b.CreateFNeg(i, "")
3450  				cplx := llvm.Undef(x.Type())
3451  				cplx = b.CreateInsertValue(cplx, r, 0, "")
3452  				cplx = b.CreateInsertValue(cplx, i, 1, "")
3453  				return cplx, nil
3454  			} else {
3455  				return llvm.Value{}, b.makeError(unop.Pos(), "todo: unknown basic type for negate: "+typ.String())
3456  			}
3457  		} else {
3458  			return llvm.Value{}, b.makeError(unop.Pos(), "todo: unknown type for negate: "+unop.X.Type().Underlying().String())
3459  		}
3460  	case token.MUL: // *x, dereference pointer
3461  		valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Pointer).Elem())
3462  		if b.targetData.TypeAllocSize(valueType) == 0 {
3463  			// zero-length data
3464  			return llvm.ConstNull(valueType), nil
3465  		} else if strings.HasSuffix(unop.X.String(), "$funcaddr") {
3466  			// CGo function pointer. The cgo part has rewritten CGo function
3467  			// pointers as stub global variables of the form:
3468  			//     var C.add unsafe.Pointer
3469  			// Instead of a load from the global, create a bitcast of the
3470  			// function pointer itself.
3471  			name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr")
3472  			pkg := b.fn.Pkg
3473  			if pkg == nil {
3474  				pkg = b.fn.Origin().Pkg
3475  			}
3476  			_, fn := b.getFunction(pkg.Members[name].(*ssa.Function))
3477  			if fn.IsNil() {
3478  				return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
3479  			}
3480  			return fn, nil
3481  		} else {
3482  			b.createNilCheck(unop.X, x, "deref")
3483  			load := b.CreateLoad(valueType, x, "")
3484  			return load, nil
3485  		}
3486  	case token.XOR: // ^x, toggle all bits in integer
3487  		return b.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil
3488  	case token.ARROW: // <-x, receive from channel
3489  		return b.createChanRecv(unop), nil
3490  	default:
3491  		return llvm.Value{}, b.makeError(unop.Pos(), "todo: unknown unop")
3492  	}
3493  }
3494