// interfaceMethod returns a function pointer for the specified // interface and method pair. func (c *compiler) interfaceMethod(iface *LLVMValue, method *types.Func) *LLVMValue { lliface := iface.LLVMValue() llitab := c.builder.CreateExtractValue(lliface, 0, "") llvalue := c.builder.CreateExtractValue(lliface, 1, "") sig := method.Type().(*types.Signature) methodset := c.types.MethodSet(sig.Recv().Type()) // TODO(axw) cache ordered method index var index int for i := 0; i < methodset.Len(); i++ { if methodset.At(i).Obj() == method { index = i break } } llitab = c.builder.CreateBitCast(llitab, llvm.PointerType(c.runtime.itab.llvm, 0), "") llifn := c.builder.CreateGEP(llitab, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 5, false), // index of itab.fun }, "") _ = index llifn = c.builder.CreateGEP(llifn, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(index), false), }, "") llifn = c.builder.CreateLoad(llifn, "") // Strip receiver. sig = types.NewSignature(nil, nil, sig.Params(), sig.Results(), sig.Variadic()) llfn := llvm.Undef(c.types.ToLLVM(sig)) llifn = c.builder.CreateIntToPtr(llifn, llfn.Type().StructElementTypes()[0], "") llfn = c.builder.CreateInsertValue(llfn, llifn, 0, "") llfn = c.builder.CreateInsertValue(llfn, llvalue, 1, "") return c.NewValue(llfn, sig) }
func (d *debugInfo) setLocation(b llvm.Builder, pos token.Pos) { position := d.Fset.Position(pos) b.SetCurrentDebugLocation(llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(position.Line), true), llvm.ConstInt(llvm.Int32Type(), uint64(position.Column), true), d.MDNode(d.context()), llvm.Value{}, })) }
func (d *BlockDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false), info.mdFileNode(d.File), info.MDNode(d.Context), llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false), llvm.ConstInt(llvm.Int32Type(), uint64(d.Column), false), llvm.ConstInt(llvm.Int32Type(), uint64(d.Id), false), }) }
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 (d *LocalVariableDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false), info.MDNode(d.Context), llvm.MDString(d.Name), info.mdFileNode(d.File), llvm.ConstInt(llvm.Int32Type(), uint64(d.Line)|(uint64(d.Argument)<<24), false), info.MDNode(d.Type), llvm.ConstNull(llvm.Int32Type()), // flags llvm.ConstNull(llvm.Int32Type()), // optional reference to inline location }) }
func (d *DerivedTypeDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false), FileDescriptor(d.File).path(), info.MDNode(d.Context), llvm.MDString(d.Name), llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false), llvm.ConstInt(llvm.Int64Type(), d.Size, false), llvm.ConstInt(llvm.Int64Type(), d.Alignment, false), llvm.ConstInt(llvm.Int64Type(), d.Offset, false), llvm.ConstInt(llvm.Int32Type(), uint64(d.Flags), false), info.MDNode(d.Base)}) }
func (d *GlobalVariableDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false), llvm.ConstNull(llvm.Int32Type()), info.MDNode(d.Context), llvm.MDString(d.Name), llvm.MDString(d.DisplayName), llvm.MDNode(nil), info.mdFileNode(d.File), llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false), info.MDNode(d.Type), constInt1(d.Local), constInt1(!d.External), d.Value}) }
func (d subrangeDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false), llvm.ConstInt(llvm.Int64Type(), uint64(d.low), true), llvm.ConstInt(llvm.Int64Type(), uint64(d.high), true), }) }
func (tm *llvmTypeMap) basicLLVMType(b *types.Basic) llvm.Type { switch b.Kind() { case types.Bool: return llvm.Int1Type() case types.Int8, types.Uint8: return llvm.Int8Type() case types.Int16, types.Uint16: return llvm.Int16Type() case types.Int32, types.Uint32: return llvm.Int32Type() case types.Uint, types.Int: return tm.inttype case types.Int64, types.Uint64: return llvm.Int64Type() case types.Float32: return llvm.FloatType() case types.Float64: return llvm.DoubleType() case types.UnsafePointer, types.Uintptr: return tm.target.IntPtrType() case types.Complex64: f32 := llvm.FloatType() elements := []llvm.Type{f32, f32} return llvm.StructType(elements, false) case types.Complex128: f64 := llvm.DoubleType() elements := []llvm.Type{f64, f64} return llvm.StructType(elements, false) case types.String: i8ptr := llvm.PointerType(llvm.Int8Type(), 0) elements := []llvm.Type{i8ptr, tm.inttype} return llvm.StructType(elements, false) } panic(fmt.Sprint("unhandled kind: ", b.Kind)) }
func (c *compiler) compareStrings(lhs, rhs *LLVMValue, op token.Token) *LLVMValue { strcmp := c.runtime.strcmp.LLVMValue() _string := strcmp.Type().ElementType().ParamTypes()[0] lhsstr := c.coerceString(lhs.LLVMValue(), _string) rhsstr := c.coerceString(rhs.LLVMValue(), _string) args := []llvm.Value{lhsstr, rhsstr} 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.NewValue(result, types.Typ[types.Bool]) }
func (d *CompileUnitDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false), d.Path.path(), llvm.ConstInt(llvm.Int32Type(), uint64(d.Language), false), llvm.MDString(d.Producer), constInt1(d.Optimized), llvm.MDString(d.CompilerFlags), llvm.ConstInt(llvm.Int32Type(), uint64(d.Runtime), false), d.mdNodeList(info, d.EnumTypes), d.mdNodeList(info, d.RetainedTypes), d.mdNodeList(info, d.Subprograms), d.mdNodeList(info, d.GlobalVariables), d.mdNodeList(info, nil), // List of imported entities llvm.MDString(""), // Split debug filename }) }
func (d *CompositeTypeDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false), FileDescriptor(d.File).path(), info.MDNode(d.Context), llvm.MDString(d.Name), llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false), llvm.ConstInt(llvm.Int64Type(), d.Size, false), llvm.ConstInt(llvm.Int64Type(), d.Alignment, false), llvm.ConstInt(llvm.Int64Type(), d.Offset, false), llvm.ConstInt(llvm.Int32Type(), uint64(d.Flags), false), info.MDNode(d.Base), // reference type derived from llvm.MDNode(info.MDNodes(d.Members)), llvm.ConstInt(llvm.Int32Type(), uint64(0), false), // Runtime language llvm.ConstInt(llvm.Int32Type(), uint64(0), false), // Base type containing the vtable pointer for this type }) }
func (d FileDescriptor) mdNode(info *DebugInfo) llvm.Value { if d == "" { return llvm.Value{} } return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false), d.path(), }) }
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 }
// makeLiteralSlice allocates a new slice, storing in it the provided elements. func (c *compiler) makeLiteralSlice(v []llvm.Value, elttyp types.Type) llvm.Value { n := llvm.ConstInt(c.types.inttype, uint64(len(v)), false) eltType := c.types.ToLLVM(elttyp) arrayType := llvm.ArrayType(eltType, len(v)) mem := c.createMalloc(llvm.SizeOf(arrayType)) mem = c.builder.CreateIntToPtr(mem, llvm.PointerType(eltType, 0), "") for i, value := range v { indices := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), uint64(i), false)} ep := c.builder.CreateGEP(mem, indices, "") c.builder.CreateStore(value, ep) } slicetyp := types.NewSlice(elttyp) struct_ := llvm.Undef(c.types.ToLLVM(slicetyp)) struct_ = c.builder.CreateInsertValue(struct_, mem, 0, "") struct_ = c.builder.CreateInsertValue(struct_, n, 1, "") struct_ = c.builder.CreateInsertValue(struct_, n, 2, "") return struct_ }
func NewLLVMTypeMap(target llvm.TargetData) *llvmTypeMap { // spec says int is either 32-bit or 64-bit. var inttype llvm.Type if target.PointerSize() >= 8 { inttype = llvm.Int64Type() } else { inttype = llvm.Int32Type() } return &llvmTypeMap{ StdSizes: &types.StdSizes{ WordSize: int64(target.PointerSize()), MaxAlign: 8, }, target: target, inttype: inttype, ptrstandin: llvm.GlobalContext().StructCreateNamed(""), } }
func (d *SubprogramDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false), FileDescriptor(d.File).path(), info.MDNode(d.Context), llvm.MDString(d.Name), llvm.MDString(d.DisplayName), llvm.MDString(""), // mips linkage name llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false), info.MDNode(d.Type), llvm.ConstNull(llvm.Int1Type()), // not static llvm.ConstAllOnes(llvm.Int1Type()), // locally defined (not extern) llvm.ConstNull(llvm.Int32Type()), // virtuality llvm.ConstNull(llvm.Int32Type()), // index into a virtual function info.MDNode(nil), // basetype containing the vtable pointer llvm.ConstInt(llvm.Int32Type(), 0, false), // flags llvm.ConstNull(llvm.Int1Type()), // not optimised d.Function, info.MDNode(nil), // Template parameters info.MDNode(nil), // function declaration descriptor llvm.MDNode(nil), // function variables llvm.ConstInt(llvm.Int32Type(), uint64(d.ScopeLine), false), // Line number where the scope of the subprogram begins }) }
// 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()) } }
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)) }
func (c *compiler) chanSelect(states []selectState, blocking bool) *LLVMValue { stackptr := c.stacksave() defer c.stackrestore(stackptr) n := uint64(len(states)) if !blocking { // blocking means there's no default case n++ } lln := llvm.ConstInt(llvm.Int32Type(), n, false) allocsize := c.builder.CreateCall(c.runtime.selectsize.LLVMValue(), []llvm.Value{lln}, "") selectp := c.builder.CreateArrayAlloca(llvm.Int8Type(), allocsize, "selectp") c.memsetZero(selectp, allocsize) selectp = c.builder.CreatePtrToInt(selectp, c.target.IntPtrType(), "") c.builder.CreateCall(c.runtime.selectinit.LLVMValue(), []llvm.Value{lln, selectp}, "") // Allocate stack for the values to send/receive. // // TODO(axw) request optimisation in ssa to special- // case receive cases with no assignment, so we know // not to allocate stack space or do a copy. resTypes := []types.Type{types.Typ[types.Int], types.Typ[types.Bool]} for _, state := range states { if state.Dir == types.RecvOnly { chantyp := state.Chan.Type().Underlying().(*types.Chan) resTypes = append(resTypes, chantyp.Elem()) } } resType := tupleType(resTypes...) llResType := c.types.ToLLVM(resType) tupleptr := c.builder.CreateAlloca(llResType, "") c.memsetZero(tupleptr, llvm.SizeOf(llResType)) var recvindex int ptrs := make([]llvm.Value, len(states)) for i, state := range states { chantyp := state.Chan.Type().Underlying().(*types.Chan) elemtyp := c.types.ToLLVM(chantyp.Elem()) if state.Dir == types.SendOnly { ptrs[i] = c.builder.CreateAlloca(elemtyp, "") c.builder.CreateStore(state.Send.LLVMValue(), ptrs[i]) } else { ptrs[i] = c.builder.CreateStructGEP(tupleptr, recvindex+2, "") recvindex++ } ptrs[i] = c.builder.CreatePtrToInt(ptrs[i], c.target.IntPtrType(), "") } // Create select{send,recv} calls. selectsend := c.runtime.selectsend.LLVMValue() selectrecv := c.runtime.selectrecv.LLVMValue() var received llvm.Value if recvindex > 0 { received = c.builder.CreateStructGEP(tupleptr, 1, "") } if !blocking { c.builder.CreateCall(c.runtime.selectdefault.LLVMValue(), []llvm.Value{selectp}, "") } for i, state := range states { ch := state.Chan.LLVMValue() if state.Dir == types.SendOnly { c.builder.CreateCall(selectsend, []llvm.Value{selectp, ch, ptrs[i]}, "") } else { c.builder.CreateCall(selectrecv, []llvm.Value{selectp, ch, ptrs[i], received}, "") } } // Fire off the select. index := c.builder.CreateCall(c.runtime.selectgo.LLVMValue(), []llvm.Value{selectp}, "") tuple := c.builder.CreateLoad(tupleptr, "") tuple = c.builder.CreateInsertValue(tuple, index, 0, "") return c.NewValue(tuple, resType) }
// indirectFunction creates an indirect function from a // given function and arguments, suitable for use with // "defer" and "go". func (c *compiler) indirectFunction(fn *LLVMValue, args []*LLVMValue) *LLVMValue { nilarytyp := types.NewSignature(nil, nil, nil, nil, false) if len(args) == 0 { val := fn.LLVMValue() ptr := c.builder.CreateExtractValue(val, 0, "") ctx := c.builder.CreateExtractValue(val, 1, "") fnval := llvm.Undef(c.types.ToLLVM(nilarytyp)) ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "") ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "") fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "") fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "") return c.NewValue(fnval, nilarytyp) } // Check if function pointer or context pointer is global/null. fnval := fn.LLVMValue() fnptr := fnval var nctx int var fnctx llvm.Value var fnctxindex uint64 var globalfn bool if fnptr.Type().TypeKind() == llvm.StructTypeKind { fnptr = c.builder.CreateExtractValue(fnval, 0, "") fnctx = c.builder.CreateExtractValue(fnval, 1, "") globalfn = !fnptr.IsAFunction().IsNil() if !globalfn { nctx++ } if !fnctx.IsNull() { fnctxindex = uint64(nctx) nctx++ } } else { // We've got a raw global function pointer. Convert to <ptr,ctx>. fnval = llvm.ConstNull(c.types.ToLLVM(fn.Type())) fnval = llvm.ConstInsertValue(fnval, fnptr, []uint32{0}) fn = c.NewValue(fnval, fn.Type()) fnctx = llvm.ConstExtractValue(fnval, []uint32{1}) globalfn = true } i8ptr := llvm.PointerType(llvm.Int8Type(), 0) llvmargs := make([]llvm.Value, len(args)+nctx) llvmargtypes := make([]llvm.Type, len(args)+nctx) for i, arg := range args { llvmargs[i+nctx] = arg.LLVMValue() llvmargtypes[i+nctx] = llvmargs[i+nctx].Type() } if !globalfn { llvmargtypes[0] = fnptr.Type() llvmargs[0] = fnptr } if !fnctx.IsNull() { llvmargtypes[fnctxindex] = fnctx.Type() llvmargs[fnctxindex] = fnctx } // TODO(axw) investigate an option for go statements // to allocate argument structure on the stack in the // initiator, and block until the spawned goroutine // has loaded the arguments from it. structtyp := llvm.StructType(llvmargtypes, false) argstruct := c.createTypeMalloc(structtyp) for i, llvmarg := range llvmargs { argptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "") c.builder.CreateStore(llvmarg, argptr) } // Create a function that will take a pointer to a structure of the type // defined above, or no parameters if there are none to pass. fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false) indirectfn := llvm.AddFunction(c.module.Module, "", fntype) i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "") currblock := c.builder.GetInsertBlock() c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry")) argstruct = indirectfn.Param(0) newargs := make([]*LLVMValue, len(args)) for i := range llvmargs[nctx:] { argptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "") newargs[i] = c.NewValue(c.builder.CreateLoad(argptr, ""), args[i].Type()) } // Unless we've got a global function, extract the // function pointer from the context. if !globalfn { fnval = llvm.Undef(fnval.Type()) fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 0, false)}, "") fnptr = c.builder.CreateLoad(fnptrptr, "") fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "") } if !fnctx.IsNull() { fnctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), fnctxindex, false)}, "") fnctx = c.builder.CreateLoad(fnctxptr, "") fnval = c.builder.CreateInsertValue(fnval, fnctx, 1, "") fn = c.NewValue(fnval, fn.Type()) } c.createCall(fn, newargs) // Indirect function calls' return values are always ignored. c.builder.CreateRetVoid() c.builder.SetInsertPointAtEnd(currblock) fnval = llvm.Undef(c.types.ToLLVM(nilarytyp)) indirectfn = c.builder.CreateBitCast(indirectfn, fnval.Type().StructElementTypes()[0], "") fnval = c.builder.CreateInsertValue(fnval, indirectfn, 0, "") fnval = c.builder.CreateInsertValue(fnval, i8argstruct, 1, "") fn = c.NewValue(fnval, nilarytyp) return fn }
func (d *CompileUnitDescriptor) mdNodeList(info *DebugInfo, list []DebugDescriptor) llvm.Value { if len(list) > 0 { return llvm.MDNode(info.MDNodes(list)) } return llvm.MDNode([]llvm.Value{llvm.ConstNull(llvm.Int32Type())}) }