github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/ssa/config.go (about) 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. 4 5 package ssa 6 7 import ( 8 "cmd/internal/obj" 9 "crypto/sha1" 10 "fmt" 11 "os" 12 "strings" 13 ) 14 15 type Config struct { 16 arch string // "amd64", etc. 17 IntSize int64 // 4 or 8 18 PtrSize int64 // 4 or 8 19 lowerBlock func(*Block) bool // lowering function 20 lowerValue func(*Value, *Config) bool // lowering function 21 registers []Register // machine registers 22 fe Frontend // callbacks into compiler frontend 23 HTML *HTMLWriter // html writer, for debugging 24 ctxt *obj.Link // Generic arch information 25 optimize bool // Do optimization 26 noDuffDevice bool // Don't use Duff's device 27 curFunc *Func 28 29 // TODO: more stuff. Compiler flags of interest, ... 30 31 // Given an environment variable used for debug hash match, 32 // what file (if any) receives the yes/no logging? 33 logfiles map[string]*os.File 34 35 // Storage for low-numbered values and blocks. 36 values [2000]Value 37 blocks [200]Block 38 39 // Reusable stackAllocState. 40 // See stackalloc.go's {new,put}StackAllocState. 41 stackAllocState *stackAllocState 42 43 domblockstore []ID // scratch space for computing dominators 44 scrSparse []*sparseSet // scratch sparse sets to be re-used. 45 } 46 47 type TypeSource interface { 48 TypeBool() Type 49 TypeInt8() Type 50 TypeInt16() Type 51 TypeInt32() Type 52 TypeInt64() Type 53 TypeUInt8() Type 54 TypeUInt16() Type 55 TypeUInt32() Type 56 TypeUInt64() Type 57 TypeInt() Type 58 TypeFloat32() Type 59 TypeFloat64() Type 60 TypeUintptr() Type 61 TypeString() Type 62 TypeBytePtr() Type // TODO: use unsafe.Pointer instead? 63 64 CanSSA(t Type) bool 65 } 66 67 type Logger interface { 68 // Logf logs a message from the compiler. 69 Logf(string, ...interface{}) 70 71 // Log returns true if logging is not a no-op 72 // some logging calls account for more than a few heap allocations. 73 Log() bool 74 75 // Fatal reports a compiler error and exits. 76 Fatalf(line int32, msg string, args ...interface{}) 77 78 // Unimplemented reports that the function cannot be compiled. 79 // It will be removed once SSA work is complete. 80 Unimplementedf(line int32, msg string, args ...interface{}) 81 82 // Warnl writes compiler messages in the form expected by "errorcheck" tests 83 Warnl(line int32, fmt_ string, args ...interface{}) 84 85 // Fowards the Debug_checknil flag from gc 86 Debug_checknil() bool 87 } 88 89 type Frontend interface { 90 TypeSource 91 Logger 92 93 // StringData returns a symbol pointing to the given string's contents. 94 StringData(string) interface{} // returns *gc.Sym 95 96 // Auto returns a Node for an auto variable of the given type. 97 // The SSA compiler uses this function to allocate space for spills. 98 Auto(Type) GCNode 99 100 // Given the name for a compound type, returns the name we should use 101 // for the parts of that compound type. 102 SplitString(LocalSlot) (LocalSlot, LocalSlot) 103 SplitInterface(LocalSlot) (LocalSlot, LocalSlot) 104 SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot) 105 SplitComplex(LocalSlot) (LocalSlot, LocalSlot) 106 107 // Line returns a string describing the given line number. 108 Line(int32) string 109 } 110 111 // interface used to hold *gc.Node. We'd use *gc.Node directly but 112 // that would lead to an import cycle. 113 type GCNode interface { 114 Typ() Type 115 String() string 116 } 117 118 // NewConfig returns a new configuration object for the given architecture. 119 func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config { 120 c := &Config{arch: arch, fe: fe} 121 switch arch { 122 case "amd64": 123 c.IntSize = 8 124 c.PtrSize = 8 125 c.lowerBlock = rewriteBlockAMD64 126 c.lowerValue = rewriteValueAMD64 127 c.registers = registersAMD64[:] 128 case "386": 129 c.IntSize = 4 130 c.PtrSize = 4 131 c.lowerBlock = rewriteBlockAMD64 132 c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support 133 case "arm": 134 c.IntSize = 4 135 c.PtrSize = 4 136 c.lowerBlock = rewriteBlockARM 137 c.lowerValue = rewriteValueARM 138 c.registers = registersARM[:] 139 default: 140 fe.Unimplementedf(0, "arch %s not implemented", arch) 141 } 142 c.ctxt = ctxt 143 c.optimize = optimize 144 145 // Don't use Duff's device on Plan 9, because floating 146 // point operations are not allowed in note handler. 147 if obj.Getgoos() == "plan9" { 148 c.noDuffDevice = true 149 } 150 151 // Assign IDs to preallocated values/blocks. 152 for i := range c.values { 153 c.values[i].ID = ID(i) 154 } 155 for i := range c.blocks { 156 c.blocks[i].ID = ID(i) 157 } 158 159 c.logfiles = make(map[string]*os.File) 160 161 return c 162 } 163 164 func (c *Config) Frontend() Frontend { return c.fe } 165 166 // NewFunc returns a new, empty function object. 167 // Caller must call f.Free() before calling NewFunc again. 168 func (c *Config) NewFunc() *Func { 169 // TODO(khr): should this function take name, type, etc. as arguments? 170 if c.curFunc != nil { 171 c.Fatalf(0, "NewFunc called without previous Free") 172 } 173 f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}} 174 c.curFunc = f 175 return f 176 } 177 178 func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } 179 func (c *Config) Log() bool { return c.fe.Log() } 180 func (c *Config) Fatalf(line int32, msg string, args ...interface{}) { c.fe.Fatalf(line, msg, args...) } 181 func (c *Config) Unimplementedf(line int32, msg string, args ...interface{}) { 182 c.fe.Unimplementedf(line, msg, args...) 183 } 184 func (c *Config) Warnl(line int32, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) } 185 func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() } 186 187 func (c *Config) logDebugHashMatch(evname, name string) { 188 file := c.logfiles[evname] 189 if file == nil { 190 file = os.Stdout 191 tmpfile := os.Getenv("GSHS_LOGFILE") 192 if tmpfile != "" { 193 var ok error 194 file, ok = os.Create(tmpfile) 195 if ok != nil { 196 c.Fatalf(0, "Could not open hash-testing logfile %s", tmpfile) 197 } 198 } 199 c.logfiles[evname] = file 200 } 201 s := fmt.Sprintf("%s triggered %s\n", evname, name) 202 file.WriteString(s) 203 file.Sync() 204 } 205 206 // DebugHashMatch returns true if environment variable evname 207 // 1) is empty (this is a special more-quickly implemented case of 3) 208 // 2) is "y" or "Y" 209 // 3) is a suffix of the sha1 hash of name 210 // 4) is a suffix of the environment variable 211 // fmt.Sprintf("%s%d", evname, n) 212 // provided that all such variables are nonempty for 0 <= i <= n 213 // Otherwise it returns false. 214 // When true is returned the message 215 // "%s triggered %s\n", evname, name 216 // is printed on the file named in environment variable 217 // GSHS_LOGFILE 218 // or standard out if that is empty or there is an error 219 // opening the file. 220 221 func (c *Config) DebugHashMatch(evname, name string) bool { 222 evhash := os.Getenv(evname) 223 if evhash == "" { 224 return true // default behavior with no EV is "on" 225 } 226 if evhash == "y" || evhash == "Y" { 227 c.logDebugHashMatch(evname, name) 228 return true 229 } 230 if evhash == "n" || evhash == "N" { 231 return false 232 } 233 // Check the hash of the name against a partial input hash. 234 // We use this feature to do a binary search to 235 // find a function that is incorrectly compiled. 236 hstr := "" 237 for _, b := range sha1.Sum([]byte(name)) { 238 hstr += fmt.Sprintf("%08b", b) 239 } 240 241 if strings.HasSuffix(hstr, evhash) { 242 c.logDebugHashMatch(evname, name) 243 return true 244 } 245 246 // Iteratively try additional hashes to allow tests for multi-point 247 // failure. 248 for i := 0; true; i++ { 249 ev := fmt.Sprintf("%s%d", evname, i) 250 evv := os.Getenv(ev) 251 if evv == "" { 252 break 253 } 254 if strings.HasSuffix(hstr, evv) { 255 c.logDebugHashMatch(ev, name) 256 return true 257 } 258 } 259 return false 260 }