Skip to content

Commit 777d3f3

Browse files
aykevldeadprogram
authored andcommitted
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.
1 parent ea3b5dc commit 777d3f3

File tree

13 files changed

+49
-6
lines changed

13 files changed

+49
-6
lines changed

builder/build.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
188188
if err != nil {
189189
return err
190190
}
191+
defer machine.Dispose()
191192

192193
// Load entire program AST into memory.
193194
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
287288
// Compile AST to IR. The compiler.CompilePackage function will
288289
// build the SSA as needed.
289290
mod, errs := compiler.CompilePackage(pkg.ImportPath, pkg, program.Package(pkg.Pkg), machine, compilerConfig, config.DumpSSA())
291+
defer mod.Context().Dispose()
292+
defer mod.Dispose()
290293
if errs != nil {
291294
return newMultiError(errs)
292295
}
@@ -432,6 +435,13 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
432435

433436
// Add job that links and optimizes all packages together.
434437
var mod llvm.Module
438+
defer func() {
439+
if !mod.IsNil() {
440+
ctx := mod.Context()
441+
mod.Dispose()
442+
ctx.Dispose()
443+
}
444+
}()
435445
var stackSizeLoads []string
436446
programJob := &compileJob{
437447
description: "link+optimize packages (LTO)",
@@ -534,6 +544,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
534544
if err != nil {
535545
return err
536546
}
547+
defer llvmBuf.Dispose()
537548
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666)
538549
case ".bc":
539550
var buf llvm.MemoryBuffer

compiler/compiler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
301301
}),
302302
)
303303
c.dibuilder.Finalize()
304+
c.dibuilder.Destroy()
304305
}
305306

306307
return c.mod, c.diagnostics

