// 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 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 (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 (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 *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 (c *compiler) callCap(arg *LLVMValue) *LLVMValue { var v llvm.Value switch typ := arg.Type().Underlying().(type) { case *types.Array: v = llvm.ConstInt(c.llvmtypes.inttype, uint64(typ.Len()), false) case *types.Pointer: atyp := typ.Elem().Underlying().(*types.Array) v = llvm.ConstInt(c.llvmtypes.inttype, uint64(atyp.Len()), false) case *types.Slice: v = c.builder.CreateExtractValue(arg.LLVMValue(), 2, "") case *types.Chan: f := c.runtime.chancap.LLVMValue() v = c.builder.CreateCall(f, []llvm.Value{arg.LLVMValue()}, "") } return c.NewValue(v, types.Typ[types.Int]) }
func (c *compiler) slice(x, low, high *LLVMValue) *LLVMValue { if low != nil { low = low.Convert(types.Typ[types.Int]).(*LLVMValue) } else { low = c.NewValue(llvm.ConstNull(c.types.inttype), types.Typ[types.Int]) } if high != nil { high = high.Convert(types.Typ[types.Int]).(*LLVMValue) } else { // all bits set is -1 high = c.NewValue(llvm.ConstAllOnes(c.types.inttype), types.Typ[types.Int]) } switch typ := x.Type().Underlying().(type) { case *types.Pointer: // *array sliceslice := c.runtime.sliceslice.LLVMValue() i8slice := sliceslice.Type().ElementType().ReturnType() sliceValue := llvm.Undef(i8slice) // temporary slice arraytyp := typ.Elem().Underlying().(*types.Array) arrayptr := x.LLVMValue() arrayptr = c.builder.CreateBitCast(arrayptr, i8slice.StructElementTypes()[0], "") arraylen := llvm.ConstInt(c.llvmtypes.inttype, uint64(arraytyp.Len()), false) sliceValue = c.builder.CreateInsertValue(sliceValue, arrayptr, 0, "") sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 1, "") sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 2, "") sliceTyp := types.NewSlice(arraytyp.Elem()) runtimeTyp := c.types.ToRuntime(sliceTyp) runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "") args := []llvm.Value{runtimeTyp, sliceValue, low.LLVMValue(), high.LLVMValue()} result := c.builder.CreateCall(sliceslice, args, "") llvmSliceTyp := c.types.ToLLVM(sliceTyp) return c.NewValue(c.coerceSlice(result, llvmSliceTyp), sliceTyp) case *types.Slice: sliceslice := c.runtime.sliceslice.LLVMValue() i8slice := sliceslice.Type().ElementType().ReturnType() sliceValue := x.LLVMValue() sliceTyp := sliceValue.Type() sliceValue = c.coerceSlice(sliceValue, i8slice) runtimeTyp := c.types.ToRuntime(x.Type()) runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "") args := []llvm.Value{runtimeTyp, sliceValue, low.LLVMValue(), high.LLVMValue()} result := c.builder.CreateCall(sliceslice, args, "") return c.NewValue(c.coerceSlice(result, sliceTyp), x.Type()) case *types.Basic: stringslice := c.runtime.stringslice.LLVMValue() llv := x.LLVMValue() args := []llvm.Value{ c.coerceString(llv, stringslice.Type().ElementType().ParamTypes()[0]), low.LLVMValue(), high.LLVMValue(), } result := c.builder.CreateCall(stringslice, args, "") return c.NewValue(c.coerceString(result, llv.Type()), x.Type()) default: panic("unimplemented") } panic("unreachable") }
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 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(), }) }
// 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_ }
// globalStringPtr returns a *string with the specified value. func (tm *TypeMap) globalStringPtr(value string) llvm.Value { strval := llvm.ConstString(value, false) strglobal := llvm.AddGlobal(tm.module, strval.Type(), "") strglobal.SetInitializer(strval) strglobal = llvm.ConstBitCast(strglobal, llvm.PointerType(llvm.Int8Type(), 0)) strlen := llvm.ConstInt(tm.inttype, uint64(len(value)), false) str := llvm.ConstStruct([]llvm.Value{strglobal, strlen}, false) g := llvm.AddGlobal(tm.module, str.Type(), "") g.SetInitializer(str) return g }
func (tm *TypeMap) arrayRuntimeType(a *types.Array) (global, ptr llvm.Value) { rtype := tm.makeRtype(a, reflect.Array) elemRuntimeType := tm.ToRuntime(a.Elem()) sliceRuntimeType := tm.ToRuntime(types.NewSlice(a.Elem())) uintptrlen := llvm.ConstInt(tm.target.IntPtrType(), uint64(a.Len()), false) arrayType := llvm.ConstNull(tm.runtime.arrayType.llvm) arrayType = llvm.ConstInsertValue(arrayType, rtype, []uint32{0}) arrayType = llvm.ConstInsertValue(arrayType, elemRuntimeType, []uint32{1}) arrayType = llvm.ConstInsertValue(arrayType, sliceRuntimeType, []uint32{2}) arrayType = llvm.ConstInsertValue(arrayType, uintptrlen, []uint32{3}) return tm.makeRuntimeTypeGlobal(arrayType, typeString(a)) }
func (c *compiler) callLen(arg *LLVMValue) *LLVMValue { var lenvalue llvm.Value switch typ := arg.Type().Underlying().(type) { case *types.Array: lenvalue = llvm.ConstInt(c.llvmtypes.inttype, uint64(typ.Len()), false) case *types.Pointer: atyp := typ.Elem().Underlying().(*types.Array) lenvalue = llvm.ConstInt(c.llvmtypes.inttype, uint64(atyp.Len()), false) case *types.Slice: lenvalue = c.builder.CreateExtractValue(arg.LLVMValue(), 1, "") case *types.Map: f := c.runtime.maplen.LLVMValue() lenvalue = c.builder.CreateCall(f, []llvm.Value{arg.LLVMValue()}, "") case *types.Basic: if isString(typ) { lenvalue = c.builder.CreateExtractValue(arg.LLVMValue(), 1, "") } case *types.Chan: f := c.runtime.chanlen.LLVMValue() lenvalue = c.builder.CreateCall(f, []llvm.Value{arg.LLVMValue()}, "") } return c.NewValue(lenvalue, types.Typ[types.Int]) }
func (d *BasicTypeDescriptor) 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), llvm.ConstInt(llvm.Int32Type(), uint64(d.TypeEncoding), false)}) }
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 (tm *TypeMap) makeRtype(t types.Type, k reflect.Kind) llvm.Value { // Not sure if there's an easier way to do this, but if you just // use ConstStruct, you end up getting a different llvm.Type. typ := llvm.ConstNull(tm.runtime.rtype.llvm) elementTypes := tm.runtime.rtype.llvm.StructElementTypes() // Size. size := llvm.ConstInt(elementTypes[0], uint64(tm.Sizeof(t)), false) typ = llvm.ConstInsertValue(typ, size, []uint32{0}) // TODO hash // TODO padding // Alignment. align := llvm.ConstInt(llvm.Int8Type(), uint64(tm.Alignof(t)), false) typ = llvm.ConstInsertValue(typ, align, []uint32{3}) // var typ = llvm.ConstInsertValue(typ, align, []uint32{4}) // field // Kind. kind := llvm.ConstInt(llvm.Int8Type(), uint64(k), false) typ = llvm.ConstInsertValue(typ, kind, []uint32{5}) // Algorithm table. alg := tm.makeAlgorithmTable(t) algptr := llvm.AddGlobal(tm.module, alg.Type(), "") algptr.SetInitializer(alg) algptr = llvm.ConstBitCast(algptr, elementTypes[6]) typ = llvm.ConstInsertValue(typ, algptr, []uint32{6}) // String representation. stringrep := tm.globalStringPtr(t.String()) typ = llvm.ConstInsertValue(typ, stringrep, []uint32{8}) // TODO gc return typ }
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 }) }
func (tm *TypeMap) makeSlice(values []llvm.Value, slicetyp llvm.Type) llvm.Value { ptrtyp := slicetyp.StructElementTypes()[0] var globalptr llvm.Value if len(values) > 0 { array := llvm.ConstArray(ptrtyp.ElementType(), values) globalptr = llvm.AddGlobal(tm.module, array.Type(), "") globalptr.SetInitializer(array) globalptr = llvm.ConstBitCast(globalptr, ptrtyp) } else { globalptr = llvm.ConstNull(ptrtyp) } len_ := llvm.ConstInt(tm.inttype, uint64(len(values)), false) slice := llvm.ConstNull(slicetyp) slice = llvm.ConstInsertValue(slice, globalptr, []uint32{0}) slice = llvm.ConstInsertValue(slice, len_, []uint32{1}) slice = llvm.ConstInsertValue(slice, len_, []uint32{2}) return slice }
func (tm *TypeMap) structRuntimeType(s *types.Struct) (global, ptr llvm.Value) { rtype := tm.makeRtype(s, reflect.Struct) structType := llvm.ConstNull(tm.runtime.structType.llvm) structType = llvm.ConstInsertValue(structType, rtype, []uint32{0}) global, ptr = tm.makeRuntimeTypeGlobal(structType, typeString(s)) tm.types.Set(s, runtimeTypeInfo{global, ptr}) fieldVars := make([]*types.Var, s.NumFields()) for i := range fieldVars { fieldVars[i] = s.Field(i) } offsets := tm.Offsetsof(fieldVars) structFields := make([]llvm.Value, len(fieldVars)) for i := range structFields { field := fieldVars[i] structField := llvm.ConstNull(tm.runtime.structField.llvm) if !field.Anonymous() { name := tm.globalStringPtr(field.Name()) name = llvm.ConstBitCast(name, tm.runtime.structField.llvm.StructElementTypes()[0]) structField = llvm.ConstInsertValue(structField, name, []uint32{0}) } if !ast.IsExported(field.Name()) { pkgpath := tm.globalStringPtr(field.Pkg().Path()) pkgpath = llvm.ConstBitCast(pkgpath, tm.runtime.structField.llvm.StructElementTypes()[1]) structField = llvm.ConstInsertValue(structField, pkgpath, []uint32{1}) } fieldType := tm.ToRuntime(field.Type()) structField = llvm.ConstInsertValue(structField, fieldType, []uint32{2}) if tag := s.Tag(i); tag != "" { tag := tm.globalStringPtr(tag) tag = llvm.ConstBitCast(tag, tm.runtime.structField.llvm.StructElementTypes()[3]) structField = llvm.ConstInsertValue(structField, tag, []uint32{3}) } offset := llvm.ConstInt(tm.runtime.structField.llvm.StructElementTypes()[4], uint64(offsets[i]), false) structField = llvm.ConstInsertValue(structField, offset, []uint32{4}) structFields[i] = structField } structFieldsSliceType := tm.runtime.structType.llvm.StructElementTypes()[1] structFieldsSlice := tm.makeSlice(structFields, structFieldsSliceType) structType = llvm.ConstInsertValue(structType, structFieldsSlice, []uint32{1}) global.SetInitializer(structType) return global, ptr }
func (tm *TypeMap) funcRuntimeType(f *types.Signature) (global, ptr llvm.Value) { rtype := tm.makeRtype(f, reflect.Func) funcType := llvm.ConstNull(tm.runtime.funcType.llvm) global, ptr = tm.makeRuntimeTypeGlobal(funcType, typeString(f)) tm.types.Set(f, runtimeTypeInfo{global, ptr}) funcType = llvm.ConstInsertValue(funcType, rtype, []uint32{0}) // dotdotdot if f.Variadic() { variadic := llvm.ConstInt(llvm.Int1Type(), 1, false) funcType = llvm.ConstInsertValue(funcType, variadic, []uint32{1}) } // in intypes := tm.rtypeSlice(f.Params()) funcType = llvm.ConstInsertValue(funcType, intypes, []uint32{2}) // out outtypes := tm.rtypeSlice(f.Results()) funcType = llvm.ConstInsertValue(funcType, outtypes, []uint32{3}) global.SetInitializer(funcType) return global, ptr }
func (tm *TypeMap) chanRuntimeType(c *types.Chan) (global, ptr llvm.Value) { rtype := tm.makeRtype(c, reflect.Chan) chanType := llvm.ConstNull(tm.runtime.chanType.llvm) chanType = llvm.ConstInsertValue(chanType, rtype, []uint32{0}) chanType = llvm.ConstInsertValue(chanType, tm.ToRuntime(c.Elem()), []uint32{1}) // go/ast and reflect disagree on values for direction. var dir reflect.ChanDir switch c.Dir() { case types.SendOnly: dir = reflect.SendDir case types.RecvOnly: dir = reflect.RecvDir case types.SendRecv: dir = reflect.SendDir | reflect.RecvDir } uintptrdir := llvm.ConstInt(tm.target.IntPtrType(), uint64(dir), false) chanType = llvm.ConstInsertValue(chanType, uintptrdir, []uint32{2}) return tm.makeRuntimeTypeGlobal(chanType, typeString(c)) }
func (lhs *LLVMValue) shift(rhs *LLVMValue, op token.Token) *LLVMValue { rhs = rhs.Convert(lhs.Type()).(*LLVMValue) lhsval := lhs.LLVMValue() bits := rhs.LLVMValue() unsigned := isUnsigned(lhs.Type()) b := lhs.compiler.builder // Shifting >= width of lhs yields undefined behaviour, so we must select. max := llvm.ConstInt(bits.Type(), uint64(lhsval.Type().IntTypeWidth()-1), false) var result llvm.Value if !unsigned && op == token.SHR { bits := b.CreateSelect(b.CreateICmp(llvm.IntULE, bits, max, ""), bits, max, "") result = b.CreateAShr(lhsval, bits, "") } else { if op == token.SHL { result = b.CreateShl(lhsval, bits, "") } else { result = b.CreateLShr(lhsval, bits, "") } zero := llvm.ConstNull(lhsval.Type()) result = b.CreateSelect(b.CreateICmp(llvm.IntULE, bits, max, ""), result, zero, "") } return lhs.compiler.NewValue(result, lhs.typ) }
// 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 (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue { switch { case v == nil: llvmtyp := c.types.ToLLVM(typ) return c.NewValue(llvm.ConstNull(llvmtyp), typ) case isString(typ): if isUntyped(typ) { typ = types.Typ[types.String] } llvmtyp := c.types.ToLLVM(typ) strval := exact.StringVal(v) strlen := len(strval) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var ptr llvm.Value if strlen > 0 { init := llvm.ConstString(strval, false) ptr = llvm.AddGlobal(c.module.Module, init.Type(), "") ptr.SetInitializer(init) ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(c.types.inttype, uint64(strlen), false) llvmvalue := llvm.Undef(llvmtyp) llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1}) return c.NewValue(llvmvalue, typ) case isInteger(typ): if isUntyped(typ) { typ = types.Typ[types.Int] } llvmtyp := c.types.ToLLVM(typ) var llvmvalue llvm.Value if isUnsigned(typ) { v, _ := exact.Uint64Val(v) llvmvalue = llvm.ConstInt(llvmtyp, v, false) } else { v, _ := exact.Int64Val(v) llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true) } return c.NewValue(llvmvalue, typ) case isBoolean(typ): if isUntyped(typ) { typ = types.Typ[types.Bool] } var llvmvalue llvm.Value if exact.BoolVal(v) { llvmvalue = llvm.ConstAllOnes(llvm.Int1Type()) } else { llvmvalue = llvm.ConstNull(llvm.Int1Type()) } return c.NewValue(llvmvalue, typ) case isFloat(typ): if isUntyped(typ) { typ = types.Typ[types.Float64] } llvmtyp := c.types.ToLLVM(typ) floatval, _ := exact.Float64Val(v) llvmvalue := llvm.ConstFloat(llvmtyp, floatval) return c.NewValue(llvmvalue, typ) case typ == types.Typ[types.UnsafePointer]: llvmtyp := c.types.ToLLVM(typ) v, _ := exact.Uint64Val(v) llvmvalue := llvm.ConstInt(llvmtyp, v, false) return c.NewValue(llvmvalue, typ) case isComplex(typ): if isUntyped(typ) { typ = types.Typ[types.Complex128] } llvmtyp := c.types.ToLLVM(typ) floattyp := llvmtyp.StructElementTypes()[0] llvmvalue := llvm.ConstNull(llvmtyp) realv := exact.Real(v) imagv := exact.Imag(v) realfloatval, _ := exact.Float64Val(realv) imagfloatval, _ := exact.Float64Val(imagv) llvmre := llvm.ConstFloat(floattyp, realfloatval) llvmim := llvm.ConstFloat(floattyp, imagfloatval) llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1}) return c.NewValue(llvmvalue, typ) } // Special case for string -> [](byte|rune) if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) { if v.Kind() == exact.String { strval := c.NewConstValue(v, types.Typ[types.String]) return strval.Convert(typ).(*LLVMValue) } } panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", typ, typ, v, v)) }
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) }