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 5package inlheur 6 7import ( 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. 31type 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. 38func 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. 50func (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). 63func (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). 78func (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). 91func (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 99func (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 106func (nf *nameFinder) reassigned(n *ir.Name) bool { 107 if nf.ro == nil { 108 return true 109 } 110 return nf.ro.Reassigned(n) 111} 112 113func (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 124func 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