compiler/compiler_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ func TestCompiler(t *testing.T) {
106106
if err != nil {
107107
t.Fatal("failed to create target machine:", err)
108108
}
109+
defer machine.Dispose()
109110

110111
// Load entire program AST into memory.
111112
lprogram, err := loader.Load(config, []string{"./testdata/" + tc.file}, config.ClangHeaders, types.Config{

compiler/llvmutil/llvm.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func CreateEntryBlockAlloca(builder llvm.Builder, t llvm.Type, name string) llvm
3434
func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
3535
ctx := t.Context()
3636
targetData := llvm.NewTargetData(mod.DataLayout())
37+
defer targetData.Dispose()
3738
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
3839
alloca = CreateEntryBlockAlloca(builder, t, name)
3940
bitcast = builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
@@ -46,6 +47,7 @@ func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, n
4647
func CreateInstructionAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, inst llvm.Value, name string) llvm.Value {
4748
ctx := mod.Context()
4849
targetData := llvm.NewTargetData(mod.DataLayout())
50+
defer targetData.Dispose()
4951
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
5052

5153
alloca := CreateEntryBlockAlloca(builder, t, name)

compiler/llvmutil/wordpack.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ import (
1515
func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needsStackObjects bool, values []llvm.Value) llvm.Value {
1616
ctx := mod.Context()
1717
targetData := llvm.NewTargetData(mod.DataLayout())
18+
defer targetData.Dispose()
1819
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
19-
uintptrType := ctx.IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8)
20+
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
2021

2122
valueTypes := make([]llvm.Type, len(values))
2223
for i, value := range values {
@@ -127,8 +128,9 @@ func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needs
127128
func EmitPointerUnpack(builder llvm.Builder, mod llvm.Module, ptr llvm.Value, valueTypes []llvm.Type) []llvm.Value {
128129
ctx := mod.Context()
129130
targetData := llvm.NewTargetData(mod.DataLayout())
131+
defer targetData.Dispose()
130132
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
131-
uintptrType := ctx.IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8)
133+
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
132134

133135
packedType := ctx.StructType(valueTypes, false)
134136

interp/interp.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,17 @@ func newRunner(mod llvm.Module, debug bool) *runner {
5050
return &r
5151
}
5252

53+
// Dispose deallocates all alloated LLVM resources.
54+
func (r *runner) dispose() {
55+
r.targetData.Dispose()
56+
r.targetData = llvm.TargetData{}
57+
}
58+
5359
// Run evaluates runtime.initAll function as much as possible at compile time.
5460
// Set debug to true if it should print output while running.
5561
func Run(mod llvm.Module, debug bool) error {
5662
r := newRunner(mod, debug)
63+
defer r.dispose()
5764

5865
initAll := mod.NamedFunction("runtime.initAll")
5966
bb := initAll.EntryBasicBlock()
@@ -196,6 +203,7 @@ func RunFunc(fn llvm.Value, debug bool) error {
196203
// Create and initialize *runner object.
197204
mod := fn.GlobalParent()
198205
r := newRunner(mod, debug)
206+
defer r.dispose()
199207
initName := fn.Name()
200208
if !strings.HasSuffix(initName, ".init") {
201209
return errorAt(fn, "interp: unexpected function name (expected *.init)")

interp/interp_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func TestInterp(t *testing.T) {
4040
func runTest(t *testing.T, pathPrefix string) {
4141
// Read the input IR.
4242
ctx := llvm.NewContext()
43+
defer ctx.Dispose()
4344
buf, err := llvm.NewMemoryBufferFromFile(pathPrefix + ".ll")
4445
os.Stat(pathPrefix + ".ll") // make sure this file is tracked by `go test` caching
4546
if err != nil {
@@ -49,6 +50,7 @@ func runTest(t *testing.T, pathPrefix string) {
4950
if err != nil {
5051
t.Fatalf("could not load module:\n%v", err)
5152
}
53+
defer mod.Dispose()
5254

5355
// Perform the transform.
5456
err = Run(mod, false)

transform/allocs.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ func OptimizeAllocs(mod llvm.Module, printAllocs *regexp.Regexp, logger func(tok
3636
}
3737

3838
targetData := llvm.NewTargetData(mod.DataLayout())
39+
defer targetData.Dispose()
3940
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
4041
builder := mod.Context().NewBuilder()
42+
defer builder.Dispose()
4143

4244
for _, heapalloc := range getUses(allocator) {
4345
logAllocs := printAllocs != nil && printAllocs.MatchString(heapalloc.InstructionParent().Parent().Name())

transform/gc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ func MakeGCStackSlots(mod llvm.Module) bool {
3333

3434
ctx := mod.Context()
3535
builder := ctx.NewBuilder()
36+
defer builder.Dispose()
3637
targetData := llvm.NewTargetData(mod.DataLayout())
38+
defer targetData.Dispose()
3739
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
3840

3941
// Look at *all* functions to see whether they are free of function pointer
@@ -326,6 +328,7 @@ func AddGlobalsBitmap(mod llvm.Module) bool {
326328

327329
ctx := mod.Context()
328330
targetData := llvm.NewTargetData(mod.DataLayout())
331+
defer targetData.Dispose()
329332
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
330333

331334
// Collect all globals that contain pointers (and thus must be scanned by

transform/interface-lowering.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,23 @@ type lowerInterfacesPass struct {
101101
// before LLVM can work on them. This is done so that a few cleanup passes can
102102
// run before assigning the final type codes.
103103
func LowerInterfaces(mod llvm.Module, config *compileopts.Config) error {
104+
targetData := llvm.NewTargetData(mod.DataLayout())
105+
defer targetData.Dispose()
104106
p := &lowerInterfacesPass{
105107
mod: mod,
106108
config: config,
107109
builder: mod.Context().NewBuilder(),
108110
ctx: mod.Context(),
109-
uintptrType: mod.Context().IntType(llvm.NewTargetData(mod.DataLayout()).PointerSize() * 8),
111+
uintptrType: mod.Context().IntType(targetData.PointerSize() * 8),
110112
types: make(map[string]*typeInfo),
111113
signatures: make(map[string]*signatureInfo),
112114
interfaces: make(map[string]*interfaceInfo),
113115
}
116+
defer p.builder.Dispose()
114117

115118
if config.Debug() {
116119
p.dibuilder = llvm.NewDIBuilder(mod)
120+
defer p.dibuilder.Destroy()
117121
defer p.dibuilder.Finalize()
118122
p.difiles = make(map[string]llvm.Metadata)
119123
}

0 commit comments

Comments
 (0)