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 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) }
// 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() }
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 (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 (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) }
// 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()) }
// 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) }
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 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 }
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 }
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 }
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) }
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) 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 }
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()) }
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 }
// createCall emits the code for a function call, // taking into account receivers, and panic/defer. func (c *compiler) createCall(fn *LLVMValue, argValues []*LLVMValue) *LLVMValue { fntyp := fn.Type().Underlying().(*types.Signature) args := make([]llvm.Value, len(argValues)) for i, arg := range argValues { args[i] = arg.LLVMValue() } var resultType types.Type switch results := fntyp.Results(); results.Len() { case 0: // no-op case 1: resultType = results.At(0).Type() default: resultType = results } // Builtins are represented as a raw function pointer. fnval := fn.LLVMValue() if fnval.Type().TypeKind() == llvm.PointerTypeKind { return c.NewValue(c.builder.CreateCall(fnval, args, ""), resultType) } // If context is constant null, then the function does // not need a context argument. fnptr := c.builder.CreateExtractValue(fnval, 0, "") context := c.builder.CreateExtractValue(fnval, 1, "") llfntyp := fnptr.Type().ElementType() paramTypes := llfntyp.ParamTypes() if context.IsNull() { return c.NewValue(c.builder.CreateCall(fnptr, args, ""), resultType) } llfntyp = llvm.FunctionType( llfntyp.ReturnType(), append([]llvm.Type{context.Type()}, paramTypes...), llfntyp.IsFunctionVarArg(), ) fnptr = c.builder.CreateBitCast(fnptr, llvm.PointerType(llfntyp, 0), "") result := c.builder.CreateCall(fnptr, append([]llvm.Value{context}, args...), "") return c.NewValue(result, resultType) }
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 }
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 }
// 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 }
// promoteInterfaceMethod promotes an interface method to a type // which has embedded the interface. // // TODO consolidate this and promoteMethod. func (c *compiler) promoteInterfaceMethod(iface *types.Interface, methodIndex int, recv types.Type, indices []int) types.Object { m := iface.Method(methodIndex) var pkg *types.Package if recv, ok := recv.(*types.Named); ok { pkg = c.objectdata[recv.Obj()].Package } recvvar := types.NewVar(pkg, "", recv) sig := m.Type().(*types.Signature) sig = types.NewSignature(recvvar, sig.Params(), sig.Results(), sig.IsVariadic()) f := &synthFunc{pkg: pkg, name: m.Name(), typ: sig} ident := ast.NewIdent(f.Name()) var isptr bool if ptr, ok := recv.(*types.Pointer); ok { isptr = true recv = ptr.Elem() } c.objects[ident] = f c.objectdata[f] = &ObjectData{Ident: ident, Package: pkg} if pkg == nil || pkg == c.pkg { if currblock := c.builder.GetInsertBlock(); !currblock.IsNil() { defer c.builder.SetInsertPointAtEnd(currblock) } llvmfn := c.Resolve(ident).LLVMValue() llvmfn = c.builder.CreateExtractValue(llvmfn, 0, "") llvmfn.SetLinkage(llvm.LinkOnceODRLinkage) entry := llvm.AddBasicBlock(llvmfn, "entry") c.builder.SetInsertPointAtEnd(entry) args := llvmfn.Params() ifaceval := args[0] if !isptr { ptr := c.builder.CreateAlloca(ifaceval.Type(), "") c.builder.CreateStore(ifaceval, ptr) ifaceval = ptr } for _, i := range indices { if i == -1 { ifaceval = c.builder.CreateLoad(ifaceval, "") } else { ifaceval = c.builder.CreateStructGEP(ifaceval, i, "") } } recvarg := c.builder.CreateExtractValue(ifaceval, 0, "") ifn := c.builder.CreateExtractValue(ifaceval, methodIndex+2, "") // Add the receiver argument type. fntyp := ifn.Type().ElementType() returnType := fntyp.ReturnType() paramTypes := fntyp.ParamTypes() paramTypes = append([]llvm.Type{recvarg.Type()}, paramTypes...) vararg := fntyp.IsFunctionVarArg() fntyp = llvm.FunctionType(returnType, paramTypes, vararg) fnptrtyp := llvm.PointerType(fntyp, 0) ifn = c.builder.CreateBitCast(ifn, fnptrtyp, "") args[0] = recvarg result := c.builder.CreateCall(ifn, args, "") if sig.Results().Len() == 0 { c.builder.CreateRetVoid() } else { c.builder.CreateRet(result) } } return f }
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() }
// createCall emits the code for a function call, taking into account // variadic functions, receivers, and panic/defer. // // dotdotdot is true if the last argument is followed with "...". func (c *compiler) createCall(fn *LLVMValue, argValues []Value, dotdotdot, invoke bool) *LLVMValue { fn_type := fn.Type().Underlying().(*types.Signature) var args []llvm.Value // TODO Move all of this to evalCallArgs? params := fn_type.Params() if nparams := int(params.Len()); nparams > 0 { if fn_type.IsVariadic() { nparams-- } for i := 0; i < nparams; i++ { value := argValues[i] args = append(args, value.LLVMValue()) } if fn_type.IsVariadic() { if dotdotdot { // Calling f(x...). Just pass the slice directly. slice_value := argValues[nparams].LLVMValue() args = append(args, slice_value) } else { varargs := make([]llvm.Value, len(argValues)-nparams) for i, value := range argValues[nparams:] { varargs[i] = value.LLVMValue() } param_type := params.At(nparams).Type().(*types.Slice).Elem() slice_value := c.makeLiteralSlice(varargs, param_type) args = append(args, slice_value) } } } var result_type types.Type switch results := fn_type.Results(); results.Len() { case 0: // no-op case 1: result_type = results.At(0).Type() default: result_type = results } // Depending on whether the function contains defer statements or not, // we'll generate either a "call" or an "invoke" instruction. var createCall = c.builder.CreateCall if invoke { f := c.functions.top() // TODO Create a method on compiler (avoid creating closures). createCall = func(fn llvm.Value, args []llvm.Value, name string) llvm.Value { currblock := c.builder.GetInsertBlock() returnblock := llvm.AddBasicBlock(currblock.Parent(), "") returnblock.MoveAfter(currblock) value := c.builder.CreateInvoke(fn, args, returnblock, f.unwindblock, "") c.builder.SetInsertPointAtEnd(returnblock) return value } } var fnptr llvm.Value fnval := fn.LLVMValue() if fnval.Type().TypeKind() == llvm.PointerTypeKind { fnptr = fnval } else { fnptr = c.builder.CreateExtractValue(fnval, 0, "") context := c.builder.CreateExtractValue(fnval, 1, "") fntyp := fnptr.Type().ElementType() paramTypes := fntyp.ParamTypes() // If the context is not a constant null, and we're not // dealing with a method (where we don't care about the value // of the receiver), then we must conditionally call the // function with the additional receiver/closure. if !context.IsNull() || fn_type.Recv() != nil { // Store the blocks for referencing in the Phi below; // note that we update the block after each createCall, // since createCall may create new blocks and we want // the predecessors to the Phi. var nullctxblock llvm.BasicBlock var nonnullctxblock llvm.BasicBlock var endblock llvm.BasicBlock var nullctxresult llvm.Value // len(paramTypes) == len(args) iff function is not a method. if !context.IsConstant() && len(paramTypes) == len(args) { currblock := c.builder.GetInsertBlock() endblock = llvm.AddBasicBlock(currblock.Parent(), "") endblock.MoveAfter(currblock) nonnullctxblock = llvm.InsertBasicBlock(endblock, "") nullctxblock = llvm.InsertBasicBlock(nonnullctxblock, "") nullctx := c.builder.CreateIsNull(context, "") c.builder.CreateCondBr(nullctx, nullctxblock, nonnullctxblock) // null context case. c.builder.SetInsertPointAtEnd(nullctxblock) nullctxresult = createCall(fnptr, args, "") nullctxblock = c.builder.GetInsertBlock() c.builder.CreateBr(endblock) c.builder.SetInsertPointAtEnd(nonnullctxblock) } // non-null context case. var result llvm.Value args := append([]llvm.Value{context}, args...) if len(paramTypes) < len(args) { returnType := fntyp.ReturnType() ctxType := context.Type() paramTypes := append([]llvm.Type{ctxType}, paramTypes...) vararg := fntyp.IsFunctionVarArg() fntyp := llvm.FunctionType(returnType, paramTypes, vararg) fnptrtyp := llvm.PointerType(fntyp, 0) fnptr = c.builder.CreateBitCast(fnptr, fnptrtyp, "") } result = createCall(fnptr, args, "") // If the return type is not void, create a // PHI node to select which value to return. if !nullctxresult.IsNil() { nonnullctxblock = c.builder.GetInsertBlock() c.builder.CreateBr(endblock) c.builder.SetInsertPointAtEnd(endblock) if result.Type().TypeKind() != llvm.VoidTypeKind { phiresult := c.builder.CreatePHI(result.Type(), "") values := []llvm.Value{nullctxresult, result} blocks := []llvm.BasicBlock{nullctxblock, nonnullctxblock} phiresult.AddIncoming(values, blocks) result = phiresult } } return c.NewValue(result, result_type) } } result := createCall(fnptr, args, "") return c.NewValue(result, result_type) }
// makeDeferBlock creates a basic block for handling // defer statements, and code is emitted to allocate and // initialise a deferred function anchor point. // // This must be called before generating any code for // the function body (not including allocating space // for parameters and results). func (c *compiler) makeDeferBlock(f *function, body *ast.BlockStmt) { currblock := c.builder.GetInsertBlock() defer c.builder.SetInsertPointAtEnd(currblock) // Create space for a pointer on the stack, which // we'll store the first panic structure in. // // TODO consider having stack space for one (or few) // defer statements, to avoid heap allocation. // // TODO delay this until just before the first "invoke" // instruction is emitted. f.deferblock = llvm.AddBasicBlock(currblock.Parent(), "defer") if hasCallExpr(body) { f.unwindblock = llvm.AddBasicBlock(currblock.Parent(), "unwind") f.unwindblock.MoveAfter(currblock) f.deferblock.MoveAfter(f.unwindblock) } else { f.deferblock.MoveAfter(currblock) } // Create a landingpad/unwind target basic block. if !f.unwindblock.IsNil() { c.builder.SetInsertPointAtEnd(f.unwindblock) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) restyp := llvm.StructType([]llvm.Type{i8ptr, llvm.Int32Type()}, false) pers := c.module.Module.NamedFunction("__gxx_personality_v0") if pers.IsNil() { persftyp := llvm.FunctionType(llvm.Int32Type(), nil, true) pers = llvm.AddFunction(c.module.Module, "__gxx_personality_v0", persftyp) } lp := c.builder.CreateLandingPad(restyp, pers, 1, "") lp.AddClause(llvm.ConstNull(i8ptr)) // Catch the exception. begin_catch := c.NamedFunction("__cxa_begin_catch", "func f(*int8) *int8") exception := c.builder.CreateExtractValue(llvm.Value(lp), 0, "") c.builder.CreateCall(begin_catch, []llvm.Value{exception}, "") end_catch := c.NamedFunction("__cxa_end_catch", "func f()") c.builder.CreateCall(end_catch, nil, "") c.builder.CreateBr(f.deferblock) } // Create a real return instruction. c.builder.SetInsertPointAtEnd(f.deferblock) rundefers := c.NamedFunction("runtime.rundefers", "func f()") c.builder.CreateCall(rundefers, nil, "") if f.results.Len() == 0 { c.builder.CreateRetVoid() } else { values := make([]llvm.Value, 0, f.results.Len()) f.results.ForEach(func(v *types.Var) { value := c.objectdata[v].Value.LLVMValue() values = append(values, value) }) if len(values) == 1 { c.builder.CreateRet(values[0]) } else { c.builder.CreateAggregateRet(values) } } }
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 }