github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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 "cmd/internal/src" 10 "os" 11 "strconv" 12 ) 13 14 // A Config holds readonly compilation information. 15 // It is created once, early during compilation, 16 // and shared across all compilations. 17 type Config struct { 18 arch string // "amd64", etc. 19 IntSize int64 // 4 or 8 20 PtrSize int64 // 4 or 8 21 RegSize int64 // 4 or 8 22 Types Types 23 lowerBlock blockRewriter // lowering function 24 lowerValue valueRewriter // lowering function 25 registers []Register // machine registers 26 gpRegMask regMask // general purpose integer register mask 27 fpRegMask regMask // floating point register mask 28 specialRegMask regMask // special register mask 29 FPReg int8 // register number of frame pointer, -1 if not used 30 LinkReg int8 // register number of link register if it is a general purpose register, -1 if not used 31 hasGReg bool // has hardware g register 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 NeedsFpScratch bool // No direct move between GP and FP register sets 38 BigEndian bool // 39 sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score 40 } 41 42 type ( 43 blockRewriter func(*Block) bool 44 valueRewriter func(*Value) bool 45 ) 46 47 type Types struct { 48 Bool Type 49 Int8 Type 50 Int16 Type 51 Int32 Type 52 Int64 Type 53 UInt8 Type 54 UInt16 Type 55 UInt32 Type 56 UInt64 Type 57 Int Type 58 Float32 Type 59 Float64 Type 60 Uintptr Type 61 String Type 62 BytePtr Type // TODO: use unsafe.Pointer instead? 63 Int32Ptr Type 64 UInt32Ptr Type 65 IntPtr Type 66 UintptrPtr Type 67 Float32Ptr Type 68 Float64Ptr Type 69 BytePtrPtr Type 70 } 71 72 type Logger interface { 73 // Logf logs a message from the compiler. 74 Logf(string, ...interface{}) 75 76 // Log returns true if logging is not a no-op 77 // some logging calls account for more than a few heap allocations. 78 Log() bool 79 80 // Fatal reports a compiler error and exits. 81 Fatalf(pos src.XPos, msg string, args ...interface{}) 82 83 // Warnl writes compiler messages in the form expected by "errorcheck" tests 84 Warnl(pos src.XPos, fmt_ string, args ...interface{}) 85 86 // Forwards the Debug flags from gc 87 Debug_checknil() bool 88 Debug_wb() bool 89 } 90 91 type Frontend interface { 92 CanSSA(t Type) bool 93 94 Logger 95 96 // StringData returns a symbol pointing to the given string's contents. 97 StringData(string) interface{} // returns *gc.Sym 98 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. 101 Auto(src.XPos, Type) GCNode 102 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 110 SplitArray(LocalSlot) LocalSlot // array must be length 1 111 SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo) 112 113 // DerefItab dereferences an itab function 114 // entry, given the symbol of the itab and 115 // the byte offset of the function pointer. 116 // It may return nil. 117 DerefItab(sym *obj.LSym, offset int64) *obj.LSym 118 119 // Line returns a string describing the given position. 120 Line(src.XPos) string 121 122 // AllocFrame assigns frame offsets to all live auto variables. 123 AllocFrame(f *Func) 124 125 // Syslook returns a symbol of the runtime function/variable with the 126 // given name. 127 Syslook(string) *obj.LSym 128 129 // UseWriteBarrier returns whether write barrier is enabled 130 UseWriteBarrier() bool 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, types Types, ctxt *obj.Link, optimize bool) *Config { 142 c := &Config{arch: arch, Types: types} 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.BigEndian = true 208 fallthrough 209 case "ppc64le": 210 c.IntSize = 8 211 c.PtrSize = 8 212 c.RegSize = 8 213 c.lowerBlock = rewriteBlockPPC64 214 c.lowerValue = rewriteValuePPC64 215 c.registers = registersPPC64[:] 216 c.gpRegMask = gpRegMaskPPC64 217 c.fpRegMask = fpRegMaskPPC64 218 c.FPReg = framepointerRegPPC64 219 c.LinkReg = linkRegPPC64 220 c.noDuffDevice = true // TODO: Resolve PPC64 DuffDevice (has zero, but not copy) 221 c.hasGReg = true 222 case "mips64": 223 c.BigEndian = true 224 fallthrough 225 case "mips64le": 226 c.IntSize = 8 227 c.PtrSize = 8 228 c.RegSize = 8 229 c.lowerBlock = rewriteBlockMIPS64 230 c.lowerValue = rewriteValueMIPS64 231 c.registers = registersMIPS64[:] 232 c.gpRegMask = gpRegMaskMIPS64 233 c.fpRegMask = fpRegMaskMIPS64 234 c.specialRegMask = specialRegMaskMIPS64 235 c.FPReg = framepointerRegMIPS64 236 c.LinkReg = linkRegMIPS64 237 c.hasGReg = true 238 case "s390x": 239 c.IntSize = 8 240 c.PtrSize = 8 241 c.RegSize = 8 242 c.lowerBlock = rewriteBlockS390X 243 c.lowerValue = rewriteValueS390X 244 c.registers = registersS390X[:] 245 c.gpRegMask = gpRegMaskS390X 246 c.fpRegMask = fpRegMaskS390X 247 c.FPReg = framepointerRegS390X 248 c.LinkReg = linkRegS390X 249 c.hasGReg = true 250 c.noDuffDevice = true 251 c.BigEndian = true 252 case "mips": 253 c.BigEndian = true 254 fallthrough 255 case "mipsle": 256 c.IntSize = 4 257 c.PtrSize = 4 258 c.RegSize = 4 259 c.lowerBlock = rewriteBlockMIPS 260 c.lowerValue = rewriteValueMIPS 261 c.registers = registersMIPS[:] 262 c.gpRegMask = gpRegMaskMIPS 263 c.fpRegMask = fpRegMaskMIPS 264 c.specialRegMask = specialRegMaskMIPS 265 c.FPReg = framepointerRegMIPS 266 c.LinkReg = linkRegMIPS 267 c.hasGReg = true 268 c.noDuffDevice = true 269 default: 270 ctxt.Diag("arch %s not implemented", arch) 271 } 272 c.ctxt = ctxt 273 c.optimize = optimize 274 c.nacl = obj.GOOS == "nacl" 275 276 // Don't use Duff's device on Plan 9 AMD64, because floating 277 // point operations are not allowed in note handler. 278 if obj.GOOS == "plan9" && arch == "amd64" { 279 c.noDuffDevice = true 280 } 281 282 if c.nacl { 283 c.noDuffDevice = true // Don't use Duff's device on NaCl 284 285 // runtime call clobber R12 on nacl 286 opcodeTable[OpARMCALLudiv].reg.clobbers |= 1 << 12 // R12 287 } 288 289 // cutoff is compared with product of numblocks and numvalues, 290 // if product is smaller than cutoff, use old non-sparse method. 291 // cutoff == 0 implies all sparse. 292 // cutoff == -1 implies none sparse. 293 // Good cutoff values seem to be O(million) depending on constant factor cost of sparse. 294 // TODO: get this from a flag, not an environment variable 295 c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash 296 ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF") 297 if ev != "" { 298 v, err := strconv.ParseInt(ev, 10, 64) 299 if err != nil { 300 ctxt.Diag("Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev) 301 } 302 c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse 303 } 304 305 return c 306 } 307 308 func (c *Config) Set387(b bool) { 309 c.NeedsFpScratch = b 310 c.use387 = b 311 } 312 313 func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff } 314 func (c *Config) Ctxt() *obj.Link { return c.ctxt }