github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/pointer/intrinsics.go (about) 1 // Copyright 2013 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 pointer 6 7 // This package defines the treatment of intrinsics, i.e. library 8 // functions requiring special analytical treatment. 9 // 10 // Most of these are C or assembly functions, but even some Go 11 // functions require may special treatment if the analysis completely 12 // replaces the implementation of an API such as reflection. 13 14 // TODO(adonovan): support a means of writing analytic summaries in 15 // the target code, so that users can summarise the effects of their 16 // own C functions using a snippet of Go. 17 18 import ( 19 "fmt" 20 21 "llvm.org/llgo/third_party/gotools/go/ssa" 22 "llvm.org/llgo/third_party/gotools/go/types" 23 ) 24 25 // Instances of 'intrinsic' generate analysis constraints for calls to 26 // intrinsic functions. 27 // Implementations may exploit information from the calling site 28 // via cgn.callersite; for shared contours this is nil. 29 type intrinsic func(a *analysis, cgn *cgnode) 30 31 // Initialized in explicit init() to defeat (spurious) initialization 32 // cycle error. 33 var intrinsicsByName = make(map[string]intrinsic) 34 35 func init() { 36 // Key strings are from Function.String(). 37 // That little dot ۰ is an Arabic zero numeral (U+06F0), 38 // categories [Nd]. 39 for name, fn := range map[string]intrinsic{ 40 // Other packages. 41 "bytes.Equal": ext۰NoEffect, 42 "bytes.IndexByte": ext۰NoEffect, 43 "crypto/aes.decryptBlockAsm": ext۰NoEffect, 44 "crypto/aes.encryptBlockAsm": ext۰NoEffect, 45 "crypto/aes.expandKeyAsm": ext۰NoEffect, 46 "crypto/aes.hasAsm": ext۰NoEffect, 47 "crypto/md5.block": ext۰NoEffect, 48 "crypto/rc4.xorKeyStream": ext۰NoEffect, 49 "crypto/sha1.block": ext۰NoEffect, 50 "crypto/sha256.block": ext۰NoEffect, 51 "hash/crc32.castagnoliSSE42": ext۰NoEffect, 52 "hash/crc32.haveSSE42": ext۰NoEffect, 53 "math.Abs": ext۰NoEffect, 54 "math.Acos": ext۰NoEffect, 55 "math.Asin": ext۰NoEffect, 56 "math.Atan": ext۰NoEffect, 57 "math.Atan2": ext۰NoEffect, 58 "math.Ceil": ext۰NoEffect, 59 "math.Cos": ext۰NoEffect, 60 "math.Dim": ext۰NoEffect, 61 "math.Exp": ext۰NoEffect, 62 "math.Exp2": ext۰NoEffect, 63 "math.Expm1": ext۰NoEffect, 64 "math.Float32bits": ext۰NoEffect, 65 "math.Float32frombits": ext۰NoEffect, 66 "math.Float64bits": ext۰NoEffect, 67 "math.Float64frombits": ext۰NoEffect, 68 "math.Floor": ext۰NoEffect, 69 "math.Frexp": ext۰NoEffect, 70 "math.Hypot": ext۰NoEffect, 71 "math.Ldexp": ext۰NoEffect, 72 "math.Log": ext۰NoEffect, 73 "math.Log10": ext۰NoEffect, 74 "math.Log1p": ext۰NoEffect, 75 "math.Log2": ext۰NoEffect, 76 "math.Max": ext۰NoEffect, 77 "math.Min": ext۰NoEffect, 78 "math.Mod": ext۰NoEffect, 79 "math.Modf": ext۰NoEffect, 80 "math.Remainder": ext۰NoEffect, 81 "math.Sin": ext۰NoEffect, 82 "math.Sincos": ext۰NoEffect, 83 "math.Sqrt": ext۰NoEffect, 84 "math.Tan": ext۰NoEffect, 85 "math.Trunc": ext۰NoEffect, 86 "math/big.addMulVVW": ext۰NoEffect, 87 "math/big.addVV": ext۰NoEffect, 88 "math/big.addVW": ext۰NoEffect, 89 "math/big.bitLen": ext۰NoEffect, 90 "math/big.divWVW": ext۰NoEffect, 91 "math/big.divWW": ext۰NoEffect, 92 "math/big.mulAddVWW": ext۰NoEffect, 93 "math/big.mulWW": ext۰NoEffect, 94 "math/big.shlVU": ext۰NoEffect, 95 "math/big.shrVU": ext۰NoEffect, 96 "math/big.subVV": ext۰NoEffect, 97 "math/big.subVW": ext۰NoEffect, 98 "net.runtime_Semacquire": ext۰NoEffect, 99 "net.runtime_Semrelease": ext۰NoEffect, 100 "net.runtime_pollClose": ext۰NoEffect, 101 "net.runtime_pollOpen": ext۰NoEffect, 102 "net.runtime_pollReset": ext۰NoEffect, 103 "net.runtime_pollServerInit": ext۰NoEffect, 104 "net.runtime_pollSetDeadline": ext۰NoEffect, 105 "net.runtime_pollUnblock": ext۰NoEffect, 106 "net.runtime_pollWait": ext۰NoEffect, 107 "net.runtime_pollWaitCanceled": ext۰NoEffect, 108 "os.epipecheck": ext۰NoEffect, 109 "runtime.BlockProfile": ext۰NoEffect, 110 "runtime.Breakpoint": ext۰NoEffect, 111 "runtime.CPUProfile": ext۰NoEffect, // good enough 112 "runtime.Caller": ext۰NoEffect, 113 "runtime.Callers": ext۰NoEffect, // good enough 114 "runtime.FuncForPC": ext۰NoEffect, 115 "runtime.GC": ext۰NoEffect, 116 "runtime.GOMAXPROCS": ext۰NoEffect, 117 "runtime.Goexit": ext۰NoEffect, 118 "runtime.GoroutineProfile": ext۰NoEffect, 119 "runtime.Gosched": ext۰NoEffect, 120 "runtime.MemProfile": ext۰NoEffect, 121 "runtime.NumCPU": ext۰NoEffect, 122 "runtime.NumGoroutine": ext۰NoEffect, 123 "runtime.ReadMemStats": ext۰NoEffect, 124 "runtime.SetBlockProfileRate": ext۰NoEffect, 125 "runtime.SetCPUProfileRate": ext۰NoEffect, 126 "runtime.SetFinalizer": ext۰runtime۰SetFinalizer, 127 "runtime.Stack": ext۰NoEffect, 128 "runtime.ThreadCreateProfile": ext۰NoEffect, 129 "runtime.cstringToGo": ext۰NoEffect, 130 "runtime.funcentry_go": ext۰NoEffect, 131 "runtime.funcline_go": ext۰NoEffect, 132 "runtime.funcname_go": ext۰NoEffect, 133 "runtime.getgoroot": ext۰NoEffect, 134 "runtime/pprof.runtime_cyclesPerSecond": ext۰NoEffect, 135 "strings.IndexByte": ext۰NoEffect, 136 "sync.runtime_Semacquire": ext۰NoEffect, 137 "sync.runtime_Semrelease": ext۰NoEffect, 138 "sync.runtime_Syncsemacquire": ext۰NoEffect, 139 "sync.runtime_Syncsemcheck": ext۰NoEffect, 140 "sync.runtime_Syncsemrelease": ext۰NoEffect, 141 "sync.runtime_procPin": ext۰NoEffect, 142 "sync.runtime_procUnpin": ext۰NoEffect, 143 "sync.runtime_registerPool": ext۰NoEffect, 144 "sync/atomic.AddInt32": ext۰NoEffect, 145 "sync/atomic.AddInt64": ext۰NoEffect, 146 "sync/atomic.AddUint32": ext۰NoEffect, 147 "sync/atomic.AddUint64": ext۰NoEffect, 148 "sync/atomic.AddUintptr": ext۰NoEffect, 149 "sync/atomic.CompareAndSwapInt32": ext۰NoEffect, 150 "sync/atomic.CompareAndSwapUint32": ext۰NoEffect, 151 "sync/atomic.CompareAndSwapUint64": ext۰NoEffect, 152 "sync/atomic.CompareAndSwapUintptr": ext۰NoEffect, 153 "sync/atomic.LoadInt32": ext۰NoEffect, 154 "sync/atomic.LoadInt64": ext۰NoEffect, 155 "sync/atomic.LoadPointer": ext۰NoEffect, // ignore unsafe.Pointers 156 "sync/atomic.LoadUint32": ext۰NoEffect, 157 "sync/atomic.LoadUint64": ext۰NoEffect, 158 "sync/atomic.LoadUintptr": ext۰NoEffect, 159 "sync/atomic.StoreInt32": ext۰NoEffect, 160 "sync/atomic.StorePointer": ext۰NoEffect, // ignore unsafe.Pointers 161 "sync/atomic.StoreUint32": ext۰NoEffect, 162 "sync/atomic.StoreUintptr": ext۰NoEffect, 163 "syscall.Close": ext۰NoEffect, 164 "syscall.Exit": ext۰NoEffect, 165 "syscall.Getpid": ext۰NoEffect, 166 "syscall.Getwd": ext۰NoEffect, 167 "syscall.Kill": ext۰NoEffect, 168 "syscall.RawSyscall": ext۰NoEffect, 169 "syscall.RawSyscall6": ext۰NoEffect, 170 "syscall.Syscall": ext۰NoEffect, 171 "syscall.Syscall6": ext۰NoEffect, 172 "syscall.runtime_AfterFork": ext۰NoEffect, 173 "syscall.runtime_BeforeFork": ext۰NoEffect, 174 "syscall.setenv_c": ext۰NoEffect, 175 "time.Sleep": ext۰NoEffect, 176 "time.now": ext۰NoEffect, 177 "time.startTimer": ext۰time۰startTimer, 178 "time.stopTimer": ext۰NoEffect, 179 } { 180 intrinsicsByName[name] = fn 181 } 182 } 183 184 // findIntrinsic returns the constraint generation function for an 185 // intrinsic function fn, or nil if the function should be handled normally. 186 // 187 func (a *analysis) findIntrinsic(fn *ssa.Function) intrinsic { 188 // Consult the *Function-keyed cache. 189 // A cached nil indicates a normal non-intrinsic function. 190 impl, ok := a.intrinsics[fn] 191 if !ok { 192 impl = intrinsicsByName[fn.String()] // may be nil 193 194 if a.isReflect(fn) { 195 if !a.config.Reflection { 196 impl = ext۰NoEffect // reflection disabled 197 } else if impl == nil { 198 // Ensure all "reflect" code is treated intrinsically. 199 impl = ext۰NotYetImplemented 200 } 201 } 202 203 a.intrinsics[fn] = impl 204 } 205 return impl 206 } 207 208 // isReflect reports whether fn belongs to the "reflect" package. 209 func (a *analysis) isReflect(fn *ssa.Function) bool { 210 if a.reflectValueObj == nil { 211 return false // "reflect" package not loaded 212 } 213 reflectPackage := a.reflectValueObj.Pkg() 214 if fn.Pkg != nil && fn.Pkg.Object == reflectPackage { 215 return true 216 } 217 // Synthetic wrappers have a nil Pkg, so they slip through the 218 // previous check. Check the receiver package. 219 // TODO(adonovan): should synthetic wrappers have a non-nil Pkg? 220 if recv := fn.Signature.Recv(); recv != nil { 221 if named, ok := deref(recv.Type()).(*types.Named); ok { 222 if named.Obj().Pkg() == reflectPackage { 223 return true // e.g. wrapper of (reflect.Value).f 224 } 225 } 226 } 227 return false 228 } 229 230 // A trivial intrinsic suitable for any function that does not: 231 // 1) induce aliases between its arguments or any global variables; 232 // 2) call any functions; or 233 // 3) create any labels. 234 // 235 // Many intrinsics (such as CompareAndSwapInt32) have a fourth kind of 236 // effect: loading or storing through a pointer. Though these could 237 // be significant, we deliberately ignore them because they are 238 // generally not worth the effort. 239 // 240 // We sometimes violate condition #3 if the function creates only 241 // non-function labels, as the control-flow graph is still sound. 242 // 243 func ext۰NoEffect(a *analysis, cgn *cgnode) {} 244 245 func ext۰NotYetImplemented(a *analysis, cgn *cgnode) { 246 fn := cgn.fn 247 a.warnf(fn.Pos(), "unsound: intrinsic treatment of %s not yet implemented", fn) 248 } 249 250 // ---------- func runtime.SetFinalizer(x, f interface{}) ---------- 251 252 // runtime.SetFinalizer(x, f) 253 type runtimeSetFinalizerConstraint struct { 254 targets nodeid // (indirect) 255 f nodeid // (ptr) 256 x nodeid 257 } 258 259 func (c *runtimeSetFinalizerConstraint) ptr() nodeid { return c.f } 260 func (c *runtimeSetFinalizerConstraint) presolve(h *hvn) { 261 h.markIndirect(onodeid(c.targets), "SetFinalizer.targets") 262 } 263 func (c *runtimeSetFinalizerConstraint) renumber(mapping []nodeid) { 264 c.targets = mapping[c.targets] 265 c.f = mapping[c.f] 266 c.x = mapping[c.x] 267 } 268 269 func (c *runtimeSetFinalizerConstraint) String() string { 270 return fmt.Sprintf("runtime.SetFinalizer(n%d, n%d)", c.x, c.f) 271 } 272 273 func (c *runtimeSetFinalizerConstraint) solve(a *analysis, delta *nodeset) { 274 for _, fObj := range delta.AppendTo(a.deltaSpace) { 275 tDyn, f, indirect := a.taggedValue(nodeid(fObj)) 276 if indirect { 277 // TODO(adonovan): we'll need to implement this 278 // when we start creating indirect tagged objects. 279 panic("indirect tagged object") 280 } 281 282 tSig, ok := tDyn.Underlying().(*types.Signature) 283 if !ok { 284 continue // not a function 285 } 286 if tSig.Recv() != nil { 287 panic(tSig) 288 } 289 if tSig.Params().Len() != 1 { 290 continue // not a unary function 291 } 292 293 // Extract x to tmp. 294 tx := tSig.Params().At(0).Type() 295 tmp := a.addNodes(tx, "SetFinalizer.tmp") 296 a.typeAssert(tx, tmp, c.x, false) 297 298 // Call f(tmp). 299 a.store(f, tmp, 1, a.sizeof(tx)) 300 301 // Add dynamic call target. 302 if a.onlineCopy(c.targets, f) { 303 a.addWork(c.targets) 304 } 305 } 306 } 307 308 func ext۰runtime۰SetFinalizer(a *analysis, cgn *cgnode) { 309 // This is the shared contour, used for dynamic calls. 310 targets := a.addOneNode(tInvalid, "SetFinalizer.targets", nil) 311 cgn.sites = append(cgn.sites, &callsite{targets: targets}) 312 params := a.funcParams(cgn.obj) 313 a.addConstraint(&runtimeSetFinalizerConstraint{ 314 targets: targets, 315 x: params, 316 f: params + 1, 317 }) 318 } 319 320 // ---------- func time.startTimer(t *runtimeTimer) ---------- 321 322 // time.StartTimer(t) 323 type timeStartTimerConstraint struct { 324 targets nodeid // (indirect) 325 t nodeid // (ptr) 326 } 327 328 func (c *timeStartTimerConstraint) ptr() nodeid { return c.t } 329 func (c *timeStartTimerConstraint) presolve(h *hvn) { 330 h.markIndirect(onodeid(c.targets), "StartTimer.targets") 331 } 332 func (c *timeStartTimerConstraint) renumber(mapping []nodeid) { 333 c.targets = mapping[c.targets] 334 c.t = mapping[c.t] 335 } 336 337 func (c *timeStartTimerConstraint) String() string { 338 return fmt.Sprintf("time.startTimer(n%d)", c.t) 339 } 340 341 func (c *timeStartTimerConstraint) solve(a *analysis, delta *nodeset) { 342 for _, tObj := range delta.AppendTo(a.deltaSpace) { 343 t := nodeid(tObj) 344 345 // We model startTimer as if it was defined thus: 346 // func startTimer(t *runtimeTimer) { t.f(t.arg) } 347 348 // We hard-code the field offsets of time.runtimeTimer: 349 // type runtimeTimer struct { 350 // 0 __identity__ 351 // 1 i int32 352 // 2 when int64 353 // 3 period int64 354 // 4 f func(int64, interface{}) 355 // 5 arg interface{} 356 // } 357 f := t + 4 358 arg := t + 5 359 360 // store t.arg to t.f.params[0] 361 // (offset 1 => skip identity) 362 a.store(f, arg, 1, 1) 363 364 // Add dynamic call target. 365 if a.onlineCopy(c.targets, f) { 366 a.addWork(c.targets) 367 } 368 } 369 } 370 371 func ext۰time۰startTimer(a *analysis, cgn *cgnode) { 372 // This is the shared contour, used for dynamic calls. 373 targets := a.addOneNode(tInvalid, "startTimer.targets", nil) 374 cgn.sites = append(cgn.sites, &callsite{targets: targets}) 375 params := a.funcParams(cgn.obj) 376 a.addConstraint(&timeStartTimerConstraint{ 377 targets: targets, 378 t: params, 379 }) 380 }