// 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 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 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 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 (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 (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 (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 test() { llvm.LinkInMCJIT() llvm.InitializeNativeTarget() llvm.InitializeNativeAsmPrinter() mod := llvm.NewModule("fac_module") // don't do that, because ExecutionEngine takes ownership over module //defer mod.Dispose() fac_args := []llvm.Type{llvm.Int32Type()} fac_type := llvm.FunctionType(llvm.Int32Type(), fac_args, false) fac := llvm.AddFunction(mod, "fac", fac_type) fac.SetFunctionCallConv(llvm.CCallConv) n := fac.Param(0) entry := llvm.AddBasicBlock(fac, "entry") iftrue := llvm.AddBasicBlock(fac, "iftrue") iffalse := llvm.AddBasicBlock(fac, "iffalse") end := llvm.AddBasicBlock(fac, "end") builder := llvm.NewBuilder() defer builder.Dispose() builder.SetInsertPointAtEnd(entry) If := builder.CreateICmp(llvm.IntEQ, n, llvm.ConstInt(llvm.Int32Type(), 0, false), "cmptmp") builder.CreateCondBr(If, iftrue, iffalse) builder.SetInsertPointAtEnd(iftrue) res_iftrue := llvm.ConstInt(llvm.Int32Type(), 1, false) builder.CreateBr(end) builder.SetInsertPointAtEnd(iffalse) n_minus := builder.CreateSub(n, llvm.ConstInt(llvm.Int32Type(), 1, false), "subtmp") call_fac_args := []llvm.Value{n_minus} call_fac := builder.CreateCall(fac, call_fac_args, "calltmp") res_iffalse := builder.CreateMul(n, call_fac, "multmp") builder.CreateBr(end) builder.SetInsertPointAtEnd(end) res := builder.CreatePHI(llvm.Int32Type(), "result") phi_vals := []llvm.Value{res_iftrue, res_iffalse} phi_blocks := []llvm.BasicBlock{iftrue, iffalse} res.AddIncoming(phi_vals, phi_blocks) builder.CreateRet(res) err := llvm.VerifyModule(mod, llvm.ReturnStatusAction) if err != nil { fmt.Println(err) return } engine, err := llvm.NewMCJITCompiler(mod, llvm.MCJITCompilerOptions{OptLevel: 2}) if err != nil { fmt.Println(err) return } defer engine.Dispose() pass := llvm.NewPassManager() defer pass.Dispose() pass.Add(engine.TargetData()) pass.AddConstantPropagationPass() pass.AddInstructionCombiningPass() pass.AddPromoteMemoryToRegisterPass() pass.AddGVNPass() pass.AddCFGSimplificationPass() pass.Run(mod) mod.Dump() exec_args := []llvm.GenericValue{llvm.NewGenericValueFromInt(llvm.Int32Type(), 10, false)} exec_res := engine.RunFunction(fac, exec_args) fmt.Println("-----------------------------------------") fmt.Println("Running fac(10) with JIT...") fmt.Printf("Result: %d\n", exec_res.Int(false)) }
// 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 }