Source file src/cmd/compile/internal/walk/order.go

     1  // Copyright 2012 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 walk
     6  
     7  import (
     8  	"fmt"
     9  	"go/constant"
    10  
    11  	"cmd/compile/internal/base"
    12  	"cmd/compile/internal/ir"
    13  	"cmd/compile/internal/reflectdata"
    14  	"cmd/compile/internal/ssa"
    15  	"cmd/compile/internal/staticinit"
    16  	"cmd/compile/internal/typecheck"
    17  	"cmd/compile/internal/types"
    18  	"cmd/internal/objabi"
    19  	"cmd/internal/src"
    20  )
    21  
    22  // Rewrite tree to use separate statements to enforce
    23  // order of evaluation. Makes walk easier, because it
    24  // can (after this runs) reorder at will within an expression.
    25  //
    26  // Rewrite m[k] op= r into m[k] = m[k] op r if op is / or %.
    27  //
    28  // Introduce temporaries as needed by runtime routines.
    29  // For example, the map runtime routines take the map key
    30  // by reference, so make sure all map keys are addressable
    31  // by copying them to temporaries as needed.
    32  // The same is true for channel operations.
    33  //
    34  // Arrange that map index expressions only appear in direct
    35  // assignments x = m[k] or m[k] = x, never in larger expressions.
    36  //
    37  // Arrange that receive expressions only appear in direct assignments
    38  // x = <-c or as standalone statements <-c, never in larger expressions.
    39  
    40  // orderState holds state during the ordering process.
    41  type orderState struct {
    42  	out  []ir.Node             // list of generated statements
    43  	temp []*ir.Name            // stack of temporary variables
    44  	free map[string][]*ir.Name // free list of unused temporaries, by type.LinkString().
    45  	edit func(ir.Node) ir.Node // cached closure of o.exprNoLHS
    46  }
    47  
    48  // order rewrites fn.Nbody to apply the ordering constraints
    49  // described in the comment at the top of the file.
    50  func order(fn *ir.Func) {
    51  	if base.Flag.W > 1 {
    52  		s := fmt.Sprintf("\nbefore order %v", fn.Sym())
    53  		ir.DumpList(s, fn.Body)
    54  	}
    55  	ir.SetPos(fn) // Set reasonable position for instrumenting code. See issue 53688.
    56  	orderBlock(&fn.Body, map[string][]*ir.Name{})
    57  }
    58  
    59  // append typechecks stmt and appends it to out.
    60  func (o *orderState) append(stmt ir.Node) {
    61  	o.out = append(o.out, typecheck.Stmt(stmt))
    62  }
    63  
    64  // newTemp allocates a new temporary with the given type,
    65  // pushes it onto the temp stack, and returns it.
    66  // If clear is true, newTemp emits code to zero the temporary.
    67  func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name {
    68  	var v *ir.Name
    69  	key := t.LinkString()
    70  	if a := o.free[key]; len(a) > 0 {
    71  		v = a[len(a)-1]
    72  		if !types.Identical(t, v.Type()) {
    73  			base.Fatalf("expected %L to have type %v", v, t)
    74  		}
    75  		o.free[key] = a[:len(a)-1]
    76  	} else {
    77  		v = typecheck.TempAt(base.Pos, ir.CurFunc, t)
    78  	}
    79  	if clear {
    80  		o.append(ir.NewAssignStmt(base.Pos, v, nil))
    81  	}
    82  
    83  	o.temp = append(o.temp, v)
    84  	return v
    85  }
    86  
    87  // copyExpr behaves like newTemp but also emits
    88  // code to initialize the temporary to the value n.
    89  func (o *orderState) copyExpr(n ir.Node) *ir.Name {
    90  	return o.copyExpr1(n, false)
    91  }
    92  
    93  // copyExprClear is like copyExpr but clears the temp before assignment.
    94  // It is provided for use when the evaluation of tmp = n turns into
    95  // a function call that is passed a pointer to the temporary as the output space.
    96  // If the call blocks before tmp has been written,
    97  // the garbage collector will still treat the temporary as live,
    98  // so we must zero it before entering that call.
    99  // Today, this only happens for channel receive operations.
   100  // (The other candidate would be map access, but map access
   101  // returns a pointer to the result data instead of taking a pointer
   102  // to be filled in.)
   103  func (o *orderState) copyExprClear(n ir.Node) *ir.Name {
   104  	return o.copyExpr1(n, true)
   105  }
   106  
   107  func (o *orderState) copyExpr1(n ir.Node, clear bool) *ir.Name {
   108  	t := n.Type()
   109  	v := o.newTemp(t, clear)
   110  	o.append(ir.NewAssignStmt(base.Pos, v, n))
   111  	return v
   112  }
   113  
   114  // cheapExpr returns a cheap version of n.
   115  // The definition of cheap is that n is a variable or constant.
   116  // If not, cheapExpr allocates a new tmp, emits tmp = n,
   117  // and then returns tmp.
   118  func (o *orderState) cheapExpr(n ir.Node) ir.Node {
   119  	if n == nil {
   120  		return nil
   121  	}
   122  
   123  	switch n.Op() {
   124  	case ir.ONAME, ir.OLITERAL, ir.ONIL:
   125  		return n
   126  	case ir.OLEN, ir.OCAP:
   127  		n := n.(*ir.UnaryExpr)
   128  		l := o.cheapExpr(n.X)
   129  		if l == n.X {
   130  			return n
   131  		}
   132  		a := ir.Copy(n).(*ir.UnaryExpr)
   133  		a.X = l
   134  		return typecheck.Expr(a)
   135  	}
   136  
   137  	return o.copyExpr(n)
   138  }
   139  
   140  // safeExpr returns a safe version of n.
   141  // The definition of safe is that n can appear multiple times
   142  // without violating the semantics of the original program,
   143  // and that assigning to the safe version has the same effect
   144  // as assigning to the original n.
   145  //
   146  // The intended use is to apply to x when rewriting x += y into x = x + y.
   147  func (o *orderState) safeExpr(n ir.Node) ir.Node {
   148  	switch n.Op() {
   149  	case ir.ONAME, ir.OLITERAL, ir.ONIL:
   150  		return n
   151  
   152  	case ir.OLEN, ir.OCAP:
   153  		n := n.(*ir.UnaryExpr)
   154  		l := o.safeExpr(n.X)
   155  		if l == n.X {
   156  			return n
   157  		}
   158  		a := ir.Copy(n).(*ir.UnaryExpr)
   159  		a.X = l
   160  		return typecheck.Expr(a)
   161  
   162  	case ir.ODOT:
   163  		n := n.(*ir.SelectorExpr)
   164  		l := o.safeExpr(n.X)
   165  		if l == n.X {
   166  			return n
   167  		}
   168  		a := ir.Copy(n).(*ir.SelectorExpr)
   169  		a.X = l
   170  		return typecheck.Expr(a)
   171  
   172  	case ir.ODOTPTR:
   173  		n := n.(*ir.SelectorExpr)
   174  		l := o.cheapExpr(n.X)
   175  		if l == n.X {
   176  			return n
   177  		}
   178  		a := ir.Copy(n).(*ir.SelectorExpr)
   179  		a.X = l
   180  		return typecheck.Expr(a)
   181  
   182  	case ir.ODEREF:
   183  		n := n.(*ir.StarExpr)
   184  		l := o.cheapExpr(n.X)
   185  		if l == n.X {
   186  			return n
   187  		}
   188  		a := ir.Copy(n).(*ir.StarExpr)
   189  		a.X = l
   190  		return typecheck.Expr(a)
   191  
   192  	case ir.OINDEX, ir.OINDEXMAP:
   193  		n := n.(*ir.IndexExpr)
   194  		var l ir.Node
   195  		if n.X.Type().IsArray() {
   196  			l = o.safeExpr(n.X)
   197  		} else {
   198  			l = o.cheapExpr(n.X)
   199  		}
   200  		r := o.cheapExpr(n.Index)
   201  		if l == n.X && r == n.Index {
   202  			return n
   203  		}
   204  		a := ir.Copy(n).(*ir.IndexExpr)
   205  		a.X = l
   206  		a.Index = r
   207  		return typecheck.Expr(a)
   208  
   209  	default:
   210  		base.Fatalf("order.safeExpr %v", n.Op())
   211  		return nil // not reached
   212  	}
   213  }
   214  
   215  // addrTemp ensures that n is okay to pass by address to runtime routines.
   216  // If the original argument n is not okay, addrTemp creates a tmp, emits
   217  // tmp = n, and then returns tmp.
   218  // The result of addrTemp MUST be assigned back to n, e.g.
   219  //
   220  //	n.Left = o.addrTemp(n.Left)
   221  func (o *orderState) addrTemp(n ir.Node) ir.Node {
   222  	if n.Op() == ir.OLITERAL || n.Op() == ir.ONIL {
   223  		// TODO: expand this to all static composite literal nodes?
   224  		n = typecheck.DefaultLit(n, nil)
   225  		types.CalcSize(n.Type())
   226  		vstat := readonlystaticname(n.Type())
   227  		var s staticinit.Schedule
   228  		s.StaticAssign(vstat, 0, n, n.Type())
   229  		if s.Out != nil {
   230  			base.Fatalf("staticassign of const generated code: %+v", n)
   231  		}
   232  		vstat = typecheck.Expr(vstat).(*ir.Name)
   233  		return vstat
   234  	}
   235  
   236  	// Prevent taking the address of an SSA-able local variable (#63332).
   237  	//
   238  	// TODO(mdempsky): Note that OuterValue unwraps OCONVNOPs, but
   239  	// IsAddressable does not. It should be possible to skip copying for
   240  	// at least some of these OCONVNOPs (e.g., reinsert them after the
   241  	// OADDR operation), but at least walkCompare needs to be fixed to
   242  	// support that (see trybot failures on go.dev/cl/541715, PS1).
   243  	if ir.IsAddressable(n) {
   244  		if name, ok := ir.OuterValue(n).(*ir.Name); ok && name.Op() == ir.ONAME {
   245  			if name.Class == ir.PAUTO && !name.Addrtaken() && ssa.CanSSA(name.Type()) {
   246  				goto Copy
   247  			}
   248  		}
   249  
   250  		return n
   251  	}
   252  
   253  Copy:
   254  	return o.copyExpr(n)
   255  }
   256  
   257  // mapKeyTemp prepares n to be a key in a map runtime call and returns n.
   258  // The first parameter is the position of n's containing node, for use in case
   259  // that n's position is not unique (e.g., if n is an ONAME).
   260  func (o *orderState) mapKeyTemp(outerPos src.XPos, t *types.Type, n ir.Node) ir.Node {
   261  	pos := outerPos
   262  	if ir.HasUniquePos(n) {
   263  		pos = n.Pos()
   264  	}
   265  	// Most map calls need to take the address of the key.
   266  	// Exception: map*_fast* calls. See golang.org/issue/19015.
   267  	alg := mapfast(t)
   268  	if alg == mapslow {
   269  		return o.addrTemp(n)
   270  	}
   271  	var kt *types.Type
   272  	switch alg {
   273  	case mapfast32:
   274  		kt = types.Types[types.TUINT32]
   275  	case mapfast64:
   276  		kt = types.Types[types.TUINT64]
   277  	case mapfast32ptr, mapfast64ptr:
   278  		kt = types.Types[types.TUNSAFEPTR]
   279  	case mapfaststr:
   280  		kt = types.Types[types.TSTRING]
   281  	}
   282  	nt := n.Type()
   283  	switch {
   284  	case nt == kt:
   285  		return n
   286  	case nt.Kind() == kt.Kind(), nt.IsPtrShaped() && kt.IsPtrShaped():
   287  		// can directly convert (e.g. named type to underlying type, or one pointer to another)
   288  		return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, kt, n))
   289  	case nt.IsInteger() && kt.IsInteger():
   290  		// can directly convert (e.g. int32 to uint32)
   291  		if n.Op() == ir.OLITERAL && nt.IsSigned() {
   292  			// avoid constant overflow error
   293  			n = ir.NewConstExpr(constant.MakeUint64(uint64(ir.Int64Val(n))), n)
   294  			n.SetType(kt)
   295  			return n
   296  		}
   297  		return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONV, kt, n))
   298  	default:
   299  		// Unsafe cast through memory.
   300  		// We'll need to do a load with type kt. Create a temporary of type kt to
   301  		// ensure sufficient alignment. nt may be under-aligned.
   302  		if uint8(kt.Alignment()) < uint8(nt.Alignment()) {
   303  			base.Fatalf("mapKeyTemp: key type is not sufficiently aligned, kt=%v nt=%v", kt, nt)
   304  		}
   305  		tmp := o.newTemp(kt, true)
   306  		// *(*nt)(&tmp) = n
   307  		var e ir.Node = typecheck.NodAddr(tmp)
   308  		e = ir.NewConvExpr(pos, ir.OCONVNOP, nt.PtrTo(), e)
   309  		e = ir.NewStarExpr(pos, e)
   310  		o.append(ir.NewAssignStmt(pos, e, n))
   311  		return tmp
   312  	}
   313  }
   314  
   315  // mapKeyReplaceStrConv replaces OBYTES2STR by OBYTES2STRTMP
   316  // in n to avoid string allocations for keys in map lookups.
   317  // Returns a bool that signals if a modification was made.
   318  //
   319  // For:
   320  //
   321  //	x = m[string(k)]
   322  //	x = m[T1{... Tn{..., string(k), ...}}]
   323  //
   324  // where k is []byte, T1 to Tn is a nesting of struct and array literals,
   325  // the allocation of backing bytes for the string can be avoided
   326  // by reusing the []byte backing array. These are special cases
   327  // for avoiding allocations when converting byte slices to strings.
   328  // It would be nice to handle these generally, but because
   329  // []byte keys are not allowed in maps, the use of string(k)
   330  // comes up in important cases in practice. See issue 3512.
   331  func mapKeyReplaceStrConv(n ir.Node) bool {
   332  	var replaced bool
   333  	switch n.Op() {
   334  	case ir.OBYTES2STR:
   335  		n := n.(*ir.ConvExpr)
   336  		n.SetOp(ir.OBYTES2STRTMP)
   337  		replaced = true
   338  	case ir.OSTRUCTLIT:
   339  		n := n.(*ir.CompLitExpr)
   340  		for _, elem := range n.List {
   341  			elem := elem.(*ir.StructKeyExpr)
   342  			if mapKeyReplaceStrConv(elem.Value) {
   343  				replaced = true
   344  			}
   345  		}
   346  	case ir.OARRAYLIT:
   347  		n := n.(*ir.CompLitExpr)
   348  		for _, elem := range n.List {
   349  			if elem.Op() == ir.OKEY {
   350  				elem = elem.(*ir.KeyExpr).Value
   351  			}
   352  			if mapKeyReplaceStrConv(elem) {
   353  				replaced = true
   354  			}
   355  		}
   356  	}
   357  	return replaced
   358  }
   359  
   360  type ordermarker int
   361  
   362  // markTemp returns the top of the temporary variable stack.
   363  func (o *orderState) markTemp() ordermarker {
   364  	return ordermarker(len(o.temp))
   365  }
   366  
   367  // popTemp pops temporaries off the stack until reaching the mark,
   368  // which must have been returned by markTemp.
   369  func (o *orderState) popTemp(mark ordermarker) {
   370  	for _, n := range o.temp[mark:] {
   371  		key := n.Type().LinkString()
   372  		o.free[key] = append(o.free[key], n)
   373  	}
   374  	o.temp = o.temp[:mark]
   375  }
   376  
   377  // stmtList orders each of the statements in the list.
   378  func (o *orderState) stmtList(l ir.Nodes) {
   379  	s := l
   380  	for i := range s {
   381  		orderMakeSliceCopy(s[i:])
   382  		o.stmt(s[i])
   383  	}
   384  }
   385  
   386  // orderMakeSliceCopy matches the pattern:
   387  //
   388  //	m = OMAKESLICE([]T, x); OCOPY(m, s)
   389  //
   390  // and rewrites it to:
   391  //
   392  //	m = OMAKESLICECOPY([]T, x, s); nil
   393  func orderMakeSliceCopy(s []ir.Node) {
   394  	if base.Flag.N != 0 || base.Flag.Cfg.Instrumenting {
   395  		return
   396  	}
   397  	if len(s) < 2 || s[0] == nil || s[0].Op() != ir.OAS || s[1] == nil || s[1].Op() != ir.OCOPY {
   398  		return
   399  	}
   400  
   401  	as := s[0].(*ir.AssignStmt)
   402  	cp := s[1].(*ir.BinaryExpr)
   403  	if as.Y == nil || as.Y.Op() != ir.OMAKESLICE || ir.IsBlank(as.X) ||
   404  		as.X.Op() != ir.ONAME || cp.X.Op() != ir.ONAME || cp.Y.Op() != ir.ONAME ||
   405  		as.X.Name() != cp.X.Name() || cp.X.Name() == cp.Y.Name() {
   406  		// The line above this one is correct with the differing equality operators:
   407  		// we want as.X and cp.X to be the same name,
   408  		// but we want the initial data to be coming from a different name.
   409  		return
   410  	}
   411  
   412  	mk := as.Y.(*ir.MakeExpr)
   413  	if mk.Esc() == ir.EscNone || mk.Len == nil || mk.Cap != nil {
   414  		return
   415  	}
   416  	mk.SetOp(ir.OMAKESLICECOPY)
   417  	mk.Cap = cp.Y
   418  	// Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
   419  	mk.SetBounded(mk.Len.Op() == ir.OLEN && ir.SameSafeExpr(mk.Len.(*ir.UnaryExpr).X, cp.Y))
   420  	as.Y = typecheck.Expr(mk)
   421  	s[1] = nil // remove separate copy call
   422  }
   423  
   424  // edge inserts coverage instrumentation for libfuzzer.
   425  func (o *orderState) edge() {
   426  	if base.Debug.Libfuzzer == 0 {
   427  		return
   428  	}
   429  
   430  	// Create a new uint8 counter to be allocated in section __sancov_cntrs
   431  	counter := staticinit.StaticName(types.Types[types.TUINT8])
   432  	counter.SetLibfuzzer8BitCounter(true)
   433  	// As well as setting SetLibfuzzer8BitCounter, we preemptively set the
   434  	// symbol type to SLIBFUZZER_8BIT_COUNTER so that the race detector
   435  	// instrumentation pass (which does not have access to the flags set by
   436  	// SetLibfuzzer8BitCounter) knows to ignore them. This information is
   437  	// lost by the time it reaches the compile step, so SetLibfuzzer8BitCounter
   438  	// is still necessary.
   439  	counter.Linksym().Type = objabi.SLIBFUZZER_8BIT_COUNTER
   440  
   441  	// We guarantee that the counter never becomes zero again once it has been
   442  	// incremented once. This implementation follows the NeverZero optimization
   443  	// presented by the paper:
   444  	// "AFL++: Combining Incremental Steps of Fuzzing Research"
   445  	// The NeverZero policy avoids the overflow to 0 by setting the counter to one
   446  	// after it reaches 255 and so, if an edge is executed at least one time, the entry is
   447  	// never 0.
   448  	// Another policy presented in the paper is the Saturated Counters policy which
   449  	// freezes the counter when it reaches the value of 255. However, a range
   450  	// of experiments showed that that decreases overall performance.
   451  	o.append(ir.NewIfStmt(base.Pos,
   452  		ir.NewBinaryExpr(base.Pos, ir.OEQ, counter, ir.NewInt(base.Pos, 0xff)),
   453  		[]ir.Node{ir.NewAssignStmt(base.Pos, counter, ir.NewInt(base.Pos, 1))},
   454  		[]ir.Node{ir.NewAssignOpStmt(base.Pos, ir.OADD, counter, ir.NewInt(base.Pos, 1))}))
   455  }
   456  
   457  // orderBlock orders the block of statements in n into a new slice,
   458  // and then replaces the old slice in n with the new slice.
   459  // free is a map that can be used to obtain temporary variables by type.
   460  func orderBlock(n *ir.Nodes, free map[string][]*ir.Name) {
   461  	if len(*n) != 0 {
   462  		// Set reasonable position for instrumenting code. See issue 53688.
   463  		// It would be nice if ir.Nodes had a position (the opening {, probably),
   464  		// but it doesn't. So we use the first statement's position instead.
   465  		ir.SetPos((*n)[0])
   466  	}
   467  	var order orderState
   468  	order.free = free
   469  	mark := order.markTemp()
   470  	order.edge()
   471  	order.stmtList(*n)
   472  	order.popTemp(mark)
   473  	*n = order.out
   474  }
   475  
   476  // exprInPlace orders the side effects in *np and
   477  // leaves them as the init list of the final *np.
   478  // The result of exprInPlace MUST be assigned back to n, e.g.
   479  //
   480  //	n.Left = o.exprInPlace(n.Left)
   481  func (o *orderState) exprInPlace(n ir.Node) ir.Node {
   482  	var order orderState
   483  	order.free = o.free
   484  	n = order.expr(n, nil)
   485  	n = ir.InitExpr(order.out, n)
   486  
   487  	// insert new temporaries from order
   488  	// at head of outer list.
   489  	o.temp = append(o.temp, order.temp...)
   490  	return n
   491  }
   492  
   493  // orderStmtInPlace orders the side effects of the single statement *np
   494  // and replaces it with the resulting statement list.
   495  // The result of orderStmtInPlace MUST be assigned back to n, e.g.
   496  //
   497  //	n.Left = orderStmtInPlace(n.Left)
   498  //
   499  // free is a map that can be used to obtain temporary variables by type.
   500  func orderStmtInPlace(n ir.Node, free map[string][]*ir.Name) ir.Node {
   501  	var order orderState
   502  	order.free = free
   503  	mark := order.markTemp()
   504  	order.stmt(n)
   505  	order.popTemp(mark)
   506  	return ir.NewBlockStmt(src.NoXPos, order.out)
   507  }
   508  
   509  // init moves n's init list to o.out.
   510  func (o *orderState) init(n ir.Node) {
   511  	if ir.MayBeShared(n) {
   512  		// For concurrency safety, don't mutate potentially shared nodes.
   513  		// First, ensure that no work is required here.
   514  		if len(n.Init()) > 0 {
   515  			base.Fatalf("order.init shared node with ninit")
   516  		}
   517  		return
   518  	}
   519  	o.stmtList(ir.TakeInit(n))
   520  }
   521  
   522  // call orders the call expression n.
   523  // n.Op is OCALLFUNC/OCALLINTER or a builtin like OCOPY.
   524  func (o *orderState) call(nn ir.Node) {
   525  	if len(nn.Init()) > 0 {
   526  		// Caller should have already called o.init(nn).
   527  		base.Fatalf("%v with unexpected ninit", nn.Op())
   528  	}
   529  	if nn.Op() == ir.OCALLMETH {
   530  		base.FatalfAt(nn.Pos(), "OCALLMETH missed by typecheck")
   531  	}
   532  
   533  	// Builtin functions.
   534  	if nn.Op() != ir.OCALLFUNC && nn.Op() != ir.OCALLINTER {
   535  		switch n := nn.(type) {
   536  		default:
   537  			base.Fatalf("unexpected call: %+v", n)
   538  		case *ir.UnaryExpr:
   539  			n.X = o.expr(n.X, nil)
   540  		case *ir.ConvExpr:
   541  			n.X = o.expr(n.X, nil)
   542  		case *ir.BinaryExpr:
   543  			n.X = o.expr(n.X, nil)
   544  			n.Y = o.expr(n.Y, nil)
   545  		case *ir.MakeExpr:
   546  			n.Len = o.expr(n.Len, nil)
   547  			n.Cap = o.expr(n.Cap, nil)
   548  		case *ir.CallExpr:
   549  			o.exprList(n.Args)
   550  		}
   551  		return
   552  	}
   553  
   554  	n := nn.(*ir.CallExpr)
   555  	typecheck.AssertFixedCall(n)
   556  
   557  	if ir.IsFuncPCIntrinsic(n) && ir.IsIfaceOfFunc(n.Args[0]) != nil {
   558  		// For internal/abi.FuncPCABIxxx(fn), if fn is a defined function,
   559  		// do not introduce temporaries here, so it is easier to rewrite it
   560  		// to symbol address reference later in walk.
   561  		return
   562  	}
   563  
   564  	n.Fun = o.expr(n.Fun, nil)
   565  	o.exprList(n.Args)
   566  }
   567  
   568  // mapAssign appends n to o.out.
   569  func (o *orderState) mapAssign(n ir.Node) {
   570  	switch n.Op() {
   571  	default:
   572  		base.Fatalf("order.mapAssign %v", n.Op())
   573  
   574  	case ir.OAS:
   575  		n := n.(*ir.AssignStmt)
   576  		if n.X.Op() == ir.OINDEXMAP {
   577  			n.Y = o.safeMapRHS(n.Y)
   578  		}
   579  		o.out = append(o.out, n)
   580  	case ir.OASOP:
   581  		n := n.(*ir.AssignOpStmt)
   582  		if n.X.Op() == ir.OINDEXMAP {
   583  			n.Y = o.safeMapRHS(n.Y)
   584  		}
   585  		o.out = append(o.out, n)
   586  	}
   587  }
   588  
   589  func (o *orderState) safeMapRHS(r ir.Node) ir.Node {
   590  	// Make sure we evaluate the RHS before starting the map insert.
   591  	// We need to make sure the RHS won't panic.  See issue 22881.
   592  	if r.Op() == ir.OAPPEND {
   593  		r := r.(*ir.CallExpr)
   594  		s := r.Args[1:]
   595  		for i, n := range s {
   596  			s[i] = o.cheapExpr(n)
   597  		}
   598  		return r
   599  	}
   600  	return o.cheapExpr(r)
   601  }
   602  
   603  // stmt orders the statement n, appending to o.out.
   604  func (o *orderState) stmt(n ir.Node) {
   605  	if n == nil {
   606  		return
   607  	}
   608  
   609  	lno := ir.SetPos(n)
   610  	o.init(n)
   611  
   612  	switch n.Op() {
   613  	default:
   614  		base.Fatalf("order.stmt %v", n.Op())
   615  
   616  	case ir.OINLMARK:
   617  		o.out = append(o.out, n)
   618  
   619  	case ir.OAS:
   620  		n := n.(*ir.AssignStmt)
   621  		t := o.markTemp()
   622  
   623  		// There's a delicate interaction here between two OINDEXMAP
   624  		// optimizations.
   625  		//
   626  		// First, we want to handle m[k] = append(m[k], ...) with a single
   627  		// runtime call to mapassign. This requires the m[k] expressions to
   628  		// satisfy ir.SameSafeExpr in walkAssign.
   629  		//
   630  		// But if k is a slow map key type that's passed by reference (e.g.,
   631  		// byte), then we want to avoid marking user variables as addrtaken,
   632  		// if that might prevent the compiler from keeping k in a register.
   633  		//
   634  		// TODO(mdempsky): It would be better if walk was responsible for
   635  		// inserting temporaries as needed.
   636  		mapAppend := n.X.Op() == ir.OINDEXMAP && n.Y.Op() == ir.OAPPEND &&
   637  			ir.SameSafeExpr(n.X, n.Y.(*ir.CallExpr).Args[0])
   638  
   639  		n.X = o.expr(n.X, nil)
   640  		if mapAppend {
   641  			indexLHS := n.X.(*ir.IndexExpr)
   642  			indexLHS.X = o.cheapExpr(indexLHS.X)
   643  			indexLHS.Index = o.cheapExpr(indexLHS.Index)
   644  
   645  			call := n.Y.(*ir.CallExpr)
   646  			arg0 := call.Args[0]
   647  			// ir.SameSafeExpr skips OCONVNOPs, so we must do the same here (#66096).
   648  			for arg0.Op() == ir.OCONVNOP {
   649  				arg0 = arg0.(*ir.ConvExpr).X
   650  			}
   651  			indexRHS := arg0.(*ir.IndexExpr)
   652  			indexRHS.X = indexLHS.X
   653  			indexRHS.Index = indexLHS.Index
   654  
   655  			o.exprList(call.Args[1:])
   656  		} else {
   657  			n.Y = o.expr(n.Y, n.X)
   658  		}
   659  		o.mapAssign(n)
   660  		o.popTemp(t)
   661  
   662  	case ir.OASOP:
   663  		n := n.(*ir.AssignOpStmt)
   664  		t := o.markTemp()
   665  		n.X = o.expr(n.X, nil)
   666  		n.Y = o.expr(n.Y, nil)
   667  
   668  		if base.Flag.Cfg.Instrumenting || n.X.Op() == ir.OINDEXMAP && (n.AsOp == ir.ODIV || n.AsOp == ir.OMOD) {
   669  			// Rewrite m[k] op= r into m[k] = m[k] op r so
   670  			// that we can ensure that if op panics
   671  			// because r is zero, the panic happens before
   672  			// the map assignment.
   673  			// DeepCopy is a big hammer here, but safeExpr
   674  			// makes sure there is nothing too deep being copied.
   675  			l1 := o.safeExpr(n.X)
   676  			l2 := ir.DeepCopy(src.NoXPos, l1)
   677  			if l2.Op() == ir.OINDEXMAP {
   678  				l2 := l2.(*ir.IndexExpr)
   679  				l2.Assigned = false
   680  			}
   681  			l2 = o.copyExpr(l2)
   682  			r := o.expr(typecheck.Expr(ir.NewBinaryExpr(n.Pos(), n.AsOp, l2, n.Y)), nil)
   683  			as := typecheck.Stmt(ir.NewAssignStmt(n.Pos(), l1, r))
   684  			o.mapAssign(as)
   685  			o.popTemp(t)
   686  			return
   687  		}
   688  
   689  		o.mapAssign(n)
   690  		o.popTemp(t)
   691  
   692  	case ir.OAS2:
   693  		n := n.(*ir.AssignListStmt)
   694  		t := o.markTemp()
   695  		o.exprList(n.Lhs)
   696  		o.exprList(n.Rhs)
   697  		o.out = append(o.out, n)
   698  		o.popTemp(t)
   699  
   700  	// Special: avoid copy of func call n.Right
   701  	case ir.OAS2FUNC:
   702  		n := n.(*ir.AssignListStmt)
   703  		t := o.markTemp()
   704  		o.exprList(n.Lhs)
   705  		call := n.Rhs[0]
   706  		o.init(call)
   707  		if ic, ok := call.(*ir.InlinedCallExpr); ok {
   708  			o.stmtList(ic.Body)
   709  
   710  			n.SetOp(ir.OAS2)
   711  			n.Rhs = ic.ReturnVars
   712  
   713  			o.exprList(n.Rhs)
   714  			o.out = append(o.out, n)
   715  		} else {
   716  			o.call(call)
   717  			o.as2func(n)
   718  		}
   719  		o.popTemp(t)
   720  
   721  	// Special: use temporary variables to hold result,
   722  	// so that runtime can take address of temporary.
   723  	// No temporary for blank assignment.
   724  	//
   725  	// OAS2MAPR: make sure key is addressable if needed,
   726  	//           and make sure OINDEXMAP is not copied out.
   727  	case ir.OAS2DOTTYPE, ir.OAS2RECV, ir.OAS2MAPR:
   728  		n := n.(*ir.AssignListStmt)
   729  		t := o.markTemp()
   730  		o.exprList(n.Lhs)
   731  
   732  		switch r := n.Rhs[0]; r.Op() {
   733  		case ir.ODOTTYPE2:
   734  			r := r.(*ir.TypeAssertExpr)
   735  			r.X = o.expr(r.X, nil)
   736  		case ir.ODYNAMICDOTTYPE2:
   737  			r := r.(*ir.DynamicTypeAssertExpr)
   738  			r.X = o.expr(r.X, nil)
   739  			r.RType = o.expr(r.RType, nil)
   740  			r.ITab = o.expr(r.ITab, nil)
   741  		case ir.ORECV:
   742  			r := r.(*ir.UnaryExpr)
   743  			r.X = o.expr(r.X, nil)
   744  		case ir.OINDEXMAP:
   745  			r := r.(*ir.IndexExpr)
   746  			r.X = o.expr(r.X, nil)
   747  			r.Index = o.expr(r.Index, nil)
   748  			// See similar conversion for OINDEXMAP below.
   749  			_ = mapKeyReplaceStrConv(r.Index)
   750  			r.Index = o.mapKeyTemp(r.Pos(), r.X.Type(), r.Index)
   751  		default:
   752  			base.Fatalf("order.stmt: %v", r.Op())
   753  		}
   754  
   755  		o.as2ok(n)
   756  		o.popTemp(t)
   757  
   758  	// Special: does not save n onto out.
   759  	case ir.OBLOCK:
   760  		n := n.(*ir.BlockStmt)
   761  		o.stmtList(n.List)
   762  
   763  	// Special: n->left is not an expression; save as is.
   764  	case ir.OBREAK,
   765  		ir.OCONTINUE,
   766  		ir.ODCL,
   767  		ir.OFALL,
   768  		ir.OGOTO,
   769  		ir.OLABEL,
   770  		ir.OTAILCALL:
   771  		o.out = append(o.out, n)
   772  
   773  	// Special: handle call arguments.
   774  	case ir.OCALLFUNC, ir.OCALLINTER:
   775  		n := n.(*ir.CallExpr)
   776  		t := o.markTemp()
   777  		o.call(n)
   778  		o.out = append(o.out, n)
   779  		o.popTemp(t)
   780  
   781  	case ir.OINLCALL:
   782  		n := n.(*ir.InlinedCallExpr)
   783  		o.stmtList(n.Body)
   784  
   785  		// discard results; double-check for no side effects
   786  		for _, result := range n.ReturnVars {
   787  			if staticinit.AnySideEffects(result) {
   788  				base.FatalfAt(result.Pos(), "inlined call result has side effects: %v", result)
   789  			}
   790  		}
   791  
   792  	case ir.OCHECKNIL, ir.OCLEAR, ir.OCLOSE, ir.OPANIC, ir.ORECV:
   793  		n := n.(*ir.UnaryExpr)
   794  		t := o.markTemp()
   795  		n.X = o.expr(n.X, nil)
   796  		o.out = append(o.out, n)
   797  		o.popTemp(t)
   798  
   799  	case ir.OCOPY:
   800  		n := n.(*ir.BinaryExpr)
   801  		t := o.markTemp()
   802  		n.X = o.expr(n.X, nil)
   803  		n.Y = o.expr(n.Y, nil)
   804  		o.out = append(o.out, n)
   805  		o.popTemp(t)
   806  
   807  	case ir.OPRINT, ir.OPRINTLN, ir.ORECOVERFP:
   808  		n := n.(*ir.CallExpr)
   809  		t := o.markTemp()
   810  		o.call(n)
   811  		o.out = append(o.out, n)
   812  		o.popTemp(t)
   813  
   814  	// Special: order arguments to inner call but not call itself.
   815  	case ir.ODEFER, ir.OGO:
   816  		n := n.(*ir.GoDeferStmt)
   817  		t := o.markTemp()
   818  		o.init(n.Call)
   819  		o.call(n.Call)
   820  		o.out = append(o.out, n)
   821  		o.popTemp(t)
   822  
   823  	case ir.ODELETE:
   824  		n := n.(*ir.CallExpr)
   825  		t := o.markTemp()
   826  		n.Args[0] = o.expr(n.Args[0], nil)
   827  		n.Args[1] = o.expr(n.Args[1], nil)
   828  		n.Args[1] = o.mapKeyTemp(n.Pos(), n.Args[0].Type(), n.Args[1])
   829  		o.out = append(o.out, n)
   830  		o.popTemp(t)
   831  
   832  	// Clean temporaries from condition evaluation at
   833  	// beginning of loop body and after for statement.
   834  	case ir.OFOR:
   835  		n := n.(*ir.ForStmt)
   836  		t := o.markTemp()
   837  		n.Cond = o.exprInPlace(n.Cond)
   838  		orderBlock(&n.Body, o.free)
   839  		n.Post = orderStmtInPlace(n.Post, o.free)
   840  		o.out = append(o.out, n)
   841  		o.popTemp(t)
   842  
   843  	// Clean temporaries from condition at
   844  	// beginning of both branches.
   845  	case ir.OIF:
   846  		n := n.(*ir.IfStmt)
   847  		t := o.markTemp()
   848  		n.Cond = o.exprInPlace(n.Cond)
   849  		o.popTemp(t)
   850  		orderBlock(&n.Body, o.free)
   851  		orderBlock(&n.Else, o.free)
   852  		o.out = append(o.out, n)
   853  
   854  	case ir.ORANGE:
   855  		// n.Right is the expression being ranged over.
   856  		// order it, and then make a copy if we need one.
   857  		// We almost always do, to ensure that we don't
   858  		// see any value changes made during the loop.
   859  		// Usually the copy is cheap (e.g., array pointer,
   860  		// chan, slice, string are all tiny).
   861  		// The exception is ranging over an array value
   862  		// (not a slice, not a pointer to array),
   863  		// which must make a copy to avoid seeing updates made during
   864  		// the range body. Ranging over an array value is uncommon though.
   865  
   866  		// Mark []byte(str) range expression to reuse string backing storage.
   867  		// It is safe because the storage cannot be mutated.
   868  		n := n.(*ir.RangeStmt)
   869  		if x, ok := n.X.(*ir.ConvExpr); ok {
   870  			switch x.Op() {
   871  			case ir.OSTR2BYTES:
   872  				x.SetOp(ir.OSTR2BYTESTMP)
   873  				fallthrough
   874  			case ir.OSTR2BYTESTMP:
   875  				x.MarkNonNil() // "range []byte(nil)" is fine
   876  			}
   877  		}
   878  
   879  		t := o.markTemp()
   880  		n.X = o.expr(n.X, nil)
   881  
   882  		orderBody := true
   883  		xt := typecheck.RangeExprType(n.X.Type())
   884  		switch k := xt.Kind(); {
   885  		default:
   886  			base.Fatalf("order.stmt range %v", n.Type())
   887  
   888  		case types.IsInt[k]:
   889  			// Used only once, no need to copy.
   890  
   891  		case k == types.TARRAY, k == types.TSLICE:
   892  			if n.Value == nil || ir.IsBlank(n.Value) {
   893  				// for i := range x will only use x once, to compute len(x).
   894  				// No need to copy it.
   895  				break
   896  			}
   897  			fallthrough
   898  
   899  		case k == types.TCHAN, k == types.TSTRING:
   900  			// chan, string, slice, array ranges use value multiple times.
   901  			// make copy.
   902  			r := n.X
   903  
   904  			if r.Type().IsString() && r.Type() != types.Types[types.TSTRING] {
   905  				r = ir.NewConvExpr(base.Pos, ir.OCONV, nil, r)
   906  				r.SetType(types.Types[types.TSTRING])
   907  				r = typecheck.Expr(r)
   908  			}
   909  
   910  			n.X = o.copyExpr(r)
   911  
   912  		case k == types.TMAP:
   913  			if isMapClear(n) {
   914  				// Preserve the body of the map clear pattern so it can
   915  				// be detected during walk. The loop body will not be used
   916  				// when optimizing away the range loop to a runtime call.
   917  				orderBody = false
   918  				break
   919  			}
   920  
   921  			// copy the map value in case it is a map literal.
   922  			// TODO(rsc): Make tmp = literal expressions reuse tmp.
   923  			// For maps tmp is just one word so it hardly matters.
   924  			r := n.X
   925  			n.X = o.copyExpr(r)
   926  
   927  			// n.Prealloc is the temp for the iterator.
   928  			// MapIterType contains pointers and needs to be zeroed.
   929  			n.Prealloc = o.newTemp(reflectdata.MapIterType(), true)
   930  		}
   931  		n.Key = o.exprInPlace(n.Key)
   932  		n.Value = o.exprInPlace(n.Value)
   933  		if orderBody {
   934  			orderBlock(&n.Body, o.free)
   935  		}
   936  		o.out = append(o.out, n)
   937  		o.popTemp(t)
   938  
   939  	case ir.ORETURN:
   940  		n := n.(*ir.ReturnStmt)
   941  		o.exprList(n.Results)
   942  		o.out = append(o.out, n)
   943  
   944  	// Special: clean case temporaries in each block entry.
   945  	// Select must enter one of its blocks, so there is no
   946  	// need for a cleaning at the end.
   947  	// Doubly special: evaluation order for select is stricter
   948  	// than ordinary expressions. Even something like p.c
   949  	// has to be hoisted into a temporary, so that it cannot be
   950  	// reordered after the channel evaluation for a different
   951  	// case (if p were nil, then the timing of the fault would
   952  	// give this away).
   953  	case ir.OSELECT:
   954  		n := n.(*ir.SelectStmt)
   955  		t := o.markTemp()
   956  		for _, ncas := range n.Cases {
   957  			r := ncas.Comm
   958  			ir.SetPos(ncas)
   959  
   960  			// Append any new body prologue to ninit.
   961  			// The next loop will insert ninit into nbody.
   962  			if len(ncas.Init()) != 0 {
   963  				base.Fatalf("order select ninit")
   964  			}
   965  			if r == nil {
   966  				continue
   967  			}
   968  			switch r.Op() {
   969  			default:
   970  				ir.Dump("select case", r)
   971  				base.Fatalf("unknown op in select %v", r.Op())
   972  
   973  			case ir.OSELRECV2:
   974  				// case x, ok = <-c
   975  				r := r.(*ir.AssignListStmt)
   976  				recv := r.Rhs[0].(*ir.UnaryExpr)
   977  				recv.X = o.expr(recv.X, nil)
   978  				if !ir.IsAutoTmp(recv.X) {
   979  					recv.X = o.copyExpr(recv.X)
   980  				}
   981  				init := ir.TakeInit(r)
   982  
   983  				colas := r.Def
   984  				do := func(i int, t *types.Type) {
   985  					n := r.Lhs[i]
   986  					if ir.IsBlank(n) {
   987  						return
   988  					}
   989  					// If this is case x := <-ch or case x, y := <-ch, the case has
   990  					// the ODCL nodes to declare x and y. We want to delay that
   991  					// declaration (and possible allocation) until inside the case body.
   992  					// Delete the ODCL nodes here and recreate them inside the body below.
   993  					if colas {
   994  						if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).X == n {
   995  							init = init[1:]
   996  
   997  							// iimport may have added a default initialization assignment,
   998  							// due to how it handles ODCL statements.
   999  							if len(init) > 0 && init[0].Op() == ir.OAS && init[0].(*ir.AssignStmt).X == n {
  1000  								init = init[1:]
  1001  							}
  1002  						}
  1003  						dcl := typecheck.Stmt(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
  1004  						ncas.PtrInit().Append(dcl)
  1005  					}
  1006  					tmp := o.newTemp(t, t.HasPointers())
  1007  					as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, n, typecheck.Conv(tmp, n.Type())))
  1008  					ncas.PtrInit().Append(as)
  1009  					r.Lhs[i] = tmp
  1010  				}
  1011  				do(0, recv.X.Type().Elem())
  1012  				do(1, types.Types[types.TBOOL])
  1013  				if len(init) != 0 {
  1014  					ir.DumpList("ninit", init)
  1015  					base.Fatalf("ninit on select recv")
  1016  				}
  1017  				orderBlock(ncas.PtrInit(), o.free)
  1018  
  1019  			case ir.OSEND:
  1020  				r := r.(*ir.SendStmt)
  1021  				if len(r.Init()) != 0 {
  1022  					ir.DumpList("ninit", r.Init())
  1023  					base.Fatalf("ninit on select send")
  1024  				}
  1025  
  1026  				// case c <- x
  1027  				// r->left is c, r->right is x, both are always evaluated.
  1028  				r.Chan = o.expr(r.Chan, nil)
  1029  
  1030  				if !ir.IsAutoTmp(r.Chan) {
  1031  					r.Chan = o.copyExpr(r.Chan)
  1032  				}
  1033  				r.Value = o.expr(r.Value, nil)
  1034  				if !ir.IsAutoTmp(r.Value) {
  1035  					r.Value = o.copyExpr(r.Value)
  1036  				}
  1037  			}
  1038  		}
  1039  		// Now that we have accumulated all the temporaries, clean them.
  1040  		// Also insert any ninit queued during the previous loop.
  1041  		// (The temporary cleaning must follow that ninit work.)
  1042  		for _, cas := range n.Cases {
  1043  			orderBlock(&cas.Body, o.free)
  1044  
  1045  			// TODO(mdempsky): Is this actually necessary?
  1046  			// walkSelect appears to walk Ninit.
  1047  			cas.Body.Prepend(ir.TakeInit(cas)...)
  1048  		}
  1049  
  1050  		o.out = append(o.out, n)
  1051  		o.popTemp(t)
  1052  
  1053  	// Special: value being sent is passed as a pointer; make it addressable.
  1054  	case ir.OSEND:
  1055  		n := n.(*ir.SendStmt)
  1056  		t := o.markTemp()
  1057  		n.Chan = o.expr(n.Chan, nil)
  1058  		n.Value = o.expr(n.Value, nil)
  1059  		if base.Flag.Cfg.Instrumenting {
  1060  			// Force copying to the stack so that (chan T)(nil) <- x
  1061  			// is still instrumented as a read of x.
  1062  			n.Value = o.copyExpr(n.Value)
  1063  		} else {
  1064  			n.Value = o.addrTemp(n.Value)
  1065  		}
  1066  		o.out = append(o.out, n)
  1067  		o.popTemp(t)
  1068  
  1069  	// TODO(rsc): Clean temporaries more aggressively.
  1070  	// Note that because walkSwitch will rewrite some of the
  1071  	// switch into a binary search, this is not as easy as it looks.
  1072  	// (If we ran that code here we could invoke order.stmt on
  1073  	// the if-else chain instead.)
  1074  	// For now just clean all the temporaries at the end.
  1075  	// In practice that's fine.
  1076  	case ir.OSWITCH:
  1077  		n := n.(*ir.SwitchStmt)
  1078  		if base.Debug.Libfuzzer != 0 && !hasDefaultCase(n) {
  1079  			// Add empty "default:" case for instrumentation.
  1080  			n.Cases = append(n.Cases, ir.NewCaseStmt(base.Pos, nil, nil))
  1081  		}
  1082  
  1083  		t := o.markTemp()
  1084  		n.Tag = o.expr(n.Tag, nil)
  1085  		for _, ncas := range n.Cases {
  1086  			o.exprListInPlace(ncas.List)
  1087  			orderBlock(&ncas.Body, o.free)
  1088  		}
  1089  
  1090  		o.out = append(o.out, n)
  1091  		o.popTemp(t)
  1092  	}
  1093  
  1094  	base.Pos = lno
  1095  }
  1096  
  1097  func hasDefaultCase(n *ir.SwitchStmt) bool {
  1098  	for _, ncas := range n.Cases {
  1099  		if len(ncas.List) == 0 {
  1100  			return true
  1101  		}
  1102  	}
  1103  	return false
  1104  }
  1105  
  1106  // exprList orders the expression list l into o.
  1107  func (o *orderState) exprList(l ir.Nodes) {
  1108  	s := l
  1109  	for i := range s {
  1110  		s[i] = o.expr(s[i], nil)
  1111  	}
  1112  }
  1113  
  1114  // exprListInPlace orders the expression list l but saves
  1115  // the side effects on the individual expression ninit lists.
  1116  func (o *orderState) exprListInPlace(l ir.Nodes) {
  1117  	s := l
  1118  	for i := range s {
  1119  		s[i] = o.exprInPlace(s[i])
  1120  	}
  1121  }
  1122  
  1123  func (o *orderState) exprNoLHS(n ir.Node) ir.Node {
  1124  	return o.expr(n, nil)
  1125  }
  1126  
  1127  // expr orders a single expression, appending side
  1128  // effects to o.out as needed.
  1129  // If this is part of an assignment lhs = *np, lhs is given.
  1130  // Otherwise lhs == nil. (When lhs != nil it may be possible
  1131  // to avoid copying the result of the expression to a temporary.)
  1132  // The result of expr MUST be assigned back to n, e.g.
  1133  //
  1134  //	n.Left = o.expr(n.Left, lhs)
  1135  func (o *orderState) expr(n, lhs ir.Node) ir.Node {
  1136  	if n == nil {
  1137  		return n
  1138  	}
  1139  	lno := ir.SetPos(n)
  1140  	n = o.expr1(n, lhs)
  1141  	base.Pos = lno
  1142  	return n
  1143  }
  1144  
  1145  func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
  1146  	o.init(n)
  1147  
  1148  	switch n.Op() {
  1149  	default:
  1150  		if o.edit == nil {
  1151  			o.edit = o.exprNoLHS // create closure once
  1152  		}
  1153  		ir.EditChildren(n, o.edit)
  1154  		return n
  1155  
  1156  	// Addition of strings turns into a function call.
  1157  	// Allocate a temporary to hold the strings.
  1158  	// Fewer than 5 strings use direct runtime helpers.
  1159  	case ir.OADDSTR:
  1160  		n := n.(*ir.AddStringExpr)
  1161  		o.exprList(n.List)
  1162  
  1163  		if len(n.List) > 5 {
  1164  			t := types.NewArray(types.Types[types.TSTRING], int64(len(n.List)))
  1165  			n.Prealloc = o.newTemp(t, false)
  1166  		}
  1167  
  1168  		// Mark string(byteSlice) arguments to reuse byteSlice backing
  1169  		// buffer during conversion. String concatenation does not
  1170  		// memorize the strings for later use, so it is safe.
  1171  		// However, we can do it only if there is at least one non-empty string literal.
  1172  		// Otherwise if all other arguments are empty strings,
  1173  		// concatstrings will return the reference to the temp string
  1174  		// to the caller.
  1175  		hasbyte := false
  1176  
  1177  		haslit := false
  1178  		for _, n1 := range n.List {
  1179  			hasbyte = hasbyte || n1.Op() == ir.OBYTES2STR
  1180  			haslit = haslit || n1.Op() == ir.OLITERAL && len(ir.StringVal(n1)) != 0
  1181  		}
  1182  
  1183  		if haslit && hasbyte {
  1184  			for _, n2 := range n.List {
  1185  				if n2.Op() == ir.OBYTES2STR {
  1186  					n2 := n2.(*ir.ConvExpr)
  1187  					n2.SetOp(ir.OBYTES2STRTMP)
  1188  				}
  1189  			}
  1190  		}
  1191  		return n
  1192  
  1193  	case ir.OINDEXMAP:
  1194  		n := n.(*ir.IndexExpr)
  1195  		n.X = o.expr(n.X, nil)
  1196  		n.Index = o.expr(n.Index, nil)
  1197  		needCopy := false
  1198  
  1199  		if !n.Assigned {
  1200  			// Enforce that any []byte slices we are not copying
  1201  			// can not be changed before the map index by forcing
  1202  			// the map index to happen immediately following the
  1203  			// conversions. See copyExpr a few lines below.
  1204  			needCopy = mapKeyReplaceStrConv(n.Index)
  1205  
  1206  			if base.Flag.Cfg.Instrumenting {
  1207  				// Race detector needs the copy.
  1208  				needCopy = true
  1209  			}
  1210  		}
  1211  
  1212  		// key may need to be be addressable
  1213  		n.Index = o.mapKeyTemp(n.Pos(), n.X.Type(), n.Index)
  1214  		if needCopy {
  1215  			return o.copyExpr(n)
  1216  		}
  1217  		return n
  1218  
  1219  	// concrete type (not interface) argument might need an addressable
  1220  	// temporary to pass to the runtime conversion routine.
  1221  	case ir.OCONVIFACE:
  1222  		n := n.(*ir.ConvExpr)
  1223  		n.X = o.expr(n.X, nil)
  1224  		if n.X.Type().IsInterface() {
  1225  			return n
  1226  		}
  1227  		if _, _, needsaddr := dataWordFuncName(n.X.Type()); needsaddr || isStaticCompositeLiteral(n.X) {
  1228  			// Need a temp if we need to pass the address to the conversion function.
  1229  			// We also process static composite literal node here, making a named static global
  1230  			// whose address we can put directly in an interface (see OCONVIFACE case in walk).
  1231  			n.X = o.addrTemp(n.X)
  1232  		}
  1233  		return n
  1234  
  1235  	case ir.OCONVNOP:
  1236  		n := n.(*ir.ConvExpr)
  1237  		if n.X.Op() == ir.OCALLMETH {
  1238  			base.FatalfAt(n.X.Pos(), "OCALLMETH missed by typecheck")
  1239  		}
  1240  		if n.Type().IsKind(types.TUNSAFEPTR) && n.X.Type().IsKind(types.TUINTPTR) && (n.X.Op() == ir.OCALLFUNC || n.X.Op() == ir.OCALLINTER) {
  1241  			call := n.X.(*ir.CallExpr)
  1242  			// When reordering unsafe.Pointer(f()) into a separate
  1243  			// statement, the conversion and function call must stay
  1244  			// together. See golang.org/issue/15329.
  1245  			o.init(call)
  1246  			o.call(call)
  1247  			if lhs == nil || lhs.Op() != ir.ONAME || base.Flag.Cfg.Instrumenting {
  1248  				return o.copyExpr(n)
  1249  			}
  1250  		} else {
  1251  			n.X = o.expr(n.X, nil)
  1252  		}
  1253  		return n
  1254  
  1255  	case ir.OANDAND, ir.OOROR:
  1256  		// ... = LHS && RHS
  1257  		//
  1258  		// var r bool
  1259  		// r = LHS
  1260  		// if r {       // or !r, for OROR
  1261  		//     r = RHS
  1262  		// }
  1263  		// ... = r
  1264  
  1265  		n := n.(*ir.LogicalExpr)
  1266  		r := o.newTemp(n.Type(), false)
  1267  
  1268  		// Evaluate left-hand side.
  1269  		lhs := o.expr(n.X, nil)
  1270  		o.out = append(o.out, typecheck.Stmt(ir.NewAssignStmt(base.Pos, r, lhs)))
  1271  
  1272  		// Evaluate right-hand side, save generated code.
  1273  		saveout := o.out
  1274  		o.out = nil
  1275  		t := o.markTemp()
  1276  		o.edge()
  1277  		rhs := o.expr(n.Y, nil)
  1278  		o.out = append(o.out, typecheck.Stmt(ir.NewAssignStmt(base.Pos, r, rhs)))
  1279  		o.popTemp(t)
  1280  		gen := o.out
  1281  		o.out = saveout
  1282  
  1283  		// If left-hand side doesn't cause a short-circuit, issue right-hand side.
  1284  		nif := ir.NewIfStmt(base.Pos, r, nil, nil)
  1285  		if n.Op() == ir.OANDAND {
  1286  			nif.Body = gen
  1287  		} else {
  1288  			nif.Else = gen
  1289  		}
  1290  		o.out = append(o.out, nif)
  1291  		return r
  1292  
  1293  	case ir.OCALLMETH:
  1294  		base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
  1295  		panic("unreachable")
  1296  
  1297  	case ir.OCALLFUNC,
  1298  		ir.OCALLINTER,
  1299  		ir.OCAP,
  1300  		ir.OCOMPLEX,
  1301  		ir.OCOPY,
  1302  		ir.OIMAG,
  1303  		ir.OLEN,
  1304  		ir.OMAKECHAN,
  1305  		ir.OMAKEMAP,
  1306  		ir.OMAKESLICE,
  1307  		ir.OMAKESLICECOPY,
  1308  		ir.OMAX,
  1309  		ir.OMIN,
  1310  		ir.ONEW,
  1311  		ir.OREAL,
  1312  		ir.ORECOVERFP,
  1313  		ir.OSTR2BYTES,
  1314  		ir.OSTR2BYTESTMP,
  1315  		ir.OSTR2RUNES:
  1316  
  1317  		if isRuneCount(n) {
  1318  			// len([]rune(s)) is rewritten to runtime.countrunes(s) later.
  1319  			conv := n.(*ir.UnaryExpr).X.(*ir.ConvExpr)
  1320  			conv.X = o.expr(conv.X, nil)
  1321  		} else {
  1322  			o.call(n)
  1323  		}
  1324  
  1325  		if lhs == nil || lhs.Op() != ir.ONAME || base.Flag.Cfg.Instrumenting {
  1326  			return o.copyExpr(n)
  1327  		}
  1328  		return n
  1329  
  1330  	case ir.OINLCALL:
  1331  		n := n.(*ir.InlinedCallExpr)
  1332  		o.stmtList(n.Body)
  1333  		return n.SingleResult()
  1334  
  1335  	case ir.OAPPEND:
  1336  		// Check for append(x, make([]T, y)...) .
  1337  		n := n.(*ir.CallExpr)
  1338  		if isAppendOfMake(n) {
  1339  			n.Args[0] = o.expr(n.Args[0], nil) // order x
  1340  			mk := n.Args[1].(*ir.MakeExpr)
  1341  			mk.Len = o.expr(mk.Len, nil) // order y
  1342  		} else {
  1343  			o.exprList(n.Args)
  1344  		}
  1345  
  1346  		if lhs == nil || lhs.Op() != ir.ONAME && !ir.SameSafeExpr(lhs, n.Args[0]) {
  1347  			return o.copyExpr(n)
  1348  		}
  1349  		return n
  1350  
  1351  	case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
  1352  		n := n.(*ir.SliceExpr)
  1353  		n.X = o.expr(n.X, nil)
  1354  		n.Low = o.cheapExpr(o.expr(n.Low, nil))
  1355  		n.High = o.cheapExpr(o.expr(n.High, nil))
  1356  		n.Max = o.cheapExpr(o.expr(n.Max, nil))
  1357  		if lhs == nil || lhs.Op() != ir.ONAME && !ir.SameSafeExpr(lhs, n.X) {
  1358  			return o.copyExpr(n)
  1359  		}
  1360  		return n
  1361  
  1362  	case ir.OCLOSURE:
  1363  		n := n.(*ir.ClosureExpr)
  1364  		if n.Transient() && len(n.Func.ClosureVars) > 0 {
  1365  			n.Prealloc = o.newTemp(typecheck.ClosureType(n), false)
  1366  		}
  1367  		return n
  1368  
  1369  	case ir.OMETHVALUE:
  1370  		n := n.(*ir.SelectorExpr)
  1371  		n.X = o.expr(n.X, nil)
  1372  		if n.Transient() {
  1373  			t := typecheck.MethodValueType(n)
  1374  			n.Prealloc = o.newTemp(t, false)
  1375  		}
  1376  		return n
  1377  
  1378  	case ir.OSLICELIT:
  1379  		n := n.(*ir.CompLitExpr)
  1380  		o.exprList(n.List)
  1381  		if n.Transient() {
  1382  			t := types.NewArray(n.Type().Elem(), n.Len)
  1383  			n.Prealloc = o.newTemp(t, false)
  1384  		}
  1385  		return n
  1386  
  1387  	case ir.ODOTTYPE, ir.ODOTTYPE2:
  1388  		n := n.(*ir.TypeAssertExpr)
  1389  		n.X = o.expr(n.X, nil)
  1390  		if !types.IsDirectIface(n.Type()) || base.Flag.Cfg.Instrumenting {
  1391  			return o.copyExprClear(n)
  1392  		}
  1393  		return n
  1394  
  1395  	case ir.ORECV:
  1396  		n := n.(*ir.UnaryExpr)
  1397  		n.X = o.expr(n.X, nil)
  1398  		return o.copyExprClear(n)
  1399  
  1400  	case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
  1401  		n := n.(*ir.BinaryExpr)
  1402  		n.X = o.expr(n.X, nil)
  1403  		n.Y = o.expr(n.Y, nil)
  1404  
  1405  		t := n.X.Type()
  1406  		switch {
  1407  		case t.IsString():
  1408  			// Mark string(byteSlice) arguments to reuse byteSlice backing
  1409  			// buffer during conversion. String comparison does not
  1410  			// memorize the strings for later use, so it is safe.
  1411  			if n.X.Op() == ir.OBYTES2STR {
  1412  				n.X.(*ir.ConvExpr).SetOp(ir.OBYTES2STRTMP)
  1413  			}
  1414  			if n.Y.Op() == ir.OBYTES2STR {
  1415  				n.Y.(*ir.ConvExpr).SetOp(ir.OBYTES2STRTMP)
  1416  			}
  1417  
  1418  		case t.IsStruct() || t.IsArray():
  1419  			// for complex comparisons, we need both args to be
  1420  			// addressable so we can pass them to the runtime.
  1421  			n.X = o.addrTemp(n.X)
  1422  			n.Y = o.addrTemp(n.Y)
  1423  		}
  1424  		return n
  1425  
  1426  	case ir.OMAPLIT:
  1427  		// Order map by converting:
  1428  		//   map[int]int{
  1429  		//     a(): b(),
  1430  		//     c(): d(),
  1431  		//     e(): f(),
  1432  		//   }
  1433  		// to
  1434  		//   m := map[int]int{}
  1435  		//   m[a()] = b()
  1436  		//   m[c()] = d()
  1437  		//   m[e()] = f()
  1438  		// Then order the result.
  1439  		// Without this special case, order would otherwise compute all
  1440  		// the keys and values before storing any of them to the map.
  1441  		// See issue 26552.
  1442  		n := n.(*ir.CompLitExpr)
  1443  		entries := n.List
  1444  		statics := entries[:0]
  1445  		var dynamics []*ir.KeyExpr
  1446  		for _, r := range entries {
  1447  			r := r.(*ir.KeyExpr)
  1448  
  1449  			if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) {
  1450  				dynamics = append(dynamics, r)
  1451  				continue
  1452  			}
  1453  
  1454  			// Recursively ordering some static entries can change them to dynamic;
  1455  			// e.g., OCONVIFACE nodes. See #31777.
  1456  			r = o.expr(r, nil).(*ir.KeyExpr)
  1457  			if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) {
  1458  				dynamics = append(dynamics, r)
  1459  				continue
  1460  			}
  1461  
  1462  			statics = append(statics, r)
  1463  		}
  1464  		n.List = statics
  1465  
  1466  		if len(dynamics) == 0 {
  1467  			return n
  1468  		}
  1469  
  1470  		// Emit the creation of the map (with all its static entries).
  1471  		m := o.newTemp(n.Type(), false)
  1472  		as := ir.NewAssignStmt(base.Pos, m, n)
  1473  		typecheck.Stmt(as)
  1474  		o.stmt(as)
  1475  
  1476  		// Emit eval+insert of dynamic entries, one at a time.
  1477  		for _, r := range dynamics {
  1478  			lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, r.Key)).(*ir.IndexExpr)
  1479  			base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
  1480  			lhs.RType = n.RType
  1481  
  1482  			as := ir.NewAssignStmt(base.Pos, lhs, r.Value)
  1483  			typecheck.Stmt(as)
  1484  			o.stmt(as)
  1485  		}
  1486  
  1487  		// Remember that we issued these assignments so we can include that count
  1488  		// in the map alloc hint.
  1489  		// We're assuming here that all the keys in the map literal are distinct.
  1490  		// If any are equal, this will be an overcount. Probably not worth accounting
  1491  		// for that, as equal keys in map literals are rare, and at worst we waste
  1492  		// a bit of space.
  1493  		n.Len += int64(len(dynamics))
  1494  
  1495  		return m
  1496  	}
  1497  
  1498  	// No return - type-assertions above. Each case must return for itself.
  1499  }
  1500  
  1501  // as2func orders OAS2FUNC nodes. It creates temporaries to ensure left-to-right assignment.
  1502  // The caller should order the right-hand side of the assignment before calling order.as2func.
  1503  // It rewrites,
  1504  //
  1505  //	a, b, a = ...
  1506  //
  1507  // as
  1508  //
  1509  //	tmp1, tmp2, tmp3 = ...
  1510  //	a, b, a = tmp1, tmp2, tmp3
  1511  //
  1512  // This is necessary to ensure left to right assignment order.
  1513  func (o *orderState) as2func(n *ir.AssignListStmt) {
  1514  	results := n.Rhs[0].Type()
  1515  	as := ir.NewAssignListStmt(n.Pos(), ir.OAS2, nil, nil)
  1516  	for i, nl := range n.Lhs {
  1517  		if !ir.IsBlank(nl) {
  1518  			typ := results.Field(i).Type
  1519  			tmp := o.newTemp(typ, typ.HasPointers())
  1520  			n.Lhs[i] = tmp
  1521  			as.Lhs = append(as.Lhs, nl)
  1522  			as.Rhs = append(as.Rhs, tmp)
  1523  		}
  1524  	}
  1525  
  1526  	o.out = append(o.out, n)
  1527  	o.stmt(typecheck.Stmt(as))
  1528  }
  1529  
  1530  // as2ok orders OAS2XXX with ok.
  1531  // Just like as2func, this also adds temporaries to ensure left-to-right assignment.
  1532  func (o *orderState) as2ok(n *ir.AssignListStmt) {
  1533  	as := ir.NewAssignListStmt(n.Pos(), ir.OAS2, nil, nil)
  1534  
  1535  	do := func(i int, typ *types.Type) {
  1536  		if nl := n.Lhs[i]; !ir.IsBlank(nl) {
  1537  			var tmp ir.Node = o.newTemp(typ, typ.HasPointers())
  1538  			n.Lhs[i] = tmp
  1539  			as.Lhs = append(as.Lhs, nl)
  1540  			if i == 1 {
  1541  				// The "ok" result is an untyped boolean according to the Go
  1542  				// spec. We need to explicitly convert it to the LHS type in
  1543  				// case the latter is a defined boolean type (#8475).
  1544  				tmp = typecheck.Conv(tmp, nl.Type())
  1545  			}
  1546  			as.Rhs = append(as.Rhs, tmp)
  1547  		}
  1548  	}
  1549  
  1550  	do(0, n.Rhs[0].Type())
  1551  	do(1, types.Types[types.TBOOL])
  1552  
  1553  	o.out = append(o.out, n)
  1554  	o.stmt(typecheck.Stmt(as))
  1555  }
  1556  

View as plain text