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