func (c *compiler) makeInterface(v *LLVMValue, iface types.Type) *LLVMValue { llv := v.LLVMValue() lltyp := llv.Type() i8ptr := llvm.PointerType(llvm.Int8Type(), 0) if lltyp.TypeKind() == llvm.PointerTypeKind { llv = c.builder.CreateBitCast(llv, i8ptr, "") } else { // If the value fits exactly in a pointer, then we can just // bitcast it. Otherwise we need to malloc. if c.target.TypeStoreSize(lltyp) <= uint64(c.target.PointerSize()) { bits := c.target.TypeSizeInBits(lltyp) if bits > 0 { llv = coerce(c.builder, llv, llvm.IntType(int(bits))) llv = c.builder.CreateIntToPtr(llv, i8ptr, "") } else { llv = llvm.ConstNull(i8ptr) } } else { ptr := c.createTypeMalloc(lltyp) c.builder.CreateStore(llv, ptr) llv = c.builder.CreateBitCast(ptr, i8ptr, "") } } value := llvm.Undef(c.types.ToLLVM(iface)) rtype := c.types.ToRuntime(v.Type()) rtype = c.builder.CreateBitCast(rtype, llvm.PointerType(llvm.Int8Type(), 0), "") value = c.builder.CreateInsertValue(value, rtype, 0, "") value = c.builder.CreateInsertValue(value, llv, 1, "") if iface.Underlying().(*types.Interface).NumMethods() > 0 { result := c.NewValue(value, types.NewInterface(nil, nil)) result, _ = result.convertE2I(iface) return result } return c.NewValue(value, iface) }
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 (tm *TypeMap) basicLLVMType(b *types.Basic) llvm.Type { switch b.Kind { case types.BoolKind: return llvm.Int1Type() case types.Int8Kind, types.Uint8Kind: return llvm.Int8Type() case types.Int16Kind, types.Uint16Kind: return llvm.Int16Type() case types.Int32Kind, types.Uint32Kind: return llvm.Int32Type() case types.Int64Kind, types.Uint64Kind: return llvm.Int64Type() case types.Float32Kind: return llvm.FloatType() case types.Float64Kind: return llvm.DoubleType() case types.UnsafePointerKind, types.UintptrKind, types.UintKind, types.IntKind: return tm.target.IntPtrType() //case Complex64: TODO //case Complex128: //case UntypedInt: //case UntypedFloat: //case UntypedComplex: case types.StringKind: i8ptr := llvm.PointerType(llvm.Int8Type(), 0) elements := []llvm.Type{i8ptr, llvm.Int32Type()} return llvm.StructType(elements, false) } panic(fmt.Sprint("unhandled kind: ", b.Kind)) }
func (v ConstValue) LLVMValue() llvm.Value { typ := types.Underlying(v.Type()) switch typ { case types.Int, types.Uint: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) // TODO 32/64bit (probably wait for gc) //int_val := v.Val.(*big.Int) //if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 { // panic(fmt.Sprint("const ", int_val, " overflows int")) //} //return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true) case types.Uint: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int8: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true) case types.Uint8, types.Byte: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false) case types.Int16: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true) case types.Uint16: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false) case types.Int32, types.Rune: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) case types.Uint32: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int64: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Uint64: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Float32: return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64())) case types.Float64: return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64())) case types.UnsafePointer, types.Uintptr: inttype := v.compiler.target.IntPtrType() return llvm.ConstInt(inttype, uint64(v.Int64()), false) case types.String: strval := (v.Val).(string) ptr := v.compiler.builder.CreateGlobalStringPtr(strval, "") len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(strval)), false) return llvm.ConstStruct([]llvm.Value{ptr, len_}, false) case types.Bool: if v := v.Val.(bool); v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) } panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind)) }
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) defineMemcpyFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) dst, src, size := fn.Param(0), fn.Param(1), fn.Param(2) pint8 := llvm.PointerType(llvm.Int8Type(), 0) dst = c.builder.CreateIntToPtr(dst, pint8, "") src = c.builder.CreateIntToPtr(src, pint8, "") sizeType := size.Type() sizeBits := sizeType.IntTypeWidth() memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(sizeBits) memcpy := c.module.NamedFunction(memcpyName) if memcpy.IsNil() { paramtypes := []llvm.Type{ pint8, pint8, size.Type(), llvm.Int32Type(), llvm.Int1Type()} memcpyType := llvm.FunctionType(llvm.VoidType(), paramtypes, false) memcpy = llvm.AddFunction(c.module.Module, memcpyName, memcpyType) } args := []llvm.Value{ dst, src, size, llvm.ConstInt(llvm.Int32Type(), 1, false), // single byte alignment llvm.ConstInt(llvm.Int1Type(), 0, false), // not volatile } c.builder.CreateCall(memcpy, args, "") c.builder.CreateRetVoid() }
func (c *compiler) defineFreeFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) ptr := fn.FirstParam() ptrtyp := llvm.PointerType(llvm.Int8Type(), 0) c.builder.CreateFree(c.builder.CreateIntToPtr(ptr, ptrtyp, "")) c.builder.CreateRetVoid() }
func (tm *LLVMTypeMap) funcLLVMType(tstr string, f *types.Signature) llvm.Type { typ, ok := tm.types[tstr] if !ok { // If there's a receiver change the receiver to an // additional (first) parameter, and take the value of // the resulting signature instead. var param_types []llvm.Type if recv := f.Recv(); recv != nil { params := f.Params() paramvars := make([]*types.Var, int(params.Len()+1)) paramvars[0] = recv for i := 0; i < int(params.Len()); i++ { paramvars[i+1] = params.At(i) } params = types.NewTuple(paramvars...) f := types.NewSignature(nil, params, f.Results(), f.IsVariadic()) return tm.ToLLVM(f) } typ = llvm.GlobalContext().StructCreateNamed("") tm.types[tstr] = typ params := f.Params() nparams := int(params.Len()) for i := 0; i < nparams; i++ { typ := params.At(i).Type() if f.IsVariadic() && i == nparams-1 { typ = types.NewSlice(typ) } llvmtyp := tm.ToLLVM(typ) param_types = append(param_types, llvmtyp) } var return_type llvm.Type results := f.Results() switch nresults := int(results.Len()); nresults { case 0: return_type = llvm.VoidType() case 1: return_type = tm.ToLLVM(results.At(0).Type()) default: elements := make([]llvm.Type, nresults) for i := range elements { result := results.At(i) elements[i] = tm.ToLLVM(result.Type()) } return_type = llvm.StructType(elements, false) } fntyp := llvm.FunctionType(return_type, param_types, false) fnptrtyp := llvm.PointerType(fntyp, 0) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) elements := []llvm.Type{fnptrtyp, i8ptr} // func, closure typ.StructSetBody(elements, false) } return typ }
func NewTypeMap(llvmtm *LLVMTypeMap, module llvm.Module, pkgpath string, exprTypes map[ast.Expr]types.Type, c *FunctionCache, r Resolver) *TypeMap { tm := &TypeMap{ LLVMTypeMap: llvmtm, module: module, pkgpath: pkgpath, types: make(map[string]runtimeTypeInfo), expr: exprTypes, functions: c, resolver: r, } // Load runtime/reflect types, and generate LLVM types for // the structures we need to populate runtime type information. pkg, err := c.compiler.parseReflect() if err != nil { panic(err) // FIXME return err } reflectLLVMType := func(name string) llvm.Type { obj := pkg.Scope.Lookup(name) if obj == nil { panic(fmt.Errorf("Failed to find type: %s", name)) } return tm.ToLLVM(obj.Type.(types.Type)) } tm.runtimeType = reflectLLVMType("runtimeType") tm.runtimeCommonType = reflectLLVMType("commonType") tm.runtimeUncommonType = reflectLLVMType("uncommonType") tm.runtimeArrayType = reflectLLVMType("arrayType") tm.runtimeChanType = reflectLLVMType("chanType") tm.runtimeFuncType = reflectLLVMType("funcType") tm.runtimeMethod = reflectLLVMType("method") tm.runtimeImethod = reflectLLVMType("imethod") tm.runtimeInterfaceType = reflectLLVMType("interfaceType") tm.runtimeMapType = reflectLLVMType("mapType") tm.runtimePtrType = reflectLLVMType("ptrType") tm.runtimeSliceType = reflectLLVMType("sliceType") tm.runtimeStructType = reflectLLVMType("structType") tm.commonType = pkg.Scope.Lookup("commonType").Type.(*types.Name) // Types for algorithms. See 'runtime/runtime.h'. uintptrType := tm.target.IntPtrType() voidPtrType := llvm.PointerType(llvm.Int8Type(), 0) boolType := llvm.Int1Type() // Create runtime algorithm function types. params := []llvm.Type{uintptrType, voidPtrType} tm.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false) params = []llvm.Type{uintptrType, uintptrType, uintptrType} tm.equalAlgFunctionType = llvm.FunctionType(boolType, params, false) params = []llvm.Type{uintptrType, voidPtrType} tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType, voidPtrType} tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) return tm }
func 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) defineMallocFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) size := fn.FirstParam() ptr := c.builder.CreateArrayMalloc(llvm.Int8Type(), size, "") // XXX memset to zero, or leave that to Go runtime code? fn_type := fn.Type().ElementType() result := c.builder.CreatePtrToInt(ptr, fn_type.ReturnType(), "") c.builder.CreateRet(result) }
func getFflush(module llvm.Module) llvm.Value { fflush := module.NamedFunction("fflush") if fflush.IsNil() { voidPtr := llvm.PointerType(llvm.Int8Type(), 0) ftyp := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{voidPtr}, false) fflush = llvm.AddFunction(module, "fflush", ftyp) fflush.SetFunctionCallConv(llvm.CCallConv) } return fflush }
func (c *compiler) createMainFunction() error { // In a PNaCl program (plugin), there should not be a "main.main"; // instead, we expect a "main.CreateModule" function. // See pkg/nacl/ppapi/ppapi.go for more details. mainMain := c.module.NamedFunction("main.main") /* if c.pnacl { // PNaCl's libppapi_stub.a implements "main", which simply // calls through to PpapiPluginMain. We define our own "main" // so that we can capture argc/argv. if !mainMain.IsNil() { return fmt.Errorf("Found main.main") } pluginMain := c.RuntimeFunction("PpapiPluginMain", "func() int32") // Synthesise a main which has no return value. We could cast // PpapiPluginMain, but this is potentially unsafe as its // calling convention is unspecified. ftyp := llvm.FunctionType(llvm.VoidType(), nil, false) mainMain = llvm.AddFunction(c.module.Module, "main.main", ftyp) entry := llvm.AddBasicBlock(mainMain, "entry") c.builder.SetInsertPointAtEnd(entry) c.builder.CreateCall(pluginMain, nil, "") c.builder.CreateRetVoid() } else */{ mainMain = c.module.NamedFunction("main.main") } if mainMain.IsNil() { return fmt.Errorf("Could not find main.main") } // runtime.main is called by main, with argc, argv, argp, // and a pointer to main.main, which must be a niladic // function with no result. runtimeMain := c.runtime.main.LLVMValue() ptrptr := llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0) ftyp := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{llvm.Int32Type(), ptrptr, ptrptr}, true) main := llvm.AddFunction(c.module.Module, "main", ftyp) c.builder.SetCurrentDebugLocation(c.debug.MDNode(nil)) entry := llvm.AddBasicBlock(main, "entry") c.builder.SetInsertPointAtEnd(entry) runtimeMainParamTypes := runtimeMain.Type().ElementType().ParamTypes() args := []llvm.Value{ main.Param(0), // argc main.Param(1), // argv main.Param(2), // argp c.builder.CreateBitCast(mainMain, runtimeMainParamTypes[3], ""), } result := c.builder.CreateCall(runtimeMain, args, "") c.builder.CreateRet(result) return nil }
// 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 (c *compiler) memsetZero(ptr llvm.Value, size llvm.Value) { memset := c.runtime.memset.LLVMValue() switch n := size.Type().IntTypeWidth() - c.target.IntPtrType().IntTypeWidth(); { case n < 0: size = c.builder.CreateZExt(size, c.target.IntPtrType(), "") case n > 0: size = c.builder.CreateTrunc(size, c.target.IntPtrType(), "") } ptr = c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "") fill := llvm.ConstNull(llvm.Int8Type()) c.builder.CreateCall(memset, []llvm.Value{ptr, fill, size}, "") }
func (c *compiler) memsetZero(ptr llvm.Value, size llvm.Value) { memset := c.NamedFunction("runtime.memset", "func f(dst unsafe.Pointer, fill byte, size uintptr)") switch n := size.Type().IntTypeWidth() - c.target.IntPtrType().IntTypeWidth(); { case n < 0: size = c.builder.CreateZExt(size, c.target.IntPtrType(), "") case n > 0: size = c.builder.CreateTrunc(size, c.target.IntPtrType(), "") } ptr = c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "") fill := llvm.ConstNull(llvm.Int8Type()) c.builder.CreateCall(memset, []llvm.Value{ptr, fill, size}, "") }
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. lt := tm.ToLLVM(t) typ := llvm.ConstNull(tm.runtimeType) elementTypes := tm.runtimeType.StructElementTypes() // Size. size := llvm.SizeOf(lt) if size.Type().IntTypeWidth() > elementTypes[0].IntTypeWidth() { size = llvm.ConstTrunc(size, elementTypes[0]) } typ = llvm.ConstInsertValue(typ, size, []uint32{0}) // TODO hash // TODO padding // Alignment. align := llvm.ConstTrunc(llvm.AlignOf(lt), llvm.Int8Type()) 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(tm.TypeString(t)) typ = llvm.ConstInsertValue(typ, stringrep, []uint32{8}) // TODO gc return typ }
func NewTypeMap(llvmtm *LLVMTypeMap, pkgpath string, exprTypes map[ast.Expr]types.Type, c *FunctionCache, p map[*ast.Object]string, r Resolver) *TypeMap { tm := &TypeMap{ LLVMTypeMap: llvmtm, pkgpath: pkgpath, types: make(map[types.Type]llvm.Value), expr: exprTypes, pkgmap: p, functions: c, resolver: r, } // Load "reflect.go", and generate LLVM types for the runtime type // structures. pkg, err := parseReflect() if err != nil { panic(err) // FIXME return err } objToLLVMType := func(name string) llvm.Type { obj := pkg.Scope.Lookup(name) return tm.ToLLVM(obj.Type.(types.Type)) } tm.runtimeType = objToLLVMType("runtimeType") tm.runtimeCommonType = objToLLVMType("commonType") tm.runtimeUncommonType = objToLLVMType("uncommonType") tm.runtimeArrayType = objToLLVMType("arrayType") tm.runtimeChanType = objToLLVMType("chanType") tm.runtimeFuncType = objToLLVMType("funcType") tm.runtimeMethod = objToLLVMType("method") tm.runtimeImethod = objToLLVMType("imethod") tm.runtimeInterfaceType = objToLLVMType("interfaceType") tm.runtimeMapType = objToLLVMType("mapType") tm.runtimePtrType = objToLLVMType("ptrType") tm.runtimeSliceType = objToLLVMType("sliceType") tm.runtimeStructType = objToLLVMType("structType") // Types for algorithms. See 'runtime/runtime.h'. uintptrType := tm.target.IntPtrType() voidPtrType := llvm.PointerType(llvm.Int8Type(), 0) boolType := llvm.Int1Type() // Create runtime algorithm function types. params := []llvm.Type{uintptrType, voidPtrType} tm.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false) params = []llvm.Type{uintptrType, uintptrType, uintptrType} tm.equalAlgFunctionType = llvm.FunctionType(boolType, params, false) params = []llvm.Type{uintptrType, voidPtrType} tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType, voidPtrType} tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) return tm }
func (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 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 (tm *llvmTypeMap) interfaceLLVMType(i *types.Interface, name string) llvm.Type { if typ, ok := tm.types.At(i).(llvm.Type); ok { return typ } // interface{} is represented as {type, value}, // and non-empty interfaces are represented as {itab, value}. i8ptr := llvm.PointerType(llvm.Int8Type(), 0) rtypeType := i8ptr valueType := i8ptr if name == "" { name = i.String() } typ := llvm.GlobalContext().StructCreateNamed(name) typ.StructSetBody([]llvm.Type{rtypeType, valueType}, false) return typ }
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) { // Each runtime type is preceded by an interface{}. initType := llvm.StructType([]llvm.Type{tm.runtimeType, v.Type()}, false) global = llvm.AddGlobal(tm.module, initType, "") ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtimeType, 0)) // interface{} containing v's *commonType representation. runtimeTypeValue := llvm.Undef(tm.runtimeType) zero := llvm.ConstNull(llvm.Int32Type()) one := llvm.ConstInt(llvm.Int32Type(), 1, false) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) if tm.commonTypePtrRuntimeType.IsNil() { // Create a dummy pointer value, which we'll update straight after // defining the runtime type info for commonType. tm.commonTypePtrRuntimeType = llvm.Undef(i8ptr) commonTypePtr := &types.Pointer{Base: tm.commonType} commonTypeGlobal, commonTypeRuntimeType := tm.makeRuntimeType(tm.commonType) tm.types[tm.commonType.String()] = runtimeTypeInfo{commonTypeGlobal, commonTypeRuntimeType} commonTypePtrGlobal, commonTypePtrRuntimeType := tm.makeRuntimeType(commonTypePtr) tm.types[commonTypePtr.String()] = runtimeTypeInfo{commonTypePtrGlobal, commonTypePtrRuntimeType} tm.commonTypePtrRuntimeType = llvm.ConstBitCast(commonTypePtrRuntimeType, i8ptr) if tm.pkgpath == tm.commonType.Package { // Update the interace{} header of the commonType/*commonType // runtime types we just created. for _, g := range [...]llvm.Value{commonTypeGlobal, commonTypePtrGlobal} { init := g.Initializer() typptr := tm.commonTypePtrRuntimeType runtimeTypeValue := llvm.ConstExtractValue(init, []uint32{0}) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, typptr, []uint32{0}) init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0}) g.SetInitializer(init) } } } commonTypePtr := llvm.ConstGEP(global, []llvm.Value{zero, one}) commonTypePtr = llvm.ConstBitCast(commonTypePtr, i8ptr) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, tm.commonTypePtrRuntimeType, []uint32{0}) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, commonTypePtr, []uint32{1}) init := llvm.Undef(initType) init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0}) init = llvm.ConstInsertValue(init, v, []uint32{1}) global.SetInitializer(init) return global, ptr }
func (tm *TypeMap) interfaceLLVMType(i *types.Interface) llvm.Type { valptr_type := llvm.PointerType(llvm.Int8Type(), 0) typptr_type := valptr_type // runtimeCommonType may not be defined yet elements := make([]llvm.Type, 2+len(i.Methods)) elements[0] = valptr_type // value elements[1] = typptr_type // type for n, m := range i.Methods { // Add an opaque pointer parameter to the function for the // struct pointer. fntype := m.Type.(*types.Func) receiver_type := &types.Pointer{Base: types.Int8} fntype.Recv = ast.NewObj(ast.Var, "") fntype.Recv.Type = receiver_type elements[n+2] = tm.ToLLVM(fntype) } return llvm.StructType(elements, false) }
func NewTypeMap(module llvm.Module, target llvm.TargetData, exprTypes map[ast.Expr]types.Type) *TypeMap { tm := &TypeMap{module: module, target: target, expr: exprTypes} tm.types = make(map[types.Type]llvm.Type) tm.runtime = make(map[types.Type]llvm.Value) // Load "reflect.go", and generate LLVM types for the runtime type // structures. pkg, err := parseReflect() if err != nil { panic(err) // FIXME return err } objToLLVMType := func(name string) llvm.Type { obj := pkg.Scope.Lookup(name) return tm.ToLLVM(obj.Type.(types.Type)) } tm.runtimeCommonType = objToLLVMType("commonType") tm.runtimeUncommonType = objToLLVMType("uncommonType") tm.runtimeArrayType = objToLLVMType("arrayType") tm.runtimeChanType = objToLLVMType("chanType") tm.runtimeFuncType = objToLLVMType("funcType") tm.runtimeInterfaceType = objToLLVMType("interfaceType") tm.runtimeMapType = objToLLVMType("mapType") tm.runtimePtrType = objToLLVMType("ptrType") tm.runtimeSliceType = objToLLVMType("sliceType") tm.runtimeStructType = objToLLVMType("structType") // Types for algorithms. See 'runtime/runtime.h'. uintptrType := tm.target.IntPtrType() voidPtrType := llvm.PointerType(llvm.Int8Type(), 0) boolType := llvm.Int1Type() // Create runtime algorithm function types. params := []llvm.Type{ llvm.PointerType(uintptrType, 0), uintptrType, voidPtrType} tm.hashAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{ llvm.PointerType(boolType, 0), uintptrType, voidPtrType, voidPtrType} tm.equalAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType} tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType, voidPtrType} tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) return tm }
func (tm *LLVMTypeMap) interfaceLLVMType(tstr string, i *types.Interface) llvm.Type { typ, ok := tm.types[tstr] if !ok { typ = llvm.GlobalContext().StructCreateNamed("") tm.types[tstr] = typ valptr_type := llvm.PointerType(llvm.Int8Type(), 0) typptr_type := valptr_type // runtimeType may not be defined yet elements := make([]llvm.Type, 2+i.NumMethods()) elements[0] = typptr_type // type elements[1] = valptr_type // value for n, m := range sortedMethods(i) { fntype := m.Type() elements[n+2] = tm.ToLLVM(fntype).StructElementTypes()[0] } typ.StructSetBody(elements, false) } return typ }
func newAlgorithmMap(m llvm.Module, runtime *runtimeInterface, target llvm.TargetData) *algorithmMap { am := &algorithmMap{ module: m, runtime: runtime, } uintptrType := target.IntPtrType() voidPtrType := llvm.PointerType(llvm.Int8Type(), 0) boolType := llvm.Int1Type() params := []llvm.Type{uintptrType, voidPtrType} am.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false) params = []llvm.Type{uintptrType, uintptrType, uintptrType} am.equalAlgFunctionType = llvm.FunctionType(boolType, params, false) params = []llvm.Type{uintptrType, voidPtrType} am.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType, voidPtrType} am.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) return am }
// makeClosure creates a closure from a function pointer and // a set of bindings. The bindings are addresses of captured // variables. func (c *compiler) makeClosure(fn *LLVMValue, bindings []*LLVMValue) *LLVMValue { types := make([]llvm.Type, len(bindings)) for i, binding := range bindings { types[i] = c.types.ToLLVM(binding.Type()) } block := c.createTypeMalloc(llvm.StructType(types, false)) for i, binding := range bindings { addressPtr := c.builder.CreateStructGEP(block, i, "") c.builder.CreateStore(binding.LLVMValue(), addressPtr) } block = c.builder.CreateBitCast(block, llvm.PointerType(llvm.Int8Type(), 0), "") // fn is a raw function pointer; ToLLVM yields {*fn, *uint8}. closure := llvm.Undef(c.types.ToLLVM(fn.Type())) fnptr := c.builder.CreateBitCast(fn.LLVMValue(), closure.Type().StructElementTypes()[0], "") closure = c.builder.CreateInsertValue(closure, fnptr, 0, "") closure = c.builder.CreateInsertValue(closure, block, 1, "") return c.NewValue(closure, fn.Type()) }
// convertI2V converts an interface to a value. func (v *LLVMValue) convertI2V(typ types.Type) (result, success Value) { typptrType := llvm.PointerType(llvm.Int8Type(), 0) runtimeType := v.compiler.types.ToRuntime(typ) runtimeType = llvm.ConstBitCast(runtimeType, typptrType) vval := v.LLVMValue() builder := v.compiler.builder ifaceType := builder.CreateExtractValue(vval, 0, "") diff := builder.CreatePtrDiff(runtimeType, ifaceType, "") zero := llvm.ConstNull(diff.Type()) predicate := builder.CreateICmp(llvm.IntEQ, diff, zero, "") // If result is zero, then we've got a match. end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end") end.MoveAfter(builder.GetInsertBlock()) nonmatch := llvm.InsertBasicBlock(end, "nonmatch") match := llvm.InsertBasicBlock(nonmatch, "match") builder.CreateCondBr(predicate, match, nonmatch) builder.SetInsertPointAtEnd(match) matchResultValue := v.loadI2V(typ).LLVMValue() builder.CreateBr(end) builder.SetInsertPointAtEnd(nonmatch) nonmatchResultValue := llvm.ConstNull(matchResultValue.Type()) builder.CreateBr(end) builder.SetInsertPointAtEnd(end) successValue := builder.CreatePHI(llvm.Int1Type(), "") resultValue := builder.CreatePHI(matchResultValue.Type(), "") successValues := []llvm.Value{llvm.ConstAllOnes(llvm.Int1Type()), llvm.ConstNull(llvm.Int1Type())} successBlocks := []llvm.BasicBlock{match, nonmatch} successValue.AddIncoming(successValues, successBlocks) success = v.compiler.NewLLVMValue(successValue, types.Bool) resultValues := []llvm.Value{matchResultValue, nonmatchResultValue} resultBlocks := []llvm.BasicBlock{match, nonmatch} resultValue.AddIncoming(resultValues, resultBlocks) result = v.compiler.NewLLVMValue(resultValue, typ) return result, success }
func (c *compiler) getBoolString(v llvm.Value) llvm.Value { startBlock := c.builder.GetInsertBlock() resultBlock := llvm.InsertBasicBlock(startBlock, "") resultBlock.MoveAfter(startBlock) falseBlock := llvm.InsertBasicBlock(resultBlock, "") CharPtr := llvm.PointerType(llvm.Int8Type(), 0) falseString := c.builder.CreateGlobalStringPtr("false", "") falseString = c.builder.CreateBitCast(falseString, CharPtr, "") trueString := c.builder.CreateGlobalStringPtr("true", "") trueString = c.builder.CreateBitCast(trueString, CharPtr, "") c.builder.CreateCondBr(v, resultBlock, falseBlock) c.builder.SetInsertPointAtEnd(falseBlock) c.builder.CreateBr(resultBlock) c.builder.SetInsertPointAtEnd(resultBlock) result := c.builder.CreatePHI(CharPtr, "") result.AddIncoming([]llvm.Value{trueString, falseString}, []llvm.BasicBlock{startBlock, falseBlock}) return result }
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 }