builder: free LLVM objects after use
This reduces the TinyGo memory consumption when running make tinygo-test from 5.8GB to around 2GB on my laptop.
Этот коммит содержится в:
родитель
ea3b5dc689
коммит
777d3f3ea5
13 изменённых файлов: 49 добавлений и 6 удалений
|
@ -188,6 +188,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer machine.Dispose()
|
||||||
|
|
||||||
// Load entire program AST into memory.
|
// Load entire program AST into memory.
|
||||||
lprogram, err := loader.Load(config, []string{pkgName}, config.ClangHeaders, types.Config{
|
lprogram, err := loader.Load(config, []string{pkgName}, config.ClangHeaders, types.Config{
|
||||||
|
@ -287,6 +288,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||||
// Compile AST to IR. The compiler.CompilePackage function will
|
// Compile AST to IR. The compiler.CompilePackage function will
|
||||||
// build the SSA as needed.
|
// build the SSA as needed.
|
||||||
mod, errs := compiler.CompilePackage(pkg.ImportPath, pkg, program.Package(pkg.Pkg), machine, compilerConfig, config.DumpSSA())
|
mod, errs := compiler.CompilePackage(pkg.ImportPath, pkg, program.Package(pkg.Pkg), machine, compilerConfig, config.DumpSSA())
|
||||||
|
defer mod.Context().Dispose()
|
||||||
|
defer mod.Dispose()
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return newMultiError(errs)
|
return newMultiError(errs)
|
||||||
}
|
}
|
||||||
|
@ -432,6 +435,13 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||||
|
|
||||||
// Add job that links and optimizes all packages together.
|
// Add job that links and optimizes all packages together.
|
||||||
var mod llvm.Module
|
var mod llvm.Module
|
||||||
|
defer func() {
|
||||||
|
if !mod.IsNil() {
|
||||||
|
ctx := mod.Context()
|
||||||
|
mod.Dispose()
|
||||||
|
ctx.Dispose()
|
||||||
|
}
|
||||||
|
}()
|
||||||
var stackSizeLoads []string
|
var stackSizeLoads []string
|
||||||
programJob := &compileJob{
|
programJob := &compileJob{
|
||||||
description: "link+optimize packages (LTO)",
|
description: "link+optimize packages (LTO)",
|
||||||
|
@ -534,6 +544,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer llvmBuf.Dispose()
|
||||||
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666)
|
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666)
|
||||||
case ".bc":
|
case ".bc":
|
||||||
var buf llvm.MemoryBuffer
|
var buf llvm.MemoryBuffer
|
||||||
|
|
|
@ -301,6 +301,7 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
c.dibuilder.Finalize()
|
c.dibuilder.Finalize()
|
||||||
|
c.dibuilder.Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.mod, c.diagnostics
|
return c.mod, c.diagnostics
|
||||||
|
|
|
@ -106,6 +106,7 @@ func TestCompiler(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("failed to create target machine:", err)
|
t.Fatal("failed to create target machine:", err)
|
||||||
}
|
}
|
||||||
|
defer machine.Dispose()
|
||||||
|
|
||||||
// Load entire program AST into memory.
|
// Load entire program AST into memory.
|
||||||
lprogram, err := loader.Load(config, []string{"./testdata/" + tc.file}, config.ClangHeaders, types.Config{
|
lprogram, err := loader.Load(config, []string{"./testdata/" + tc.file}, config.ClangHeaders, types.Config{
|
||||||
|
|
|
@ -34,6 +34,7 @@ func CreateEntryBlockAlloca(builder llvm.Builder, t llvm.Type, name string) llvm
|
||||||
func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
|
func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
||||||
alloca = CreateEntryBlockAlloca(builder, t, name)
|
alloca = CreateEntryBlockAlloca(builder, t, name)
|
||||||
bitcast = builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
|
bitcast = builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
|
||||||
|
@ -46,6 +47,7 @@ func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, n
|
||||||
func CreateInstructionAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, inst llvm.Value, name string) llvm.Value {
|
func CreateInstructionAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, inst llvm.Value, name string) llvm.Value {
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
|
||||||
|
|
||||||
alloca := CreateEntryBlockAlloca(builder, t, name)
|
alloca := CreateEntryBlockAlloca(builder, t, name)
|
||||||
|
|
|
@ -15,8 +15,9 @@ import (
|
||||||
func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needsStackObjects bool, values []llvm.Value) llvm.Value {
|
func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needsStackObjects bool, values []llvm.Value) llvm.Value {
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
uintptrType := ctx.IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8)
|
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
||||||
|
|
||||||
valueTypes := make([]llvm.Type, len(values))
|
valueTypes := make([]llvm.Type, len(values))
|
||||||
for i, value := range values {
|
for i, value := range values {
|
||||||
|
@ -127,8 +128,9 @@ func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needs
|
||||||
func EmitPointerUnpack(builder llvm.Builder, mod llvm.Module, ptr llvm.Value, valueTypes []llvm.Type) []llvm.Value {
|
func EmitPointerUnpack(builder llvm.Builder, mod llvm.Module, ptr llvm.Value, valueTypes []llvm.Type) []llvm.Value {
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
uintptrType := ctx.IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8)
|
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
||||||
|
|
||||||
packedType := ctx.StructType(valueTypes, false)
|
packedType := ctx.StructType(valueTypes, false)
|
||||||
|
|
||||||
|
|
|
@ -50,10 +50,17 @@ func newRunner(mod llvm.Module, debug bool) *runner {
|
||||||
return &r
|
return &r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dispose deallocates all alloated LLVM resources.
|
||||||
|
func (r *runner) dispose() {
|
||||||
|
r.targetData.Dispose()
|
||||||
|
r.targetData = llvm.TargetData{}
|
||||||
|
}
|
||||||
|
|
||||||
// Run evaluates runtime.initAll function as much as possible at compile time.
|
// Run evaluates runtime.initAll function as much as possible at compile time.
|
||||||
// Set debug to true if it should print output while running.
|
// Set debug to true if it should print output while running.
|
||||||
func Run(mod llvm.Module, debug bool) error {
|
func Run(mod llvm.Module, debug bool) error {
|
||||||
r := newRunner(mod, debug)
|
r := newRunner(mod, debug)
|
||||||
|
defer r.dispose()
|
||||||
|
|
||||||
initAll := mod.NamedFunction("runtime.initAll")
|
initAll := mod.NamedFunction("runtime.initAll")
|
||||||
bb := initAll.EntryBasicBlock()
|
bb := initAll.EntryBasicBlock()
|
||||||
|
@ -196,6 +203,7 @@ func RunFunc(fn llvm.Value, debug bool) error {
|
||||||
// Create and initialize *runner object.
|
// Create and initialize *runner object.
|
||||||
mod := fn.GlobalParent()
|
mod := fn.GlobalParent()
|
||||||
r := newRunner(mod, debug)
|
r := newRunner(mod, debug)
|
||||||
|
defer r.dispose()
|
||||||
initName := fn.Name()
|
initName := fn.Name()
|
||||||
if !strings.HasSuffix(initName, ".init") {
|
if !strings.HasSuffix(initName, ".init") {
|
||||||
return errorAt(fn, "interp: unexpected function name (expected *.init)")
|
return errorAt(fn, "interp: unexpected function name (expected *.init)")
|
||||||
|
|
|
@ -40,6 +40,7 @@ func TestInterp(t *testing.T) {
|
||||||
func runTest(t *testing.T, pathPrefix string) {
|
func runTest(t *testing.T, pathPrefix string) {
|
||||||
// Read the input IR.
|
// Read the input IR.
|
||||||
ctx := llvm.NewContext()
|
ctx := llvm.NewContext()
|
||||||
|
defer ctx.Dispose()
|
||||||
buf, err := llvm.NewMemoryBufferFromFile(pathPrefix + ".ll")
|
buf, err := llvm.NewMemoryBufferFromFile(pathPrefix + ".ll")
|
||||||
os.Stat(pathPrefix + ".ll") // make sure this file is tracked by `go test` caching
|
os.Stat(pathPrefix + ".ll") // make sure this file is tracked by `go test` caching
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,6 +50,7 @@ func runTest(t *testing.T, pathPrefix string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not load module:\n%v", err)
|
t.Fatalf("could not load module:\n%v", err)
|
||||||
}
|
}
|
||||||
|
defer mod.Dispose()
|
||||||
|
|
||||||
// Perform the transform.
|
// Perform the transform.
|
||||||
err = Run(mod, false)
|
err = Run(mod, false)
|
||||||
|
|
|
@ -36,8 +36,10 @@ func OptimizeAllocs(mod llvm.Module, printAllocs *regexp.Regexp, logger func(tok
|
||||||
}
|
}
|
||||||
|
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
builder := mod.Context().NewBuilder()
|
builder := mod.Context().NewBuilder()
|
||||||
|
defer builder.Dispose()
|
||||||
|
|
||||||
for _, heapalloc := range getUses(allocator) {
|
for _, heapalloc := range getUses(allocator) {
|
||||||
logAllocs := printAllocs != nil && printAllocs.MatchString(heapalloc.InstructionParent().Parent().Name())
|
logAllocs := printAllocs != nil && printAllocs.MatchString(heapalloc.InstructionParent().Parent().Name())
|
||||||
|
|
|
@ -33,7 +33,9 @@ func MakeGCStackSlots(mod llvm.Module) bool {
|
||||||
|
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
builder := ctx.NewBuilder()
|
builder := ctx.NewBuilder()
|
||||||
|
defer builder.Dispose()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
||||||
|
|
||||||
// Look at *all* functions to see whether they are free of function pointer
|
// Look at *all* functions to see whether they are free of function pointer
|
||||||
|
@ -326,6 +328,7 @@ func AddGlobalsBitmap(mod llvm.Module) bool {
|
||||||
|
|
||||||
ctx := mod.Context()
|
ctx := mod.Context()
|
||||||
targetData := llvm.NewTargetData(mod.DataLayout())
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
||||||
|
|
||||||
// Collect all globals that contain pointers (and thus must be scanned by
|
// Collect all globals that contain pointers (and thus must be scanned by
|
||||||
|
|
|
@ -101,19 +101,23 @@ type lowerInterfacesPass struct {
|
||||||
// before LLVM can work on them. This is done so that a few cleanup passes can
|
// before LLVM can work on them. This is done so that a few cleanup passes can
|
||||||
// run before assigning the final type codes.
|
// run before assigning the final type codes.
|
||||||
func LowerInterfaces(mod llvm.Module, config *compileopts.Config) error {
|
func LowerInterfaces(mod llvm.Module, config *compileopts.Config) error {
|
||||||
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
p := &lowerInterfacesPass{
|
p := &lowerInterfacesPass{
|
||||||
mod: mod,
|
mod: mod,
|
||||||
config: config,
|
config: config,
|
||||||
builder: mod.Context().NewBuilder(),
|
builder: mod.Context().NewBuilder(),
|
||||||
ctx: mod.Context(),
|
ctx: mod.Context(),
|
||||||
uintptrType: mod.Context().IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8),
|
uintptrType: mod.Context().IntType(targetData.PointerSize() * 8),
|
||||||
types: make(map[string]*typeInfo),
|
types: make(map[string]*typeInfo),
|
||||||
signatures: make(map[string]*signatureInfo),
|
signatures: make(map[string]*signatureInfo),
|
||||||
interfaces: make(map[string]*interfaceInfo),
|
interfaces: make(map[string]*interfaceInfo),
|
||||||
}
|
}
|
||||||
|
defer p.builder.Dispose()
|
||||||
|
|
||||||
if config.Debug() {
|
if config.Debug() {
|
||||||
p.dibuilder = llvm.NewDIBuilder(mod)
|
p.dibuilder = llvm.NewDIBuilder(mod)
|
||||||
|
defer p.dibuilder.Destroy()
|
||||||
defer p.dibuilder.Finalize()
|
defer p.dibuilder.Finalize()
|
||||||
p.difiles = make(map[string]llvm.Metadata)
|
p.difiles = make(map[string]llvm.Metadata)
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,10 +161,12 @@ func LowerReflect(mod llvm.Module) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Assign typecodes the way the reflect package expects.
|
// Assign typecodes the way the reflect package expects.
|
||||||
uintptrType := mod.Context().IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8)
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
|
uintptrType := mod.Context().IntType(targetData.PointerSize() * 8)
|
||||||
state := typeCodeAssignmentState{
|
state := typeCodeAssignmentState{
|
||||||
fallbackIndex: 1,
|
fallbackIndex: 1,
|
||||||
uintptrLen: llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8,
|
uintptrLen: targetData.PointerSize() * 8,
|
||||||
namedBasicTypes: make(map[string]int),
|
namedBasicTypes: make(map[string]int),
|
||||||
namedNonBasicTypes: make(map[string]int),
|
namedNonBasicTypes: make(map[string]int),
|
||||||
arrayTypes: make(map[string]int),
|
arrayTypes: make(map[string]int),
|
||||||
|
|
|
@ -114,7 +114,9 @@ func OptimizeReflectImplements(mod llvm.Module) {
|
||||||
defer builder.Dispose()
|
defer builder.Dispose()
|
||||||
|
|
||||||
// Get a few useful object for use later.
|
// Get a few useful object for use later.
|
||||||
uintptrType := mod.Context().IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8)
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
||||||
|
defer targetData.Dispose()
|
||||||
|
uintptrType := mod.Context().IntType(targetData.PointerSize() * 8)
|
||||||
|
|
||||||
// Look up the (reflect.Value).Implements() method.
|
// Look up the (reflect.Value).Implements() method.
|
||||||
var implementsFunc llvm.Value
|
var implementsFunc llvm.Value
|
||||||
|
|
|
@ -32,6 +32,7 @@ var defaultTestConfig = &compileopts.Config{
|
||||||
func testTransform(t *testing.T, pathPrefix string, transform func(mod llvm.Module)) {
|
func testTransform(t *testing.T, pathPrefix string, transform func(mod llvm.Module)) {
|
||||||
// Read the input IR.
|
// Read the input IR.
|
||||||
ctx := llvm.NewContext()
|
ctx := llvm.NewContext()
|
||||||
|
defer ctx.Dispose()
|
||||||
buf, err := llvm.NewMemoryBufferFromFile(pathPrefix + ".ll")
|
buf, err := llvm.NewMemoryBufferFromFile(pathPrefix + ".ll")
|
||||||
os.Stat(pathPrefix + ".ll") // make sure this file is tracked by `go test` caching
|
os.Stat(pathPrefix + ".ll") // make sure this file is tracked by `go test` caching
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -41,6 +42,7 @@ func testTransform(t *testing.T, pathPrefix string, transform func(mod llvm.Modu
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not load module:\n%v", err)
|
t.Fatalf("could not load module:\n%v", err)
|
||||||
}
|
}
|
||||||
|
defer mod.Dispose()
|
||||||
|
|
||||||
// Perform the transform.
|
// Perform the transform.
|
||||||
transform(mod)
|
transform(mod)
|
||||||
|
@ -141,6 +143,7 @@ func compileGoFileForTesting(t *testing.T, filename string) llvm.Module {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("failed to create target machine:", err)
|
t.Fatal("failed to create target machine:", err)
|
||||||
}
|
}
|
||||||
|
defer machine.Dispose()
|
||||||
|
|
||||||
// Load entire program AST into memory.
|
// Load entire program AST into memory.
|
||||||
lprogram, err := loader.Load(config, []string{filename}, config.ClangHeaders, types.Config{
|
lprogram, err := loader.Load(config, []string{filename}, config.ClangHeaders, types.Config{
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче