1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 arch string // "amd64", etc.
18 IntSize int64 // 4 or 8
19 PtrSize int64 // 4 or 8
20 lowerBlock func(*Block) bool // lowering function
21 lowerValue func(*Value, *Config) bool // lowering function
22 registers []Register // machine registers
23 fe Frontend // callbacks into compiler frontend
24 HTML *HTMLWriter // html writer, for debugging
25 ctxt *obj.Link // Generic arch information
26 optimize bool // Do optimization
27 noDuffDevice bool // Don't use Duff's device
28 sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
31 // TODO: more stuff. Compiler flags of interest, ...
33 // Given an environment variable used for debug hash match,
34 // what file (if any) receives the yes/no logging?
35 logfiles map[string]*os.File
37 // Storage for low-numbered values and blocks.
41 // Reusable stackAllocState.
42 // See stackalloc.go's {new,put}StackAllocState.
43 stackAllocState *stackAllocState
45 domblockstore []ID // scratch space for computing dominators
46 scrSparse []*sparseSet // scratch sparse sets to be re-used.
49 type TypeSource interface {
64 TypeBytePtr() Type // TODO: use unsafe.Pointer instead?
69 type Logger interface {
70 // Logf logs a message from the compiler.
71 Logf(string, ...interface{})
73 // Log returns true if logging is not a no-op
74 // some logging calls account for more than a few heap allocations.
77 // Fatal reports a compiler error and exits.
78 Fatalf(line int32, msg string, args ...interface{})
80 // Unimplemented reports that the function cannot be compiled.
81 // It will be removed once SSA work is complete.
82 Unimplementedf(line int32, msg string, args ...interface{})
84 // Warnl writes compiler messages in the form expected by "errorcheck" tests
85 Warnl(line int32, fmt_ string, args ...interface{})
87 // Fowards the Debug_checknil flag from gc
91 type Frontend interface {
95 // StringData returns a symbol pointing to the given string's contents.
96 StringData(string) interface{} // returns *gc.Sym
98 // Auto returns a Node for an auto variable of the given type.
99 // The SSA compiler uses this function to allocate space for spills.
102 // Given the name for a compound type, returns the name we should use
103 // for the parts of that compound type.
104 SplitString(LocalSlot) (LocalSlot, LocalSlot)
105 SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
106 SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
107 SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
108 SplitStruct(LocalSlot, int) LocalSlot
110 // Line returns a string describing the given line number.
114 // interface used to hold *gc.Node. We'd use *gc.Node directly but
115 // that would lead to an import cycle.
116 type GCNode interface {
121 // NewConfig returns a new configuration object for the given architecture.
122 func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config {
123 c := &Config{arch: arch, fe: fe}
128 c.lowerBlock = rewriteBlockAMD64
129 c.lowerValue = rewriteValueAMD64
130 c.registers = registersAMD64[:]
134 c.lowerBlock = rewriteBlockAMD64
135 c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
139 c.lowerBlock = rewriteBlockARM
140 c.lowerValue = rewriteValueARM
141 c.registers = registersARM[:]
143 fe.Unimplementedf(0, "arch %s not implemented", arch)
146 c.optimize = optimize
148 // Don't use Duff's device on Plan 9, because floating
149 // point operations are not allowed in note handler.
150 if obj.Getgoos() == "plan9" {
151 c.noDuffDevice = true
154 // Assign IDs to preallocated values/blocks.
155 for i := range c.values {
156 c.values[i].ID = ID(i)
158 for i := range c.blocks {
159 c.blocks[i].ID = ID(i)
162 c.logfiles = make(map[string]*os.File)
164 // cutoff is compared with product of numblocks and numvalues,
165 // if product is smaller than cutoff, use old non-sparse method.
166 // cutoff == 0 implies all sparse.
167 // cutoff == -1 implies none sparse.
168 // Good cutoff values seem to be O(million) depending on constant factor cost of sparse.
169 // TODO: get this from a flag, not an environment variable
170 c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash
171 ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF")
173 v, err := strconv.ParseInt(ev, 10, 64)
175 fe.Fatalf(0, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
177 c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
183 func (c *Config) Frontend() Frontend { return c.fe }
184 func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
186 // NewFunc returns a new, empty function object.
187 // Caller must call f.Free() before calling NewFunc again.
188 func (c *Config) NewFunc() *Func {
189 // TODO(khr): should this function take name, type, etc. as arguments?
190 if c.curFunc != nil {
191 c.Fatalf(0, "NewFunc called without previous Free")
193 f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}}
198 func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
199 func (c *Config) Log() bool { return c.fe.Log() }
200 func (c *Config) Fatalf(line int32, msg string, args ...interface{}) { c.fe.Fatalf(line, msg, args...) }
201 func (c *Config) Unimplementedf(line int32, msg string, args ...interface{}) {
202 c.fe.Unimplementedf(line, msg, args...)
204 func (c *Config) Warnl(line int32, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) }
205 func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
207 func (c *Config) logDebugHashMatch(evname, name string) {
208 file := c.logfiles[evname]
211 tmpfile := os.Getenv("GSHS_LOGFILE")
214 file, ok = os.Create(tmpfile)
216 c.Fatalf(0, "Could not open hash-testing logfile %s", tmpfile)
219 c.logfiles[evname] = file
221 s := fmt.Sprintf("%s triggered %s\n", evname, name)
226 // DebugHashMatch returns true if environment variable evname
227 // 1) is empty (this is a special more-quickly implemented case of 3)
229 // 3) is a suffix of the sha1 hash of name
230 // 4) is a suffix of the environment variable
231 // fmt.Sprintf("%s%d", evname, n)
232 // provided that all such variables are nonempty for 0 <= i <= n
233 // Otherwise it returns false.
234 // When true is returned the message
235 // "%s triggered %s\n", evname, name
236 // is printed on the file named in environment variable
238 // or standard out if that is empty or there is an error
241 func (c *Config) DebugHashMatch(evname, name string) bool {
242 evhash := os.Getenv(evname)
244 return true // default behavior with no EV is "on"
246 if evhash == "y" || evhash == "Y" {
247 c.logDebugHashMatch(evname, name)
250 if evhash == "n" || evhash == "N" {
253 // Check the hash of the name against a partial input hash.
254 // We use this feature to do a binary search to
255 // find a function that is incorrectly compiled.
257 for _, b := range sha1.Sum([]byte(name)) {
258 hstr += fmt.Sprintf("%08b", b)
261 if strings.HasSuffix(hstr, evhash) {
262 c.logDebugHashMatch(evname, name)
266 // Iteratively try additional hashes to allow tests for multi-point
268 for i := 0; true; i++ {
269 ev := fmt.Sprintf("%s%d", evname, i)
274 if strings.HasSuffix(hstr, evv) {
275 c.logDebugHashMatch(ev, name)
282 func (c *Config) DebugNameMatch(evname, name string) bool {
283 return os.Getenv(evname) == name