func (tm *llvmTypeMap) funcLLVMType(f *types.Signature, name string) llvm.Type { // If there's a receiver change the receiver to an // additional (first) parameter, and take the value of // the resulting signature instead. if recv := f.Recv(); recv != nil { params := f.Params() paramvars := make([]*types.Var, int(params.Len()+1)) paramvars[0] = recv for i := 0; i < int(params.Len()); i++ { paramvars[i+1] = params.At(i) } params = types.NewTuple(paramvars...) f := types.NewSignature(nil, nil, params, f.Results(), f.Variadic()) return tm.toLLVM(f, name) } if typ, ok := tm.types.At(f).(llvm.Type); ok { return typ } typ := llvm.GlobalContext().StructCreateNamed(name) tm.types.Set(f, typ) params := f.Params() param_types := make([]llvm.Type, params.Len()) for i := range param_types { llvmtyp := tm.ToLLVM(params.At(i).Type()) param_types[i] = llvmtyp } var return_type llvm.Type results := f.Results() switch nresults := int(results.Len()); nresults { case 0: return_type = llvm.VoidType() case 1: return_type = tm.ToLLVM(results.At(0).Type()) default: elements := make([]llvm.Type, nresults) for i := range elements { result := results.At(i) elements[i] = tm.ToLLVM(result.Type()) } return_type = llvm.StructType(elements, false) } fntyp := llvm.FunctionType(return_type, param_types, false) fnptrtyp := llvm.PointerType(fntyp, 0) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) elements := []llvm.Type{fnptrtyp, i8ptr} // func, closure typ.StructSetBody(elements, false) return typ }
func (tm *llvmTypeMap) sliceLLVMType(s *types.Slice, name string) llvm.Type { typ, ok := tm.types.At(s).(llvm.Type) if !ok { typ = llvm.GlobalContext().StructCreateNamed(name) tm.types.Set(s, typ) elements := []llvm.Type{ llvm.PointerType(tm.ToLLVM(s.Elem()), 0), tm.inttype, tm.inttype, } typ.StructSetBody(elements, false) } return typ }
func (tm *llvmTypeMap) structLLVMType(s *types.Struct, name string) llvm.Type { typ, ok := tm.types.At(s).(llvm.Type) if !ok { typ = llvm.GlobalContext().StructCreateNamed(name) tm.types.Set(s, typ) elements := make([]llvm.Type, s.NumFields()) for i := range elements { f := s.Field(i) ft := f.Type() elements[i] = tm.ToLLVM(ft) } typ.StructSetBody(elements, false) } return typ }
func (tm *llvmTypeMap) interfaceLLVMType(i *types.Interface, name string) llvm.Type { if typ, ok := tm.types.At(i).(llvm.Type); ok { return typ } // interface{} is represented as {type, value}, // and non-empty interfaces are represented as {itab, value}. i8ptr := llvm.PointerType(llvm.Int8Type(), 0) rtypeType := i8ptr valueType := i8ptr if name == "" { name = i.String() } typ := llvm.GlobalContext().StructCreateNamed(name) typ.StructSetBody([]llvm.Type{rtypeType, valueType}, false) return typ }
func NewLLVMTypeMap(target llvm.TargetData) *llvmTypeMap { // spec says int is either 32-bit or 64-bit. var inttype llvm.Type if target.PointerSize() >= 8 { inttype = llvm.Int64Type() } else { inttype = llvm.Int32Type() } return &llvmTypeMap{ StdSizes: &types.StdSizes{ WordSize: int64(target.PointerSize()), MaxAlign: 8, }, target: target, inttype: inttype, ptrstandin: llvm.GlobalContext().StructCreateNamed(""), } }
func (tm *TypeMap) interfaceFuncWrapper(f llvm.Value) llvm.Value { ftyp := f.Type().ElementType() paramTypes := ftyp.ParamTypes() recvType := paramTypes[0] paramTypes[0] = llvm.PointerType(llvm.Int8Type(), 0) newf := llvm.AddFunction(f.GlobalParent(), f.Name()+".ifn", llvm.FunctionType( ftyp.ReturnType(), paramTypes, ftyp.IsFunctionVarArg(), )) b := llvm.GlobalContext().NewBuilder() defer b.Dispose() entry := llvm.AddBasicBlock(newf, "entry") b.SetInsertPointAtEnd(entry) args := make([]llvm.Value, len(paramTypes)) for i := range paramTypes { args[i] = newf.Param(i) } recvBits := int(tm.target.TypeSizeInBits(recvType)) if recvBits > 0 { args[0] = b.CreatePtrToInt(args[0], tm.target.IntPtrType(), "") if args[0].Type().IntTypeWidth() > recvBits { args[0] = b.CreateTrunc(args[0], llvm.IntType(recvBits), "") } args[0] = coerce(b, args[0], recvType) } else { args[0] = llvm.ConstNull(recvType) } result := b.CreateCall(f, args, "") if result.Type().TypeKind() == llvm.VoidTypeKind { b.CreateRetVoid() } else { b.CreateRet(result) } return newf }
func (compiler *compiler) compile(filenames []string, importpath string) (m *Module, err error) { buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple) if err != nil { return nil, err } impcfg := &loader.Config{ Fset: token.NewFileSet(), TypeChecker: types.Config{ Import: llgoimporter.NewImporter(buildctx).Import, Sizes: compiler.llvmtypes, }, Build: &buildctx.Context, } // Must use parseFiles, so we retain comments; // this is important for annotation processing. astFiles, err := parseFiles(impcfg.Fset, filenames) if err != nil { return nil, err } // 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 pkgname := astFiles[0].Name.String(); importpath == "" || pkgname == "main" { importpath = pkgname } impcfg.CreateFromFiles(importpath, astFiles...) // Create a "runtime" package too, so we can reference // its types and functions in the compiler and generated // code. if importpath != "runtime" { astFiles, err := parseRuntime(&buildctx.Context, impcfg.Fset) if err != nil { return nil, err } impcfg.CreateFromFiles("runtime", astFiles...) } iprog, err := impcfg.Load() if err != nil { return nil, err } program := ssa.Create(iprog, 0) var mainPkginfo, runtimePkginfo *loader.PackageInfo if pkgs := iprog.InitialPackages(); len(pkgs) == 1 { mainPkginfo, runtimePkginfo = pkgs[0], pkgs[0] } else { mainPkginfo, runtimePkginfo = pkgs[0], pkgs[1] } mainPkg := program.CreatePackage(mainPkginfo) // Create a Module, which contains the LLVM bitcode. modulename := importpath compiler.module = &Module{Module: llvm.NewModule(modulename), Name: modulename} compiler.module.SetTarget(compiler.TargetTriple) compiler.module.SetDataLayout(compiler.dataLayout) // Create a new translation unit. unit := newUnit(compiler, mainPkg) // Create the runtime interface. compiler.runtime, err = newRuntimeInterface( runtimePkginfo.Pkg, compiler.module.Module, compiler.llvmtypes, FuncResolver(unit), ) if err != nil { return nil, err } // Create a struct responsible for mapping static types to LLVM types, // and to runtime/dynamic type values. compiler.types = NewTypeMap( importpath, compiler.llvmtypes, compiler.module.Module, compiler.runtime, MethodResolver(unit), ) // Create a Builder, for building LLVM instructions. compiler.builder = llvm.GlobalContext().NewBuilder() defer compiler.builder.Dispose() // Initialise debugging. compiler.debug.module = compiler.module.Module compiler.debug.Fset = impcfg.Fset compiler.debug.Sizes = compiler.llvmtypes mainPkg.Build() unit.translatePackage(mainPkg) compiler.processAnnotations(unit, mainPkginfo) if runtimePkginfo != mainPkginfo { compiler.processAnnotations(unit, runtimePkginfo) } // Finalise debugging. for _, cu := range compiler.debug.cu { compiler.module.AddNamedMetadataOperand( "llvm.dbg.cu", compiler.debug.MDNode(cu), ) } // Export runtime type information. var exportedTypes []types.Type for _, m := range mainPkg.Members { if t, ok := m.(*ssa.Type); ok && ast.IsExported(t.Name()) { exportedTypes = append(exportedTypes, t.Type()) } } compiler.exportRuntimeTypes(exportedTypes, importpath == "runtime") if importpath == "main" { // Wrap "main.main" in a call to runtime.main. if err = compiler.createMainFunction(); err != nil { return nil, fmt.Errorf("failed to create main.main: %v", err) } } else { if err := llgoimporter.Export(buildctx, mainPkg.Object); err != nil { return nil, fmt.Errorf("failed to export package data: %v", err) } } return compiler.module, nil }