Source file src/cmd/compile/internal/inline/inlheur/names.go

     1  // Copyright 2023 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 inlheur
     6  
     7  import (
     8  	"cmd/compile/internal/ir"
     9  	"go/constant"
    10  )
    11  
    12  // nameFinder provides a set of "isXXX" query methods for clients to
    13  // ask whether a given AST node corresponds to a function, a constant
    14  // value, and so on. These methods use an underlying ir.ReassignOracle
    15  // to return more precise results in cases where an "interesting"
    16  // value is assigned to a singly-defined local temp. Example:
    17  //
    18  //	const q = 101
    19  //	fq := func() int { return q }
    20  //	copyOfConstant := q
    21  //	copyOfFunc := f
    22  //	interestingCall(copyOfConstant, copyOfFunc)
    23  //
    24  // A name finder query method invoked on the arguments being passed to
    25  // "interestingCall" will be able detect that 'copyOfConstant' always
    26  // evaluates to a constant (even though it is in fact a PAUTO local
    27  // variable). A given nameFinder can also operate without using
    28  // ir.ReassignOracle (in cases where it is not practical to look
    29  // at the entire function); in such cases queries will still work
    30  // for explicit constant values and functions.
    31  type nameFinder struct {
    32  	ro *ir.ReassignOracle
    33  }
    34  
    35  // newNameFinder returns a new nameFinder object with a reassignment
    36  // oracle initialized based on the function fn, or if fn is nil,
    37  // without an underlying ReassignOracle.
    38  func newNameFinder(fn *ir.Func) *nameFinder {
    39  	var ro *ir.ReassignOracle
    40  	if fn != nil {
    41  		ro = &ir.ReassignOracle{}
    42  		ro.Init(fn)
    43  	}
    44  	return &nameFinder{ro: ro}
    45  }
    46  
    47  // funcName returns the *ir.Name for the func or method
    48  // corresponding to node 'n', or nil if n can't be proven
    49  // to contain a function value.
    50  func (nf *nameFinder) funcName(n ir.Node) *ir.Name {
    51  	sv := n
    52  	if nf.ro != nil {
    53  		sv = nf.ro.StaticValue(n)
    54  	}
    55  	if name := ir.StaticCalleeName(sv); name != nil {
    56  		return name
    57  	}
    58  	return nil
    59  }
    60  
    61  // isAllocatedMem returns true if node n corresponds to a memory
    62  // allocation expression (make, new, or equivalent).
    63  func (nf *nameFinder) isAllocatedMem(n ir.Node) bool {
    64  	sv := n
    65  	if nf.ro != nil {
    66  		sv = nf.ro.StaticValue(n)
    67  	}
    68  	switch sv.Op() {
    69  	case ir.OMAKESLICE, ir.ONEW, ir.OPTRLIT, ir.OSLICELIT:
    70  		return true
    71  	}
    72  	return false
    73  }
    74  
    75  // constValue returns the underlying constant.Value for an AST node n
    76  // if n is itself a constant value/expr, or if n is a singly assigned
    77  // local containing constant expr/value (or nil not constant).
    78  func (nf *nameFinder) constValue(n ir.Node) constant.Value {
    79  	sv := n
    80  	if nf.ro != nil {
    81  		sv = nf.ro.StaticValue(n)
    82  	}
    83  	if sv.Op() == ir.OLITERAL {
    84  		return sv.Val()
    85  	}
    86  	return nil
    87  }
    88  
    89  // isNil returns whether n is nil (or singly
    90  // assigned local containing nil).
    91  func (nf *nameFinder) isNil(n ir.Node) bool {
    92  	sv := n
    93  	if nf.ro != nil {
    94  		sv = nf.ro.StaticValue(n)
    95  	}
    96  	return sv.Op() == ir.ONIL
    97  }
    98  
    99  func (nf *nameFinder) staticValue(n ir.Node) ir.Node {
   100  	if nf.ro == nil {
   101  		return n
   102  	}
   103  	return nf.ro.StaticValue(n)
   104  }
   105  
   106  func (nf *nameFinder) reassigned(n *ir.Name) bool {
   107  	if nf.ro == nil {
   108  		return true
   109  	}
   110  	return nf.ro.Reassigned(n)
   111  }
   112  
   113  func (nf *nameFinder) isConcreteConvIface(n ir.Node) bool {
   114  	sv := n
   115  	if nf.ro != nil {
   116  		sv = nf.ro.StaticValue(n)
   117  	}
   118  	if sv.Op() != ir.OCONVIFACE {
   119  		return false
   120  	}
   121  	return !sv.(*ir.ConvExpr).X.Type().IsInterface()
   122  }
   123  
   124  func isSameFuncName(v1, v2 *ir.Name) bool {
   125  	// NB: there are a few corner cases where pointer equality
   126  	// doesn't work here, but this should be good enough for
   127  	// our purposes here.
   128  	return v1 == v2
   129  }
   130  

View as plain text