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 flagRegMask regMask // flag register mask
24 fe Frontend // callbacks into compiler frontend
25 HTML *HTMLWriter // html writer, for debugging
26 ctxt *obj.Link // Generic arch information
27 optimize bool // Do optimization
28 noDuffDevice bool // Don't use Duff's device
29 sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
32 // TODO: more stuff. Compiler flags of interest, ...
34 // Given an environment variable used for debug hash match,
35 // what file (if any) receives the yes/no logging?
36 logfiles map[string]*os.File
38 // Storage for low-numbered values and blocks.
42 // Reusable stackAllocState.
43 // See stackalloc.go's {new,put}StackAllocState.
44 stackAllocState *stackAllocState
46 domblockstore []ID // scratch space for computing dominators
47 scrSparse []*sparseSet // scratch sparse sets to be re-used.
50 type TypeSource interface {
65 TypeBytePtr() Type // TODO: use unsafe.Pointer instead?
70 type Logger interface {
71 // Logf logs a message from the compiler.
72 Logf(string, ...interface{})
74 // Log returns true if logging is not a no-op
75 // some logging calls account for more than a few heap allocations.
78 // Fatal reports a compiler error and exits.
79 Fatalf(line int32, msg string, args ...interface{})
81 // Unimplemented reports that the function cannot be compiled.
82 // It will be removed once SSA work is complete.
83 Unimplementedf(line int32, msg string, args ...interface{})
85 // Warnl writes compiler messages in the form expected by "errorcheck" tests
86 Warnl(line int32, fmt_ string, args ...interface{})
88 // Fowards the Debug_checknil flag from gc
92 type Frontend interface {
96 // StringData returns a symbol pointing to the given string's contents.
97 StringData(string) interface{} // returns *gc.Sym
99 // Auto returns a Node for an auto variable of the given type.
100 // The SSA compiler uses this function to allocate space for spills.
103 // Given the name for a compound type, returns the name we should use
104 // for the parts of that compound type.
105 SplitString(LocalSlot) (LocalSlot, LocalSlot)
106 SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
107 SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
108 SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
109 SplitStruct(LocalSlot, int) LocalSlot
111 // Line returns a string describing the given line number.
115 // interface used to hold *gc.Node. We'd use *gc.Node directly but
116 // that would lead to an import cycle.
117 type GCNode interface {
122 // NewConfig returns a new configuration object for the given architecture.
123 func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config {
124 c := &Config{arch: arch, fe: fe}
129 c.lowerBlock = rewriteBlockAMD64
130 c.lowerValue = rewriteValueAMD64
131 c.registers = registersAMD64[:]
132 c.flagRegMask = flagRegMaskAMD64
136 c.lowerBlock = rewriteBlockAMD64
137 c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
141 c.lowerBlock = rewriteBlockARM
142 c.lowerValue = rewriteValueARM
143 c.registers = registersARM[:]
144 c.flagRegMask = flagRegMaskARM
146 fe.Unimplementedf(0, "arch %s not implemented", arch)
149 c.optimize = optimize
151 // Don't use Duff's device on Plan 9, because floating
152 // point operations are not allowed in note handler.
153 if obj.Getgoos() == "plan9" {
154 c.noDuffDevice = true
157 // Assign IDs to preallocated values/blocks.
158 for i := range c.values {
159 c.values[i].ID = ID(i)
161 for i := range c.blocks {
162 c.blocks[i].ID = ID(i)
165 c.logfiles = make(map[string]*os.File)
167 // cutoff is compared with product of numblocks and numvalues,
168 // if product is smaller than cutoff, use old non-sparse method.
169 // cutoff == 0 implies all sparse.
170 // cutoff == -1 implies none sparse.
171 // Good cutoff values seem to be O(million) depending on constant factor cost of sparse.
172 // TODO: get this from a flag, not an environment variable
173 c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash
174 ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF")
176 v, err := strconv.ParseInt(ev, 10, 64)
178 fe.Fatalf(0, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
180 c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
186 func (c *Config) Frontend() Frontend { return c.fe }
187 func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
189 // NewFunc returns a new, empty function object.
190 // Caller must call f.Free() before calling NewFunc again.
191 func (c *Config) NewFunc() *Func {
192 // TODO(khr): should this function take name, type, etc. as arguments?
193 if c.curFunc != nil {
194 c.Fatalf(0, "NewFunc called without previous Free")
196 f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}}
201 func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
202 func (c *Config) Log() bool { return c.fe.Log() }
203 func (c *Config) Fatalf(line int32, msg string, args ...interface{}) { c.fe.Fatalf(line, msg, args...) }
204 func (c *Config) Unimplementedf(line int32, msg string, args ...interface{}) {
205 c.fe.Unimplementedf(line, msg, args...)
207 func (c *Config) Warnl(line int32, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) }
208 func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
210 func (c *Config) logDebugHashMatch(evname, name string) {
211 file := c.logfiles[evname]
214 tmpfile := os.Getenv("GSHS_LOGFILE")
217 file, ok = os.Create(tmpfile)
219 c.Fatalf(0, "Could not open hash-testing logfile %s", tmpfile)
222 c.logfiles[evname] = file
224 s := fmt.Sprintf("%s triggered %s\n", evname, name)
229 // DebugHashMatch returns true if environment variable evname
230 // 1) is empty (this is a special more-quickly implemented case of 3)
232 // 3) is a suffix of the sha1 hash of name
233 // 4) is a suffix of the environment variable
234 // fmt.Sprintf("%s%d", evname, n)
235 // provided that all such variables are nonempty for 0 <= i <= n
236 // Otherwise it returns false.
237 // When true is returned the message
238 // "%s triggered %s\n", evname, name
239 // is printed on the file named in environment variable
241 // or standard out if that is empty or there is an error
244 func (c *Config) DebugHashMatch(evname, name string) bool {
245 evhash := os.Getenv(evname)
247 return true // default behavior with no EV is "on"
249 if evhash == "y" || evhash == "Y" {
250 c.logDebugHashMatch(evname, name)
253 if evhash == "n" || evhash == "N" {
256 // Check the hash of the name against a partial input hash.
257 // We use this feature to do a binary search to
258 // find a function that is incorrectly compiled.
260 for _, b := range sha1.Sum([]byte(name)) {
261 hstr += fmt.Sprintf("%08b", b)
264 if strings.HasSuffix(hstr, evhash) {
265 c.logDebugHashMatch(evname, name)
269 // Iteratively try additional hashes to allow tests for multi-point
271 for i := 0; true; i++ {
272 ev := fmt.Sprintf("%s%d", evname, i)
277 if strings.HasSuffix(hstr, evv) {
278 c.logDebugHashMatch(ev, name)
285 func (c *Config) DebugNameMatch(evname, name string) bool {
286 return os.Getenv(evname) == name