コード例 #1
0
ファイル: typemap.go プロジェクト: rvedam/llgo
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value, name string) (global, ptr llvm.Value) {
	global = llvm.AddGlobal(tm.module, v.Type(), typeSymbol(name))
	global.SetInitializer(v)
	global.SetLinkage(llvm.LinkOnceAnyLinkage)
	ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0))
	return global, ptr
}
コード例 #2
0
ファイル: runtime.go プロジェクト: rvedam/llgo
func (c *compiler) createMalloc(size llvm.Value) llvm.Value {
	malloc := c.runtime.malloc.LLVMValue()
	switch n := size.Type().IntTypeWidth() - c.target.IntPtrType().IntTypeWidth(); {
	case n < 0:
		size = c.builder.CreateZExt(size, c.target.IntPtrType(), "")
	case n > 0:
		size = c.builder.CreateTrunc(size, c.target.IntPtrType(), "")
	}
	return c.builder.CreateCall(malloc, []llvm.Value{size}, "")
}
コード例 #3
0
ファイル: runtime.go プロジェクト: rvedam/llgo
func (c *compiler) memsetZero(ptr llvm.Value, size llvm.Value) {
	memset := c.runtime.memset.LLVMValue()
	switch n := size.Type().IntTypeWidth() - c.target.IntPtrType().IntTypeWidth(); {
	case n < 0:
		size = c.builder.CreateZExt(size, c.target.IntPtrType(), "")
	case n > 0:
		size = c.builder.CreateTrunc(size, c.target.IntPtrType(), "")
	}
	ptr = c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "")
	fill := llvm.ConstNull(llvm.Int8Type())
	c.builder.CreateCall(memset, []llvm.Value{ptr, fill, size}, "")
}
コード例 #4
0
ファイル: debug.go プロジェクト: rvedam/llgo
// declare creates an llvm.dbg.declare call for the specified function
// parameter or local variable.
func (d *debugInfo) declare(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) {
	tag := tagAutoVariable
	if paramIndex >= 0 {
		tag = tagArgVariable
	}
	ld := debug.NewLocalVariableDescriptor(tag)
	ld.Argument = uint32(paramIndex + 1)
	ld.Name = llv.Name()
	if file := d.Fset.File(v.Pos()); file != nil {
		ld.Line = uint32(file.Position(v.Pos()).Line)
		ld.File = &d.getCompileUnit(file).Path
	}
	ld.Type = d.TypeDebugDescriptor(deref(v.Type()))
	ld.Context = d.context()
	b.InsertDeclare(d.module, llvm.MDNode([]llvm.Value{llv}), d.MDNode(ld))
}
コード例 #5
0
ファイル: typemap.go プロジェクト: rvedam/llgo
func (tm *TypeMap) makeSlice(values []llvm.Value, slicetyp llvm.Type) llvm.Value {
	ptrtyp := slicetyp.StructElementTypes()[0]
	var globalptr llvm.Value
	if len(values) > 0 {
		array := llvm.ConstArray(ptrtyp.ElementType(), values)
		globalptr = llvm.AddGlobal(tm.module, array.Type(), "")
		globalptr.SetInitializer(array)
		globalptr = llvm.ConstBitCast(globalptr, ptrtyp)
	} else {
		globalptr = llvm.ConstNull(ptrtyp)
	}
	len_ := llvm.ConstInt(tm.inttype, uint64(len(values)), false)
	slice := llvm.ConstNull(slicetyp)
	slice = llvm.ConstInsertValue(slice, globalptr, []uint32{0})
	slice = llvm.ConstInsertValue(slice, len_, []uint32{1})
	slice = llvm.ConstInsertValue(slice, len_, []uint32{2})
	return slice
}
コード例 #6
0
ファイル: coerce.go プロジェクト: rvedam/llgo
// coerce yields a value of the the type specified, initialised
// to the exact bit pattern as in the specified value.
//
// Note: the value's type and the specified target type must have
// the same size. If the source is an aggregate, then the target
// must also be an aggregate with the same number of fields, each
// of which must have the same size.
func coerce(b llvm.Builder, v llvm.Value, t llvm.Type) llvm.Value {
	// FIXME don't do this with alloca
	switch t.TypeKind() {
	case llvm.ArrayTypeKind, llvm.StructTypeKind:
		ptr := b.CreateAlloca(t, "")
		ptrv := b.CreateBitCast(ptr, llvm.PointerType(v.Type(), 0), "")
		b.CreateStore(v, ptrv)
		return b.CreateLoad(ptr, "")
	}
	vt := v.Type()
	switch vt.TypeKind() {
	case llvm.ArrayTypeKind, llvm.StructTypeKind:
		ptr := b.CreateAlloca(vt, "")
		b.CreateStore(v, ptr)
		ptrt := b.CreateBitCast(ptr, llvm.PointerType(t, 0), "")
		return b.CreateLoad(ptrt, "")
	}
	return b.CreateBitCast(v, t, "")
}
コード例 #7
0
ファイル: debug.go プロジェクト: rvedam/llgo
func (d *debugInfo) pushFunctionContext(fnptr llvm.Value, sig *types.Signature, pos token.Pos) {
	subprog := &debug.SubprogramDescriptor{
		Name:        fnptr.Name(),
		DisplayName: fnptr.Name(),
		Function:    fnptr,
	}
	file := d.Fset.File(pos)
	cu := d.getCompileUnit(file)
	subprog.File = file.Name()
	subprog.Context = &cu.Path
	if file != nil {
		subprog.Line = uint32(file.Line(pos))
		subprog.ScopeLine = uint32(file.Line(pos)) // TODO(axw)
	}
	sigType := d.TypeDebugDescriptor(sig).(*debug.CompositeTypeDescriptor)
	subroutineType := sigType.Members[0]
	subprog.Type = subroutineType
	cu.Subprograms = append(cu.Subprograms, subprog)
	d.pushContext(subprog)
}
コード例 #8
0
ファイル: typemap.go プロジェクト: rvedam/llgo
func (tm *TypeMap) interfaceFuncWrapper(f llvm.Value) llvm.Value {
	ftyp := f.Type().ElementType()
	paramTypes := ftyp.ParamTypes()
	recvType := paramTypes[0]
	paramTypes[0] = llvm.PointerType(llvm.Int8Type(), 0)
	newf := llvm.AddFunction(f.GlobalParent(), f.Name()+".ifn", llvm.FunctionType(
		ftyp.ReturnType(),
		paramTypes,
		ftyp.IsFunctionVarArg(),
	))

	b := llvm.GlobalContext().NewBuilder()
	defer b.Dispose()
	entry := llvm.AddBasicBlock(newf, "entry")
	b.SetInsertPointAtEnd(entry)
	args := make([]llvm.Value, len(paramTypes))
	for i := range paramTypes {
		args[i] = newf.Param(i)
	}

	recvBits := int(tm.target.TypeSizeInBits(recvType))
	if recvBits > 0 {
		args[0] = b.CreatePtrToInt(args[0], tm.target.IntPtrType(), "")
		if args[0].Type().IntTypeWidth() > recvBits {
			args[0] = b.CreateTrunc(args[0], llvm.IntType(recvBits), "")
		}
		args[0] = coerce(b, args[0], recvType)
	} else {
		args[0] = llvm.ConstNull(recvType)
	}

	result := b.CreateCall(f, args, "")
	if result.Type().TypeKind() == llvm.VoidTypeKind {
		b.CreateRetVoid()
	} else {
		b.CreateRet(result)
	}
	return newf
}
コード例 #9
0
ファイル: indirect.go プロジェクト: rvedam/llgo
// indirectFunction creates an indirect function from a
// given function and arguments, suitable for use with
// "defer" and "go".
func (c *compiler) indirectFunction(fn *LLVMValue, args []*LLVMValue) *LLVMValue {
	nilarytyp := types.NewSignature(nil, nil, nil, nil, false)
	if len(args) == 0 {
		val := fn.LLVMValue()
		ptr := c.builder.CreateExtractValue(val, 0, "")
		ctx := c.builder.CreateExtractValue(val, 1, "")
		fnval := llvm.Undef(c.types.ToLLVM(nilarytyp))
		ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "")
		ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "")
		fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "")
		fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "")
		return c.NewValue(fnval, nilarytyp)
	}

	// Check if function pointer or context pointer is global/null.
	fnval := fn.LLVMValue()
	fnptr := fnval
	var nctx int
	var fnctx llvm.Value
	var fnctxindex uint64
	var globalfn bool
	if fnptr.Type().TypeKind() == llvm.StructTypeKind {
		fnptr = c.builder.CreateExtractValue(fnval, 0, "")
		fnctx = c.builder.CreateExtractValue(fnval, 1, "")
		globalfn = !fnptr.IsAFunction().IsNil()
		if !globalfn {
			nctx++
		}
		if !fnctx.IsNull() {
			fnctxindex = uint64(nctx)
			nctx++
		}
	} else {
		// We've got a raw global function pointer. Convert to <ptr,ctx>.
		fnval = llvm.ConstNull(c.types.ToLLVM(fn.Type()))
		fnval = llvm.ConstInsertValue(fnval, fnptr, []uint32{0})
		fn = c.NewValue(fnval, fn.Type())
		fnctx = llvm.ConstExtractValue(fnval, []uint32{1})
		globalfn = true
	}

	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	llvmargs := make([]llvm.Value, len(args)+nctx)
	llvmargtypes := make([]llvm.Type, len(args)+nctx)
	for i, arg := range args {
		llvmargs[i+nctx] = arg.LLVMValue()
		llvmargtypes[i+nctx] = llvmargs[i+nctx].Type()
	}
	if !globalfn {
		llvmargtypes[0] = fnptr.Type()
		llvmargs[0] = fnptr
	}
	if !fnctx.IsNull() {
		llvmargtypes[fnctxindex] = fnctx.Type()
		llvmargs[fnctxindex] = fnctx
	}

	// TODO(axw) investigate an option for go statements
	// to allocate argument structure on the stack in the
	// initiator, and block until the spawned goroutine
	// has loaded the arguments from it.
	structtyp := llvm.StructType(llvmargtypes, false)
	argstruct := c.createTypeMalloc(structtyp)
	for i, llvmarg := range llvmargs {
		argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "")
		c.builder.CreateStore(llvmarg, argptr)
	}

	// Create a function that will take a pointer to a structure of the type
	// defined above, or no parameters if there are none to pass.
	fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false)
	indirectfn := llvm.AddFunction(c.module.Module, "", fntype)
	i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "")
	currblock := c.builder.GetInsertBlock()
	c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry"))
	argstruct = indirectfn.Param(0)
	newargs := make([]*LLVMValue, len(args))
	for i := range llvmargs[nctx:] {
		argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "")
		newargs[i] = c.NewValue(c.builder.CreateLoad(argptr, ""), args[i].Type())
	}

	// Unless we've got a global function, extract the
	// function pointer from the context.
	if !globalfn {
		fnval = llvm.Undef(fnval.Type())
		fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), 0, false)}, "")
		fnptr = c.builder.CreateLoad(fnptrptr, "")
		fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "")
	}
	if !fnctx.IsNull() {
		fnctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), fnctxindex, false)}, "")
		fnctx = c.builder.CreateLoad(fnctxptr, "")
		fnval = c.builder.CreateInsertValue(fnval, fnctx, 1, "")
		fn = c.NewValue(fnval, fn.Type())
	}
	c.createCall(fn, newargs)

	// Indirect function calls' return values are always ignored.
	c.builder.CreateRetVoid()
	c.builder.SetInsertPointAtEnd(currblock)

	fnval = llvm.Undef(c.types.ToLLVM(nilarytyp))
	indirectfn = c.builder.CreateBitCast(indirectfn, fnval.Type().StructElementTypes()[0], "")
	fnval = c.builder.CreateInsertValue(fnval, indirectfn, 0, "")
	fnval = c.builder.CreateInsertValue(fnval, i8argstruct, 1, "")
	fn = c.NewValue(fnval, nilarytyp)
	return fn
}
コード例 #10
0
ファイル: typemap.go プロジェクト: rvedam/llgo
func (tm *TypeMap) pointerRuntimeType(p *types.Pointer) (global, ptr llvm.Value) {
	// Is the base type a named type from another package? If so, we'll
	// create a reference to the externally defined symbol.
	linkage := llvm.LinkOnceAnyLinkage
	switch elem := p.Elem().(type) {
	case *types.Basic:
		if tm.pkgpath != "runtime" {
			global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(typeString(p)))
			global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm))
			global.SetLinkage(llvm.CommonLinkage)
			return global, global
		}
		linkage = llvm.ExternalLinkage
	case *types.Named:
		path := "runtime"
		if pkg := elem.Obj().Pkg(); pkg != nil {
			path = pkg.Path()
		}
		if path != tm.pkgpath {
			global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(typeString(p)))
			global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm))
			global.SetLinkage(llvm.CommonLinkage)
			return global, global
		}
		linkage = llvm.ExternalLinkage
	}

	rtype := tm.makeRtype(p, reflect.Ptr)
	if n, ok := p.Elem().(*types.Named); ok {
		uncommonTypeInit := tm.uncommonType(n, p)
		uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "")
		uncommonType.SetInitializer(uncommonTypeInit)
		rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9})
	}

	ptrType := llvm.ConstNull(tm.runtime.ptrType.llvm)
	var baseTypeGlobal llvm.Value
	if p.Elem().Underlying() == p {
		// Recursive pointer.
		ptrType = llvm.ConstInsertValue(ptrType, rtype, []uint32{0})
		global, ptr = tm.makeRuntimeTypeGlobal(ptrType, typeString(p))
		baseTypeGlobal = global
		// Update the global with its own pointer in the elem field.
		ptrType = global.Initializer()
		ptrType = llvm.ConstInsertValue(ptrType, ptr, []uint32{1})
		global.SetInitializer(ptrType)
	} else {
		var baseTypePtr llvm.Value
		baseTypeGlobal, baseTypePtr = tm.toRuntime(p.Elem())
		ptrType = llvm.ConstInsertValue(ptrType, rtype, []uint32{0})
		ptrType = llvm.ConstInsertValue(ptrType, baseTypePtr, []uint32{1})
		global, ptr = tm.makeRuntimeTypeGlobal(ptrType, typeString(p))
	}
	global.SetLinkage(linkage)

	// Set ptrToThis in the base type's rtype.
	baseType := baseTypeGlobal.Initializer()
	if !baseType.IsNull() {
		if baseType.Type() == tm.runtime.rtype.llvm {
			baseType = llvm.ConstInsertValue(baseType, ptr, []uint32{10})
		} else {
			rtype := llvm.ConstExtractValue(baseType, []uint32{0})
			rtype = llvm.ConstInsertValue(rtype, ptr, []uint32{10})
			baseType = llvm.ConstInsertValue(baseType, rtype, []uint32{0})
		}
		baseTypeGlobal.SetInitializer(baseType)
	}
	return global, ptr
}
コード例 #11
0
ファイル: value.go プロジェクト: rvedam/llgo
func (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue {
	switch {
	case v == nil:
		llvmtyp := c.types.ToLLVM(typ)
		return c.NewValue(llvm.ConstNull(llvmtyp), typ)

	case isString(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.String]
		}
		llvmtyp := c.types.ToLLVM(typ)
		strval := exact.StringVal(v)
		strlen := len(strval)
		i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
		var ptr llvm.Value
		if strlen > 0 {
			init := llvm.ConstString(strval, false)
			ptr = llvm.AddGlobal(c.module.Module, init.Type(), "")
			ptr.SetInitializer(init)
			ptr = llvm.ConstBitCast(ptr, i8ptr)
		} else {
			ptr = llvm.ConstNull(i8ptr)
		}
		len_ := llvm.ConstInt(c.types.inttype, uint64(strlen), false)
		llvmvalue := llvm.Undef(llvmtyp)
		llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0})
		llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1})
		return c.NewValue(llvmvalue, typ)

	case isInteger(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Int]
		}
		llvmtyp := c.types.ToLLVM(typ)
		var llvmvalue llvm.Value
		if isUnsigned(typ) {
			v, _ := exact.Uint64Val(v)
			llvmvalue = llvm.ConstInt(llvmtyp, v, false)
		} else {
			v, _ := exact.Int64Val(v)
			llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true)
		}
		return c.NewValue(llvmvalue, typ)

	case isBoolean(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Bool]
		}
		var llvmvalue llvm.Value
		if exact.BoolVal(v) {
			llvmvalue = llvm.ConstAllOnes(llvm.Int1Type())
		} else {
			llvmvalue = llvm.ConstNull(llvm.Int1Type())
		}
		return c.NewValue(llvmvalue, typ)

	case isFloat(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Float64]
		}
		llvmtyp := c.types.ToLLVM(typ)
		floatval, _ := exact.Float64Val(v)
		llvmvalue := llvm.ConstFloat(llvmtyp, floatval)
		return c.NewValue(llvmvalue, typ)

	case typ == types.Typ[types.UnsafePointer]:
		llvmtyp := c.types.ToLLVM(typ)
		v, _ := exact.Uint64Val(v)
		llvmvalue := llvm.ConstInt(llvmtyp, v, false)
		return c.NewValue(llvmvalue, typ)

	case isComplex(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Complex128]
		}
		llvmtyp := c.types.ToLLVM(typ)
		floattyp := llvmtyp.StructElementTypes()[0]
		llvmvalue := llvm.ConstNull(llvmtyp)
		realv := exact.Real(v)
		imagv := exact.Imag(v)
		realfloatval, _ := exact.Float64Val(realv)
		imagfloatval, _ := exact.Float64Val(imagv)
		llvmre := llvm.ConstFloat(floattyp, realfloatval)
		llvmim := llvm.ConstFloat(floattyp, imagfloatval)
		llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0})
		llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1})
		return c.NewValue(llvmvalue, typ)
	}

	// Special case for string -> [](byte|rune)
	if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) {
		if v.Kind() == exact.String {
			strval := c.NewConstValue(v, types.Typ[types.String])
			return strval.Convert(typ).(*LLVMValue)
		}
	}

	panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", typ, typ, v, v))
}
コード例 #12
0
ファイル: ssa.go プロジェクト: rvedam/llgo
func (fr *frame) instruction(instr ssa.Instruction) {
	fr.logf("[%T] %v @ %s\n", instr, instr, fr.pkg.Prog.Fset.Position(instr.Pos()))
	if fr.GenerateDebug {
		fr.debug.setLocation(fr.builder, instr.Pos())
	}

	// Check if we'll need to backpatch; see comment
	// in fr.value().
	if v, ok := instr.(ssa.Value); ok {
		if b := fr.backpatcher(v); b != nil {
			defer b()
		}
	}

	switch instr := instr.(type) {
	case *ssa.Alloc:
		typ := fr.llvmtypes.ToLLVM(deref(instr.Type()))
		var value llvm.Value
		if instr.Heap {
			value = fr.createTypeMalloc(typ)
			value.SetName(instr.Comment)
			fr.env[instr] = fr.NewValue(value, instr.Type())
		} else {
			value = fr.env[instr].LLVMValue()
		}
		fr.memsetZero(value, llvm.SizeOf(typ))

	case *ssa.BinOp:
		lhs, rhs := fr.value(instr.X), fr.value(instr.Y)
		fr.env[instr] = lhs.BinaryOp(instr.Op, rhs).(*LLVMValue)

	case *ssa.Call:
		fn, args, result := fr.prepareCall(instr)
		// Some builtins may only be used immediately, and not
		// deferred; in this case, "fn" will be nil, and result
		// may be non-nil (it will be nil for builtins without
		// results.)
		if fn == nil {
			if result != nil {
				fr.env[instr] = result
			}
		} else {
			result = fr.createCall(fn, args)
			fr.env[instr] = result
		}

	case *ssa.ChangeInterface:
		x := fr.value(instr.X)
		// The source type must be a non-empty interface,
		// as ChangeInterface cannot fail (E2I may fail).
		if instr.Type().Underlying().(*types.Interface).NumMethods() > 0 {
			// TODO(axw) optimisation for I2I case where we
			// know statically the methods to carry over.
			x = x.convertI2E()
			x, _ = x.convertE2I(instr.Type())
		} else {
			x = x.convertI2E()
			x = fr.NewValue(x.LLVMValue(), instr.Type())
		}
		fr.env[instr] = x

	case *ssa.ChangeType:
		value := fr.value(instr.X).LLVMValue()
		if _, ok := instr.Type().Underlying().(*types.Pointer); ok {
			value = fr.builder.CreateBitCast(value, fr.llvmtypes.ToLLVM(instr.Type()), "")
		}
		v := fr.NewValue(value, instr.Type())
		if _, ok := instr.X.(*ssa.Phi); ok {
			v = phiValue(fr.compiler, v)
		}
		fr.env[instr] = v

	case *ssa.Convert:
		v := fr.value(instr.X)
		if _, ok := instr.X.(*ssa.Phi); ok {
			v = phiValue(fr.compiler, v)
		}
		fr.env[instr] = v.Convert(instr.Type()).(*LLVMValue)

	//case *ssa.DebugRef:

	case *ssa.Defer:
		fn, args, result := fr.prepareCall(instr)
		if result != nil {
			panic("illegal use of builtin in defer statement")
		}
		fn = fr.indirectFunction(fn, args)
		fr.createCall(fr.runtime.pushdefer, []*LLVMValue{fn})

	case *ssa.Extract:
		tuple := fr.value(instr.Tuple).LLVMValue()
		elem := fr.builder.CreateExtractValue(tuple, instr.Index, instr.Name())
		elemtyp := instr.Type()
		fr.env[instr] = fr.NewValue(elem, elemtyp)

	case *ssa.Field:
		value := fr.value(instr.X).LLVMValue()
		field := fr.builder.CreateExtractValue(value, instr.Field, instr.Name())
		fieldtyp := instr.Type()
		fr.env[instr] = fr.NewValue(field, fieldtyp)

	case *ssa.FieldAddr:
		// TODO: implement nil check and panic.
		// TODO: combine a chain of {Field,Index}Addrs into a single GEP.
		ptr := fr.value(instr.X).LLVMValue()
		fieldptr := fr.builder.CreateStructGEP(ptr, instr.Field, instr.Name())
		fieldptrtyp := instr.Type()
		fr.env[instr] = fr.NewValue(fieldptr, fieldptrtyp)

	case *ssa.Go:
		fn, args, result := fr.prepareCall(instr)
		if result != nil {
			panic("illegal use of builtin in go statement")
		}
		fn = fr.indirectFunction(fn, args)
		fr.createCall(fr.runtime.Go, []*LLVMValue{fn})

	case *ssa.If:
		cond := fr.value(instr.Cond).LLVMValue()
		block := instr.Block()
		trueBlock := fr.block(block.Succs[0])
		falseBlock := fr.block(block.Succs[1])
		fr.builder.CreateCondBr(cond, trueBlock, falseBlock)

	case *ssa.Index:
		// FIXME Surely we should be dealing with an
		// *array, so we can do a GEP?
		array := fr.value(instr.X).LLVMValue()
		arrayptr := fr.builder.CreateAlloca(array.Type(), "")
		fr.builder.CreateStore(array, arrayptr)
		index := fr.value(instr.Index).LLVMValue()
		zero := llvm.ConstNull(index.Type())
		addr := fr.builder.CreateGEP(arrayptr, []llvm.Value{zero, index}, "")
		fr.env[instr] = fr.NewValue(fr.builder.CreateLoad(addr, ""), instr.Type())

	case *ssa.IndexAddr:
		// TODO: implement nil-check and panic.
		// TODO: combine a chain of {Field,Index}Addrs into a single GEP.
		x := fr.value(instr.X).LLVMValue()
		index := fr.value(instr.Index).LLVMValue()
		var addr llvm.Value
		var elemtyp types.Type
		zero := llvm.ConstNull(index.Type())
		switch typ := instr.X.Type().Underlying().(type) {
		case *types.Slice:
			elemtyp = typ.Elem()
			x = fr.builder.CreateExtractValue(x, 0, "")
			addr = fr.builder.CreateGEP(x, []llvm.Value{index}, "")
		case *types.Pointer: // *array
			elemtyp = typ.Elem().Underlying().(*types.Array).Elem()
			addr = fr.builder.CreateGEP(x, []llvm.Value{zero, index}, "")
		}
		fr.env[instr] = fr.NewValue(addr, types.NewPointer(elemtyp))

	case *ssa.Jump:
		succ := instr.Block().Succs[0]
		fr.builder.CreateBr(fr.block(succ))

	case *ssa.Lookup:
		x := fr.value(instr.X)
		index := fr.value(instr.Index)
		if isString(x.Type().Underlying()) {
			fr.env[instr] = fr.stringIndex(x, index)
		} else {
			fr.env[instr] = fr.mapLookup(x, index, instr.CommaOk)
		}

	case *ssa.MakeChan:
		fr.env[instr] = fr.makeChan(instr.Type(), fr.value(instr.Size))

	case *ssa.MakeClosure:
		fn := fr.resolveFunction(instr.Fn.(*ssa.Function))
		bindings := make([]*LLVMValue, len(instr.Bindings))
		for i, binding := range instr.Bindings {
			bindings[i] = fr.value(binding)
		}
		fr.env[instr] = fr.makeClosure(fn, bindings)

	case *ssa.MakeInterface:
		receiver := fr.value(instr.X)
		fr.env[instr] = fr.makeInterface(receiver, instr.Type())

	case *ssa.MakeMap:
		fr.env[instr] = fr.makeMap(instr.Type(), fr.value(instr.Reserve))

	case *ssa.MakeSlice:
		length := fr.value(instr.Len)
		capacity := fr.value(instr.Cap)
		fr.env[instr] = fr.makeSlice(instr.Type(), length, capacity)

	case *ssa.MapUpdate:
		m := fr.value(instr.Map)
		k := fr.value(instr.Key)
		v := fr.value(instr.Value)
		fr.mapUpdate(m, k, v)

	case *ssa.Next:
		iter := fr.value(instr.Iter)
		if !instr.IsString {
			fr.env[instr] = fr.mapIterNext(iter)
			return
		}

		// String range
		//
		// We make some assumptions for now around the
		// current state of affairs in go.tools/ssa.
		//
		//  - Range's block is a predecessor of Next's.
		//      (this is currently true, but may change in the future;
		//       adonovan says he will expose the dominator tree
		//       computation in the future, which we can use here).
		//  - Next is the first non-Phi instruction in its block.
		//      (this is not strictly necessary; we can move the Phi
		//       to the top of the block, and defer the tuple creation
		//       to Extract).
		assert(instr.Iter.(*ssa.Range).Block() == instr.Block().Preds[0])
		for _, blockInstr := range instr.Block().Instrs {
			if instr == blockInstr {
				break
			}
			_, isphi := blockInstr.(*ssa.Phi)
			assert(isphi)
		}
		preds := instr.Block().Preds
		llpreds := make([]llvm.BasicBlock, len(preds))
		for i, b := range preds {
			llpreds[i] = fr.block(b)
		}
		fr.env[instr] = fr.stringIterNext(iter, llpreds)

	case *ssa.Panic:
		arg := fr.value(instr.X).LLVMValue()
		fr.builder.CreateCall(fr.runtime.panic_.LLVMValue(), []llvm.Value{arg}, "")
		fr.builder.CreateUnreachable()

	case *ssa.Phi:
		typ := instr.Type()
		phi := fr.builder.CreatePHI(fr.llvmtypes.ToLLVM(typ), instr.Comment)
		fr.env[instr] = fr.NewValue(phi, typ)
		values := make([]llvm.Value, len(instr.Edges))
		blocks := make([]llvm.BasicBlock, len(instr.Edges))
		block := instr.Block()
		for i, edge := range instr.Edges {
			values[i] = fr.value(edge).LLVMValue()
			blocks[i] = fr.block(block.Preds[i])
		}
		phi.AddIncoming(values, blocks)

	case *ssa.Range:
		x := fr.value(instr.X)
		switch x.Type().Underlying().(type) {
		case *types.Map:
			fr.env[instr] = fr.mapIterInit(x)
		case *types.Basic: // string
			fr.env[instr] = x
		default:
			panic(fmt.Sprintf("unhandled range for type %T", x.Type()))
		}

	case *ssa.Return:
		switch n := len(instr.Results); n {
		case 0:
			// https://code.google.com/p/go/issues/detail?id=7022
			if r := instr.Parent().Signature.Results(); r != nil && r.Len() > 0 {
				fr.builder.CreateUnreachable()
			} else {
				fr.builder.CreateRetVoid()
			}
		case 1:
			fr.builder.CreateRet(fr.value(instr.Results[0]).LLVMValue())
		default:
			values := make([]llvm.Value, n)
			for i, result := range instr.Results {
				values[i] = fr.value(result).LLVMValue()
			}
			fr.builder.CreateAggregateRet(values)
		}

	case *ssa.RunDefers:
		fr.builder.CreateCall(fr.runtime.rundefers.LLVMValue(), nil, "")

	case *ssa.Select:
		states := make([]selectState, len(instr.States))
		for i, state := range instr.States {
			states[i] = selectState{
				Dir:  state.Dir,
				Chan: fr.value(state.Chan),
				Send: fr.value(state.Send),
			}
		}
		fr.env[instr] = fr.chanSelect(states, instr.Blocking)

	case *ssa.Send:
		fr.chanSend(fr.value(instr.Chan), fr.value(instr.X))

	case *ssa.Slice:
		x := fr.value(instr.X)
		low := fr.value(instr.Low)
		high := fr.value(instr.High)
		fr.env[instr] = fr.slice(x, low, high)

	case *ssa.Store:
		addr := fr.value(instr.Addr).LLVMValue()
		value := fr.value(instr.Val).LLVMValue()
		// The bitcast is necessary to handle recursive pointer stores.
		addr = fr.builder.CreateBitCast(addr, llvm.PointerType(value.Type(), 0), "")
		fr.builder.CreateStore(value, addr)

	case *ssa.TypeAssert:
		x := fr.value(instr.X)
		if iface, ok := x.Type().Underlying().(*types.Interface); ok && iface.NumMethods() > 0 {
			x = x.convertI2E()
		}
		if !instr.CommaOk {
			if _, ok := instr.AssertedType.Underlying().(*types.Interface); ok {
				fr.env[instr] = x.mustConvertE2I(instr.AssertedType)
			} else {
				fr.env[instr] = x.mustConvertE2V(instr.AssertedType)
			}
		} else {
			var result, success *LLVMValue
			if _, ok := instr.AssertedType.Underlying().(*types.Interface); ok {
				result, success = x.convertE2I(instr.AssertedType)
			} else {
				result, success = x.convertE2V(instr.AssertedType)
			}
			resultval := result.LLVMValue()
			okval := success.LLVMValue()
			pairtyp := llvm.StructType([]llvm.Type{resultval.Type(), okval.Type()}, false)
			pair := llvm.Undef(pairtyp)
			pair = fr.builder.CreateInsertValue(pair, resultval, 0, "")
			pair = fr.builder.CreateInsertValue(pair, okval, 1, "")
			fr.env[instr] = fr.NewValue(pair, instr.Type())
		}

	case *ssa.UnOp:
		operand := fr.value(instr.X)
		switch instr.Op {
		case token.ARROW:
			fr.env[instr] = fr.chanRecv(operand, instr.CommaOk)
		case token.MUL:
			// The bitcast is necessary to handle recursive pointer loads.
			llptr := fr.builder.CreateBitCast(operand.LLVMValue(), llvm.PointerType(fr.llvmtypes.ToLLVM(instr.Type()), 0), "")
			fr.env[instr] = fr.NewValue(fr.builder.CreateLoad(llptr, ""), instr.Type())
		default:
			fr.env[instr] = operand.UnaryOp(instr.Op).(*LLVMValue)
		}

	default:
		panic(fmt.Sprintf("unhandled: %v", instr))
	}
}