func (tm *TypeMap) interfaceRuntimeType(i *types.Interface) (global, ptr llvm.Value) { rtype := tm.makeRtype(i, reflect.Interface) interfaceType := llvm.ConstNull(tm.runtime.interfaceType.llvm) global, ptr = tm.makeRuntimeTypeGlobal(interfaceType, typeString(i)) tm.types.Set(i, runtimeTypeInfo{global, ptr}) interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0}) methodset := tm.MethodSet(i) imethods := make([]llvm.Value, methodset.Len()) for index := 0; index < methodset.Len(); index++ { method := methodset.At(index).Obj() imethod := llvm.ConstNull(tm.runtime.imethod.llvm) name := tm.globalStringPtr(method.Name()) name = llvm.ConstBitCast(name, tm.runtime.imethod.llvm.StructElementTypes()[0]) mtyp := tm.ToRuntime(method.Type()) imethod = llvm.ConstInsertValue(imethod, name, []uint32{0}) if !ast.IsExported(method.Name()) { pkgpath := tm.globalStringPtr(method.Pkg().Path()) pkgpath = llvm.ConstBitCast(pkgpath, tm.runtime.imethod.llvm.StructElementTypes()[1]) imethod = llvm.ConstInsertValue(imethod, pkgpath, []uint32{1}) } imethod = llvm.ConstInsertValue(imethod, mtyp, []uint32{2}) imethods[index] = imethod } imethodsSliceType := tm.runtime.interfaceType.llvm.StructElementTypes()[1] imethodsSlice := tm.makeSlice(imethods, imethodsSliceType) interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1}) global.SetInitializer(interfaceType) return global, ptr }
func (tm *TypeMap) interfaceRuntimeType(tstr string, i *types.Interface) (global, ptr llvm.Value) { rtype := tm.makeRtype(i, reflect.Interface) interfaceType := llvm.ConstNull(tm.runtimeInterfaceType) global, ptr = tm.makeRuntimeTypeGlobal(interfaceType) tm.types.record(tstr, global, ptr) interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0}) methodset := i.MethodSet() imethods := make([]llvm.Value, methodset.Len()) for index := 0; index < methodset.Len(); index++ { method := methodset.At(index).Obj() imethod := llvm.ConstNull(tm.runtimeImethod) name := tm.globalStringPtr(method.Name()) name = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[0]) //pkgpath := tm.globalStringPtr(tm.functions.objectdata[method].Package.Path()) //pkgpath = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[1]) mtyp := tm.ToRuntime(method.Type()) imethod = llvm.ConstInsertValue(imethod, name, []uint32{0}) //imethod = llvm.ConstInsertValue(imethod, pkgpath, []uint32{1}) imethod = llvm.ConstInsertValue(imethod, mtyp, []uint32{2}) imethods[index] = imethod } imethodsSliceType := tm.runtimeInterfaceType.StructElementTypes()[1] imethodsSlice := tm.makeSlice(imethods, imethodsSliceType) interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1}) global.SetInitializer(interfaceType) return global, ptr }
func (tm *TypeMap) uncommonType(n *types.Named, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj().Name()) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) _, path := tm.qualifiedName(n) pkgpathPtr := tm.globalStringPtr(path) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) methodset := tm.functions.methods(n) methodfuncs := methodset.nonptr if ptr { methodfuncs = methodset.ptr } // Store methods. methods := make([]llvm.Value, len(methodfuncs)) for i, mfunc := range methodfuncs { ftyp := mfunc.Type().(*types.Signature) method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(mfunc.Name()) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { ftyp := types.NewSignature(nil, nil, ftyp.Params(), ftyp.Results(), ftyp.IsVariadic()) mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() tfn = llvm.ConstExtractValue(tfn, []uint32{0}) tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn if !ptr && tm.Sizeof(ftyp.Recv().Type()) > int64(tm.target.PointerSize()) { mfunc := methodset.lookup(mfunc.Name(), true) ifn = tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() ifn = llvm.ConstExtractValue(ifn, []uint32{0}) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[i] = method } methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := tm.makeSlice(methods, methodsSliceType) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }
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) nameRuntimeType(n *types.Named) (global, ptr llvm.Value) { name := typeString(n) path := "runtime" if pkg := n.Obj().Pkg(); pkg != nil { path = pkg.Path() } if path != tm.pkgpath { // We're not compiling the package from whence the type came, // so we'll just create a pointer to it here. global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(name)) global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm)) global.SetLinkage(llvm.CommonLinkage) return global, global } // If the underlying type is Basic, then we always create // a new global. Otherwise, we clone the value returned // from toRuntime in case it is cached and reused. underlying := n.Underlying() if basic, ok := underlying.(*types.Basic); ok { global, ptr = tm.basicRuntimeType(basic, true) global.SetName(typeSymbol(name)) } else { global, ptr = tm.toRuntime(underlying) clone := llvm.AddGlobal(tm.module, global.Type().ElementType(), typeSymbol(name)) clone.SetInitializer(global.Initializer()) global = clone ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0)) } global.SetLinkage(llvm.ExternalLinkage) // Locate the rtype. underlyingRuntimeType := global.Initializer() rtype := underlyingRuntimeType if rtype.Type() != tm.runtime.rtype.llvm { rtype = llvm.ConstExtractValue(rtype, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := tm.uncommonType(n, nil) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9}) // Replace the rtype's string representation with the one from // uncommonType. XXX should we have the package name prepended? Probably. namePtr := llvm.ConstExtractValue(uncommonTypeInit, []uint32{0}) rtype = llvm.ConstInsertValue(rtype, namePtr, []uint32{8}) // Update the global's initialiser. Note that we take a copy // of the underlying type; we're not updating a shared type. if underlyingRuntimeType.Type() != tm.runtime.rtype.llvm { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, rtype, []uint32{0}) } else { underlyingRuntimeType = rtype } global.SetInitializer(underlyingRuntimeType) return global, ptr }
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) basicRuntimeType(b *types.Basic) llvm.Value { commonType := tm.makeCommonType(b, reflect.Kind(b.Kind)) result := llvm.AddGlobal(tm.module, commonType.Type(), "") elementTypes := tm.runtimeCommonType.StructElementTypes() ptr := llvm.ConstBitCast(result, elementTypes[9]) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9}) result.SetInitializer(commonType) return result }
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 }
// 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) 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 (tm *TypeMap) mapRuntimeType(m *types.Map) llvm.Value { result := llvm.AddGlobal(tm.module, tm.runtimeMapType, "") elementTypes := tm.runtimeCommonType.StructElementTypes() ptr := llvm.ConstBitCast(result, elementTypes[9]) commonType := tm.makeCommonType(m, reflect.Map) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9}) init := llvm.ConstNull(tm.runtimeMapType) init = llvm.ConstInsertValue(init, commonType, []uint32{0}) result.SetInitializer(init) // TODO set key, elem return result }
func (tm *TypeMap) structRuntimeType(s *types.Struct) llvm.Value { result := llvm.AddGlobal(tm.module, tm.runtimeStructType, "") elementTypes := tm.runtimeCommonType.StructElementTypes() ptr := llvm.ConstBitCast(result, elementTypes[9]) commonType := tm.makeCommonType(s, reflect.Struct) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9}) init := llvm.ConstNull(tm.runtimeStructType) init = llvm.ConstInsertValue(init, commonType, []uint32{0}) result.SetInitializer(init) // TODO set fields //panic("unimplemented") return result }
func (tm *TypeMap) nameRuntimeType(n *types.Name) llvm.Value { underlyingRuntimeType := tm.ToRuntime(n.Underlying).Initializer() result := llvm.AddGlobal(tm.module, underlyingRuntimeType.Type(), "") result.SetName("__llgo.reflect." + n.Obj.Name) elementTypes := tm.runtimeCommonType.StructElementTypes() ptr := llvm.ConstBitCast(result, elementTypes[9]) commonType := llvm.ConstInsertValue(underlyingRuntimeType, ptr, []uint32{9}) uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) // TODO uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{8}) // TODO set string, uncommonType. result.SetInitializer(commonType) return result }
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 }
// 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 (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 (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) { runtimeTypeValue := llvm.ConstNull(tm.runtimeType) 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)) // Set ptrToThis in v's commonType. if v.Type() == tm.runtimeCommonType { v = llvm.ConstInsertValue(v, ptr, []uint32{9}) } else { commonType := llvm.ConstExtractValue(v, []uint32{0}) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9}) v = llvm.ConstInsertValue(v, commonType, []uint32{0}) } init := llvm.Undef(initType) //runtimeTypeValue = llvm.ConstInsertValue() TODO init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0}) init = llvm.ConstInsertValue(init, v, []uint32{1}) global.SetInitializer(init) return }
// convertI2V converts an interface to a value. func (v *LLVMValue) convertI2V(typ types.Type) Value { typptrType := llvm.PointerType(llvm.Int8Type(), 0) runtimeType := v.compiler.types.ToRuntime(typ) runtimeType = llvm.ConstBitCast(runtimeType, typptrType) vptr := v.pointer.LLVMValue() builder := v.compiler.builder ifaceType := builder.CreateLoad(builder.CreateStructGEP(vptr, 1, ""), "") diff := builder.CreatePtrDiff(runtimeType, ifaceType, "") zero := llvm.ConstNull(diff.Type()) predicate := builder.CreateICmp(llvm.IntEQ, diff, zero, "") llvmtype := v.compiler.types.ToLLVM(typ) result := builder.CreateAlloca(llvmtype, "") // 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) value := builder.CreateLoad(builder.CreateStructGEP(vptr, 0, ""), "") value = builder.CreateBitCast(value, result.Type(), "") value = builder.CreateLoad(value, "") builder.CreateStore(value, result) builder.CreateBr(end) // TODO should return {value, ok} builder.SetInsertPointAtEnd(nonmatch) builder.CreateStore(llvm.ConstNull(llvmtype), result) builder.CreateBr(end) //builder.SetInsertPointAtEnd(end) result = builder.CreateLoad(result, "") return v.compiler.NewLLVMValue(result, typ) }
func (compiler *compiler) Compile(fset *token.FileSet, files []*ast.File, importpath string) (m *Module, err error) { // FIXME create a compilation state, rather than storing in 'compiler'. compiler.fileset = fset compiler.initfuncs = nil compiler.varinitfuncs = nil // Type-check, and store object data. compiler.objects = make(map[*ast.Ident]types.Object) compiler.objectdata = make(map[types.Object]*ObjectData) compiler.methodsets = make(map[types.Type]*methodset) compiler.llvmtypes = NewLLVMTypeMap(compiler.target) pkg, exprtypes, err := compiler.typecheck(importpath, fset, files) if err != nil { return nil, err } compiler.pkg = pkg importpath = pkgpath(pkg) // Create a Module, which contains the LLVM bitcode. Dispose it on panic, // otherwise we'll set a finalizer at the end. The caller may invoke // Dispose manually, which will render the finalizer a no-op. modulename := importpath compiler.module = &Module{llvm.NewModule(modulename), modulename, false} compiler.module.SetTarget(compiler.TargetTriple) compiler.module.SetDataLayout(compiler.target.String()) defer func() { if e := recover(); e != nil { compiler.module.Dispose() panic(e) } }() // Create a struct responsible for mapping static types to LLVM types, // and to runtime/dynamic type values. var resolver Resolver = compiler compiler.FunctionCache = NewFunctionCache(compiler) compiler.types = NewTypeMap(compiler.llvmtypes, compiler.module.Module, importpath, exprtypes, compiler.FunctionCache, resolver) // Create a Builder, for building LLVM instructions. compiler.builder = newBuilder(compiler.types) defer compiler.builder.Dispose() // Compile each file in the package. for _, file := range files { for _, decl := range file.Decls { compiler.VisitDecl(decl) } } // Define intrinsics for use by the runtime: malloc, free, memcpy, etc. // These could be defined in LLVM IR, and may be moved there later. if importpath == "runtime" { compiler.defineRuntimeIntrinsics() } // Export runtime type information. if importpath == "runtime" { compiler.exportBuiltinRuntimeTypes() } // Wrap "main.main" in a call to runtime.main. if importpath == "main" { err = compiler.createMainFunction() if err != nil { return nil, err } } // Create global constructors. The initfuncs/varinitfuncs // slices are in the order of visitation; we generate the // list of constructors in the reverse order. // // The llgo linker will link modules in the order of // package dependency, i.e. if A requires B, then llgo-link // will link the modules in the order A, B. The "runtime" // package is always last. // // At program initialisation, the runtime initialisation // function (runtime.main) will invoke the constructors // in reverse order. var initfuncs [][]llvm.Value if compiler.varinitfuncs != nil { initfuncs = append(initfuncs, compiler.varinitfuncs) } if compiler.initfuncs != nil { initfuncs = append(initfuncs, compiler.initfuncs) } if initfuncs != nil { ctortype := llvm.PointerType(llvm.Int8Type(), 0) var ctors []llvm.Value var index int = 0 for _, initfuncs := range initfuncs { for _, fnptr := range initfuncs { name := fmt.Sprintf("__llgo.ctor.%s.%d", importpath, index) fnptr.SetName(name) fnptr = llvm.ConstBitCast(fnptr, ctortype) ctors = append(ctors, fnptr) index++ } } for i, n := 0, len(ctors); i < n/2; i++ { ctors[i], ctors[n-i-1] = ctors[n-i-1], ctors[i] } ctorsInit := llvm.ConstArray(ctortype, ctors) ctorsVar := llvm.AddGlobal(compiler.module.Module, ctorsInit.Type(), "runtime.ctors") ctorsVar.SetInitializer(ctorsInit) ctorsVar.SetLinkage(llvm.AppendingLinkage) } // Create debug metadata. //compiler.createMetadata() return compiler.module, nil }
func (v ConstValue) LLVMValue() llvm.Value { typ := types.Underlying(v.Type()) if name, ok := typ.(*types.Name); ok { typ = name.Underlying } switch typ.(*types.Basic).Kind { case types.IntKind, types.UintKind: 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.Int8Kind: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true) case types.Uint8Kind: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false) case types.Int16Kind: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true) case types.Uint16Kind: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false) case types.Int32Kind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) case types.Uint32Kind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int64Kind: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Uint64Kind: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), false) case types.Float32Kind: return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64())) case types.Float64Kind: return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64())) case types.Complex64Kind: r_, i_ := v.Complex() r := llvm.ConstFloat(llvm.FloatType(), r_) i := llvm.ConstFloat(llvm.FloatType(), i_) return llvm.ConstStruct([]llvm.Value{r, i}, false) case types.Complex128Kind: r_, i_ := v.Complex() r := llvm.ConstFloat(llvm.DoubleType(), r_) i := llvm.ConstFloat(llvm.DoubleType(), i_) return llvm.ConstStruct([]llvm.Value{r, i}, false) case types.UnsafePointerKind, types.UintptrKind: inttype := v.compiler.target.IntPtrType() return llvm.ConstInt(inttype, uint64(v.Int64()), false) case types.StringKind: strval := (v.Val).(string) strlen := len(strval) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var ptr llvm.Value if strlen > 0 { ptr = v.compiler.builder.CreateGlobalStringPtr(strval, "") ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(strlen), false) return llvm.ConstStruct([]llvm.Value{ptr, len_}, false) case types.BoolKind: 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 (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) { global = llvm.AddGlobal(tm.module, v.Type(), "") global.SetInitializer(v) ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtimeType, 0)) return global, ptr }
func (tm *TypeMap) uncommonType(n *types.Named, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj().Name()) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) // FIXME clean this up var pkgpathPtr llvm.Value var path string if data, ok := tm.functions.objectdata[n.Obj()]; ok { path = pkgpath(data.Package) } if path != "" { pkgpathPtr = tm.globalStringPtr(path) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) } methodset := tm.functions.methods(n) methodfuncs := methodset.nonptr if ptr { methodfuncs = methodset.ptr } // Store methods. methods := make([]llvm.Value, len(methodfuncs)) for i, mfunc := range methodfuncs { ftyp := mfunc.Type().(*types.Signature) method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(mfunc.Name()) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { ftyp := types.NewSignature(nil, ftyp.Params(), ftyp.Results(), ftyp.IsVariadic()) mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() tfn = llvm.ConstExtractValue(tfn, []uint32{0}) tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn if !ptr && tm.Sizeof(ftyp.Recv().Type()) > int64(tm.target.PointerSize()) { mfunc := methodset.lookup(mfunc.Name(), true) ifn = tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() ifn = llvm.ConstExtractValue(ifn, []uint32{0}) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[i] = method } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(tm.inttype, uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }
func (tm *TypeMap) nameRuntimeType(n *types.Name) (global, ptr llvm.Value) { pkgpath := tm.pkgmap[n.Obj] if pkgpath == "" { // XXX "builtin"? pkgpath = "runtime" } globalname := "__llgo.type.name." + pkgpath + "." + n.Obj.Name if pkgpath != tm.pkgpath { // We're not compiling the package from whence the type came, // so we'll just create a pointer to it here. global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname) global.SetInitializer(llvm.ConstNull(tm.runtimeType)) global.SetLinkage(llvm.CommonLinkage) return global, global } underlying := n.Underlying if name, ok := underlying.(*types.Name); ok { underlying = name.Underlying } global, ptr = tm.makeRuntimeType(underlying) globalInit := global.Initializer() // Locate the common type. underlyingRuntimeType := llvm.ConstExtractValue(globalInit, []uint32{1}) commonType := underlyingRuntimeType if underlyingRuntimeType.Type() != tm.runtimeCommonType { commonType = llvm.ConstExtractValue(commonType, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj.Name) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) pkgpathPtr := tm.globalStringPtr(pkgpath) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) // Replace the commonType's string representation. commonType = llvm.ConstInsertValue(commonType, namePtr, []uint32{8}) methods := make([]llvm.Value, len(n.Methods)) for index, m := range n.Methods { method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(m.Name) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) ftyp := m.Type.(*types.Func) { recv := ftyp.Recv ftyp.Recv = nil mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) ftyp.Recv = recv } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // ifn (single-word receiver function pointer for interface calls) ifn := tm.resolver.Resolve(m).LLVMValue() // TODO generate trampoline as necessary. ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) method = llvm.ConstInsertValue(method, ifn, []uint32{4}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(m).LLVMValue() tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[index] = method } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{9}) // Update the global's initialiser. Note that we take a copy // of the underlying type; we're not updating a shared type. if underlyingRuntimeType.Type() != tm.runtimeCommonType { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, commonType, []uint32{0}) } else { underlyingRuntimeType = commonType } globalInit = llvm.ConstInsertValue(globalInit, underlyingRuntimeType, []uint32{1}) global.SetName(globalname) global.SetInitializer(globalInit) return global, ptr }
func (fr *frame) value(v ssa.Value) (result *LLVMValue) { switch v := v.(type) { case nil: return nil case *ssa.Function: result, ok := fr.funcvals[v] if ok { return result } // fr.globals[v] has the function in raw pointer form; // we must convert it to <f,ctx> form. If the function // does not have a receiver, then create a wrapper // function that has an additional "context" parameter. f := fr.resolveFunction(v) if v.Signature.Recv() == nil && len(v.FreeVars) == 0 { f = contextFunction(fr.compiler, f) } pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(f.Type())) fnptr := llvm.ConstBitCast(f.LLVMValue(), pair.Type().StructElementTypes()[0]) pair = llvm.ConstInsertValue(pair, fnptr, []uint32{0}) result = fr.NewValue(pair, f.Type()) fr.funcvals[v] = result return result case *ssa.Const: return fr.NewConstValue(v.Value, v.Type()) case *ssa.Global: if g, ok := fr.globals[v]; ok { return g } // Create an external global. Globals for this package are defined // on entry to translatePackage, and have initialisers. llelemtyp := fr.llvmtypes.ToLLVM(deref(v.Type())) llglobal := llvm.AddGlobal(fr.module.Module, llelemtyp, v.String()) global := fr.NewValue(llglobal, v.Type()) fr.globals[v] = global return global } if value, ok := fr.env[v]; ok { return value } // Instructions are not necessarily visited before they are used (e.g. Phi // edges) so we must "backpatch": create a value with the resultant type, // and then replace it when we visit the instruction. if b, ok := fr.backpatch[v]; ok { return b } if fr.backpatch == nil { fr.backpatch = make(map[ssa.Value]*LLVMValue) } // Note: we must not create a constant here (e.g. Undef/ConstNull), as // it is not permissible to replace a constant with a non-constant. // We must create the value in its own standalone basic block, so we can // dispose of it after replacing. currBlock := fr.builder.GetInsertBlock() fr.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(currBlock.Parent(), "")) placeholder := fr.compiler.builder.CreatePHI(fr.llvmtypes.ToLLVM(v.Type()), "") fr.builder.SetInsertPointAtEnd(currBlock) value := fr.NewValue(placeholder, v.Type()) fr.backpatch[v] = value return value }
func (tm *TypeMap) uncommonType(n *types.Name, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj.Name) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) var pkgpathPtr llvm.Value if n.Package != "" { pkgpathPtr = tm.globalStringPtr(n.Package) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) } // Store methods. methods := make([]llvm.Value, 0, len(n.Methods)) for _, m := range n.Methods { ftyp := m.Type.(*types.Func) ptrrecv := !types.Identical(ftyp.Recv.Type.(types.Type), n) if !ptr && ptrrecv { // For a type T, we only store methods where the // receiver is T and not *T. For *T we store both. continue } method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(m.Name) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { recv := ftyp.Recv ftyp.Recv = nil mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) ftyp.Recv = recv } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(m).LLVMValue() tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn needload := ptr && !ptrrecv if !needload { recvtyp := tm.ToLLVM(ftyp.Recv.Type.(types.Type)) needload = int(tm.target.TypeAllocSize(recvtyp)) > tm.target.PointerSize() } if needload { // If the receiver type is wider than a word, we // need to use an intermediate function which takes // a pointer-receiver, loads it, and then calls the // standard receiver function. fname := fmt.Sprintf("*%s.%s", ftyp.Recv.Type, m.Name) ifn = tm.module.NamedFunction(fname) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods = append(methods, method) } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }
func (compiler *compiler) Compile(fset *token.FileSet, files []*ast.File, importpath string) (m *Module, err error) { // FIXME create a compilation state, rather than storing in 'compiler'. compiler.fileset = fset compiler.initfuncs = nil compiler.varinitfuncs = nil // If no import path is specified, or the package's // name (not path) is "main", then set the import // path to be the same as the package's name. if importpath == "" || files[0].Name.String() == "main" { importpath = files[0].Name.String() } // Type-check, and store object data. compiler.typeinfo.Types = make(map[ast.Expr]types.Type) compiler.typeinfo.Values = make(map[ast.Expr]exact.Value) compiler.typeinfo.Objects = make(map[*ast.Ident]types.Object) compiler.typeinfo.Implicits = make(map[ast.Node]types.Object) compiler.typeinfo.Selections = make(map[*ast.SelectorExpr]*types.Selection) compiler.objectdata = make(map[types.Object]*ObjectData) compiler.methodsets = make(map[types.Type]*methodset) compiler.exportedtypes = nil compiler.llvmtypes = NewLLVMTypeMap(compiler.target) pkg, err := compiler.typecheck(importpath, fset, files) if err != nil { return nil, err } compiler.pkg = pkg // Create a Module, which contains the LLVM bitcode. Dispose it on panic, // otherwise we'll set a finalizer at the end. The caller may invoke // Dispose manually, which will render the finalizer a no-op. modulename := importpath compiler.module = &Module{llvm.NewModule(modulename), modulename, false} compiler.module.SetTarget(compiler.TargetTriple) compiler.module.SetDataLayout(compiler.target.String()) defer func() { if e := recover(); e != nil { compiler.module.Dispose() panic(e) } }() // Create a struct responsible for mapping static types to LLVM types, // and to runtime/dynamic type values. var resolver Resolver = compiler compiler.FunctionCache = NewFunctionCache(compiler) compiler.types = NewTypeMap(compiler.llvmtypes, compiler.module.Module, importpath, compiler.FunctionCache, resolver) // Create a Builder, for building LLVM instructions. compiler.builder = newBuilder(compiler.types) defer compiler.builder.Dispose() compiler.debug_info = &llvm.DebugInfo{} // Compile each file in the package. for _, file := range files { compiler.compile_unit = &llvm.CompileUnitDescriptor{ Language: llvm.DW_LANG_Go, Path: llvm.FileDescriptor(fset.File(file.Pos()).Name()), Producer: LLGOProducer, Runtime: LLGORuntimeVersion, } compiler.pushDebugContext(&compiler.compile_unit.Path) for _, decl := range file.Decls { compiler.VisitDecl(decl) } compiler.popDebugContext() if len(compiler.debug_context) > 0 { log.Panicln(compiler.debug_context) } compiler.module.AddNamedMetadataOperand("llvm.dbg.cu", compiler.debug_info.MDNode(compiler.compile_unit)) } // Export runtime type information. compiler.exportRuntimeTypes() // Wrap "main.main" in a call to runtime.main. if importpath == "main" { err = compiler.createMainFunction() if err != nil { return nil, err } } else { var e = exporter{compiler: compiler} if err := e.Export(pkg); err != nil { return nil, err } } // Create global constructors. The initfuncs/varinitfuncs // slices are in the order of visitation; we generate the // list of constructors in the reverse order. // // The llgo linker will link modules in the order of // package dependency, i.e. if A requires B, then llgo-link // will link the modules in the order A, B. The "runtime" // package is always last. // // At program initialisation, the runtime initialisation // function (runtime.main) will invoke the constructors // in reverse order. var initfuncs [][]llvm.Value if compiler.varinitfuncs != nil { initfuncs = append(initfuncs, compiler.varinitfuncs) } if compiler.initfuncs != nil { initfuncs = append(initfuncs, compiler.initfuncs) } if initfuncs != nil { ctortype := llvm.PointerType(llvm.Int8Type(), 0) var ctors []llvm.Value var index int = 0 for _, initfuncs := range initfuncs { for _, fnptr := range initfuncs { name := fmt.Sprintf("__llgo.ctor.%s.%d", importpath, index) fnptr.SetName(name) fnptr = llvm.ConstBitCast(fnptr, ctortype) ctors = append(ctors, fnptr) index++ } } for i, n := 0, len(ctors); i < n/2; i++ { ctors[i], ctors[n-i-1] = ctors[n-i-1], ctors[i] } ctorsInit := llvm.ConstArray(ctortype, ctors) ctorsVar := llvm.AddGlobal(compiler.module.Module, ctorsInit.Type(), "runtime.ctors") ctorsVar.SetInitializer(ctorsInit) ctorsVar.SetLinkage(llvm.AppendingLinkage) } // Create debug metadata. //compiler.createMetadata() return compiler.module, nil }
// p != nil iff we're generatig the uncommonType for a pointer type. func (tm *TypeMap) uncommonType(n *types.Named, p *types.Pointer) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtime.uncommonType.llvm) namePtr := tm.globalStringPtr(n.Obj().Name()) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) var path string if pkg := n.Obj().Pkg(); pkg != nil { path = pkg.Path() } pkgpathPtr := tm.globalStringPtr(path) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) // If we're dealing with an interface, stop now; // we store interface methods on the interface // type. if _, ok := n.Underlying().(*types.Interface); ok { return uncommonTypeInit } var methodset, pmethodset *types.MethodSet if p != nil { methodset = tm.MethodSet(p) } else { methodset = tm.MethodSet(n) } // Store methods. All methods must be stored, not only exported ones; // this is to allow satisfying of interfaces with non-exported methods. methods := make([]llvm.Value, methodset.Len()) for i := range methods { sel := methodset.At(i) mname := sel.Obj().Name() mfunc := tm.methodResolver.ResolveMethod(sel) ftyp := mfunc.Type().(*types.Signature) method := llvm.ConstNull(tm.runtime.method.llvm) name := tm.globalStringPtr(mname) name = llvm.ConstBitCast(name, tm.runtime.method.llvm.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { ftyp := types.NewSignature(nil, nil, ftyp.Params(), ftyp.Results(), ftyp.Variadic()) mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := llvm.ConstPtrToInt(mfunc.LLVMValue(), tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn if p == nil { if tm.Sizeof(n) > int64(tm.target.PointerSize()) { if pmethodset == nil { pmethodset = tm.MethodSet(types.NewPointer(n)) } pmfunc := tm.methodResolver.ResolveMethod(pmethodset.Lookup(sel.Obj().Pkg(), mname)) ifn = llvm.ConstPtrToInt(pmfunc.LLVMValue(), tm.target.IntPtrType()) } else if _, ok := n.Underlying().(*types.Pointer); !ok { // Create a wrapper function that takes an *int8, // and coerces to the receiver type. ifn = tm.interfaceFuncWrapper(mfunc.LLVMValue()) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[i] = method } methodsSliceType := tm.runtime.uncommonType.llvm.StructElementTypes()[2] methodsSlice := tm.makeSlice(methods, methodsSliceType) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }
func (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue { switch { case v.Kind() == exact.Unknown: // TODO nil literals should be represented more appropriately once the exact-package supports it. 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)", c.types.TypeString(typ), typ, v, v)) }
func (c *compiler) VisitFuncLit(lit *ast.FuncLit) Value { ftyp := c.types.expr[lit].Type.(*types.Signature) // Walk the function literal, promoting stack vars not defined // in the function literal, and storing the ident's for non-const // values not declared in the function literal. // // (First, set a dummy "stack" value for the params and results.) var dummyfunc LLVMValue dummyfunc.stack = &dummyfunc paramVars := ftyp.Params() resultVars := ftyp.Results() c.functions.push(&function{ LLVMValue: &dummyfunc, results: resultVars, }) v := &identVisitor{compiler: c} ast.Walk(v, lit.Body) c.functions.pop() // Create closure by adding a context parameter to the function, // and bind it with the values of the stack vars found in the // step above. origfnpairtyp := c.types.ToLLVM(ftyp) fnpairtyp := origfnpairtyp fntyp := origfnpairtyp.StructElementTypes()[0].ElementType() if v.captures != nil { // Add the additional context param. ctxfields := make([]*types.Field, len(v.captures)) for i, capturevar := range v.captures { ctxfields[i] = &types.Field{ Type: types.NewPointer(capturevar.Type()), } } ctxtyp := types.NewPointer(types.NewStruct(ctxfields, nil)) llvmctxtyp := c.types.ToLLVM(ctxtyp) rettyp := fntyp.ReturnType() paramtyps := append([]llvm.Type{llvmctxtyp}, fntyp.ParamTypes()...) vararg := fntyp.IsFunctionVarArg() fntyp = llvm.FunctionType(rettyp, paramtyps, vararg) opaqueptrtyp := origfnpairtyp.StructElementTypes()[1] elttyps := []llvm.Type{llvm.PointerType(fntyp, 0), opaqueptrtyp} fnpairtyp = llvm.StructType(elttyps, false) } fnptr := llvm.AddFunction(c.module.Module, "", fntyp) fnvalue := llvm.ConstNull(fnpairtyp) fnvalue = llvm.ConstInsertValue(fnvalue, fnptr, []uint32{0}) currBlock := c.builder.GetInsertBlock() f := c.NewValue(fnvalue, ftyp) captureVars := types.NewTuple(v.captures...) c.buildFunction(f, captureVars, paramVars, resultVars, lit.Body, ftyp.IsVariadic()) // Closure? Bind values to a context block. if v.captures != nil { // Store the free variables in the heap allocated block. block := c.createTypeMalloc(fntyp.ParamTypes()[0].ElementType()) for i, contextvar := range v.captures { value := c.objectdata[contextvar].Value blockPtr := c.builder.CreateStructGEP(block, i, "") c.builder.CreateStore(value.pointer.LLVMValue(), blockPtr) } // Cast the function pointer type back to the original // type, without the context parameter. fnptr = llvm.ConstBitCast(fnptr, origfnpairtyp.StructElementTypes()[0]) fnvalue = llvm.Undef(origfnpairtyp) fnvalue = llvm.ConstInsertValue(fnvalue, fnptr, []uint32{0}) // Set the context value. i8ptr := llvm.PointerType(llvm.Int8Type(), 0) block = c.builder.CreateBitCast(block, i8ptr, "") fnvalue = c.builder.CreateInsertValue(fnvalue, block, 1, "") f.value = fnvalue } else { c.builder.SetInsertPointAtEnd(currBlock) } return f }