github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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 "strconv" 13 "strings" 14 ) 15 16 type Config struct { 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 39 BigEndian bool // 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 42 curFunc *Func 43 44 // TODO: more stuff. Compiler flags of interest, ... 45 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 49 50 // Storage for low-numbered values and blocks. 51 values [2000]Value 52 blocks [200]Block 53 54 // Reusable stackAllocState. 55 // See stackalloc.go's {new,put}StackAllocState. 56 stackAllocState *stackAllocState 57 58 domblockstore []ID // scratch space for computing dominators 59 scrSparse []*sparseSet // scratch sparse sets to be re-used. 60 } 61 62 type TypeSource interface { 63 TypeBool() Type 64 TypeInt8() Type 65 TypeInt16() Type 66 TypeInt32() Type 67 TypeInt64() Type 68 TypeUInt8() Type 69 TypeUInt16() Type 70 TypeUInt32() Type 71 TypeUInt64() Type 72 TypeInt() Type 73 TypeFloat32() Type 74 TypeFloat64() Type 75 TypeUintptr() Type 76 TypeString() Type 77 TypeBytePtr() Type // TODO: use unsafe.Pointer instead? 78 79 CanSSA(t Type) bool 80 } 81 82 type Logger interface { 83 // Logf logs a message from the compiler. 84 Logf(string, ...interface{}) 85 86 // Log returns true if logging is not a no-op 87 // some logging calls account for more than a few heap allocations. 88 Log() bool 89 90 // Fatal reports a compiler error and exits. 91 Fatalf(line int32, msg string, args ...interface{}) 92 93 // Warnl writes compiler messages in the form expected by "errorcheck" tests 94 Warnl(line int32, fmt_ string, args ...interface{}) 95 96 // Forwards the Debug flags from gc 97 Debug_checknil() bool 98 Debug_wb() bool 99 } 100 101 type Frontend interface { 102 TypeSource 103 Logger 104 105 // StringData returns a symbol pointing to the given string's contents. 106 StringData(string) interface{} // returns *gc.Sym 107 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. 110 Auto(Type) GCNode 111 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) 121 122 // Line returns a string describing the given line number. 123 Line(int32) string 124 125 // AllocFrame assigns frame offsets to all live auto variables. 126 AllocFrame(f *Func) 127 128 // Syslook returns a symbol of the runtime function/variable with the 129 // given name. 130 Syslook(string) interface{} // returns *gc.Sym 131 } 132 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 { 136 Typ() Type 137 String() string 138 } 139 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} 143 switch arch { 144 case "amd64": 145 c.IntSize = 8 146 c.PtrSize = 8 147 c.RegSize = 8 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 155 c.hasGReg = false 156 case "amd64p32": 157 c.IntSize = 4 158 c.PtrSize = 4 159 c.RegSize = 8 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 167 c.hasGReg = false 168 c.noDuffDevice = true 169 case "386": 170 c.IntSize = 4 171 c.PtrSize = 4 172 c.RegSize = 4 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 180 c.hasGReg = false 181 case "arm": 182 c.IntSize = 4 183 c.PtrSize = 4 184 c.RegSize = 4 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 192 c.hasGReg = true 193 case "arm64": 194 c.IntSize = 8 195 c.PtrSize = 8 196 c.RegSize = 8 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 204 c.hasGReg = true 205 c.noDuffDevice = obj.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend 206 case "ppc64": 207 c.OldArch = true 208 c.BigEndian = true 209 fallthrough 210 case "ppc64le": 211 c.IntSize = 8 212 c.PtrSize = 8 213 c.RegSize = 8 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 223 c.hasGReg = true 224 case "mips64": 225 c.BigEndian = true 226 fallthrough 227 case "mips64le": 228 c.IntSize = 8 229 c.PtrSize = 8 230 c.RegSize = 8 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 239 c.hasGReg = true 240 case "s390x": 241 c.IntSize = 8 242 c.PtrSize = 8 243 c.RegSize = 8 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 251 c.hasGReg = true 252 c.noDuffDevice = true 253 c.BigEndian = true 254 case "mips": 255 c.BigEndian = true 256 fallthrough 257 case "mipsle": 258 c.IntSize = 4 259 c.PtrSize = 4 260 c.RegSize = 4 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 269 c.hasGReg = true 270 c.noDuffDevice = true 271 default: 272 fe.Fatalf(0, "arch %s not implemented", arch) 273 } 274 c.ctxt = ctxt 275 c.optimize = optimize 276 c.nacl = obj.GOOS == "nacl" 277 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 282 } 283 284 if c.nacl { 285 c.noDuffDevice = true // Don't use Duff's device on NaCl 286 287 // runtime call clobber R12 on nacl 288 opcodeTable[OpARMUDIVrtcall].reg.clobbers |= 1 << 12 // R12 289 } 290 291 // Assign IDs to preallocated values/blocks. 292 for i := range c.values { 293 c.values[i].ID = ID(i) 294 } 295 for i := range c.blocks { 296 c.blocks[i].ID = ID(i) 297 } 298 299 c.logfiles = make(map[string]*os.File) 300 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") 309 if ev != "" { 310 v, err := strconv.ParseInt(ev, 10, 64) 311 if err != nil { 312 fe.Fatalf(0, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev) 313 } 314 c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse 315 } 316 317 return c 318 } 319 320 func (c *Config) Set387(b bool) { 321 c.NeedsFpScratch = b 322 c.use387 = b 323 } 324 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 } 328 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") 335 } 336 f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}} 337 c.curFunc = f 338 return f 339 } 340 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() } 347 348 func (c *Config) logDebugHashMatch(evname, name string) { 349 file := c.logfiles[evname] 350 if file == nil { 351 file = os.Stdout 352 tmpfile := os.Getenv("GSHS_LOGFILE") 353 if tmpfile != "" { 354 var ok error 355 file, ok = os.Create(tmpfile) 356 if ok != nil { 357 c.Fatalf(0, "Could not open hash-testing logfile %s", tmpfile) 358 } 359 } 360 c.logfiles[evname] = file 361 } 362 s := fmt.Sprintf("%s triggered %s\n", evname, name) 363 file.WriteString(s) 364 file.Sync() 365 } 366 367 // DebugHashMatch returns true if environment variable evname 368 // 1) is empty (this is a special more-quickly implemented case of 3) 369 // 2) is "y" or "Y" 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 378 // GSHS_LOGFILE 379 // or standard out if that is empty or there is an error 380 // opening the file. 381 382 func (c *Config) DebugHashMatch(evname, name string) bool { 383 evhash := os.Getenv(evname) 384 if evhash == "" { 385 return true // default behavior with no EV is "on" 386 } 387 if evhash == "y" || evhash == "Y" { 388 c.logDebugHashMatch(evname, name) 389 return true 390 } 391 if evhash == "n" || evhash == "N" { 392 return false 393 } 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. 397 hstr := "" 398 for _, b := range sha1.Sum([]byte(name)) { 399 hstr += fmt.Sprintf("%08b", b) 400 } 401 402 if strings.HasSuffix(hstr, evhash) { 403 c.logDebugHashMatch(evname, name) 404 return true 405 } 406 407 // Iteratively try additional hashes to allow tests for multi-point 408 // failure. 409 for i := 0; true; i++ { 410 ev := fmt.Sprintf("%s%d", evname, i) 411 evv := os.Getenv(ev) 412 if evv == "" { 413 break 414 } 415 if strings.HasSuffix(hstr, evv) { 416 c.logDebugHashMatch(ev, name) 417 return true 418 } 419 } 420 return false 421 } 422 423 func (c *Config) DebugNameMatch(evname, name string) bool { 424 return os.Getenv(evname) == name 425 }