Beispiel #1
0
func NewTypeMap(llvmtm *LLVMTypeMap, module llvm.Module, pkgpath string, exprTypes map[ast.Expr]types.Type, c *FunctionCache, r Resolver) *TypeMap {
	tm := &TypeMap{
		LLVMTypeMap: llvmtm,
		module:      module,
		pkgpath:     pkgpath,
		types:       make(map[string]runtimeTypeInfo),
		expr:        exprTypes,
		functions:   c,
		resolver:    r,
	}

	// Load runtime/reflect types, and generate LLVM types for
	// the structures we need to populate runtime type information.
	pkg, err := c.compiler.parseReflect()
	if err != nil {
		panic(err) // FIXME return err
	}
	reflectLLVMType := func(name string) llvm.Type {
		obj := pkg.Scope.Lookup(name)
		if obj == nil {
			panic(fmt.Errorf("Failed to find type: %s", name))
		}
		return tm.ToLLVM(obj.Type.(types.Type))
	}
	tm.runtimeType = reflectLLVMType("runtimeType")
	tm.runtimeCommonType = reflectLLVMType("commonType")
	tm.runtimeUncommonType = reflectLLVMType("uncommonType")
	tm.runtimeArrayType = reflectLLVMType("arrayType")
	tm.runtimeChanType = reflectLLVMType("chanType")
	tm.runtimeFuncType = reflectLLVMType("funcType")
	tm.runtimeMethod = reflectLLVMType("method")
	tm.runtimeImethod = reflectLLVMType("imethod")
	tm.runtimeInterfaceType = reflectLLVMType("interfaceType")
	tm.runtimeMapType = reflectLLVMType("mapType")
	tm.runtimePtrType = reflectLLVMType("ptrType")
	tm.runtimeSliceType = reflectLLVMType("sliceType")
	tm.runtimeStructType = reflectLLVMType("structType")
	tm.commonType = pkg.Scope.Lookup("commonType").Type.(*types.Name)

	// Types for algorithms. See 'runtime/runtime.h'.
	uintptrType := tm.target.IntPtrType()
	voidPtrType := llvm.PointerType(llvm.Int8Type(), 0)
	boolType := llvm.Int1Type()

	// Create runtime algorithm function types.
	params := []llvm.Type{uintptrType, voidPtrType}
	tm.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false)
	params = []llvm.Type{uintptrType, uintptrType, uintptrType}
	tm.equalAlgFunctionType = llvm.FunctionType(boolType, params, false)
	params = []llvm.Type{uintptrType, voidPtrType}
	tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)
	params = []llvm.Type{uintptrType, voidPtrType, voidPtrType}
	tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)

	return tm
}
Beispiel #2
0
func NewTypeMap(llvmtm *LLVMTypeMap, pkgpath string, exprTypes map[ast.Expr]types.Type, c *FunctionCache, p map[*ast.Object]string, r Resolver) *TypeMap {
	tm := &TypeMap{
		LLVMTypeMap: llvmtm,
		pkgpath:     pkgpath,
		types:       make(map[types.Type]llvm.Value),
		expr:        exprTypes,
		pkgmap:      p,
		functions:   c,
		resolver:    r,
	}

	// Load "reflect.go", and generate LLVM types for the runtime type
	// structures.
	pkg, err := parseReflect()
	if err != nil {
		panic(err) // FIXME return err
	}
	objToLLVMType := func(name string) llvm.Type {
		obj := pkg.Scope.Lookup(name)
		return tm.ToLLVM(obj.Type.(types.Type))
	}
	tm.runtimeType = objToLLVMType("runtimeType")
	tm.runtimeCommonType = objToLLVMType("commonType")
	tm.runtimeUncommonType = objToLLVMType("uncommonType")
	tm.runtimeArrayType = objToLLVMType("arrayType")
	tm.runtimeChanType = objToLLVMType("chanType")
	tm.runtimeFuncType = objToLLVMType("funcType")
	tm.runtimeMethod = objToLLVMType("method")
	tm.runtimeImethod = objToLLVMType("imethod")
	tm.runtimeInterfaceType = objToLLVMType("interfaceType")
	tm.runtimeMapType = objToLLVMType("mapType")
	tm.runtimePtrType = objToLLVMType("ptrType")
	tm.runtimeSliceType = objToLLVMType("sliceType")
	tm.runtimeStructType = objToLLVMType("structType")

	// Types for algorithms. See 'runtime/runtime.h'.
	uintptrType := tm.target.IntPtrType()
	voidPtrType := llvm.PointerType(llvm.Int8Type(), 0)
	boolType := llvm.Int1Type()

	// Create runtime algorithm function types.
	params := []llvm.Type{uintptrType, voidPtrType}
	tm.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false)
	params = []llvm.Type{uintptrType, uintptrType, uintptrType}
	tm.equalAlgFunctionType = llvm.FunctionType(boolType, params, false)
	params = []llvm.Type{uintptrType, voidPtrType}
	tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)
	params = []llvm.Type{uintptrType, voidPtrType, voidPtrType}
	tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)

	return tm
}
Beispiel #3
0
func getnewgoroutine(module llvm.Module) llvm.Value {
	fn := module.NamedFunction("llgo_newgoroutine")
	if fn.IsNil() {
		i8Ptr := llvm.PointerType(llvm.Int8Type(), 0)
		VoidFnPtr := llvm.PointerType(llvm.FunctionType(
			llvm.VoidType(), []llvm.Type{i8Ptr}, false), 0)
		i32 := llvm.Int32Type()
		fn_type := llvm.FunctionType(
			llvm.VoidType(), []llvm.Type{VoidFnPtr, i8Ptr, i32}, true)
		fn = llvm.AddFunction(module, "llgo_newgoroutine", fn_type)
		fn.SetFunctionCallConv(llvm.CCallConv)
	}
	return fn
}
Beispiel #4
0
func (c *compiler) defineMemcpyFunction(fn llvm.Value) {
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	dst, src, size := fn.Param(0), fn.Param(1), fn.Param(2)

	pint8 := llvm.PointerType(llvm.Int8Type(), 0)
	dst = c.builder.CreateIntToPtr(dst, pint8, "")
	src = c.builder.CreateIntToPtr(src, pint8, "")

	sizeType := size.Type()
	sizeBits := sizeType.IntTypeWidth()
	memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(sizeBits)
	memcpy := c.module.NamedFunction(memcpyName)
	if memcpy.IsNil() {
		paramtypes := []llvm.Type{
			pint8, pint8, size.Type(), llvm.Int32Type(), llvm.Int1Type()}
		memcpyType := llvm.FunctionType(llvm.VoidType(), paramtypes, false)
		memcpy = llvm.AddFunction(c.module.Module, memcpyName, memcpyType)
	}

	args := []llvm.Value{
		dst, src, size,
		llvm.ConstInt(llvm.Int32Type(), 1, false), // single byte alignment
		llvm.ConstInt(llvm.Int1Type(), 0, false),  // not volatile
	}
	c.builder.CreateCall(memcpy, args, "")
	c.builder.CreateRetVoid()
}
Beispiel #5
0
func (tm *TypeMap) funcLLVMType(f *types.Func) llvm.Type {
	param_types := make([]llvm.Type, 0)

	// Add receiver parameter.
	if f.Recv != nil {
		recv_type := f.Recv.Type.(types.Type)
		param_types = append(param_types, tm.ToLLVM(recv_type))
	}

	for _, param := range f.Params {
		param_type := param.Type.(types.Type)
		param_types = append(param_types, tm.ToLLVM(param_type))
	}

	var return_type llvm.Type
	switch len(f.Results) {
	case 0:
		return_type = llvm.VoidType()
	case 1:
		return_type = tm.ToLLVM(f.Results[0].Type.(types.Type))
	default:
		elements := make([]llvm.Type, len(f.Results))
		for i, result := range f.Results {
			elements[i] = tm.ToLLVM(result.Type.(types.Type))
		}
		return_type = llvm.StructType(elements, false)
	}

	fn_type := llvm.FunctionType(return_type, param_types, false)
	return llvm.PointerType(fn_type, 0)
}
Beispiel #6
0
func NewTypeMap(module llvm.Module, target llvm.TargetData, exprTypes map[ast.Expr]types.Type) *TypeMap {
	tm := &TypeMap{module: module, target: target, expr: exprTypes}
	tm.types = make(map[types.Type]llvm.Type)
	tm.runtime = make(map[types.Type]llvm.Value)

	// Load "reflect.go", and generate LLVM types for the runtime type
	// structures.
	pkg, err := parseReflect()
	if err != nil {
		panic(err) // FIXME return err
	}
	objToLLVMType := func(name string) llvm.Type {
		obj := pkg.Scope.Lookup(name)
		return tm.ToLLVM(obj.Type.(types.Type))
	}
	tm.runtimeCommonType = objToLLVMType("commonType")
	tm.runtimeUncommonType = objToLLVMType("uncommonType")
	tm.runtimeArrayType = objToLLVMType("arrayType")
	tm.runtimeChanType = objToLLVMType("chanType")
	tm.runtimeFuncType = objToLLVMType("funcType")
	tm.runtimeInterfaceType = objToLLVMType("interfaceType")
	tm.runtimeMapType = objToLLVMType("mapType")
	tm.runtimePtrType = objToLLVMType("ptrType")
	tm.runtimeSliceType = objToLLVMType("sliceType")
	tm.runtimeStructType = objToLLVMType("structType")

	// Types for algorithms. See 'runtime/runtime.h'.
	uintptrType := tm.target.IntPtrType()
	voidPtrType := llvm.PointerType(llvm.Int8Type(), 0)
	boolType := llvm.Int1Type()

	// Create runtime algorithm function types.
	params := []llvm.Type{
		llvm.PointerType(uintptrType, 0), uintptrType, voidPtrType}
	tm.hashAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)
	params = []llvm.Type{
		llvm.PointerType(boolType, 0), uintptrType, voidPtrType, voidPtrType}
	tm.equalAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)
	params = []llvm.Type{uintptrType, voidPtrType}
	tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)
	params = []llvm.Type{uintptrType, voidPtrType, voidPtrType}
	tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)

	return tm
}
Beispiel #7
0
func (tm *LLVMTypeMap) funcLLVMType(tstr string, f *types.Signature) llvm.Type {
	typ, ok := tm.types[tstr]
	if !ok {
		// If there's a receiver change the receiver to an
		// additional (first) parameter, and take the value of
		// the resulting signature instead.
		var param_types []llvm.Type
		if recv := f.Recv(); recv != nil {
			params := f.Params()
			paramvars := make([]*types.Var, int(params.Len()+1))
			paramvars[0] = recv
			for i := 0; i < int(params.Len()); i++ {
				paramvars[i+1] = params.At(i)
			}
			params = types.NewTuple(paramvars...)
			f := types.NewSignature(nil, params, f.Results(), f.IsVariadic())
			return tm.ToLLVM(f)
		}

		typ = llvm.GlobalContext().StructCreateNamed("")
		tm.types[tstr] = typ

		params := f.Params()
		nparams := int(params.Len())
		for i := 0; i < nparams; i++ {
			typ := params.At(i).Type()
			if f.IsVariadic() && i == nparams-1 {
				typ = types.NewSlice(typ)
			}
			llvmtyp := tm.ToLLVM(typ)
			param_types = append(param_types, llvmtyp)
		}

		var return_type llvm.Type
		results := f.Results()
		switch nresults := int(results.Len()); nresults {
		case 0:
			return_type = llvm.VoidType()
		case 1:
			return_type = tm.ToLLVM(results.At(0).Type())
		default:
			elements := make([]llvm.Type, nresults)
			for i := range elements {
				result := results.At(i)
				elements[i] = tm.ToLLVM(result.Type())
			}
			return_type = llvm.StructType(elements, false)
		}

		fntyp := llvm.FunctionType(return_type, param_types, false)
		fnptrtyp := llvm.PointerType(fntyp, 0)
		i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
		elements := []llvm.Type{fnptrtyp, i8ptr} // func, closure
		typ.StructSetBody(elements, false)
	}
	return typ
}
Beispiel #8
0
Datei: alg.go Projekt: minux/llgo
func newAlgorithmMap(m llvm.Module, runtime *runtimeInterface, target llvm.TargetData) *algorithmMap {
	am := &algorithmMap{
		module:  m,
		runtime: runtime,
	}
	uintptrType := target.IntPtrType()
	voidPtrType := llvm.PointerType(llvm.Int8Type(), 0)
	boolType := llvm.Int1Type()
	params := []llvm.Type{uintptrType, voidPtrType}
	am.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false)
	params = []llvm.Type{uintptrType, uintptrType, uintptrType}
	am.equalAlgFunctionType = llvm.FunctionType(boolType, params, false)
	params = []llvm.Type{uintptrType, voidPtrType}
	am.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)
	params = []llvm.Type{uintptrType, voidPtrType, voidPtrType}
	am.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false)
	return am
}
Beispiel #9
0
func (tm *llvmTypeMap) funcLLVMType(f *types.Signature, name string) llvm.Type {
	// If there's a receiver change the receiver to an
	// additional (first) parameter, and take the value of
	// the resulting signature instead.
	if recv := f.Recv(); recv != nil {
		params := f.Params()
		paramvars := make([]*types.Var, int(params.Len()+1))
		paramvars[0] = recv
		for i := 0; i < int(params.Len()); i++ {
			paramvars[i+1] = params.At(i)
		}
		params = types.NewTuple(paramvars...)
		f := types.NewSignature(nil, nil, params, f.Results(), f.Variadic())
		return tm.toLLVM(f, name)
	}

	if typ, ok := tm.types.At(f).(llvm.Type); ok {
		return typ
	}
	typ := llvm.GlobalContext().StructCreateNamed(name)
	tm.types.Set(f, typ)

	params := f.Params()
	param_types := make([]llvm.Type, params.Len())
	for i := range param_types {
		llvmtyp := tm.ToLLVM(params.At(i).Type())
		param_types[i] = llvmtyp
	}

	var return_type llvm.Type
	results := f.Results()
	switch nresults := int(results.Len()); nresults {
	case 0:
		return_type = llvm.VoidType()
	case 1:
		return_type = tm.ToLLVM(results.At(0).Type())
	default:
		elements := make([]llvm.Type, nresults)
		for i := range elements {
			result := results.At(i)
			elements[i] = tm.ToLLVM(result.Type())
		}
		return_type = llvm.StructType(elements, false)
	}

	fntyp := llvm.FunctionType(return_type, param_types, false)
	fnptrtyp := llvm.PointerType(fntyp, 0)
	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	elements := []llvm.Type{fnptrtyp, i8ptr} // func, closure
	typ.StructSetBody(elements, false)
	return typ
}
Beispiel #10
0
func (c *compiler) createMainFunction() error {
	// In a PNaCl program (plugin), there should not be a "main.main";
	// instead, we expect a "main.CreateModule" function.
	// See pkg/nacl/ppapi/ppapi.go for more details.
	mainMain := c.module.NamedFunction("main.main")
	if c.pnacl {
		// PNaCl's libppapi_stub.a implements "main", which simply
		// calls through to PpapiPluginMain. We define our own "main"
		// so that we can capture argc/argv.
		if !mainMain.IsNil() {
			return fmt.Errorf("Found main.main")
		}
		pluginMain := c.NamedFunction("PpapiPluginMain", "func() int32")

		// Synthesise a main which has no return value. We could cast
		// PpapiPluginMain, but this is potentially unsafe as its
		// calling convention is unspecified.
		ftyp := llvm.FunctionType(llvm.VoidType(), nil, false)
		mainMain = llvm.AddFunction(c.module.Module, "main.main", ftyp)
		entry := llvm.AddBasicBlock(mainMain, "entry")
		c.builder.SetInsertPointAtEnd(entry)
		c.builder.CreateCall(pluginMain, nil, "")
		c.builder.CreateRetVoid()
	} else {
		mainMain = c.module.NamedFunction("main.main")
	}

	if mainMain.IsNil() {
		return fmt.Errorf("Could not find main.main")
	}

	// runtime.main is called by main, with argc, argv, argp,
	// and a pointer to main.main, which must be a niladic
	// function with no result.
	runtimeMain := c.NamedFunction("runtime.main", "func(int32, **byte, **byte, *int8) int32")
	main := c.NamedFunction("main", "func(int32, **byte, **byte) int32")
	c.builder.SetCurrentDebugLocation(c.debug_info.MDNode(nil))
	entry := llvm.AddBasicBlock(main, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	mainMain = c.builder.CreateBitCast(mainMain, runtimeMain.Type().ElementType().ParamTypes()[3], "")
	args := []llvm.Value{main.Param(0), main.Param(1), main.Param(2), mainMain}
	result := c.builder.CreateCall(runtimeMain, args, "")
	c.builder.CreateRet(result)
	return nil
}
Beispiel #11
0
// indirectFunction creates an indirect function from a
// given function, suitable for use with "defer" and "go".
func (c *compiler) indirectFunction(fn *LLVMValue, args []Value, dotdotdot bool) *LLVMValue {
	nilarytyp := &types.Signature{}
	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, "")
		fn = c.NewValue(fnval, nilarytyp)
		return fn
	}

	// TODO check if function pointer is global. I suppose
	// the same can be done with the context ptr...
	fnval := fn.LLVMValue()
	fnptr := c.builder.CreateExtractValue(fnval, 0, "")
	ctx := c.builder.CreateExtractValue(fnval, 1, "")
	nctx := 1 // fnptr
	if !ctx.IsNull() {
		nctx++ // fnctx
	}

	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()
	}
	llvmargtypes[0] = fnptr.Type()
	llvmargs[0] = fnptr
	if nctx > 1 {
		llvmargtypes[1] = ctx.Type()
		llvmargs[1] = ctx
	}

	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)
	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)}, "")
		ptrtyp := types.NewPointer(args[i].Type())
		args[i] = c.NewValue(argptr, ptrtyp).makePointee()
	}

	// Extract the function pointer.
	// TODO if function is a global, elide.
	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 nctx > 1 {
		ctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), 1, false)}, "")
		ctx = c.builder.CreateLoad(ctxptr, "")
		fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "")
		fn = c.NewValue(fnval, fn.Type())
	}
	c.createCall(fn, args, dotdotdot, false)

	// 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
}
Beispiel #12
0
func (c *compiler) VisitGoStmt(stmt *ast.GoStmt) {
	//stmt.Call *ast.CallExpr
	// TODO
	var fn *LLVMValue
	switch x := (stmt.Call.Fun).(type) {
	case *ast.Ident:
		fn = c.Resolve(x.Obj).(*LLVMValue)
		if fn == nil {
			panic(fmt.Sprintf(
				"No function found with name '%s'", x.String()))
		}
	default:
		fn = c.VisitExpr(stmt.Call.Fun).(*LLVMValue)
	}

	// Evaluate arguments, store in a structure on the stack.
	var args_struct_type llvm.Type
	var args_mem llvm.Value
	var args_size llvm.Value
	if stmt.Call.Args != nil {
		param_types := make([]llvm.Type, 0)
		fn_type := types.Deref(fn.Type()).(*types.Func)
		for _, param := range fn_type.Params {
			typ := param.Type.(types.Type)
			param_types = append(param_types, c.types.ToLLVM(typ))
		}
		args_struct_type = llvm.StructType(param_types, false)
		args_mem = c.builder.CreateAlloca(args_struct_type, "")
		for i, expr := range stmt.Call.Args {
			value_i := c.VisitExpr(expr)
			value_i = value_i.Convert(fn_type.Params[i].Type.(types.Type))
			arg_i := c.builder.CreateGEP(args_mem, []llvm.Value{
				llvm.ConstInt(llvm.Int32Type(), 0, false),
				llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "")
			c.builder.CreateStore(value_i.LLVMValue(), arg_i)
		}
		args_size = llvm.SizeOf(args_struct_type)
		args_size = llvm.ConstTrunc(args_size, llvm.Int32Type())
	} else {
		args_struct_type = llvm.VoidType()
		args_mem = llvm.ConstNull(llvm.PointerType(args_struct_type, 0))
		args_size = llvm.ConstInt(llvm.Int32Type(), 0, false)
	}

	// When done, return to where we were.
	defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock())

	// 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.
	indirect_fn_type := llvm.FunctionType(
		llvm.VoidType(),
		[]llvm.Type{llvm.PointerType(args_struct_type, 0)}, false)
	indirect_fn := llvm.AddFunction(c.module.Module, "", indirect_fn_type)
	indirect_fn.SetFunctionCallConv(llvm.CCallConv)

	// Call "newgoroutine" with the indirect function and stored args.
	newgoroutine := getnewgoroutine(c.module.Module)
	ngr_param_types := newgoroutine.Type().ElementType().ParamTypes()
	fn_arg := c.builder.CreateBitCast(indirect_fn, ngr_param_types[0], "")
	args_arg := c.builder.CreateBitCast(args_mem,
		llvm.PointerType(llvm.Int8Type(), 0), "")
	c.builder.CreateCall(newgoroutine,
		[]llvm.Value{fn_arg, args_arg, args_size}, "")

	entry := llvm.AddBasicBlock(indirect_fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	var args []llvm.Value
	if stmt.Call.Args != nil {
		args_mem = indirect_fn.Param(0)
		args = make([]llvm.Value, len(stmt.Call.Args))
		for i := range stmt.Call.Args {
			arg_i := c.builder.CreateGEP(args_mem, []llvm.Value{
				llvm.ConstInt(llvm.Int32Type(), 0, false),
				llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "")
			args[i] = c.builder.CreateLoad(arg_i, "")
		}
	}
	c.builder.CreateCall(fn.LLVMValue(), args, "")
	c.builder.CreateRetVoid()
}
Beispiel #13
0
func (compiler *compiler) Compile(fset *token.FileSet,
	pkg *ast.Package,
	exprTypes map[ast.Expr]types.Type) (m *Module, err error) {
	// FIXME create a compilation state, rather than storing in 'compiler'.
	compiler.fileset = fset
	compiler.pkg = pkg
	compiler.initfuncs = make([]Value, 0)

	// Create a Builder, for building LLVM instructions.
	compiler.builder = llvm.GlobalContext().NewBuilder()
	defer compiler.builder.Dispose()

	// Create a TargetMachine from the OS & Arch.
	triple := fmt.Sprintf("%s-unknown-%s",
		getTripleArchName(compiler.targetArch),
		compiler.targetOs)
	var machine llvm.TargetMachine
	for target := llvm.FirstTarget(); target.C != nil && machine.C == nil; target = target.NextTarget() {
		if target.Name() == compiler.targetArch {
			machine = target.CreateTargetMachine(triple, "", "",
				llvm.CodeGenLevelDefault,
				llvm.RelocDefault,
				llvm.CodeModelDefault)
			defer machine.Dispose()
		}
	}

	if machine.C == nil {
		err = fmt.Errorf("Invalid target triple: %s", triple)
		return
	}

	// Create a Module, which contains the LLVM bitcode. Dispose it on panic,
	// otherwise we'll set a finalizer at the end. The caller may invoke
	// Dispose manually, which will render the finalizer a no-op.
	modulename := pkg.Name
	compiler.target = machine.TargetData()
	compiler.module = &Module{llvm.NewModule(modulename), modulename, false}
	compiler.module.SetTarget(triple)
	compiler.module.SetDataLayout(compiler.target.String())
	defer func() {
		if e := recover(); e != nil {
			compiler.module.Dispose()
			panic(e)
			//err = e.(error)
		}
	}()
	compiler.types = NewTypeMap(compiler.module.Module, compiler.target, exprTypes)

	// Create a mapping from objects back to packages, so we can create the
	// appropriate symbol names.
	compiler.pkgmap = createPackageMap(pkg)

	// Compile each file in the package.
	for _, file := range pkg.Files {
		file.Scope.Outer = pkg.Scope
		compiler.filescope = file.Scope
		compiler.scope = file.Scope
		compiler.fixConstDecls(file)
		for _, decl := range file.Decls {
			compiler.VisitDecl(decl)
		}
	}

	// Define intrinsics for use by the runtime: malloc, free, memcpy, etc.
	compiler.defineRuntimeIntrinsics()

	// Create global constructors.
	//
	// XXX When imports are handled, we'll need to defer creating
	//     llvm.global_ctors until we create an executable. This is
	//     due to (a) imports having to be initialised before the
	//     importer, and (b) LLVM having no specified order of
	//     initialisation for ctors with the same priority.
	if len(compiler.initfuncs) > 0 {
		elttypes := []llvm.Type{
			llvm.Int32Type(),
			llvm.PointerType(
				llvm.FunctionType(llvm.VoidType(), nil, false), 0)}
		ctortype := llvm.StructType(elttypes, false)
		ctors := make([]llvm.Value, len(compiler.initfuncs))
		for i, fn := range compiler.initfuncs {
			struct_values := []llvm.Value{
				llvm.ConstInt(llvm.Int32Type(), 1, false),
				fn.LLVMValue()}
			ctors[i] = llvm.ConstStruct(struct_values, false)
		}

		global_ctors_init := llvm.ConstArray(ctortype, ctors)
		global_ctors_var := llvm.AddGlobal(
			compiler.module.Module, global_ctors_init.Type(),
			"llvm.global_ctors")
		global_ctors_var.SetInitializer(global_ctors_init)
		global_ctors_var.SetLinkage(llvm.AppendingLinkage)
	}

	// Create debug metadata.
	compiler.createMetadata()

	return compiler.module, nil
}
Beispiel #14
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
}
Beispiel #15
0
func (compiler *compiler) Compile(fset *token.FileSet,
	pkg *ast.Package, importpath string,
	exprTypes map[ast.Expr]types.Type) (m *Module, err error) {
	// FIXME create a compilation state, rather than storing in 'compiler'.
	compiler.fileset = fset
	compiler.pkg = pkg
	compiler.importpath = importpath
	compiler.initfuncs = nil
	compiler.varinitfuncs = nil

	// Create a Builder, for building LLVM instructions.
	compiler.builder = llvm.GlobalContext().NewBuilder()
	defer compiler.builder.Dispose()

	// Create a TargetMachine from the OS & Arch.
	triple := compiler.GetTargetTriple()
	var machine llvm.TargetMachine
	for target := llvm.FirstTarget(); target.C != nil && machine.C == nil; target = target.NextTarget() {
		if target.Name() == compiler.targetArch {
			machine = target.CreateTargetMachine(triple, "", "",
				llvm.CodeGenLevelDefault,
				llvm.RelocDefault,
				llvm.CodeModelDefault)
			defer machine.Dispose()
		}
	}

	if machine.C == nil {
		err = fmt.Errorf("Invalid target triple: %s", triple)
		return
	}

	// Create a Module, which contains the LLVM bitcode. Dispose it on panic,
	// otherwise we'll set a finalizer at the end. The caller may invoke
	// Dispose manually, which will render the finalizer a no-op.
	modulename := pkg.Name
	compiler.target = machine.TargetData()
	compiler.module = &Module{llvm.NewModule(modulename), modulename, false}
	compiler.module.SetTarget(triple)
	compiler.module.SetDataLayout(compiler.target.String())
	defer func() {
		if e := recover(); e != nil {
			compiler.module.Dispose()
			panic(e)
			//err = e.(error)
		}
	}()

	// Create a mapping from objects back to packages, so we can create the
	// appropriate symbol names.
	compiler.pkgmap = createPackageMap(pkg, importpath)

	// Create a struct responsible for mapping static types to LLVM types,
	// and to runtime/dynamic type values.
	var resolver Resolver = compiler
	llvmtypemap := NewLLVMTypeMap(compiler.module.Module, compiler.target)
	compiler.FunctionCache = NewFunctionCache(compiler)
	compiler.types = NewTypeMap(llvmtypemap, importpath, exprTypes, compiler.FunctionCache, compiler.pkgmap, resolver)

	// Compile each file in the package.
	for _, file := range pkg.Files {
		file.Scope.Outer = pkg.Scope
		compiler.filescope = file.Scope
		compiler.scope = file.Scope
		compiler.fixConstDecls(file)
		for _, decl := range file.Decls {
			compiler.VisitDecl(decl)
		}
	}

	// Define intrinsics for use by the runtime: malloc, free, memcpy, etc.
	// These could be defined in LLVM IR, and may be moved there later.
	if pkg.Name == "runtime" {
		compiler.defineRuntimeIntrinsics()
	}

	// Export runtime type information.
	if pkg.Name == "runtime" {
		compiler.exportBuiltinRuntimeTypes()
	}

	// Create global constructors.
	//
	// XXX When imports are handled, we'll need to defer creating
	//     llvm.global_ctors until we create an executable. This is
	//     due to (a) imports having to be initialised before the
	//     importer, and (b) LLVM having no specified order of
	//     initialisation for ctors with the same priority.
	var initfuncs [][]Value
	if compiler.varinitfuncs != nil {
		initfuncs = append(initfuncs, compiler.varinitfuncs)
	}
	if compiler.initfuncs != nil {
		initfuncs = append(initfuncs, compiler.initfuncs)
	}
	if initfuncs != nil {
		elttypes := []llvm.Type{llvm.Int32Type(), llvm.PointerType(llvm.FunctionType(llvm.VoidType(), nil, false), 0)}
		ctortype := llvm.StructType(elttypes, false)
		var ctors []llvm.Value
		var priority uint64
		for _, initfuncs := range initfuncs {
			for _, fn := range initfuncs {
				priorityval := llvm.ConstInt(llvm.Int32Type(), uint64(priority), false)
				struct_values := []llvm.Value{priorityval, fn.LLVMValue()}
				ctors = append(ctors, llvm.ConstStruct(struct_values, false))
				priority++
			}
		}
		global_ctors_init := llvm.ConstArray(ctortype, ctors)
		global_ctors_var := llvm.AddGlobal(compiler.module.Module, global_ctors_init.Type(), "llvm.global_ctors")
		global_ctors_var.SetInitializer(global_ctors_init)
		global_ctors_var.SetLinkage(llvm.AppendingLinkage)
	}

	// Create debug metadata.
	//compiler.createMetadata()

	return compiler.module, nil
}
Beispiel #16
0
func (compiler *compiler) Compile(fset *token.FileSet,
	pkg *ast.Package, importpath string,
	exprTypes map[ast.Expr]types.Type) (m *Module, err error) {

	// FIXME I'd prefer if we didn't modify global state. Perhaps
	// we should always take a copy of types.Universe?
	defer func() {
		types.Universe.Lookup("true").Data = types.Const{true}
		types.Universe.Lookup("false").Data = types.Const{false}
	}()

	// FIXME create a compilation state, rather than storing in 'compiler'.
	compiler.fileset = fset
	compiler.pkg = pkg
	compiler.importpath = importpath
	compiler.initfuncs = nil
	compiler.varinitfuncs = nil

	// Create a Builder, for building LLVM instructions.
	compiler.builder = llvm.GlobalContext().NewBuilder()
	defer compiler.builder.Dispose()

	// Create a Module, which contains the LLVM bitcode. Dispose it on panic,
	// otherwise we'll set a finalizer at the end. The caller may invoke
	// Dispose manually, which will render the finalizer a no-op.
	modulename := pkg.Name
	compiler.module = &Module{llvm.NewModule(modulename), modulename, false}
	compiler.module.SetTarget(compiler.TargetTriple)
	compiler.module.SetDataLayout(compiler.target.String())
	defer func() {
		if e := recover(); e != nil {
			compiler.module.Dispose()
			panic(e)
			//err = e.(error)
		}
	}()

	// Create a mapping from objects back to packages, so we can create the
	// appropriate symbol names.
	compiler.pkgmap = createPackageMap(pkg, importpath)

	// Create a struct responsible for mapping static types to LLVM types,
	// and to runtime/dynamic type values.
	var resolver Resolver = compiler
	compiler.FunctionCache = NewFunctionCache(compiler)
	compiler.types = NewTypeMap(compiler.llvmtypes, compiler.module.Module, importpath, exprTypes, compiler.FunctionCache, resolver)

	// Compile each file in the package.
	for _, file := range pkg.Files {
		file.Scope.Outer = pkg.Scope
		compiler.filescope = file.Scope
		compiler.scope = file.Scope
		compiler.fixConstDecls(file)
		for _, decl := range file.Decls {
			compiler.VisitDecl(decl)
		}
	}

	// Define intrinsics for use by the runtime: malloc, free, memcpy, etc.
	// These could be defined in LLVM IR, and may be moved there later.
	if pkg.Name == "runtime" {
		compiler.defineRuntimeIntrinsics()
	}

	// Export runtime type information.
	if pkg.Name == "runtime" {
		compiler.exportBuiltinRuntimeTypes()
	}

	// Wrap "main.main" in a call to runtime.main.
	if pkg.Name == "main" {
		err = compiler.createMainFunction()
		if err != nil {
			return nil, err
		}
	}

	// Create global constructors. The initfuncs/varinitfuncs
	// slices are in the order of visitation; we generate the
	// list of constructors in the reverse order.
	//
	// The llgo linker will link modules in the order of
	// package dependency, i.e. if A requires B, then llgo-link
	// will link the modules in the order A, B. The "runtime"
	// package is always last.
	//
	// At program initialisation, the runtime initialisation
	// function (runtime.main) will invoke the constructors
	// in reverse order.
	var initfuncs [][]Value
	if compiler.varinitfuncs != nil {
		initfuncs = append(initfuncs, compiler.varinitfuncs)
	}
	if compiler.initfuncs != nil {
		initfuncs = append(initfuncs, compiler.initfuncs)
	}
	if initfuncs != nil {
		ctortype := llvm.PointerType(llvm.FunctionType(llvm.VoidType(), nil, false), 0)
		var ctors []llvm.Value
		var index int = 0
		for _, initfuncs := range initfuncs {
			for _, fn := range initfuncs {
				fnval := fn.LLVMValue()
				fnval.SetName("__llgo.ctor." + compiler.importpath + strconv.Itoa(index))
				ctors = append(ctors, fnval)
				index++
			}
		}
		for i, n := 0, len(ctors); i < n/2; i++ {
			ctors[i], ctors[n-i-1] = ctors[n-i-1], ctors[i]
		}
		ctorsInit := llvm.ConstArray(ctortype, ctors)
		ctorsVar := llvm.AddGlobal(compiler.module.Module, ctorsInit.Type(), "runtime.ctors")
		ctorsVar.SetInitializer(ctorsInit)
		ctorsVar.SetLinkage(llvm.AppendingLinkage)
	}

	// Create debug metadata.
	//compiler.createMetadata()

	return compiler.module, nil
}
Beispiel #17
0
func (compiler *compiler) Compile(fset *token.FileSet,
	pkg *ast.Package, importpath string,
	exprTypes map[ast.Expr]types.Type) (m *Module, err error) {

	// FIXME I'd prefer if we didn't modify global state. Perhaps
	// we should always take a copy of types.Universe?
	defer func() {
		types.Universe.Lookup("true").Data = types.Const{true}
		types.Universe.Lookup("false").Data = types.Const{false}
	}()

	// FIXME create a compilation state, rather than storing in 'compiler'.
	compiler.fileset = fset
	compiler.pkg = pkg
	compiler.importpath = importpath
	compiler.initfuncs = nil
	compiler.varinitfuncs = nil

	// Create a Builder, for building LLVM instructions.
	compiler.builder = llvm.GlobalContext().NewBuilder()
	defer compiler.builder.Dispose()

	// Create a Module, which contains the LLVM bitcode. Dispose it on panic,
	// otherwise we'll set a finalizer at the end. The caller may invoke
	// Dispose manually, which will render the finalizer a no-op.
	modulename := pkg.Name
	compiler.module = &Module{llvm.NewModule(modulename), modulename, false}
	compiler.module.SetTarget(compiler.TargetTriple)
	compiler.module.SetDataLayout(compiler.target.String())
	defer func() {
		if e := recover(); e != nil {
			compiler.module.Dispose()
			panic(e)
			//err = e.(error)
		}
	}()

	// Create a mapping from objects back to packages, so we can create the
	// appropriate symbol names.
	compiler.pkgmap = createPackageMap(pkg, importpath)

	// Create a struct responsible for mapping static types to LLVM types,
	// and to runtime/dynamic type values.
	var resolver Resolver = compiler
	compiler.FunctionCache = NewFunctionCache(compiler)
	compiler.types = NewTypeMap(compiler.llvmtypes, compiler.module.Module, importpath, exprTypes, compiler.FunctionCache, resolver)

	// Compile each file in the package.
	for _, file := range pkg.Files {
		file.Scope.Outer = pkg.Scope
		compiler.filescope = file.Scope
		compiler.scope = file.Scope
		compiler.fixConstDecls(file)
		for _, decl := range file.Decls {
			compiler.VisitDecl(decl)
		}
	}

	// Define intrinsics for use by the runtime: malloc, free, memcpy, etc.
	// These could be defined in LLVM IR, and may be moved there later.
	if pkg.Name == "runtime" {
		compiler.defineRuntimeIntrinsics()
	}

	// Export runtime type information.
	if pkg.Name == "runtime" {
		compiler.exportBuiltinRuntimeTypes()
	}

	// Create global constructors. The initfuncs/varinitfuncs
	// slices are in the order of visitation, and that is how
	// their priorities are assigned.
	//
	// The llgo linker (llgo-link) is responsible for reordering
	// global constructors according to package dependency order.
	var initfuncs [][]Value
	if compiler.varinitfuncs != nil {
		initfuncs = append(initfuncs, compiler.varinitfuncs)
	}
	if compiler.initfuncs != nil {
		initfuncs = append(initfuncs, compiler.initfuncs)
	}
	if initfuncs != nil {
		elttypes := []llvm.Type{llvm.Int32Type(), llvm.PointerType(llvm.FunctionType(llvm.VoidType(), nil, false), 0)}
		ctortype := llvm.StructType(elttypes, false)
		var ctors []llvm.Value
		var priority uint64 = 1
		for _, initfuncs := range initfuncs {
			for _, fn := range initfuncs {
				priorityval := llvm.ConstInt(llvm.Int32Type(), uint64(priority), false)
				struct_values := []llvm.Value{priorityval, fn.LLVMValue()}
				ctors = append(ctors, llvm.ConstStruct(struct_values, false))
				priority++
			}
		}
		global_ctors_init := llvm.ConstArray(ctortype, ctors)
		global_ctors_var := llvm.AddGlobal(compiler.module.Module, global_ctors_init.Type(), "llvm.global_ctors")
		global_ctors_var.SetInitializer(global_ctors_init)
		global_ctors_var.SetLinkage(llvm.AppendingLinkage)
	}

	// Create debug metadata.
	//compiler.createMetadata()

	return compiler.module, nil
}
Beispiel #18
0
// Create a constructor function which initialises a global.
// TODO collapse all global inits into one init function?
func (c *compiler) createGlobals(idents []*ast.Ident, values []ast.Expr, pkg string) {
	globals := make([]*LLVMValue, len(idents))
	for i, ident := range idents {
		if !isBlank(ident.Name) {
			t := c.typeinfo.Objects[ident].Type()
			llvmtyp := c.types.ToLLVM(t)
			gv := llvm.AddGlobal(c.module.Module, llvmtyp, pkg+"."+ident.Name)
			g := c.NewValue(gv, types.NewPointer(t)).makePointee()
			globals[i] = g
			c.objectdata[c.typeinfo.Objects[ident]].Value = g
		}
	}

	if len(values) == 0 {
		for _, g := range globals {
			if g != nil {
				typ := g.pointer.value.Type().ElementType()
				initializer := llvm.ConstNull(typ)
				g.pointer.value.SetInitializer(initializer)
			}
		}
		return
	} else if len(values) == len(idents) {
		// Non-compound. Initialise global variables with constant
		// values (if any). If all expressions are constant, return
		// immediately after, to avoid the unnecessary function
		// below.
		allconst := true
		for i, expr := range values {
			if constval := c.typeinfo.Values[expr]; constval != nil {
				if globals[i] != nil {
					gv := globals[i].pointer.value
					value := c.VisitExpr(expr)
					value = value.Convert(globals[i].Type())
					gv.SetInitializer(value.LLVMValue())
				}
			} else {
				allconst = false
			}
		}
		if allconst {
			return
		}
	}

	// There are non-const expressions, so we must create an init()
	// function to evaluate the expressions and initialise the globals.
	if block := c.builder.GetInsertBlock(); !block.IsNil() {
		defer c.builder.SetInsertPointAtEnd(block)
	}
	llvmfntype := llvm.FunctionType(llvm.VoidType(), nil, false)
	fn := llvm.AddFunction(c.module.Module, "", llvmfntype)
	// Pushing nil, children don't need access to a "real" init function handle
	c.functions.push(nil)
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)

	if len(values) == 1 && len(idents) > 1 {
		values := c.destructureExpr(values[0])
		for i, v := range values {
			if globals[i] != nil {
				gv := globals[i].pointer.value
				gv.SetInitializer(llvm.Undef(gv.Type().ElementType()))
				c.builder.CreateStore(v.LLVMValue(), gv)
			}
		}
	} else {
		for i, expr := range values {
			if constval := c.typeinfo.Values[expr]; constval == nil {
				// Must evaluate regardless of whether value is
				// assigned, in event of side-effects.
				v := c.VisitExpr(expr)
				if globals[i] != nil {
					gv := globals[i].pointer.value
					gv.SetInitializer(llvm.Undef(gv.Type().ElementType()))
					v = v.Convert(globals[i].Type())
					c.builder.CreateStore(v.LLVMValue(), gv)
				}
			}
		}
	}
	c.builder.CreateRetVoid()
	c.varinitfuncs = append(c.varinitfuncs, fn)
	c.functions.pop()
}