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  }