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 }
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 }
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 }
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() }
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) }
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 }
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 }
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 }
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 }
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 }
// 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 }
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() }
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 }
// 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 }
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 }
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 }
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 }
// 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() }