func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value, name string) (global, ptr llvm.Value) { global = llvm.AddGlobal(tm.module, v.Type(), typeSymbol(name)) global.SetInitializer(v) global.SetLinkage(llvm.LinkOnceAnyLinkage) ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0)) return global, ptr }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) const eqalgsig = "func(uintptr, unsafe.Pointer, unsafe.Pointer) bool" var equalAlg llvm.Value switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: equalAlg = tm.functions.NamedFunction("runtime.streqalg", eqalgsig) case types.Float32: equalAlg = tm.functions.NamedFunction("runtime.f32eqalg", eqalgsig) case types.Float64: equalAlg = tm.functions.NamedFunction("runtime.f64eqalg", eqalgsig) case types.Complex64: equalAlg = tm.functions.NamedFunction("runtime.c64eqalg", eqalgsig) case types.Complex128: equalAlg = tm.functions.NamedFunction("runtime.c128eqalg", eqalgsig) } } if equalAlg.IsNil() { equalAlg = tm.functions.NamedFunction("runtime.memequal", eqalgsig) } elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
func (c *compiler) createMalloc(size llvm.Value) llvm.Value { malloc := c.NamedFunction("runtime.malloc", "func f(uintptr) unsafe.Pointer") if size.Type().IntTypeWidth() > c.target.IntPtrType().IntTypeWidth() { size = c.builder.CreateTrunc(size, c.target.IntPtrType(), "") } return c.builder.CreateCall(malloc, []llvm.Value{size}, "") }
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() }
// Debug intrinsic collectors. func createGlobalVariableMetadata(global llvm.Value) llvm.DebugDescriptor { return &llvm.GlobalVariableDescriptor{ Name: global.Name(), DisplayName: global.Name(), //File: //Line: Type: int32_debug_type, // FIXME Value: global} }
func (c *compiler) createMalloc(size llvm.Value) llvm.Value { malloc := c.NamedFunction("runtime.malloc", "func(uintptr) unsafe.Pointer") 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(), "") } return c.builder.CreateCall(malloc, []llvm.Value{size}, "") }
func (c *compiler) createMalloc(size llvm.Value) llvm.Value { malloc := c.runtime.malloc.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(), "") } return c.builder.CreateCall(malloc, []llvm.Value{size}, "") }
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 (b *Builder) CreateLoad(v llvm.Value, name string) llvm.Value { if v.Type().ElementType() == b.types.ptrstandin { // We represent recursive pointer types (T = *T) // in LLVM as a pointer to "ptrstdin", where // ptrstandin is a unique named struct. // // Cast the the pointer to a pointer to its own type first. v = b.CreateBitCast(v, llvm.PointerType(v.Type(), 0), "") } return b.Builder.CreateLoad(v, name) }
func (c *compiler) makeFunc(ident *ast.Ident, ftyp *types.Signature) *LLVMValue { fname := ident.String() if ftyp.Recv() == nil && fname == "init" { // Make "init" functions anonymous. fname = "" } else { var pkgname string if recv := ftyp.Recv(); recv != nil { var recvname string switch recvtyp := recv.Type().(type) { case *types.Pointer: if named, ok := recvtyp.Elem().(*types.Named); ok { obj := named.Obj() recvname = "*" + obj.Name() pkgname = obj.Pkg().Path() } case *types.Named: named := recvtyp obj := named.Obj() recvname = obj.Name() pkgname = obj.Pkg().Path() } if recvname != "" { fname = fmt.Sprintf("%s.%s", recvname, fname) } else { // If the receiver is an unnamed struct, we're // synthesising a method for an unnamed struct // type. There's no meaningful name to give the // function, so leave it up to LLVM. fname = "" } } else { obj := c.typeinfo.Objects[ident] pkgname = obj.Pkg().Path() } if fname != "" { fname = pkgname + "." + fname } } // gcimporter may produce multiple AST objects for the same function. llvmftyp := c.types.ToLLVM(ftyp) var fn llvm.Value if fname != "" { fn = c.module.Module.NamedFunction(fname) } if fn.IsNil() { llvmfptrtyp := llvmftyp.StructElementTypes()[0].ElementType() fn = llvm.AddFunction(c.module.Module, fname, llvmfptrtyp) } fn = llvm.ConstInsertValue(llvm.ConstNull(llvmftyp), fn, []uint32{0}) return c.NewValue(fn, ftyp) }
// coerce yields a value of the the type specified, initialised // to the exact bit pattern as in the specified value. // // Note: the specified value must be a non-aggregate, and its type // and the specified type must have the same size. func (c *compiler) coerce(v llvm.Value, t llvm.Type) llvm.Value { switch t.TypeKind() { case llvm.ArrayTypeKind, llvm.StructTypeKind: ptr := c.builder.CreateAlloca(t, "") ptrv := c.builder.CreateBitCast(ptr, llvm.PointerType(v.Type(), 0), "") c.builder.CreateStore(v, ptrv) return c.builder.CreateLoad(ptr, "") default: return c.builder.CreateBitCast(v, t, "") } panic("unreachable") }
func (c *compiler) newStackVarEx(argument int, stackf *LLVMValue, v types.Object, value llvm.Value, name string) (stackvalue llvm.Value, stackvar *LLVMValue) { typ := v.Type() // We need to put alloca instructions in the top block or the values // displayed when inspecting these variables in a debugger will be // completely messed up. curBlock := c.builder.GetInsertBlock() if p := curBlock.Parent(); !p.IsNil() { fb := p.FirstBasicBlock() fi := fb.FirstInstruction() if !fb.IsNil() && !fi.IsNil() { c.builder.SetInsertPointBefore(fi) } } old := c.builder.CurrentDebugLocation() c.builder.SetCurrentDebugLocation(llvm.Value{}) stackvalue = c.builder.CreateAlloca(c.types.ToLLVM(typ), name) // For arguments we want to insert the store instruction // without debug information to ensure that they are executed // (and hence have proper values) before the debugger hits the // first line in a function. if argument == 0 { c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) } if !value.IsNil() { c.builder.CreateStore(value, stackvalue) } c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) ptrvalue := c.NewValue(stackvalue, types.NewPointer(typ)) stackvar = ptrvalue.makePointee() stackvar.stack = stackf c.objectdata[v].Value = stackvar file := c.fileset.File(v.Pos()) tag := llvm.DW_TAG_auto_variable if argument > 0 { tag = llvm.DW_TAG_arg_variable } ld := llvm.NewLocalVariableDescriptor(tag) ld.Argument = uint32(argument) ld.Line = uint32(file.Line(v.Pos())) ld.Name = name ld.File = &llvm.ContextDescriptor{llvm.FileDescriptor(file.Name())} ld.Type = c.tollvmDebugDescriptor(typ) ld.Context = c.currentDebugContext() c.builder.InsertDeclare(c.module.Module, llvm.MDNode([]llvm.Value{stackvalue}), c.debug_info.MDNode(ld)) return stackvalue, stackvar }
func (b *Builder) CreateStore(v, ptr llvm.Value) { if !b.types.ptrstandin.IsNil() { vtyp, ptrtyp := v.Type(), ptr.Type() if vtyp == ptrtyp { // We must be dealing with a pointer to a recursive pointer // type, so bitcast the pointer to a pointer to its own // type first. ptr = b.CreateBitCast(ptr, llvm.PointerType(ptrtyp, 0), "") } } b.Builder.CreateStore(v, ptr) }
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 (b *Builder) CreateStore(v, ptr llvm.Value) { if !b.types.ptrstandin.IsNil() { vtyp, ptrtyp := v.Type(), ptr.Type() if vtyp == ptrtyp || ptrtyp.ElementType() == b.types.ptrstandin { // We must be dealing with a pointer to a recursive pointer // type, so bitcast the value to the pointer's base, opaque // pointer type. v = b.CreateBitCast(v, ptrtyp.ElementType(), "") } } b.Builder.CreateStore(v, ptr) }
func (b *Builder) CreateLoad(v llvm.Value, name string) llvm.Value { result := b.Builder.CreateLoad(v, name) if !b.types.ptrstandin.IsNil() && result.Type() == b.types.ptrstandin { // We represent recursive pointer types (T = *T) // in LLVM as a pointer to "ptrstdin", where // ptrstandin is a pointer to a unique named struct. // // Cast the result of loading the pointer back to // the same type as the pointer loaded from. result = b.CreateBitCast(result, v.Type(), "") } return result }
func (c *compiler) newStackVarEx(argument int, stackf *LLVMValue, v types.Object, value llvm.Value, name string) (stackvalue llvm.Value, stackvar *LLVMValue) { typ := v.Type() // We need to put alloca instructions in the top block or the values // displayed when inspecting these variables in a debugger will be // completely messed up. curBlock := c.builder.GetInsertBlock() if p := curBlock.Parent(); !p.IsNil() { fb := p.FirstBasicBlock() fi := fb.FirstInstruction() if !fb.IsNil() && !fi.IsNil() { c.builder.SetInsertPointBefore(fi) } } old := c.builder.CurrentDebugLocation() c.builder.SetCurrentDebugLocation(llvm.Value{}) stackvalue = c.builder.CreateAlloca(c.types.ToLLVM(typ), name) // For arguments we want to insert the store instruction // without debug information to ensure that they are executed // (and hence have proper values) before the debugger hits the // first line in a function. if argument == 0 { c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) } if !value.IsNil() { c.builder.CreateStore(value, stackvalue) } c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) ptrvalue := c.NewValue(stackvalue, types.NewPointer(typ)) stackvar = ptrvalue.makePointee() stackvar.stack = stackf c.objectdata[v].Value = stackvar // Generate debug metadata (will return nil // if debug-data generation is disabled). if descriptor := c.createLocalVariableMetadata(v, argument); descriptor != nil { c.builder.InsertDeclare( c.module.Module, llvm.MDNode([]llvm.Value{stackvalue}), c.debug_info.MDNode(descriptor), ) } return stackvalue, stackvar }
func (v *LLVMValue) chanSend(value Value) { var ptr llvm.Value if value, ok := value.(*LLVMValue); ok && value.pointer != nil { ptr = value.pointer.LLVMValue() } elttyp := types.Underlying(v.typ).(*types.Chan).Elt c := v.compiler if ptr.IsNil() { ptr = c.builder.CreateAlloca(c.types.ToLLVM(elttyp), "") value := value.Convert(elttyp).LLVMValue() c.builder.CreateStore(value, ptr) } uintptr_ := c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "") f := c.NamedFunction("runtime.chansend", "func f(c, ptr uintptr)") c.builder.CreateCall(f, []llvm.Value{v.LLVMValue(), uintptr_}, "") }
// declare creates an llvm.dbg.declare call for the specified function // parameter or local variable. func (d *debugInfo) declare(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) { tag := tagAutoVariable if paramIndex >= 0 { tag = tagArgVariable } ld := debug.NewLocalVariableDescriptor(tag) ld.Argument = uint32(paramIndex + 1) ld.Name = llv.Name() if file := d.Fset.File(v.Pos()); file != nil { ld.Line = uint32(file.Position(v.Pos()).Line) ld.File = &d.getCompileUnit(file).Path } ld.Type = d.TypeDebugDescriptor(deref(v.Type())) ld.Context = d.context() b.InsertDeclare(d.module, llvm.MDNode([]llvm.Value{llv}), d.MDNode(ld)) }
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 (c *compiler) buildPtrRecvFunction(fn llvm.Value) llvm.Value { defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock()) ifname := "*" + fn.Name() ifn := c.module.Module.NamedFunction(ifname) fntyp := fn.Type().ElementType() entry := llvm.AddBasicBlock(ifn, "entry") c.builder.SetInsertPointAtEnd(entry) args := ifn.Params() args[0] = c.builder.CreateLoad(args[0], "recv") result := c.builder.CreateCall(fn, args, "") if fntyp.ReturnType().TypeKind() == llvm.VoidTypeKind { c.builder.CreateRetVoid() } else { c.builder.CreateRet(result) } return ifn }
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 }
// coerce yields a value of the the type specified, initialised // to the exact bit pattern as in the specified value. // // Note: the value's type and the specified target type must have // the same size. If the source is an aggregate, then the target // must also be an aggregate with the same number of fields, each // of which must have the same size. func coerce(b llvm.Builder, v llvm.Value, t llvm.Type) llvm.Value { // FIXME don't do this with alloca switch t.TypeKind() { case llvm.ArrayTypeKind, llvm.StructTypeKind: ptr := b.CreateAlloca(t, "") ptrv := b.CreateBitCast(ptr, llvm.PointerType(v.Type(), 0), "") b.CreateStore(v, ptrv) return b.CreateLoad(ptr, "") } vt := v.Type() switch vt.TypeKind() { case llvm.ArrayTypeKind, llvm.StructTypeKind: ptr := b.CreateAlloca(vt, "") b.CreateStore(v, ptr) ptrt := b.CreateBitCast(ptr, llvm.PointerType(t, 0), "") return b.CreateLoad(ptrt, "") } return b.CreateBitCast(v, t, "") }
func (v *LLVMValue) UnaryOp(op token.Token) Value { b := v.compiler.builder switch op { case token.SUB: var value llvm.Value if isFloat(v.typ) { zero := llvm.ConstNull(v.compiler.types.ToLLVM(v.Type())) value = b.CreateFSub(zero, v.LLVMValue(), "") } else { value = b.CreateNeg(v.LLVMValue(), "") } return v.compiler.NewValue(value, v.typ) case token.ADD: return v // No-op case token.AND: if typ, ok := v.typ.Underlying().(*types.Pointer); ok { if typ.Elem().Underlying() == typ { // Taking the address of a recursive pointer // yields a value with the same type. value := v.pointer.value basetyp := value.Type().ElementType() value = b.CreateBitCast(value, basetyp, "") return v.compiler.NewValue(value, v.typ) } } return v.pointer case token.NOT: value := b.CreateNot(v.LLVMValue(), "") return v.compiler.NewValue(value, v.typ) case token.XOR: lhs := v.LLVMValue() rhs := llvm.ConstAllOnes(lhs.Type()) value := b.CreateXor(lhs, rhs, "") return v.compiler.NewValue(value, v.typ) case token.ARROW: value, _ := v.chanRecv(false) return value default: panic(fmt.Sprintf("Unhandled operator: %s", op)) } panic("unreachable") }
func (d *debugInfo) pushFunctionContext(fnptr llvm.Value, sig *types.Signature, pos token.Pos) { subprog := &debug.SubprogramDescriptor{ Name: fnptr.Name(), DisplayName: fnptr.Name(), Function: fnptr, } file := d.Fset.File(pos) cu := d.getCompileUnit(file) subprog.File = file.Name() subprog.Context = &cu.Path if file != nil { subprog.Line = uint32(file.Line(pos)) subprog.ScopeLine = uint32(file.Line(pos)) // TODO(axw) } sigType := d.TypeDebugDescriptor(sig).(*debug.CompositeTypeDescriptor) subroutineType := sigType.Members[0] subprog.Type = subroutineType cu.Subprograms = append(cu.Subprograms, subprog) d.pushContext(subprog) }
// coerce yields a value of the the type specified, initialised // to the exact bit pattern as in the specified value. // // Note: the specified value must be a non-aggregate, and its type // and the specified type must have the same size. func (c *compiler) coerce(v llvm.Value, t llvm.Type) llvm.Value { switch t.TypeKind() { case llvm.ArrayTypeKind, llvm.StructTypeKind: ptr := c.builder.CreateAlloca(t, "") ptrv := c.builder.CreateBitCast(ptr, llvm.PointerType(v.Type(), 0), "") c.builder.CreateStore(v, ptrv) return c.builder.CreateLoad(ptr, "") } vt := v.Type() switch vt.TypeKind() { case llvm.ArrayTypeKind, llvm.StructTypeKind: ptr := c.builder.CreateAlloca(vt, "") c.builder.CreateStore(v, ptr) ptrt := c.builder.CreateBitCast(ptr, llvm.PointerType(t, 0), "") return c.builder.CreateLoad(ptrt, "") } return c.builder.CreateBitCast(v, t, "") }
func (v *LLVMValue) chanSend(value Value) { var ptr llvm.Value if value, ok := value.(*LLVMValue); ok && value.pointer != nil { ptr = value.pointer.LLVMValue() } elttyp := v.typ.Underlying().(*types.Chan).Elem() c := v.compiler if ptr.IsNil() { ptr = c.builder.CreateAlloca(c.types.ToLLVM(elttyp), "") value := value.Convert(elttyp).LLVMValue() c.builder.CreateStore(value, ptr) } uintptr_ := c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "") nb := boolLLVMValue(false) f := c.NamedFunction("runtime.chansend", "func(t *chanType, c, ptr uintptr, nb bool) bool") chantyp := c.types.ToRuntime(v.typ.Underlying()) chantyp = c.builder.CreateBitCast(chantyp, f.Type().ElementType().ParamTypes()[0], "") c.builder.CreateCall(f, []llvm.Value{chantyp, v.LLVMValue(), uintptr_, nb}, "") // Ignore result; only used in runtime. }
func (tm *TypeMap) interfaceRuntimeType(i *types.Interface) (global, ptr llvm.Value) { rtype := tm.makeRtype(i, reflect.Interface) interfaceType := llvm.ConstNull(tm.runtimeInterfaceType) interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0}) imethods := make([]llvm.Value, i.NumMethods()) for index := range imethods { method := i.Method(index) //name, pkgPath, type imethod := llvm.ConstNull(tm.runtimeImethod) name := tm.globalStringPtr(method.Name()) name = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[0]) imethod = llvm.ConstInsertValue(imethod, name, []uint32{0}) //imethod = llvm.ConstInsertValue(imethod, , []uint32{1}) //imethod = llvm.ConstInsertValue(imethod, , []uint32{2}) imethods[index] = imethod } var imethodsGlobalPtr llvm.Value imethodPtrType := llvm.PointerType(tm.runtimeImethod, 0) if len(imethods) > 0 { imethodsArray := llvm.ConstArray(tm.runtimeImethod, imethods) imethodsGlobalPtr = llvm.AddGlobal(tm.module, imethodsArray.Type(), "") imethodsGlobalPtr.SetInitializer(imethodsArray) imethodsGlobalPtr = llvm.ConstBitCast(imethodsGlobalPtr, imethodPtrType) } else { imethodsGlobalPtr = llvm.ConstNull(imethodPtrType) } len_ := llvm.ConstInt(tm.inttype, uint64(i.NumMethods()), false) imethodsSliceType := tm.runtimeInterfaceType.StructElementTypes()[1] imethodsSlice := llvm.ConstNull(imethodsSliceType) imethodsSlice = llvm.ConstInsertValue(imethodsSlice, imethodsGlobalPtr, []uint32{0}) imethodsSlice = llvm.ConstInsertValue(imethodsSlice, len_, []uint32{1}) imethodsSlice = llvm.ConstInsertValue(imethodsSlice, len_, []uint32{2}) interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1}) return tm.makeRuntimeTypeGlobal(interfaceType) }
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() }