diff options
author | Ayke van Laethem <[email protected]> | 2022-06-24 00:09:03 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2023-02-17 22:54:34 +0100 |
commit | 4e8453167f42976aad87099ffdb3746fc540d6a6 (patch) | |
tree | b3acee7dc97a19219fd1a84cabaf9b9d8eba1f3a /compiler/interface.go | |
parent | ebb410afd916047ee17f0e51dfba36ad3a6c002b (diff) | |
download | tinygo-4e8453167f42976aad87099ffdb3746fc540d6a6.tar.gz tinygo-4e8453167f42976aad87099ffdb3746fc540d6a6.zip |
all: refactor reflect package
This is a big commit that changes the way runtime type information is stored in
the binary. Instead of compressing it and storing it in a number of sidetables,
it is stored similar to how the Go compiler toolchain stores it (but still more
compactly).
This has a number of advantages:
* It is much easier to add new features to reflect support. They can simply
be added to these structs without requiring massive changes (especially in
the reflect lowering pass).
* It removes the reflect lowering pass, which was a large amount of hard to
understand and debug code.
* The reflect lowering pass also required merging all LLVM IR into one
module, which is terrible for performance especially when compiling large
amounts of code. See issue 2870 for details.
* It is (probably!) easier to reason about for the compiler.
The downside is that it increases code size a bit, especially when reflect is
involved. I hope to fix some of that in later patches.
Diffstat (limited to 'compiler/interface.go')
-rw-r--r-- | compiler/interface.go | 450 |
1 files changed, 288 insertions, 162 deletions
diff --git a/compiler/interface.go b/compiler/interface.go index 2007b7d7c..a359f33a4 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -6,6 +6,7 @@ package compiler // interface-lowering.go for more details. import ( + "fmt" "go/token" "go/types" "strconv" @@ -15,6 +16,49 @@ import ( "tinygo.org/x/go-llvm" ) +// Type kinds for basic types. +// They must match the constants for the Kind type in src/reflect/type.go. +var basicTypes = [...]uint8{ + types.Bool: 1, + types.Int: 2, + types.Int8: 3, + types.Int16: 4, + types.Int32: 5, + types.Int64: 6, + types.Uint: 7, + types.Uint8: 8, + types.Uint16: 9, + types.Uint32: 10, + types.Uint64: 11, + types.Uintptr: 12, + types.Float32: 13, + types.Float64: 14, + types.Complex64: 15, + types.Complex128: 16, + types.String: 17, + types.UnsafePointer: 18, +} + +// These must also match the constants for the Kind type in src/reflect/type.go. +const ( + typeKindChan = 19 + typeKindInterface = 20 + typeKindPointer = 21 + typeKindSlice = 22 + typeKindArray = 23 + typeKindSignature = 24 + typeKindMap = 25 + typeKindStruct = 26 +) + +// Flags stored in the first byte of the struct field byte array. Must be kept +// up to date with src/reflect/type.go. +const ( + structFieldFlagAnonymous = 1 << iota + structFieldFlagHasTag + structFieldFlagIsExported +) + // createMakeInterface emits the LLVM IR for the *ssa.MakeInterface instruction. // It tries to put the type in the interface value, but if that's not possible, // it will do an allocation of the right size and put that in the interface @@ -23,10 +67,9 @@ import ( // An interface value is a {typecode, value} tuple named runtime._interface. func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.Pos) llvm.Value { itfValue := b.emitPointerPack([]llvm.Value{val}) - itfTypeCodeGlobal := b.getTypeCode(typ) - itfTypeCode := b.CreatePtrToInt(itfTypeCodeGlobal, b.uintptrType, "") + itfType := b.getTypeCode(typ) itf := llvm.Undef(b.getLLVMRuntimeType("_interface")) - itf = b.CreateInsertValue(itf, itfTypeCode, 0, "") + itf = b.CreateInsertValue(itf, itfType, 0, "") itf = b.CreateInsertValue(itf, itfValue, 1, "") return itf } @@ -41,118 +84,236 @@ func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type) } // getTypeCode returns a reference to a type code. -// It returns a pointer to an external global which should be replaced with the -// real type in the interface lowering pass. +// A type code is a pointer to a constant global that describes the type. +// This function returns a pointer to the 'kind' field (which might not be the +// first field in the struct). func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { + ms := c.program.MethodSets.MethodSet(typ) + hasMethodSet := ms.Len() != 0 + if _, ok := typ.Underlying().(*types.Interface); ok { + hasMethodSet = false + } globalName := "reflect/types.type:" + getTypeCodeName(typ) global := c.mod.NamedGlobal(globalName) if global.IsNil() { - // Create a new typecode global. - global = llvm.AddGlobal(c.mod, c.getLLVMRuntimeType("typecodeID"), globalName) - // Some type classes contain more information for underlying types or - // element types. Store it directly in the typecode global to make - // reflect lowering simpler. - var references llvm.Value - var length int64 - var methodSet llvm.Value - var ptrTo llvm.Value - var typeAssert llvm.Value + var typeFields []llvm.Value + // Define the type fields. These must match the structs in + // src/reflect/type.go (ptrType, arrayType, etc). See the comment at the + // top of src/reflect/type.go for more information on the layout of these structs. + typeFieldTypes := []*types.Var{ + types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]), + } switch typ := typ.(type) { + case *types.Basic: + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), + ) case *types.Named: - references = c.getTypeCode(typ.Underlying()) - case *types.Chan: - references = c.getTypeCode(typ.Elem()) + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), + types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]), + ) + case *types.Chan, *types.Slice: + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), + types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]), + ) case *types.Pointer: - references = c.getTypeCode(typ.Elem()) - case *types.Slice: - references = c.getTypeCode(typ.Elem()) + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]), + ) case *types.Array: - references = c.getTypeCode(typ.Elem()) - length = typ.Len() + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), + types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]), + types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]), + ) + case *types.Map: + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), + ) case *types.Struct: - // Take a pointer to the typecodeID of the first field (if it exists). - structGlobal := c.makeStructTypeFields(typ) - references = llvm.ConstBitCast(structGlobal, global.Type()) + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]), + types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), + types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))), + ) case *types.Interface: - methodSetGlobal := c.getInterfaceMethodSet(typ) - references = llvm.ConstBitCast(methodSetGlobal, global.Type()) - } - if _, ok := typ.Underlying().(*types.Interface); !ok { - methodSet = c.getTypeMethodSet(typ) - } else { - typeAssert = c.getInterfaceImplementsFunc(typ) - typeAssert = llvm.ConstPtrToInt(typeAssert, c.uintptrType) - } - if _, ok := typ.Underlying().(*types.Pointer); !ok { - ptrTo = c.getTypeCode(types.NewPointer(typ)) - } - globalValue := llvm.ConstNull(global.GlobalValueType()) - if !references.IsNil() { - globalValue = c.builder.CreateInsertValue(globalValue, references, 0, "") + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), + ) + // TODO: methods + case *types.Signature: + typeFieldTypes = append(typeFieldTypes, + types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), + ) + // TODO: signature params and return values } - if length != 0 { - lengthValue := llvm.ConstInt(c.uintptrType, uint64(length), false) - globalValue = c.builder.CreateInsertValue(globalValue, lengthValue, 1, "") + if hasMethodSet { + // This method set is appended at the start of the struct. It is + // removed in the interface lowering pass. + // TODO: don't remove these and instead do what upstream Go is doing + // instead. See: https://research.swtch.com/interfaces. This can + // likely be optimized in LLVM using + // https://llvm.org/docs/TypeMetadata.html. + typeFieldTypes = append([]*types.Var{ + types.NewVar(token.NoPos, nil, "methodSet", types.Typ[types.UnsafePointer]), + }, typeFieldTypes...) } - if !methodSet.IsNil() { - globalValue = c.builder.CreateInsertValue(globalValue, methodSet, 2, "") - } - if !ptrTo.IsNil() { - globalValue = c.builder.CreateInsertValue(globalValue, ptrTo, 3, "") + globalType := types.NewStruct(typeFieldTypes, nil) + global = llvm.AddGlobal(c.mod, c.getLLVMType(globalType), globalName) + metabyte := getTypeKind(typ) + switch typ := typ.(type) { + case *types.Basic: + typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))} + case *types.Named: + typeFields = []llvm.Value{ + c.getTypeCode(types.NewPointer(typ)), // ptrTo + c.getTypeCode(typ.Underlying()), // underlying + } + metabyte |= 1 << 5 // "named" flag + case *types.Chan: + typeFields = []llvm.Value{ + c.getTypeCode(types.NewPointer(typ)), // ptrTo + c.getTypeCode(typ.Elem()), // elementType + } + case *types.Slice: + typeFields = []llvm.Value{ + c.getTypeCode(types.NewPointer(typ)), // ptrTo + c.getTypeCode(typ.Elem()), // elementType + } + case *types.Pointer: + typeFields = []llvm.Value{c.getTypeCode(typ.Elem())} + case *types.Array: + typeFields = []llvm.Value{ + c.getTypeCode(types.NewPointer(typ)), // ptrTo + c.getTypeCode(typ.Elem()), // elementType + llvm.ConstInt(c.uintptrType, uint64(typ.Len()), false), // length + } + case *types.Map: + typeFields = []llvm.Value{ + c.getTypeCode(types.NewPointer(typ)), // ptrTo + } + case *types.Struct: + typeFields = []llvm.Value{ + llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields + c.getTypeCode(types.NewPointer(typ)), // ptrTo + } + structFieldType := c.getLLVMRuntimeType("structField") + var fields []llvm.Value + for i := 0; i < typ.NumFields(); i++ { + field := typ.Field(i) + var flags uint8 + if field.Anonymous() { + flags |= structFieldFlagAnonymous + } + if typ.Tag(i) != "" { + flags |= structFieldFlagHasTag + } + if token.IsExported(field.Name()) { + flags |= structFieldFlagIsExported + } + data := string(flags) + field.Name() + "\x00" + if typ.Tag(i) != "" { + if len(typ.Tag(i)) > 0xff { + c.addError(field.Pos(), fmt.Sprintf("struct tag is %d bytes which is too long, max is 255", len(typ.Tag(i)))) + } + data += string([]byte{byte(len(typ.Tag(i)))}) + typ.Tag(i) + } + dataInitializer := c.ctx.ConstString(data, false) + dataGlobal := llvm.AddGlobal(c.mod, dataInitializer.Type(), globalName+"."+field.Name()) + dataGlobal.SetInitializer(dataInitializer) + dataGlobal.SetAlignment(1) + dataGlobal.SetUnnamedAddr(true) + dataGlobal.SetLinkage(llvm.InternalLinkage) + dataGlobal.SetGlobalConstant(true) + fieldType := c.getTypeCode(field.Type()) + fields = append(fields, llvm.ConstNamedStruct(structFieldType, []llvm.Value{ + fieldType, + llvm.ConstGEP(dataGlobal.GlobalValueType(), dataGlobal, []llvm.Value{ + llvm.ConstInt(c.ctx.Int32Type(), 0, false), + llvm.ConstInt(c.ctx.Int32Type(), 0, false), + }), + })) + } + typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields)) + case *types.Interface: + typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))} + // TODO: methods + case *types.Signature: + typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))} + // TODO: params, return values, etc } - if !typeAssert.IsNil() { - globalValue = c.builder.CreateInsertValue(globalValue, typeAssert, 4, "") + // Prepend metadata byte. + typeFields = append([]llvm.Value{ + llvm.ConstInt(c.ctx.Int8Type(), uint64(metabyte), false), + }, typeFields...) + if hasMethodSet { + typeFields = append([]llvm.Value{ + llvm.ConstBitCast(c.getTypeMethodSet(typ), c.i8ptrType), + }, typeFields...) } + alignment := c.targetData.TypeAllocSize(c.i8ptrType) + globalValue := c.ctx.ConstStruct(typeFields, false) global.SetInitializer(globalValue) global.SetLinkage(llvm.LinkOnceODRLinkage) global.SetGlobalConstant(true) + global.SetAlignment(int(alignment)) + if c.Debug { + file := c.getDIFile("<Go type>") + diglobal := c.dibuilder.CreateGlobalVariableExpression(file, llvm.DIGlobalVariableExpression{ + Name: "type " + typ.String(), + File: file, + Line: 1, + Type: c.getDIType(globalType), + LocalToUnit: false, + Expr: c.dibuilder.CreateExpression(nil), + AlignInBits: uint32(alignment * 8), + }) + global.AddMetadata(0, diglobal) + } } - return global + offset := uint64(0) + if hasMethodSet { + // The pointer to the method set is always the first element of the + // global (if there is a method set). However, the pointer we return + // should point to the 'kind' field not the method set. + offset = 1 + } + return llvm.ConstGEP(global.GlobalValueType(), global, []llvm.Value{ + llvm.ConstInt(llvm.Int32Type(), 0, false), + llvm.ConstInt(llvm.Int32Type(), offset, false), + }) } -// makeStructTypeFields creates a new global that stores all type information -// related to this struct type, and returns the resulting global. This global is -// actually an array of all the fields in the structs. -func (c *compilerContext) makeStructTypeFields(typ *types.Struct) llvm.Value { - // The global is an array of runtime.structField structs. - runtimeStructField := c.getLLVMRuntimeType("structField") - structGlobalType := llvm.ArrayType(runtimeStructField, typ.NumFields()) - structGlobal := llvm.AddGlobal(c.mod, structGlobalType, "reflect/types.structFields") - structGlobalValue := llvm.ConstNull(structGlobalType) - for i := 0; i < typ.NumFields(); i++ { - fieldGlobalValue := llvm.ConstNull(runtimeStructField) - fieldGlobalValue = c.builder.CreateInsertValue(fieldGlobalValue, c.getTypeCode(typ.Field(i).Type()), 0, "") - fieldNameType, fieldName := c.makeGlobalArray([]byte(typ.Field(i).Name()), "reflect/types.structFieldName", c.ctx.Int8Type()) - fieldName.SetLinkage(llvm.PrivateLinkage) - fieldName.SetUnnamedAddr(true) - fieldName = llvm.ConstGEP(fieldNameType, fieldName, []llvm.Value{ - llvm.ConstInt(c.ctx.Int32Type(), 0, false), - llvm.ConstInt(c.ctx.Int32Type(), 0, false), - }) - fieldGlobalValue = c.builder.CreateInsertValue(fieldGlobalValue, fieldName, 1, "") - if typ.Tag(i) != "" { - fieldTagType, fieldTag := c.makeGlobalArray([]byte(typ.Tag(i)), "reflect/types.structFieldTag", c.ctx.Int8Type()) - fieldTag.SetLinkage(llvm.PrivateLinkage) - fieldTag.SetUnnamedAddr(true) - fieldTag = llvm.ConstGEP(fieldTagType, fieldTag, []llvm.Value{ - llvm.ConstInt(c.ctx.Int32Type(), 0, false), - llvm.ConstInt(c.ctx.Int32Type(), 0, false), - }) - fieldGlobalValue = c.builder.CreateInsertValue(fieldGlobalValue, fieldTag, 2, "") - } - if typ.Field(i).Embedded() { - fieldEmbedded := llvm.ConstInt(c.ctx.Int1Type(), 1, false) - fieldGlobalValue = c.builder.CreateInsertValue(fieldGlobalValue, fieldEmbedded, 3, "") - } - structGlobalValue = c.builder.CreateInsertValue(structGlobalValue, fieldGlobalValue, i, "") +// getTypeKind returns the type kind for the given type, as defined by +// reflect.Kind. +func getTypeKind(t types.Type) uint8 { + switch t := t.Underlying().(type) { + case *types.Basic: + return basicTypes[t.Kind()] + case *types.Chan: + return typeKindChan + case *types.Interface: + return typeKindInterface + case *types.Pointer: + return typeKindPointer + case *types.Slice: + return typeKindSlice + case *types.Array: + return typeKindArray + case *types.Signature: + return typeKindSignature + case *types.Map: + return typeKindMap + case *types.Struct: + return typeKindStruct + default: + panic("unknown type") } - structGlobal.SetInitializer(structGlobalValue) - structGlobal.SetUnnamedAddr(true) - structGlobal.SetLinkage(llvm.PrivateLinkage) - return structGlobal } -var basicTypes = [...]string{ +var basicTypeNames = [...]string{ types.Bool: "bool", types.Int: "int", types.Int8: "int8", @@ -183,7 +344,7 @@ func getTypeCodeName(t types.Type) string { case *types.Array: return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem()) case *types.Basic: - return "basic:" + basicTypes[t.Kind()] + return "basic:" + basicTypeNames[t.Kind()] case *types.Chan: return "chan:" + getTypeCodeName(t.Elem()) case *types.Interface: @@ -235,75 +396,40 @@ func getTypeCodeName(t types.Type) string { // getTypeMethodSet returns a reference (GEP) to a global method set. This // method set should be unreferenced after the interface lowering pass. func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value { - global := c.mod.NamedGlobal(typ.String() + "$methodset") - zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) - if !global.IsNil() { - // the method set already exists - return llvm.ConstGEP(global.GlobalValueType(), global, []llvm.Value{zero, zero}) - } - - ms := c.program.MethodSets.MethodSet(typ) - if ms.Len() == 0 { - // no methods, so can leave that one out - return llvm.ConstPointerNull(llvm.PointerType(c.getLLVMRuntimeType("interfaceMethodInfo"), 0)) - } - - methods := make([]llvm.Value, ms.Len()) - interfaceMethodInfoType := c.getLLVMRuntimeType("interfaceMethodInfo") - for i := 0; i < ms.Len(); i++ { - method := ms.At(i) - signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func)) - fn := c.program.MethodValue(method) - llvmFnType, llvmFn := c.getFunction(fn) - if llvmFn.IsNil() { - // compiler error, so panic - panic("cannot find function: " + c.getFunctionInfo(fn).linkName) + globalName := typ.String() + "$methodset" + global := c.mod.NamedGlobal(globalName) + if global.IsNil() { + ms := c.program.MethodSets.MethodSet(typ) + + // Create method set. + var signatures, wrappers []llvm.Value + for i := 0; i < ms.Len(); i++ { + method := ms.At(i) + signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func)) + signatures = append(signatures, signatureGlobal) + fn := c.program.MethodValue(method) + llvmFnType, llvmFn := c.getFunction(fn) + if llvmFn.IsNil() { + // compiler error, so panic + panic("cannot find function: " + c.getFunctionInfo(fn).linkName) + } + wrapper := c.getInterfaceInvokeWrapper(fn, llvmFnType, llvmFn) + wrappers = append(wrappers, wrapper) } - wrapper := c.getInterfaceInvokeWrapper(fn, llvmFnType, llvmFn) - methodInfo := llvm.ConstNamedStruct(interfaceMethodInfoType, []llvm.Value{ - signatureGlobal, - llvm.ConstPtrToInt(wrapper, c.uintptrType), - }) - methods[i] = methodInfo - } - arrayType := llvm.ArrayType(interfaceMethodInfoType, len(methods)) - value := llvm.ConstArray(interfaceMethodInfoType, methods) - global = llvm.AddGlobal(c.mod, arrayType, typ.String()+"$methodset") - global.SetInitializer(value) - global.SetGlobalConstant(true) - global.SetLinkage(llvm.LinkOnceODRLinkage) - return llvm.ConstGEP(arrayType, global, []llvm.Value{zero, zero}) -} -// getInterfaceMethodSet returns a global variable with the method set of the -// given named interface type. This method set is used by the interface lowering -// pass. -func (c *compilerContext) getInterfaceMethodSet(typ types.Type) llvm.Value { - name := typ.String() - if _, ok := typ.(*types.Named); !ok { - // Anonymous interface. - name = "reflect/types.interface:" + name - } - global := c.mod.NamedGlobal(name + "$interface") - zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) - if !global.IsNil() { - // method set already exist, return it - return llvm.ConstGEP(global.GlobalValueType(), global, []llvm.Value{zero, zero}) - } - - // Every method is a *i8 reference indicating the signature of this method. - methods := make([]llvm.Value, typ.Underlying().(*types.Interface).NumMethods()) - for i := range methods { - method := typ.Underlying().(*types.Interface).Method(i) - methods[i] = c.getMethodSignature(method) + // Construct global value. + globalValue := c.ctx.ConstStruct([]llvm.Value{ + llvm.ConstInt(c.uintptrType, uint64(ms.Len()), false), + llvm.ConstArray(c.i8ptrType, signatures), + c.ctx.ConstStruct(wrappers, false), + }, false) + global = llvm.AddGlobal(c.mod, globalValue.Type(), globalName) + global.SetInitializer(globalValue) + global.SetGlobalConstant(true) + global.SetUnnamedAddr(true) + global.SetLinkage(llvm.LinkOnceODRLinkage) } - - value := llvm.ConstArray(c.i8ptrType, methods) - global = llvm.AddGlobal(c.mod, value.Type(), name+"$interface") - global.SetInitializer(value) - global.SetGlobalConstant(true) - global.SetLinkage(llvm.LinkOnceODRLinkage) - return llvm.ConstGEP(value.Type(), global, []llvm.Value{zero, zero}) + return global } // getMethodSignatureName returns a unique name (that can be used as the name of @@ -443,7 +569,7 @@ func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) ll fnName := getTypeCodeName(assertedType.Underlying()) + ".$typeassert" llvmFn := c.mod.NamedFunction(fnName) if llvmFn.IsNil() { - llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.uintptrType}, false) + llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.i8ptrType}, false) llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType) c.addStandardDeclaredAttributes(llvmFn) methods := c.getMethodsString(assertedType.Underlying().(*types.Interface)) @@ -464,7 +590,7 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value { for i := 0; i < sig.Params().Len(); i++ { paramTuple = append(paramTuple, sig.Params().At(i)) } - paramTuple = append(paramTuple, types.NewVar(token.NoPos, nil, "$typecode", types.Typ[types.Uintptr])) + paramTuple = append(paramTuple, types.NewVar(token.NoPos, nil, "$typecode", types.Typ[types.UnsafePointer])) llvmFnType := c.getRawFuncType(types.NewSignature(sig.Recv(), types.NewTuple(paramTuple...), sig.Results(), false)) llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType) c.addStandardDeclaredAttributes(llvmFn) @@ -601,7 +727,7 @@ func typestring(t types.Type) string { case *types.Array: return "[" + strconv.FormatInt(t.Len(), 10) + "]" + typestring(t.Elem()) case *types.Basic: - return basicTypes[t.Kind()] + return basicTypeNames[t.Kind()] case *types.Chan: switch t.Dir() { case types.SendRecv: |