Skip to content

Commit f59690f

Browse files
committed
Allow larger systems to have a larger max stack alloc
Fixes #3331
1 parent fa4ca63 commit f59690f

File tree

6 files changed

+19
-15
lines changed

6 files changed

+19
-15
lines changed

builder/build.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
197197
Scheduler: config.Scheduler(),
198198
AutomaticStackSize: config.AutomaticStackSize(),
199199
DefaultStackSize: config.StackSize(),
200+
MaxStackAlloc: config.MaxStackAlloc(),
200201
NeedsStackObjects: config.NeedsStackObjects(),
201202
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
202203
}

compileopts/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ func (c *Config) StackSize() uint64 {
189189
return c.Target.DefaultStackSize
190190
}
191191

192+
// MaxStackAlloc returns the size of the maximum allocation to put on the stack vs heap.
193+
func (c *Config) MaxStackAlloc() uint64 {
194+
if c.StackSize() > 32*1024 {
195+
return 1024
196+
}
197+
198+
return 256
199+
}
200+
192201
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
193202
// calculates and patches in the checksum for the 2nd stage bootloader.
194203
func (c *Config) RP2040BootPatch() bool {

compiler/compiler.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type Config struct {
5353
Scheduler string
5454
AutomaticStackSize bool
5555
DefaultStackSize uint64
56+
MaxStackAlloc uint64
5657
NeedsStackObjects bool
5758
Debug bool // Whether to emit debug information in the LLVM module.
5859
}
@@ -1997,8 +1998,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
19971998
case *ssa.Alloc:
19981999
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
19992000
size := b.targetData.TypeAllocSize(typ)
2000-
// Move all "large" allocations to the heap. This value is also transform.maxStackAlloc.
2001-
if expr.Heap || size > 256 {
2001+
// Move all "large" allocations to the heap.
2002+
if expr.Heap || size > b.MaxStackAlloc {
20022003
// Calculate ^uintptr(0)
20032004
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
20042005
if size > maxSize {

transform/allocs.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,14 @@ import (
1313
"tinygo.org/x/go-llvm"
1414
)
1515

16-
// maxStackAlloc is the maximum size of an object that will be allocated on the
17-
// stack. Bigger objects have increased risk of stack overflows and thus will
18-
// always be heap allocated.
19-
//
20-
// TODO: tune this, this is just a random value.
21-
// This value is also used in the compiler when translating ssa.Alloc nodes.
22-
const maxStackAlloc = 256
23-
2416
// OptimizeAllocs tries to replace heap allocations with stack allocations
2517
// whenever possible. It relies on the LLVM 'nocapture' flag for interprocedural
2618
// escape analysis, and within a function looks whether an allocation can escape
2719
// to the heap.
2820
// If printAllocs is non-nil, it indicates the regexp of functions for which a
2921
// heap allocation explanation should be printed (why the object can't be stack
3022
// allocated).
31-
func OptimizeAllocs(mod llvm.Module, printAllocs *regexp.Regexp, logger func(token.Position, string)) {
23+
func OptimizeAllocs(mod llvm.Module, printAllocs *regexp.Regexp, maxStackAlloc uint64, logger func(token.Position, string)) {
3224
allocator := mod.NamedFunction("runtime.alloc")
3325
if allocator.IsNil() {
3426
// nothing to optimize

transform/allocs_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
func TestAllocs(t *testing.T) {
1818
t.Parallel()
1919
testTransform(t, "testdata/allocs", func(mod llvm.Module) {
20-
transform.OptimizeAllocs(mod, nil, nil)
20+
transform.OptimizeAllocs(mod, nil, 256, nil)
2121
})
2222
}
2323

@@ -47,7 +47,7 @@ func TestAllocs2(t *testing.T) {
4747

4848
// Run heap to stack transform.
4949
var testOutputs []allocsTestOutput
50-
transform.OptimizeAllocs(mod, regexp.MustCompile("."), func(pos token.Position, msg string) {
50+
transform.OptimizeAllocs(mod, regexp.MustCompile("."), 256, func(pos token.Position, msg string) {
5151
testOutputs = append(testOutputs, allocsTestOutput{
5252
filename: filepath.Base(pos.Filename),
5353
line: pos.Line,

transform/optimizer.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ func Optimize(mod llvm.Module, config *compileopts.Config) []error {
6464
// Run TinyGo-specific optimization passes.
6565
OptimizeStringToBytes(mod)
6666
OptimizeReflectImplements(mod)
67-
OptimizeAllocs(mod, nil, nil)
67+
maxStackSize := config.MaxStackAlloc()
68+
OptimizeAllocs(mod, nil, maxStackSize, nil)
6869
err = LowerInterfaces(mod, config)
6970
if err != nil {
7071
return []error{err}
@@ -84,7 +85,7 @@ func Optimize(mod llvm.Module, config *compileopts.Config) []error {
8485
}
8586

8687
// Run TinyGo-specific interprocedural optimizations.
87-
OptimizeAllocs(mod, config.Options.PrintAllocs, func(pos token.Position, msg string) {
88+
OptimizeAllocs(mod, config.Options.PrintAllocs, maxStackSize, func(pos token.Position, msg string) {
8889
fmt.Fprintln(os.Stderr, pos.String()+": "+msg)
8990
})
9091
OptimizeStringToBytes(mod)

0 commit comments

Comments
 (0)