Example #1
0
func (tm *TypeMap) interfaceRuntimeType(i *types.Interface) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(i, reflect.Interface)
	interfaceType := llvm.ConstNull(tm.runtime.interfaceType.llvm)
	global, ptr = tm.makeRuntimeTypeGlobal(interfaceType, typeString(i))
	tm.types.Set(i, runtimeTypeInfo{global, ptr})
	interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0})
	methodset := tm.MethodSet(i)
	imethods := make([]llvm.Value, methodset.Len())
	for index := 0; index < methodset.Len(); index++ {
		method := methodset.At(index).Obj()
		imethod := llvm.ConstNull(tm.runtime.imethod.llvm)
		name := tm.globalStringPtr(method.Name())
		name = llvm.ConstBitCast(name, tm.runtime.imethod.llvm.StructElementTypes()[0])
		mtyp := tm.ToRuntime(method.Type())
		imethod = llvm.ConstInsertValue(imethod, name, []uint32{0})
		if !ast.IsExported(method.Name()) {
			pkgpath := tm.globalStringPtr(method.Pkg().Path())
			pkgpath = llvm.ConstBitCast(pkgpath, tm.runtime.imethod.llvm.StructElementTypes()[1])
			imethod = llvm.ConstInsertValue(imethod, pkgpath, []uint32{1})
		}
		imethod = llvm.ConstInsertValue(imethod, mtyp, []uint32{2})
		imethods[index] = imethod
	}
	imethodsSliceType := tm.runtime.interfaceType.llvm.StructElementTypes()[1]
	imethodsSlice := tm.makeSlice(imethods, imethodsSliceType)
	interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1})
	global.SetInitializer(interfaceType)
	return global, ptr
}
Example #2
0
func (tm *TypeMap) nameRuntimeType(n *types.Named) (global, ptr llvm.Value) {
	name := typeString(n)
	path := "runtime"
	if pkg := n.Obj().Pkg(); pkg != nil {
		path = pkg.Path()
	}
	if path != tm.pkgpath {
		// We're not compiling the package from whence the type came,
		// so we'll just create a pointer to it here.
		global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(name))
		global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm))
		global.SetLinkage(llvm.CommonLinkage)
		return global, global
	}

	// If the underlying type is Basic, then we always create
	// a new global. Otherwise, we clone the value returned
	// from toRuntime in case it is cached and reused.
	underlying := n.Underlying()
	if basic, ok := underlying.(*types.Basic); ok {
		global, ptr = tm.basicRuntimeType(basic, true)
		global.SetName(typeSymbol(name))
	} else {
		global, ptr = tm.toRuntime(underlying)
		clone := llvm.AddGlobal(tm.module, global.Type().ElementType(), typeSymbol(name))
		clone.SetInitializer(global.Initializer())
		global = clone
		ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0))
	}
	global.SetLinkage(llvm.ExternalLinkage)

	// Locate the rtype.
	underlyingRuntimeType := global.Initializer()
	rtype := underlyingRuntimeType
	if rtype.Type() != tm.runtime.rtype.llvm {
		rtype = llvm.ConstExtractValue(rtype, []uint32{0})
	}

	// Insert the uncommon type.
	uncommonTypeInit := tm.uncommonType(n, nil)
	uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "")
	uncommonType.SetInitializer(uncommonTypeInit)
	rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9})

	// Replace the rtype's string representation with the one from
	// uncommonType. XXX should we have the package name prepended? Probably.
	namePtr := llvm.ConstExtractValue(uncommonTypeInit, []uint32{0})
	rtype = llvm.ConstInsertValue(rtype, namePtr, []uint32{8})

	// Update the global's initialiser. Note that we take a copy
	// of the underlying type; we're not updating a shared type.
	if underlyingRuntimeType.Type() != tm.runtime.rtype.llvm {
		underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, rtype, []uint32{0})
	} else {
		underlyingRuntimeType = rtype
	}
	global.SetInitializer(underlyingRuntimeType)
	return global, ptr
}
Example #3
0
func (tm *TypeMap) mapRuntimeType(m *types.Map) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(m, reflect.Map)
	mapType := llvm.ConstNull(tm.runtime.mapType.llvm)
	mapType = llvm.ConstInsertValue(mapType, rtype, []uint32{0})
	mapType = llvm.ConstInsertValue(mapType, tm.ToRuntime(m.Key()), []uint32{1})
	mapType = llvm.ConstInsertValue(mapType, tm.ToRuntime(m.Elem()), []uint32{2})
	return tm.makeRuntimeTypeGlobal(mapType, typeString(m))
}
Example #4
0
func (tm *TypeMap) sliceRuntimeType(s *types.Slice) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(s, reflect.Slice)
	sliceType := llvm.ConstNull(tm.runtime.sliceType.llvm)
	global, ptr = tm.makeRuntimeTypeGlobal(sliceType, typeString(s))
	tm.types.Set(s, runtimeTypeInfo{global, ptr})
	sliceType = llvm.ConstInsertValue(sliceType, rtype, []uint32{0})
	elemRuntimeType := tm.ToRuntime(s.Elem())
	sliceType = llvm.ConstInsertValue(sliceType, elemRuntimeType, []uint32{1})
	global.SetInitializer(sliceType)
	return global, ptr
}
Example #5
0
func (tm *TypeMap) arrayRuntimeType(a *types.Array) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(a, reflect.Array)
	elemRuntimeType := tm.ToRuntime(a.Elem())
	sliceRuntimeType := tm.ToRuntime(types.NewSlice(a.Elem()))
	uintptrlen := llvm.ConstInt(tm.target.IntPtrType(), uint64(a.Len()), false)
	arrayType := llvm.ConstNull(tm.runtime.arrayType.llvm)
	arrayType = llvm.ConstInsertValue(arrayType, rtype, []uint32{0})
	arrayType = llvm.ConstInsertValue(arrayType, elemRuntimeType, []uint32{1})
	arrayType = llvm.ConstInsertValue(arrayType, sliceRuntimeType, []uint32{2})
	arrayType = llvm.ConstInsertValue(arrayType, uintptrlen, []uint32{3})
	return tm.makeRuntimeTypeGlobal(arrayType, typeString(a))
}
Example #6
0
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
}
Example #7
0
func (tm *TypeMap) chanRuntimeType(c *types.Chan) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(c, reflect.Chan)
	chanType := llvm.ConstNull(tm.runtime.chanType.llvm)
	chanType = llvm.ConstInsertValue(chanType, rtype, []uint32{0})
	chanType = llvm.ConstInsertValue(chanType, tm.ToRuntime(c.Elem()), []uint32{1})

	// go/ast and reflect disagree on values for direction.
	var dir reflect.ChanDir
	switch c.Dir() {
	case types.SendOnly:
		dir = reflect.SendDir
	case types.RecvOnly:
		dir = reflect.RecvDir
	case types.SendRecv:
		dir = reflect.SendDir | reflect.RecvDir
	}
	uintptrdir := llvm.ConstInt(tm.target.IntPtrType(), uint64(dir), false)
	chanType = llvm.ConstInsertValue(chanType, uintptrdir, []uint32{2})
	return tm.makeRuntimeTypeGlobal(chanType, typeString(c))
}
Example #8
0
func (tm *TypeMap) funcRuntimeType(f *types.Signature) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(f, reflect.Func)
	funcType := llvm.ConstNull(tm.runtime.funcType.llvm)
	global, ptr = tm.makeRuntimeTypeGlobal(funcType, typeString(f))
	tm.types.Set(f, runtimeTypeInfo{global, ptr})
	funcType = llvm.ConstInsertValue(funcType, rtype, []uint32{0})
	// dotdotdot
	if f.Variadic() {
		variadic := llvm.ConstInt(llvm.Int1Type(), 1, false)
		funcType = llvm.ConstInsertValue(funcType, variadic, []uint32{1})
	}
	// in
	intypes := tm.rtypeSlice(f.Params())
	funcType = llvm.ConstInsertValue(funcType, intypes, []uint32{2})
	// out
	outtypes := tm.rtypeSlice(f.Results())
	funcType = llvm.ConstInsertValue(funcType, outtypes, []uint32{3})
	global.SetInitializer(funcType)
	return global, ptr
}
Example #9
0
func (tm *TypeMap) structRuntimeType(s *types.Struct) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(s, reflect.Struct)
	structType := llvm.ConstNull(tm.runtime.structType.llvm)
	structType = llvm.ConstInsertValue(structType, rtype, []uint32{0})
	global, ptr = tm.makeRuntimeTypeGlobal(structType, typeString(s))
	tm.types.Set(s, runtimeTypeInfo{global, ptr})
	fieldVars := make([]*types.Var, s.NumFields())
	for i := range fieldVars {
		fieldVars[i] = s.Field(i)
	}
	offsets := tm.Offsetsof(fieldVars)
	structFields := make([]llvm.Value, len(fieldVars))
	for i := range structFields {
		field := fieldVars[i]
		structField := llvm.ConstNull(tm.runtime.structField.llvm)
		if !field.Anonymous() {
			name := tm.globalStringPtr(field.Name())
			name = llvm.ConstBitCast(name, tm.runtime.structField.llvm.StructElementTypes()[0])
			structField = llvm.ConstInsertValue(structField, name, []uint32{0})
		}
		if !ast.IsExported(field.Name()) {
			pkgpath := tm.globalStringPtr(field.Pkg().Path())
			pkgpath = llvm.ConstBitCast(pkgpath, tm.runtime.structField.llvm.StructElementTypes()[1])
			structField = llvm.ConstInsertValue(structField, pkgpath, []uint32{1})
		}
		fieldType := tm.ToRuntime(field.Type())
		structField = llvm.ConstInsertValue(structField, fieldType, []uint32{2})
		if tag := s.Tag(i); tag != "" {
			tag := tm.globalStringPtr(tag)
			tag = llvm.ConstBitCast(tag, tm.runtime.structField.llvm.StructElementTypes()[3])
			structField = llvm.ConstInsertValue(structField, tag, []uint32{3})
		}
		offset := llvm.ConstInt(tm.runtime.structField.llvm.StructElementTypes()[4], uint64(offsets[i]), false)
		structField = llvm.ConstInsertValue(structField, offset, []uint32{4})
		structFields[i] = structField
	}
	structFieldsSliceType := tm.runtime.structType.llvm.StructElementTypes()[1]
	structFieldsSlice := tm.makeSlice(structFields, structFieldsSliceType)
	structType = llvm.ConstInsertValue(structType, structFieldsSlice, []uint32{1})
	global.SetInitializer(structType)
	return global, ptr
}
Example #10
0
func (tm *TypeMap) makeRtype(t types.Type, k reflect.Kind) llvm.Value {
	// Not sure if there's an easier way to do this, but if you just
	// use ConstStruct, you end up getting a different llvm.Type.
	typ := llvm.ConstNull(tm.runtime.rtype.llvm)
	elementTypes := tm.runtime.rtype.llvm.StructElementTypes()

	// Size.
	size := llvm.ConstInt(elementTypes[0], uint64(tm.Sizeof(t)), false)
	typ = llvm.ConstInsertValue(typ, size, []uint32{0})

	// TODO hash
	// TODO padding

	// Alignment.
	align := llvm.ConstInt(llvm.Int8Type(), uint64(tm.Alignof(t)), false)
	typ = llvm.ConstInsertValue(typ, align, []uint32{3}) // var
	typ = llvm.ConstInsertValue(typ, align, []uint32{4}) // field

	// Kind.
	kind := llvm.ConstInt(llvm.Int8Type(), uint64(k), false)
	typ = llvm.ConstInsertValue(typ, kind, []uint32{5})

	// Algorithm table.
	alg := tm.makeAlgorithmTable(t)
	algptr := llvm.AddGlobal(tm.module, alg.Type(), "")
	algptr.SetInitializer(alg)
	algptr = llvm.ConstBitCast(algptr, elementTypes[6])
	typ = llvm.ConstInsertValue(typ, algptr, []uint32{6})

	// String representation.
	stringrep := tm.globalStringPtr(t.String())
	typ = llvm.ConstInsertValue(typ, stringrep, []uint32{8})

	// TODO gc
	return typ
}
Example #11
0
// 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
}
Example #12
0
// p != nil iff we're generatig the uncommonType for a pointer type.
func (tm *TypeMap) uncommonType(n *types.Named, p *types.Pointer) llvm.Value {
	uncommonTypeInit := llvm.ConstNull(tm.runtime.uncommonType.llvm)
	namePtr := tm.globalStringPtr(n.Obj().Name())
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0})
	var path string
	if pkg := n.Obj().Pkg(); pkg != nil {
		path = pkg.Path()
	}
	pkgpathPtr := tm.globalStringPtr(path)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1})

	// If we're dealing with an interface, stop now;
	// we store interface methods on the interface
	// type.
	if _, ok := n.Underlying().(*types.Interface); ok {
		return uncommonTypeInit
	}

	var methodset, pmethodset *types.MethodSet
	if p != nil {
		methodset = tm.MethodSet(p)
	} else {
		methodset = tm.MethodSet(n)
	}

	// Store methods. All methods must be stored, not only exported ones;
	// this is to allow satisfying of interfaces with non-exported methods.
	methods := make([]llvm.Value, methodset.Len())
	for i := range methods {
		sel := methodset.At(i)
		mname := sel.Obj().Name()
		mfunc := tm.methodResolver.ResolveMethod(sel)
		ftyp := mfunc.Type().(*types.Signature)

		method := llvm.ConstNull(tm.runtime.method.llvm)
		name := tm.globalStringPtr(mname)
		name = llvm.ConstBitCast(name, tm.runtime.method.llvm.StructElementTypes()[0])
		// name
		method = llvm.ConstInsertValue(method, name, []uint32{0})
		// pkgPath
		method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1})
		// mtyp (method type, no receiver)
		{
			ftyp := types.NewSignature(nil, nil, ftyp.Params(), ftyp.Results(), ftyp.Variadic())
			mtyp := tm.ToRuntime(ftyp)
			method = llvm.ConstInsertValue(method, mtyp, []uint32{2})
		}
		// typ (function type, with receiver)
		typ := tm.ToRuntime(ftyp)
		method = llvm.ConstInsertValue(method, typ, []uint32{3})

		// tfn (standard method/function pointer for plain method calls)
		tfn := llvm.ConstPtrToInt(mfunc.LLVMValue(), tm.target.IntPtrType())

		// ifn (single-word receiver function pointer for interface calls)
		ifn := tfn
		if p == nil {
			if tm.Sizeof(n) > int64(tm.target.PointerSize()) {
				if pmethodset == nil {
					pmethodset = tm.MethodSet(types.NewPointer(n))
				}
				pmfunc := tm.methodResolver.ResolveMethod(pmethodset.Lookup(sel.Obj().Pkg(), mname))
				ifn = llvm.ConstPtrToInt(pmfunc.LLVMValue(), tm.target.IntPtrType())
			} else if _, ok := n.Underlying().(*types.Pointer); !ok {
				// Create a wrapper function that takes an *int8,
				// and coerces to the receiver type.
				ifn = tm.interfaceFuncWrapper(mfunc.LLVMValue())
				ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType())
			}
		}

		method = llvm.ConstInsertValue(method, ifn, []uint32{4})
		method = llvm.ConstInsertValue(method, tfn, []uint32{5})
		methods[i] = method
	}
	methodsSliceType := tm.runtime.uncommonType.llvm.StructElementTypes()[2]
	methodsSlice := tm.makeSlice(methods, methodsSliceType)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2})
	return uncommonTypeInit
}
Example #13
0
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
}
Example #14
0
File: value.go Project: 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))
}
Example #15
0
File: ssa.go Project: rvedam/llgo
// prepareCall returns the evaluated function and arguments.
//
// For builtins that may not be used in go/defer, prepareCall
// will emits inline code. In this case, prepareCall returns
// nil for fn and args, and returns a non-nil value for result.
func (fr *frame) prepareCall(instr ssa.CallInstruction) (fn *LLVMValue, args []*LLVMValue, result *LLVMValue) {
	call := instr.Common()
	args = make([]*LLVMValue, len(call.Args))
	for i, arg := range call.Args {
		args[i] = fr.value(arg)
	}

	if call.IsInvoke() {
		fn := fr.interfaceMethod(fr.value(call.Value), call.Method)
		return fn, args, nil
	}

	switch v := call.Value.(type) {
	case *ssa.Builtin:
		// handled below
	case *ssa.Function:
		// Function handled specially; value() will convert
		// a function to one with a context argument.
		fn = fr.resolveFunction(v)
		pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(fn.Type()))
		pair = llvm.ConstInsertValue(pair, fn.LLVMValue(), []uint32{0})
		fn = fr.NewValue(pair, fn.Type())
		return fn, args, nil
	default:
		fn = fr.value(call.Value)
		return fn, args, nil
	}

	// Builtins may only be used in calls (i.e. can't be assigned),
	// and only print[ln], panic and recover may be used in go/defer.
	builtin := call.Value.(*ssa.Builtin)
	switch builtin.Name() {
	case "print", "println":
		// print/println generates a call-site specific anonymous
		// function to print the values. It's not inline because
		// print/println may be deferred.
		params := make([]*types.Var, len(call.Args))
		for i, arg := range call.Args {
			// make sure to use args[i].Type(), not call.Args[i].Type(),
			// as the evaluated expression converts untyped.
			params[i] = types.NewParam(arg.Pos(), nil, arg.Name(), args[i].Type())
		}
		sig := types.NewSignature(nil, nil, types.NewTuple(params...), nil, false)
		llfntyp := fr.llvmtypes.ToLLVM(sig)
		llfnptr := llvm.AddFunction(fr.module.Module, "", llfntyp.StructElementTypes()[0].ElementType())
		currBlock := fr.builder.GetInsertBlock()
		entry := llvm.AddBasicBlock(llfnptr, "entry")
		fr.builder.SetInsertPointAtEnd(entry)
		internalArgs := make([]Value, len(args))
		for i, arg := range args {
			internalArgs[i] = fr.NewValue(llfnptr.Param(i), arg.Type())
		}
		fr.printValues(builtin.Name() == "println", internalArgs...)
		fr.builder.CreateRetVoid()
		fr.builder.SetInsertPointAtEnd(currBlock)
		return fr.NewValue(llfnptr, sig), args, nil

	case "panic":
		panic("TODO: panic")

	case "recover":
		// TODO(axw) determine number of frames to skip in pc check
		indirect := fr.NewValue(llvm.ConstNull(llvm.Int32Type()), types.Typ[types.Int32])
		return fr.runtime.recover_, []*LLVMValue{indirect}, nil

	case "append":
		return nil, nil, fr.callAppend(args[0], args[1])

	case "close":
		return fr.runtime.chanclose, args, nil

	case "cap":
		return nil, nil, fr.callCap(args[0])

	case "len":
		return nil, nil, fr.callLen(args[0])

	case "copy":
		return nil, nil, fr.callCopy(args[0], args[1])

	case "delete":
		fr.callDelete(args[0], args[1])
		return nil, nil, nil

	case "real":
		return nil, nil, args[0].extractComplexComponent(0)

	case "imag":
		return nil, nil, args[0].extractComplexComponent(1)

	case "complex":
		r := args[0].LLVMValue()
		i := args[1].LLVMValue()
		typ := instr.Value().Type()
		cmplx := llvm.Undef(fr.llvmtypes.ToLLVM(typ))
		cmplx = fr.builder.CreateInsertValue(cmplx, r, 0, "")
		cmplx = fr.builder.CreateInsertValue(cmplx, i, 1, "")
		return nil, nil, fr.NewValue(cmplx, typ)

	default:
		panic("unimplemented: " + builtin.Name())
	}
}
Example #16
0
File: ssa.go Project: rvedam/llgo
func (fr *frame) value(v ssa.Value) (result *LLVMValue) {
	switch v := v.(type) {
	case nil:
		return nil
	case *ssa.Function:
		result, ok := fr.funcvals[v]
		if ok {
			return result
		}
		// fr.globals[v] has the function in raw pointer form;
		// we must convert it to <f,ctx> form. If the function
		// does not have a receiver, then create a wrapper
		// function that has an additional "context" parameter.
		f := fr.resolveFunction(v)
		if v.Signature.Recv() == nil && len(v.FreeVars) == 0 {
			f = contextFunction(fr.compiler, f)
		}
		pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(f.Type()))
		fnptr := llvm.ConstBitCast(f.LLVMValue(), pair.Type().StructElementTypes()[0])
		pair = llvm.ConstInsertValue(pair, fnptr, []uint32{0})
		result = fr.NewValue(pair, f.Type())
		fr.funcvals[v] = result
		return result
	case *ssa.Const:
		return fr.NewConstValue(v.Value, v.Type())
	case *ssa.Global:
		if g, ok := fr.globals[v]; ok {
			return g
		}
		// Create an external global. Globals for this package are defined
		// on entry to translatePackage, and have initialisers.
		llelemtyp := fr.llvmtypes.ToLLVM(deref(v.Type()))
		llglobal := llvm.AddGlobal(fr.module.Module, llelemtyp, v.String())
		global := fr.NewValue(llglobal, v.Type())
		fr.globals[v] = global
		return global
	}
	if value, ok := fr.env[v]; ok {
		return value
	}

	// Instructions are not necessarily visited before they are used (e.g. Phi
	// edges) so we must "backpatch": create a value with the resultant type,
	// and then replace it when we visit the instruction.
	if b, ok := fr.backpatch[v]; ok {
		return b
	}
	if fr.backpatch == nil {
		fr.backpatch = make(map[ssa.Value]*LLVMValue)
	}
	// Note: we must not create a constant here (e.g. Undef/ConstNull), as
	// it is not permissible to replace a constant with a non-constant.
	// We must create the value in its own standalone basic block, so we can
	// dispose of it after replacing.
	currBlock := fr.builder.GetInsertBlock()
	fr.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(currBlock.Parent(), ""))
	placeholder := fr.compiler.builder.CreatePHI(fr.llvmtypes.ToLLVM(v.Type()), "")
	fr.builder.SetInsertPointAtEnd(currBlock)
	value := fr.NewValue(placeholder, v.Type())
	fr.backpatch[v] = value
	return value
}