Пример #1
0
func (c *compiler) VisitFuncProtoDecl(f *ast.FuncDecl) *LLVMValue {
	if f.Name.Obj != nil {
		if result, ok := f.Name.Obj.Data.(*LLVMValue); ok {
			return result
		}
	}

	var ftyp *types.Func
	fname := f.Name.String()
	if f.Recv == nil && fname == "init" {
		// Make "init" functions anonymous.
		fname = ""
		// "init" functions aren't recorded by the parser, so f.Name.Obj is
		// not set.
		ftyp = &types.Func{ /* no params or result */ }
	} else {
		ftyp = f.Name.Obj.Type.(*types.Func)
		if ftyp.Recv != nil {
			recv := ftyp.Recv.Type.(types.Type)
			fname = fmt.Sprintf("%s.%s", recv, fname)
		} else if c.module.Name != "main" || fname != "main" {
			pkgname := c.pkgmap[f.Name.Obj]
			fname = pkgname + "." + fname
		}
	}

	// gcimporter may produce multiple AST objects for the same function.
	fn := c.module.Module.NamedFunction(fname)
	if fn.IsNil() {
		llvmftyp := c.types.ToLLVM(ftyp).ElementType()
		fn = llvm.AddFunction(c.module.Module, fname, llvmftyp)
		if ftyp.Recv != nil {
			// Create an interface function if the receiver is
			// not a pointer type.
			recvtyp := ftyp.Recv.Type.(types.Type)
			if _, ptr := recvtyp.(*types.Pointer); !ptr {
				returntyp := llvmftyp.ReturnType()
				paramtypes := llvmftyp.ParamTypes()
				paramtypes[0] = llvm.PointerType(paramtypes[0], 0)
				ifntyp := llvm.FunctionType(returntyp, paramtypes, false)
				llvm.AddFunction(c.module.Module, "*"+fname, ifntyp)
			}
		}
	}
	result := c.NewLLVMValue(fn, ftyp)
	if f.Name.Obj != nil {
		f.Name.Obj.Data = result
		f.Name.Obj.Type = ftyp
	}
	return result
}
Пример #2
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()
}
Пример #3
0
func addExterns(m *llgo.Module) {
	CharPtr := llvm.PointerType(llvm.Int8Type(), 0)
	fn_type := llvm.FunctionType(
		llvm.Int32Type(), []llvm.Type{CharPtr}, false)
	fflush := llvm.AddFunction(m.Module, "fflush", fn_type)
	fflush.SetFunctionCallConv(llvm.CCallConv)
}
Пример #4
0
func (c *compiler) compareStrings(lhs, rhs *LLVMValue, op token.Token) *LLVMValue {
	strcmp := c.module.Module.NamedFunction("runtime.strcmp")
	if strcmp.IsNil() {
		string_type := c.types.ToLLVM(types.String)
		param_types := []llvm.Type{string_type, string_type}
		func_type := llvm.FunctionType(llvm.Int32Type(), param_types, false)
		strcmp = llvm.AddFunction(c.module.Module, "runtime.strcmp", func_type)
	}
	args := []llvm.Value{lhs.LLVMValue(), rhs.LLVMValue()}
	result := c.builder.CreateCall(strcmp, args, "")
	zero := llvm.ConstNull(llvm.Int32Type())
	var pred llvm.IntPredicate
	switch op {
	case token.EQL:
		pred = llvm.IntEQ
	case token.LSS:
		pred = llvm.IntSLT
	case token.GTR:
		pred = llvm.IntSGT
	case token.LEQ:
		pred = llvm.IntSLE
	case token.GEQ:
		pred = llvm.IntSGE
	case token.NEQ:
		panic("NEQ is handled in LLVMValue.BinaryOp")
	default:
		panic("unreachable")
	}
	result = c.builder.CreateICmp(pred, result, zero, "")
	return c.NewLLVMValue(result, types.Bool)
}
Пример #5
0
// mapInsert inserts a key into a map, returning a pointer to the memory
// location for the value.
func (c *compiler) mapInsert(m *LLVMValue, key Value) *LLVMValue {
	mapType := m.Type().(*types.Map)
	mapinsert := c.module.Module.NamedFunction("runtime.mapinsert")
	ptrType := c.target.IntPtrType()
	if mapinsert.IsNil() {
		// params: dynamic type, mapptr, keyptr
		paramTypes := []llvm.Type{ptrType, ptrType, ptrType}
		funcType := llvm.FunctionType(ptrType, paramTypes, false)
		mapinsert = llvm.AddFunction(c.module.Module, "runtime.mapinsert", funcType)
	}
	args := make([]llvm.Value, 3)
	args[0] = llvm.ConstPtrToInt(c.types.ToRuntime(m.Type()), ptrType)
	args[1] = c.builder.CreatePtrToInt(m.pointer.LLVMValue(), ptrType, "")

	if lv, islv := key.(*LLVMValue); islv && lv.pointer != nil {
		args[2] = c.builder.CreatePtrToInt(lv.pointer.LLVMValue(), ptrType, "")
	}
	if args[2].IsNil() {
		// Create global constant, so we can take its address.
		global := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(key.Type()), "")
		global.SetGlobalConstant(true)
		global.SetInitializer(key.LLVMValue())
		args[2] = c.builder.CreatePtrToInt(global, ptrType, "")
	}

	eltPtrType := &types.Pointer{Base: mapType.Elt}
	result := c.builder.CreateCall(mapinsert, args, "")
	result = c.builder.CreateIntToPtr(result, c.types.ToLLVM(eltPtrType), "")
	value := c.NewLLVMValue(result, eltPtrType)
	return value.makePointee()
}
Пример #6
0
// interfacesEqual compares two interfaces for equality, returning
// a dynamic boolean value.
func (lhs *LLVMValue) compareI2I(rhs *LLVMValue) Value {
	c := lhs.compiler
	b := c.builder

	lhsValue := b.CreateExtractValue(lhs.LLVMValue(), 0, "")
	rhsValue := b.CreateExtractValue(rhs.LLVMValue(), 0, "")
	lhsType := b.CreateExtractValue(lhs.LLVMValue(), 1, "")
	rhsType := b.CreateExtractValue(rhs.LLVMValue(), 1, "")

	llvmUintptr := c.target.IntPtrType()
	runtimeCompareI2I := c.module.Module.NamedFunction("runtime.compareI2I")
	if runtimeCompareI2I.IsNil() {
		args := []llvm.Type{llvmUintptr, llvmUintptr, llvmUintptr, llvmUintptr}
		functype := llvm.FunctionType(llvm.Int1Type(), args, false)
		runtimeCompareI2I = llvm.AddFunction(
			c.module.Module, "runtime.compareI2I", functype)
	}

	args := []llvm.Value{
		c.builder.CreatePtrToInt(lhsType, llvmUintptr, ""),
		c.builder.CreatePtrToInt(rhsType, llvmUintptr, ""),
		c.builder.CreatePtrToInt(lhsValue, llvmUintptr, ""),
		c.builder.CreatePtrToInt(rhsValue, llvmUintptr, ""),
	}

	result := c.builder.CreateCall(runtimeCompareI2I, args, "")
	return c.NewLLVMValue(result, types.Bool)
}
Пример #7
0
Файл: ssa.go Проект: pcc/llgo
// contextFunction creates a wrapper function that
// has the same signature as the specified function,
// but has an additional first parameter that accepts
// and ignores the function context value.
//
// contextFunction must be called with a global function
// pointer.
func contextFunction(c *compiler, f *LLVMValue) *LLVMValue {
	defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock())
	resultType := c.llvmtypes.ToLLVM(f.Type())
	fnptr := f.LLVMValue()
	contextType := resultType.StructElementTypes()[1]
	llfntyp := fnptr.Type().ElementType()
	llfntyp = llvm.FunctionType(
		llfntyp.ReturnType(),
		append([]llvm.Type{contextType}, llfntyp.ParamTypes()...),
		llfntyp.IsFunctionVarArg(),
	)
	wrapper := llvm.AddFunction(c.module.Module, fnptr.Name()+".ctx", llfntyp)
	wrapper.SetLinkage(llvm.PrivateLinkage)
	entry := llvm.AddBasicBlock(wrapper, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	args := make([]llvm.Value, len(llfntyp.ParamTypes())-1)
	for i := range args {
		args[i] = wrapper.Param(i + 1)
	}
	result := c.builder.CreateCall(fnptr, args, "")
	switch nresults := f.Type().(*types.Signature).Results().Len(); nresults {
	case 0:
		c.builder.CreateRetVoid()
	case 1:
		c.builder.CreateRet(result)
	default:
		results := make([]llvm.Value, nresults)
		for i := range results {
			results[i] = c.builder.CreateExtractValue(result, i, "")
		}
		c.builder.CreateAggregateRet(results)
	}
	return c.NewValue(wrapper, f.Type())
}
Пример #8
0
func (c *compiler) VisitFuncProtoDecl(f *ast.FuncDecl) Value {
	var fn_type *types.Func
	fn_name := f.Name.String()

	exported := ast.IsExported(fn_name)
	if fn_name == "init" {
		// Make "init" functions anonymous.
		fn_name = ""
		// "init" functions aren't recorded by the parser, so f.Name.Obj is
		// not set.
		fn_type = &types.Func{ /* no params or result */ }
	} else {
		fn_type = f.Name.Obj.Type.(*types.Func)
		if c.module.Name == "main" && fn_name == "main" {
			exported = true
		} else {
			pkgname := c.pkgmap[f.Name.Obj]
			fn_name = pkgname + "." + fn_name
		}
	}

	llvm_fn_type := c.types.ToLLVM(fn_type).ElementType()
	fn := llvm.AddFunction(c.module.Module, fn_name, llvm_fn_type)
	if exported {
		fn.SetLinkage(llvm.ExternalLinkage)
	}

	result := c.NewLLVMValue(fn, fn_type)
	if f.Name.Obj != nil {
		f.Name.Obj.Data = result
		f.Name.Obj.Type = fn_type
	}
	return result
}
Пример #9
0
func (c *compiler) VisitFuncLit(lit *ast.FuncLit) Value {
	ftyp := c.types.expr[lit].(*types.Func)
	fn_value := llvm.AddFunction(c.module.Module, "", c.types.ToLLVM(ftyp).ElementType())
	fn_value.SetFunctionCallConv(llvm.FastCallConv)
	defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock())
	f := c.NewLLVMValue(fn_value, ftyp)
	c.buildFunction(f, ftyp.Params, lit.Body)
	return f
}
Пример #10
0
func getPrintf(module llvm.Module) llvm.Value {
	printf := module.NamedFunction("printf")
	if printf.IsNil() {
		charPtr := llvm.PointerType(llvm.Int8Type(), 0)
		ftyp := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{charPtr}, true)
		printf = llvm.AddFunction(module, "printf", ftyp)
		printf.SetFunctionCallConv(llvm.CCallConv)
	}
	return printf
}
Пример #11
0
func getFflush(module llvm.Module) llvm.Value {
	fflush := module.NamedFunction("fflush")
	if fflush.IsNil() {
		voidPtr := llvm.PointerType(llvm.Int8Type(), 0)
		ftyp := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{voidPtr}, false)
		fflush = llvm.AddFunction(module, "fflush", ftyp)
		fflush.SetFunctionCallConv(llvm.CCallConv)
	}
	return fflush
}
Пример #12
0
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value {
	f, _ := c.functions[name+":"+signature]
	if !f.IsNil() {
		return f
	}

	if strings.HasPrefix(name, c.module.Name+".") {
		obj := c.pkg.Scope.Lookup(name[len(c.module.Name)+1:])
		value := c.Resolve(obj)
		f = value.LLVMValue()
	} else {
		fset := token.NewFileSet()
		code := `package runtime;import("unsafe");` + signature + `{panic()}`
		file, err := parser.ParseFile(fset, "", code, 0)
		if err != nil {
			panic(err)
		}

		// Parse the runtime package, since we may need to refer to
		// its types. TODO cache the package.
		buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0)
		if err != nil {
			panic(err)
		}
		runtimefiles := make([]string, len(buildpkg.GoFiles))
		for i, f := range buildpkg.GoFiles {
			runtimefiles[i] = path.Join(buildpkg.Dir, f)
		}

		files, err := parseFiles(fset, runtimefiles)
		if err != nil {
			panic(err)
		}
		files["<src>"] = file
		pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe)
		if err != nil {
			panic(err)
		}

		_, err = types.Check(fset, pkg)
		if err != nil {
			panic(err)
		}

		fdecl := file.Decls[len(file.Decls)-1].(*ast.FuncDecl)
		ftype := fdecl.Name.Obj.Type.(*types.Func)
		llvmfptrtype := c.types.ToLLVM(ftype)
		f = llvm.AddFunction(c.module.Module, name, llvmfptrtype.ElementType())
		if !strings.HasPrefix(name, "llvm.") {
			f.SetLinkage(llvm.AvailableExternallyLinkage)
		}
	}
	c.functions[name+":"+signature] = f
	return f
}
Пример #13
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.RuntimeFunction("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.runtime.main.LLVMValue()

	ptrptr := llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0)
	ftyp := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{llvm.Int32Type(), ptrptr, ptrptr}, true)
	main := llvm.AddFunction(c.module.Module, "main", ftyp)

	c.builder.SetCurrentDebugLocation(c.debug.MDNode(nil))
	entry := llvm.AddBasicBlock(main, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	runtimeMainParamTypes := runtimeMain.Type().ElementType().ParamTypes()
	args := []llvm.Value{
		main.Param(0), // argc
		main.Param(1), // argv
		main.Param(2), // argp
		c.builder.CreateBitCast(mainMain, runtimeMainParamTypes[3], ""),
	}
	result := c.builder.CreateCall(runtimeMain, args, "")
	c.builder.CreateRet(result)
	return nil
}
Пример #14
0
func (c *compiler) makeFunc(ident *ast.Ident, ftyp *types.Signature) *LLVMValue {
	fname := ident.String()
	if ftyp.Recv() == nil && fname == "init" {
		// Make "init" functions anonymous.
		fname = ""
	} else {
		var pkgname string
		if recv := ftyp.Recv(); recv != nil {
			var recvname string
			switch recvtyp := recv.Type().(type) {
			case *types.Pointer:
				if named, ok := recvtyp.Elem().(*types.Named); ok {
					obj := named.Obj()
					recvname = "*" + obj.Name()
					pkgname = obj.Pkg().Path()
				}
			case *types.Named:
				named := recvtyp
				obj := named.Obj()
				recvname = obj.Name()
				pkgname = obj.Pkg().Path()
			}

			if recvname != "" {
				fname = fmt.Sprintf("%s.%s", recvname, fname)
			} else {
				// If the receiver is an unnamed struct, we're
				// synthesising a method for an unnamed struct
				// type. There's no meaningful name to give the
				// function, so leave it up to LLVM.
				fname = ""
			}
		} else {
			obj := c.typeinfo.Objects[ident]
			pkgname = obj.Pkg().Path()
		}
		if fname != "" {
			fname = pkgname + "." + fname
		}
	}

	// gcimporter may produce multiple AST objects for the same function.
	llvmftyp := c.types.ToLLVM(ftyp)
	var fn llvm.Value
	if fname != "" {
		fn = c.module.Module.NamedFunction(fname)
	}
	if fn.IsNil() {
		llvmfptrtyp := llvmftyp.StructElementTypes()[0].ElementType()
		fn = llvm.AddFunction(c.module.Module, fname, llvmfptrtyp)
	}
	fn = llvm.ConstInsertValue(llvm.ConstNull(llvmftyp), fn, []uint32{0})
	return c.NewValue(fn, ftyp)
}
Пример #15
0
func (c *compiler) concatenateStrings(lhs, rhs *LLVMValue) *LLVMValue {
	strcat := c.module.Module.NamedFunction("runtime.strcat")
	if strcat.IsNil() {
		string_type := c.types.ToLLVM(types.String)
		param_types := []llvm.Type{string_type, string_type}
		func_type := llvm.FunctionType(string_type, param_types, false)
		strcat = llvm.AddFunction(c.module.Module, "runtime.strcat", func_type)
	}
	args := []llvm.Value{lhs.LLVMValue(), rhs.LLVMValue()}
	result := c.builder.CreateCall(strcat, args, "")
	return c.NewLLVMValue(result, types.String)
}
Пример #16
0
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value {
	f, _ := c.functions[name+":"+signature]
	if !f.IsNil() {
		return f
	}

	if strings.HasPrefix(name, c.module.Name+".") {
		obj := c.pkg.Scope.Lookup(name[len(c.module.Name)+1:])
		value := c.Resolve(obj)
		f = value.LLVMValue()
	} else {
		fset := token.NewFileSet()
		code := `package runtime;import("unsafe");` + signature + `{panic()}`
		file, err := parser.ParseFile(fset, "", code, 0)
		if err != nil {
			panic(err)
		}

		// Parse the runtime package, since we may need to refer to
		// its types. Can't be cached, because type-checking can't
		// be done twice on the AST.
		buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0)
		if err != nil {
			panic(err)
		}

		// All types visible to the compiler are in "types.go".
		runtimefiles := []string{path.Join(buildpkg.Dir, "types.go")}

		files, err := parseFiles(fset, runtimefiles)
		if err != nil {
			panic(err)
		}
		files["<src>"] = file

		pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe)
		if err != nil {
			panic(err)
		}

		_, err = types.Check("", c.compiler, fset, pkg)
		if err != nil {
			panic(err)
		}

		fdecl := file.Decls[len(file.Decls)-1].(*ast.FuncDecl)
		ftype := fdecl.Name.Obj.Type.(*types.Func)
		llvmfptrtype := c.types.ToLLVM(ftype)
		f = llvm.AddFunction(c.module.Module, name, llvmfptrtype.ElementType())
	}
	c.functions[name+":"+signature] = f
	return f
}
Пример #17
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
}
Пример #18
0
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value {
	f, _ := c.functions[name+":"+signature]
	if !f.IsNil() {
		return f
	}

	if strings.HasPrefix(name, c.module.Name+".") {
		obj := c.pkg.Scope().Lookup(name[len(c.module.Name)+1:])
		if obj == nil {
			panic("Missing function: " + name)
		}
		value := c.Resolve(c.objectdata[obj].Ident)
		f = llvm.ConstExtractValue(value.LLVMValue(), []uint32{0})
	} else {
		fset := token.NewFileSet()
		code := `package runtime;import("unsafe");` + signature + `{panic("")}`
		file, err := parser.ParseFile(fset, "", code, 0)
		if err != nil {
			panic(err)
		}

		// Parse the runtime package, since we may need to refer to
		// its types. Can't be cached, because type-checking can't
		// be done twice on the AST.
		buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0)
		if err != nil {
			panic(err)
		}

		// All types visible to the compiler are in "types.go".
		runtimefiles := []string{path.Join(buildpkg.Dir, "types.go")}

		files, err := parseFiles(fset, runtimefiles)
		if err != nil {
			panic(err)
		}
		files = append(files, file)
		_, _, err = c.typecheck("runtime", fset, files)
		if err != nil {
			panic(err)
		}

		fdecl := file.Decls[len(file.Decls)-1].(*ast.FuncDecl)
		ftype := c.objects[fdecl.Name].Type().(*types.Signature)
		llvmfntyp := c.types.ToLLVM(ftype).StructElementTypes()[0].ElementType()
		f = llvm.AddFunction(c.module.Module, name, llvmfntyp)
	}
	c.functions[name+":"+signature] = f
	return f
}
Пример #19
0
func (c *compiler) VisitFuncProtoDecl(f *ast.FuncDecl) *LLVMValue {
	if f.Name.Obj != nil {
		if result, ok := f.Name.Obj.Data.(*LLVMValue); ok {
			return result
		}
	}

	var fn_type *types.Func
	fn_name := f.Name.String()
	if f.Recv == nil && fn_name == "init" {
		// Make "init" functions anonymous.
		fn_name = ""
		// "init" functions aren't recorded by the parser, so f.Name.Obj is
		// not set.
		fn_type = &types.Func{ /* no params or result */ }
	} else {
		fn_type = f.Name.Obj.Type.(*types.Func)
		if c.module.Name != "main" || fn_name != "main" {
			if fn_type.Recv != nil {
				recv := fn_type.Recv
				if recvtyp, ok := recv.Type.(*types.Pointer); ok {
					recv = recvtyp.Base.(*types.Name).Obj
				} else {
					recv = recv.Type.(*types.Name).Obj
				}
				pkgname := c.pkgmap[recv]
				fn_name = pkgname + "." + recv.Name + "." + fn_name
			} else {
				pkgname := c.pkgmap[f.Name.Obj]
				fn_name = pkgname + "." + fn_name
			}
		}
	}

	llvm_fn_type := c.types.ToLLVM(fn_type).ElementType()

	// gcimporter may produce multiple AST objects for the same function.
	fn := c.module.Module.NamedFunction(fn_name)
	if fn.IsNil() {
		fn = llvm.AddFunction(c.module.Module, fn_name, llvm_fn_type)
	}
	result := c.NewLLVMValue(fn, fn_type)
	if f.Name.Obj != nil {
		f.Name.Obj.Data = result
		f.Name.Obj.Type = fn_type
	}
	return result
}
Пример #20
0
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value {
	f, _ := c.functions[name+":"+signature]
	if !f.IsNil() {
		return f
	}

	if strings.HasPrefix(name, c.module.Name+".") {
		obj := c.pkg.Scope().Lookup(name[len(c.module.Name)+1:])
		if obj == nil {
			panic("Missing function: " + name)
		}
		value := c.Resolve(c.objectdata[obj].Ident)
		f = llvm.ConstExtractValue(value.LLVMValue(), []uint32{0})
	} else {
		if c.runtimetypespkg == nil {
			// Parse the runtime package, since we may need to refer to
			// its types.
			buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0)
			if err != nil {
				panic(err)
			}

			// All types visible to the compiler are in "types.go".
			runtimefiles := []string{path.Join(buildpkg.Dir, "types.go")}

			fset := token.NewFileSet()
			files, err := parseFiles(fset, runtimefiles)
			if err != nil {
				panic(err)
			}
			c.runtimetypespkg, err = c.typecheck("runtime", fset, files)
			if err != nil {
				panic(err)
			}
		}

		pkg := c.runtimetypespkg
		scope := pkg.Scope().Child(0)
		ftype, _, err := types.Eval(signature+"{panic()}", pkg, scope)
		if err != nil {
			panic(err)
		}
		llvmfntyp := c.types.ToLLVM(ftype).StructElementTypes()[0].ElementType()
		f = llvm.AddFunction(c.module.Module, name, llvmfntyp)
	}
	c.functions[name+":"+signature] = f
	return f
}
Пример #21
0
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value {
	// TODO set these to actual functions.
	hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0))
	printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0))
	copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0))

	equalAlgName := "runtime.memequal"
	equalAlg := tm.module.NamedFunction(equalAlgName)
	if equalAlg.IsNil() {
		equalAlg = llvm.AddFunction(
			tm.module, equalAlgName, tm.equalAlgFunctionType)
	}

	elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg}
	return llvm.ConstStruct(elems, false)
}
Пример #22
0
func (c *compiler) VisitAppend(expr *ast.CallExpr) Value {
	// TODO handle ellpisis arg
	s := c.VisitExpr(expr.Args[0])
	elem := c.VisitExpr(expr.Args[1])

	appendName := "runtime.sliceappend"
	appendFun := c.module.NamedFunction(appendName)
	uintptrTyp := c.target.IntPtrType()
	var i8slice llvm.Type
	if appendFun.IsNil() {
		i8slice = c.types.ToLLVM(&types.Slice{Elt: types.Int8})
		args := []llvm.Type{uintptrTyp, i8slice, i8slice}
		appendFunTyp := llvm.FunctionType(i8slice, args, false)
		appendFun = llvm.AddFunction(c.module.Module, appendName, appendFunTyp)
	} else {
		i8slice = appendFun.Type().ReturnType()
	}
	i8ptr := i8slice.StructElementTypes()[0]

	// Coerce first argument into an []int8.
	a_ := s.LLVMValue()
	sliceTyp := a_.Type()
	a := c.coerceSlice(a_, i8slice)

	// Construct a fresh []int8 for the temporary slice.
	b_ := elem.LLVMValue()
	one := llvm.ConstInt(llvm.Int32Type(), 1, false)
	mem := c.builder.CreateAlloca(elem.LLVMValue().Type(), "")
	c.builder.CreateStore(b_, mem)
	b := llvm.Undef(i8slice)
	b = c.builder.CreateInsertValue(b, c.builder.CreateBitCast(mem, i8ptr, ""), 0, "")
	b = c.builder.CreateInsertValue(b, one, 1, "")
	b = c.builder.CreateInsertValue(b, one, 2, "")

	// Call runtime function, then coerce the result.
	runtimeTyp := c.types.ToRuntime(s.Type())
	runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, uintptrTyp, "")
	args := []llvm.Value{runtimeTyp, a, b}
	result := c.builder.CreateCall(appendFun, args, "")
	return c.NewLLVMValue(c.coerceSlice(result, sliceTyp), s.Type())
}
Пример #23
0
Файл: ssa.go Проект: minux/llgo
func (u *unit) resolveFunction(f *ssa.Function) *LLVMValue {
	if v, ok := u.globals[f]; ok {
		return v
	}
	name := f.String()
	if f.Enclosing != nil {
		// Anonymous functions are not guaranteed to
		// have unique identifiers at the global scope.
		name = f.Enclosing.String() + ":" + name
	}
	// It's possible that the function already exists in the module;
	// for example, if it's a runtime intrinsic that the compiler
	// has already referenced.
	llvmFunction := u.module.Module.NamedFunction(name)
	if llvmFunction.IsNil() {
		llvmType := u.llvmtypes.ToLLVM(f.Signature)
		llvmType = llvmType.StructElementTypes()[0].ElementType()
		if len(f.FreeVars) > 0 {
			// Add an implicit first argument.
			returnType := llvmType.ReturnType()
			paramTypes := llvmType.ParamTypes()
			vararg := llvmType.IsFunctionVarArg()
			blockElementTypes := make([]llvm.Type, len(f.FreeVars))
			for i, fv := range f.FreeVars {
				blockElementTypes[i] = u.llvmtypes.ToLLVM(fv.Type())
			}
			blockType := llvm.StructType(blockElementTypes, false)
			blockPtrType := llvm.PointerType(blockType, 0)
			paramTypes = append([]llvm.Type{blockPtrType}, paramTypes...)
			llvmType = llvm.FunctionType(returnType, paramTypes, vararg)
		}
		llvmFunction = llvm.AddFunction(u.module.Module, name, llvmType)
		if f.Enclosing != nil {
			llvmFunction.SetLinkage(llvm.PrivateLinkage)
		}
		u.undefinedFuncs[f] = true
	}
	v := u.NewValue(llvmFunction, f.Signature)
	u.globals[f] = v
	return v
}
Пример #24
0
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
}
Пример #25
0
func (c *compiler) VisitFuncLit(lit *ast.FuncLit) Value {
	fn_type := c.VisitFuncType(lit.Type)
	fn := llvm.AddFunction(c.module.Module, "", c.types.ToLLVM(fn_type))
	fn.SetFunctionCallConv(llvm.FastCallConv)

	defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock())
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)

	fn_value := c.NewLLVMValue(fn, fn_type)
	c.functions = append(c.functions, fn_value)
	c.VisitBlockStmt(lit.Body)
	if fn_type.Results == nil {
		lasti := entry.LastInstruction()
		if lasti.IsNil() || lasti.Opcode() != llvm.Ret {
			// Assume nil return type, AST should be checked first.
			c.builder.CreateRetVoid()
		}
	}
	c.functions = c.functions[0 : len(c.functions)-1]
	return fn_value
}
Пример #26
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 f() 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")
	}

	// runtime.main is called by main, with argc, argv,
	// and a pointer to main.main.
	runtimeMain := c.NamedFunction("runtime.main", "func f(int32, **byte, **byte, func()) int32")
	main := c.NamedFunction("main", "func f(int32, **byte, **byte) int32")
	entry := llvm.AddBasicBlock(main, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	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
}
Пример #27
0
// Create a constructor function which initialises a global.
// TODO collapse all global inits into one init function?
func (c *compiler) createGlobal(e ast.Expr, t types.Type, name string, export bool) (g *LLVMValue) {
	if e == nil {
		gv := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(t), name)
		if !export {
			gv.SetLinkage(llvm.InternalLinkage)
		}
		g = c.NewLLVMValue(gv, &types.Pointer{Base: t})
		if !isArray(t) {
			return g.makePointee()
		}
		return g
	}

	if block := c.builder.GetInsertBlock(); !block.IsNil() {
		defer c.builder.SetInsertPointAtEnd(block)
	}
	fn_type := new(types.Func)
	llvm_fn_type := c.types.ToLLVM(fn_type).ElementType()
	fn := llvm.AddFunction(c.module.Module, "", llvm_fn_type)
	fn.SetLinkage(llvm.InternalLinkage)
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)

	// Visit the expression. Dereference if necessary, and generalise
	// the type if one hasn't been specified.
	init_ := c.VisitExpr(e)
	_, isconst := init_.(ConstValue)
	if t == nil {
		t = init_.Type()
	} else {
		init_ = init_.Convert(t)
	}

	// If the result is a constant, discard the function before
	// creating any llvm.Value's.
	if isconst {
		fn.EraseFromParentAsFunction()
		fn = llvm.Value{nil}
	}

	// Set the initialiser. If it's a non-const value, then
	// we'll have to do the assignment in a global constructor
	// function.
	gv := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(t), name)
	if !export {
		gv.SetLinkage(llvm.InternalLinkage)
	}
	g = c.NewLLVMValue(gv, &types.Pointer{Base: t})
	if !isArray(t) {
		g = g.makePointee()
	}
	if isconst {
		// Initialiser is constant; discard function and return global now.
		gv.SetInitializer(init_.LLVMValue())
	} else {
		gv.SetInitializer(llvm.ConstNull(c.types.ToLLVM(t)))
		c.builder.CreateStore(init_.LLVMValue(), gv)
	}

	if !fn.IsNil() {
		c.builder.CreateRetVoid()
		// FIXME order global ctors
		fn_value := c.NewLLVMValue(fn, fn_type)
		c.initfuncs = append(c.initfuncs, fn_value)
	}
	return g
}
Пример #28
0
Файл: ssa.go Проект: pcc/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())
	}
}
Пример #29
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
}
Пример #30
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()
}