aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/stackalloc.go
blob: 0bd64a1a141250b145850fe7c455c75a6ae5fc90 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa

// stackalloc allocates storage in the stack frame for
// all Values that did not get a register.
func stackalloc(f *Func) {
	home := f.RegAlloc

	// Start with space for callee arguments/returns.
	var n int64
	for _, b := range f.Blocks {
		if b.Kind != BlockCall {
			continue
		}
		v := b.Control
		if n < v.AuxInt {
			n = v.AuxInt
		}
	}

	// TODO: group variables by ptr/nonptr, size, etc.  Emit ptr vars last
	// so stackmap is smaller.

	// Assign stack locations to phis first, because we
	// must also assign the same locations to the phi copies
	// introduced during regalloc.
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			if v.Op != OpPhi {
				continue
			}
			if v.Type.IsMemory() { // TODO: only "regallocable" types
				continue
			}
			n = align(n, v.Type.Alignment())
			loc := &LocalSlot{n}
			n += v.Type.Size()
			home = setloc(home, v, loc)
			for _, w := range v.Args {
				home = setloc(home, w, loc)
			}
		}
	}

	// Now do all other unassigned values.
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			if v.ID < ID(len(home)) && home[v.ID] != nil {
				continue
			}
			if v.Type.IsMemory() { // TODO: only "regallocable" types
				continue
			}
			if len(v.Args) == 0 {
				// v will have been materialized wherever it is needed.
				continue
			}
			if len(v.Args) == 1 && (v.Args[0].Op == OpSP || v.Args[0].Op == OpSB) {
				continue
			}
			n = align(n, v.Type.Alignment())
			loc := &LocalSlot{n}
			n += v.Type.Size()
			home = setloc(home, v, loc)
		}
	}

	// Finally, allocate space for all autos that we used
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			s, ok := v.Aux.(*AutoSymbol)
			if !ok || s.Offset >= 0 {
				continue
			}
			t := s.Typ
			n = align(n, t.Alignment())
			s.Offset = n
			n += t.Size()
		}
	}

	n = align(n, f.Config.ptrSize)
	n += f.Config.ptrSize // space for return address.  TODO: arch-dependent
	f.RegAlloc = home
	f.FrameSize = n

	// TODO: share stack slots among noninterfering (& gc type compatible) values
}

// align increases n to the next multiple of a.  a must be a power of 2.
func align(n int64, a int64) int64 {
	return (n + a - 1) &^ (a - 1)
}