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 RegSize int64 // 4 or 8
21 lowerBlock func(*Block, *Config) bool // lowering function
22 lowerValue func(*Value, *Config) bool // lowering function
23 registers []Register // machine registers
24 gpRegMask regMask // general purpose integer register mask
25 fpRegMask regMask // floating point register mask
26 specialRegMask regMask // special register mask
27 FPReg int8 // register number of frame pointer, -1 if not used
28 LinkReg int8 // register number of link register if it is a general purpose register, -1 if not used
29 hasGReg bool // has hardware g register
30 fe Frontend // callbacks into compiler frontend
31 HTML *HTMLWriter // html writer, for debugging
32 ctxt *obj.Link // Generic arch information
33 optimize bool // Do optimization
34 noDuffDevice bool // Don't use Duff's device
35 nacl bool // GOOS=nacl
36 use387 bool // GO386=387
37 OldArch bool // True for older versions of architecture, e.g. true for PPC64BE, false for PPC64LE
38 NeedsFpScratch bool // No direct move between GP and FP register sets
40 DebugTest bool // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
41 sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
44 // TODO: more stuff. Compiler flags of interest, ...
46 // Given an environment variable used for debug hash match,
47 // what file (if any) receives the yes/no logging?
48 logfiles map[string]*os.File
50 // Storage for low-numbered values and blocks.
54 // Reusable stackAllocState.
55 // See stackalloc.go's {new,put}StackAllocState.
56 stackAllocState *stackAllocState
58 domblockstore []ID // scratch space for computing dominators
59 scrSparse []*sparseSet // scratch sparse sets to be re-used.
62 type TypeSource interface {
77 TypeBytePtr() Type // TODO: use unsafe.Pointer instead?
82 type Logger interface {
83 // Logf logs a message from the compiler.
84 Logf(string, ...interface{})
86 // Log returns true if logging is not a no-op
87 // some logging calls account for more than a few heap allocations.
90 // Fatal reports a compiler error and exits.
91 Fatalf(line int32, msg string, args ...interface{})
93 // Warnl writes compiler messages in the form expected by "errorcheck" tests
94 Warnl(line int32, fmt_ string, args ...interface{})
96 // Forwards the Debug flags from gc
101 type Frontend interface {
105 // StringData returns a symbol pointing to the given string's contents.
106 StringData(string) interface{} // returns *gc.Sym
108 // Auto returns a Node for an auto variable of the given type.
109 // The SSA compiler uses this function to allocate space for spills.
112 // Given the name for a compound type, returns the name we should use
113 // for the parts of that compound type.
114 SplitString(LocalSlot) (LocalSlot, LocalSlot)
115 SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
116 SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
117 SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
118 SplitStruct(LocalSlot, int) LocalSlot
119 SplitArray(LocalSlot) LocalSlot // array must be length 1
120 SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
122 // Line returns a string describing the given line number.
125 // AllocFrame assigns frame offsets to all live auto variables.
128 // Syslook returns a symbol of the runtime function/variable with the
130 Syslook(string) interface{} // returns *gc.Sym
133 // interface used to hold *gc.Node. We'd use *gc.Node directly but
134 // that would lead to an import cycle.
135 type GCNode interface {
140 // NewConfig returns a new configuration object for the given architecture.
141 func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config {
142 c := &Config{arch: arch, fe: fe}
148 c.lowerBlock = rewriteBlockAMD64
149 c.lowerValue = rewriteValueAMD64
150 c.registers = registersAMD64[:]
151 c.gpRegMask = gpRegMaskAMD64
152 c.fpRegMask = fpRegMaskAMD64
153 c.FPReg = framepointerRegAMD64
154 c.LinkReg = linkRegAMD64
160 c.lowerBlock = rewriteBlockAMD64
161 c.lowerValue = rewriteValueAMD64
162 c.registers = registersAMD64[:]
163 c.gpRegMask = gpRegMaskAMD64
164 c.fpRegMask = fpRegMaskAMD64
165 c.FPReg = framepointerRegAMD64
166 c.LinkReg = linkRegAMD64
168 c.noDuffDevice = true
173 c.lowerBlock = rewriteBlock386
174 c.lowerValue = rewriteValue386
175 c.registers = registers386[:]
176 c.gpRegMask = gpRegMask386
177 c.fpRegMask = fpRegMask386
178 c.FPReg = framepointerReg386
179 c.LinkReg = linkReg386
185 c.lowerBlock = rewriteBlockARM
186 c.lowerValue = rewriteValueARM
187 c.registers = registersARM[:]
188 c.gpRegMask = gpRegMaskARM
189 c.fpRegMask = fpRegMaskARM
190 c.FPReg = framepointerRegARM
191 c.LinkReg = linkRegARM
197 c.lowerBlock = rewriteBlockARM64
198 c.lowerValue = rewriteValueARM64
199 c.registers = registersARM64[:]
200 c.gpRegMask = gpRegMaskARM64
201 c.fpRegMask = fpRegMaskARM64
202 c.FPReg = framepointerRegARM64
203 c.LinkReg = linkRegARM64
205 c.noDuffDevice = obj.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend
214 c.lowerBlock = rewriteBlockPPC64
215 c.lowerValue = rewriteValuePPC64
216 c.registers = registersPPC64[:]
217 c.gpRegMask = gpRegMaskPPC64
218 c.fpRegMask = fpRegMaskPPC64
219 c.FPReg = framepointerRegPPC64
220 c.LinkReg = linkRegPPC64
221 c.noDuffDevice = true // TODO: Resolve PPC64 DuffDevice (has zero, but not copy)
222 c.NeedsFpScratch = true
231 c.lowerBlock = rewriteBlockMIPS64
232 c.lowerValue = rewriteValueMIPS64
233 c.registers = registersMIPS64[:]
234 c.gpRegMask = gpRegMaskMIPS64
235 c.fpRegMask = fpRegMaskMIPS64
236 c.specialRegMask = specialRegMaskMIPS64
237 c.FPReg = framepointerRegMIPS64
238 c.LinkReg = linkRegMIPS64
244 c.lowerBlock = rewriteBlockS390X
245 c.lowerValue = rewriteValueS390X
246 c.registers = registersS390X[:]
247 c.gpRegMask = gpRegMaskS390X
248 c.fpRegMask = fpRegMaskS390X
249 c.FPReg = framepointerRegS390X
250 c.LinkReg = linkRegS390X
252 c.noDuffDevice = true
261 c.lowerBlock = rewriteBlockMIPS
262 c.lowerValue = rewriteValueMIPS
263 c.registers = registersMIPS[:]
264 c.gpRegMask = gpRegMaskMIPS
265 c.fpRegMask = fpRegMaskMIPS
266 c.specialRegMask = specialRegMaskMIPS
267 c.FPReg = framepointerRegMIPS
268 c.LinkReg = linkRegMIPS
270 c.noDuffDevice = true
272 fe.Fatalf(0, "arch %s not implemented", arch)
275 c.optimize = optimize
276 c.nacl = obj.GOOS == "nacl"
278 // Don't use Duff's device on Plan 9 AMD64, because floating
279 // point operations are not allowed in note handler.
280 if obj.GOOS == "plan9" && arch == "amd64" {
281 c.noDuffDevice = true
285 c.noDuffDevice = true // Don't use Duff's device on NaCl
287 // runtime call clobber R12 on nacl
288 opcodeTable[OpARMUDIVrtcall].reg.clobbers |= 1 << 12 // R12
291 // Assign IDs to preallocated values/blocks.
292 for i := range c.values {
293 c.values[i].ID = ID(i)
295 for i := range c.blocks {
296 c.blocks[i].ID = ID(i)
299 c.logfiles = make(map[string]*os.File)
301 // cutoff is compared with product of numblocks and numvalues,
302 // if product is smaller than cutoff, use old non-sparse method.
303 // cutoff == 0 implies all sparse.
304 // cutoff == -1 implies none sparse.
305 // Good cutoff values seem to be O(million) depending on constant factor cost of sparse.
306 // TODO: get this from a flag, not an environment variable
307 c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash
308 ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF")
310 v, err := strconv.ParseInt(ev, 10, 64)
312 fe.Fatalf(0, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
314 c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
320 func (c *Config) Set387(b bool) {
325 func (c *Config) Frontend() Frontend { return c.fe }
326 func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
327 func (c *Config) Ctxt() *obj.Link { return c.ctxt }
329 // NewFunc returns a new, empty function object.
330 // Caller must call f.Free() before calling NewFunc again.
331 func (c *Config) NewFunc() *Func {
332 // TODO(khr): should this function take name, type, etc. as arguments?
333 if c.curFunc != nil {
334 c.Fatalf(0, "NewFunc called without previous Free")
336 f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}}
341 func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
342 func (c *Config) Log() bool { return c.fe.Log() }
343 func (c *Config) Fatalf(line int32, msg string, args ...interface{}) { c.fe.Fatalf(line, msg, args...) }
344 func (c *Config) Warnl(line int32, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) }
345 func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
346 func (c *Config) Debug_wb() bool { return c.fe.Debug_wb() }
348 func (c *Config) logDebugHashMatch(evname, name string) {
349 file := c.logfiles[evname]
352 tmpfile := os.Getenv("GSHS_LOGFILE")
355 file, ok = os.Create(tmpfile)
357 c.Fatalf(0, "Could not open hash-testing logfile %s", tmpfile)
360 c.logfiles[evname] = file
362 s := fmt.Sprintf("%s triggered %s\n", evname, name)
367 // DebugHashMatch returns true if environment variable evname
368 // 1) is empty (this is a special more-quickly implemented case of 3)
370 // 3) is a suffix of the sha1 hash of name
371 // 4) is a suffix of the environment variable
372 // fmt.Sprintf("%s%d", evname, n)
373 // provided that all such variables are nonempty for 0 <= i <= n
374 // Otherwise it returns false.
375 // When true is returned the message
376 // "%s triggered %s\n", evname, name
377 // is printed on the file named in environment variable
379 // or standard out if that is empty or there is an error
382 func (c *Config) DebugHashMatch(evname, name string) bool {
383 evhash := os.Getenv(evname)
385 return true // default behavior with no EV is "on"
387 if evhash == "y" || evhash == "Y" {
388 c.logDebugHashMatch(evname, name)
391 if evhash == "n" || evhash == "N" {
394 // Check the hash of the name against a partial input hash.
395 // We use this feature to do a binary search to
396 // find a function that is incorrectly compiled.
398 for _, b := range sha1.Sum([]byte(name)) {
399 hstr += fmt.Sprintf("%08b", b)
402 if strings.HasSuffix(hstr, evhash) {
403 c.logDebugHashMatch(evname, name)
407 // Iteratively try additional hashes to allow tests for multi-point
409 for i := 0; true; i++ {
410 ev := fmt.Sprintf("%s%d", evname, i)
415 if strings.HasSuffix(hstr, evv) {
416 c.logDebugHashMatch(ev, name)
423 func (c *Config) DebugNameMatch(evname, name string) bool {
424 return os.Getenv(evname) == name