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

     1  // Copyright 2009 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  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  	"cmd/compile/internal/ssa"
    11  	"cmd/compile/internal/staticdata"
    12  	"cmd/compile/internal/staticinit"
    13  	"cmd/compile/internal/typecheck"
    14  	"cmd/compile/internal/types"
    15  	"cmd/internal/obj"
    16  )
    17  
    18  // walkCompLit walks a composite literal node:
    19  // OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT (all CompLitExpr), or OPTRLIT (AddrExpr).
    20  func walkCompLit(n ir.Node, init *ir.Nodes) ir.Node {
    21  	if isStaticCompositeLiteral(n) && !ssa.CanSSA(n.Type()) {
    22  		n := n.(*ir.CompLitExpr) // not OPTRLIT
    23  		// n can be directly represented in the read-only data section.
    24  		// Make direct reference to the static data. See issue 12841.
    25  		vstat := readonlystaticname(n.Type())
    26  		fixedlit(initKindStatic, n, vstat, init)
    27  		return typecheck.Expr(vstat)
    28  	}
    29  	var_ := typecheck.TempAt(base.Pos, ir.CurFunc, n.Type())
    30  	anylit(n, var_, init)
    31  	return var_
    32  }
    33  
    34  // readonlystaticname returns a name backed by a read-only static data symbol.
    35  func readonlystaticname(t *types.Type) *ir.Name {
    36  	n := staticinit.StaticName(t)
    37  	n.MarkReadonly()
    38  	n.Linksym().Set(obj.AttrContentAddressable, true)
    39  	n.Linksym().Set(obj.AttrLocal, true)
    40  	return n
    41  }
    42  
    43  func isSimpleName(nn ir.Node) bool {
    44  	if nn.Op() != ir.ONAME || ir.IsBlank(nn) {
    45  		return false
    46  	}
    47  	n := nn.(*ir.Name)
    48  	return n.OnStack()
    49  }
    50  
    51  // initGenType is a bitmap indicating the types of generation that will occur for a static value.
    52  type initGenType uint8
    53  
    54  const (
    55  	initDynamic initGenType = 1 << iota // contains some dynamic values, for which init code will be generated
    56  	initConst                           // contains some constant values, which may be written into data symbols
    57  )
    58  
    59  // getdyn calculates the initGenType for n.
    60  // If top is false, getdyn is recursing.
    61  func getdyn(n ir.Node, top bool) initGenType {
    62  	switch n.Op() {
    63  	default:
    64  		if isStaticLiteral(n) {
    65  			return initConst
    66  		}
    67  		return initDynamic
    68  
    69  	case ir.OSLICELIT:
    70  		n := n.(*ir.CompLitExpr)
    71  		if !top {
    72  			return initDynamic
    73  		}
    74  		if n.Len/4 > int64(len(n.List)) {
    75  			// <25% of entries have explicit values.
    76  			// Very rough estimation, it takes 4 bytes of instructions
    77  			// to initialize 1 byte of result. So don't use a static
    78  			// initializer if the dynamic initialization code would be
    79  			// smaller than the static value.
    80  			// See issue 23780.
    81  			return initDynamic
    82  		}
    83  
    84  	case ir.OARRAYLIT, ir.OSTRUCTLIT:
    85  	}
    86  	lit := n.(*ir.CompLitExpr)
    87  
    88  	var mode initGenType
    89  	for _, n1 := range lit.List {
    90  		switch n1.Op() {
    91  		case ir.OKEY:
    92  			n1 = n1.(*ir.KeyExpr).Value
    93  		case ir.OSTRUCTKEY:
    94  			n1 = n1.(*ir.StructKeyExpr).Value
    95  		}
    96  		mode |= getdyn(n1, false)
    97  		if mode == initDynamic|initConst {
    98  			break
    99  		}
   100  	}
   101  	return mode
   102  }
   103  
   104  // isStaticLiteral reports whether n is a compile-time (non-composite)
   105  // constant, which can be represented in the read-only data section.
   106  func isStaticLiteral(n ir.Node) bool {
   107  	// A string reference requires a relocation, not allowed
   108  	// in static data in FIPS mode.
   109  	return ir.IsConstNode(n) && !(base.Ctxt.IsFIPS() && n.Type().IsString())
   110  }
   111  
   112  // isStaticCompositeLiteral reports whether a composite literal n
   113  // is a compile-time constant, which can be represented in the
   114  // read-only data section.
   115  func isStaticCompositeLiteral(n ir.Node) bool {
   116  	switch n.Op() {
   117  	case ir.OSLICELIT:
   118  		return false
   119  	case ir.OARRAYLIT:
   120  		n := n.(*ir.CompLitExpr)
   121  		for _, r := range n.List {
   122  			if r.Op() == ir.OKEY {
   123  				r = r.(*ir.KeyExpr).Value
   124  			}
   125  			if !isStaticCompositeLiteral(r) {
   126  				return false
   127  			}
   128  		}
   129  		return true
   130  	case ir.OSTRUCTLIT:
   131  		n := n.(*ir.CompLitExpr)
   132  		for _, r := range n.List {
   133  			r := r.(*ir.StructKeyExpr)
   134  			if !isStaticCompositeLiteral(r.Value) {
   135  				return false
   136  			}
   137  		}
   138  		return true
   139  	case ir.ONIL:
   140  		return true
   141  	case ir.OLITERAL:
   142  		return isStaticLiteral(n)
   143  	case ir.OCONVIFACE:
   144  		// See staticinit.Schedule.StaticAssign's OCONVIFACE case for comments.
   145  		if base.Ctxt.IsFIPS() && base.Ctxt.Flag_shared {
   146  			return false
   147  		}
   148  		n := n.(*ir.ConvExpr)
   149  		val := ir.Node(n)
   150  		for val.Op() == ir.OCONVIFACE {
   151  			val = val.(*ir.ConvExpr).X
   152  		}
   153  		if val.Type().IsInterface() {
   154  			return val.Op() == ir.ONIL
   155  		}
   156  		if types.IsDirectIface(val.Type()) && val.Op() == ir.ONIL {
   157  			return true
   158  		}
   159  		return isStaticCompositeLiteral(val)
   160  	}
   161  	return false
   162  }
   163  
   164  // initKind is a kind of static initialization: static, dynamic, or local.
   165  // Static initialization represents literals and
   166  // literal components of composite literals.
   167  // Dynamic initialization represents non-literals and
   168  // non-literal components of composite literals.
   169  // LocalCode initialization represents initialization
   170  // that occurs purely in generated code local to the function of use.
   171  // Initialization code is sometimes generated in passes,
   172  // first static then dynamic.
   173  type initKind uint8
   174  
   175  const (
   176  	initKindStatic initKind = iota + 1
   177  	initKindDynamic
   178  	initKindLocalCode
   179  )
   180  
   181  // fixedlit handles struct, array, and slice literals.
   182  // TODO: expand documentation.
   183  func fixedlit(kind initKind, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
   184  	isBlank := var_ == ir.BlankNode
   185  	var splitnode func(ir.Node) (a ir.Node, value ir.Node)
   186  	switch n.Op() {
   187  	case ir.OARRAYLIT, ir.OSLICELIT:
   188  		var k int64
   189  		splitnode = func(r ir.Node) (ir.Node, ir.Node) {
   190  			if r.Op() == ir.OKEY {
   191  				kv := r.(*ir.KeyExpr)
   192  				k = typecheck.IndexConst(kv.Key)
   193  				r = kv.Value
   194  			}
   195  			a := ir.NewIndexExpr(base.Pos, var_, ir.NewInt(base.Pos, k))
   196  			k++
   197  			if isBlank {
   198  				return ir.BlankNode, r
   199  			}
   200  			return a, r
   201  		}
   202  	case ir.OSTRUCTLIT:
   203  		splitnode = func(rn ir.Node) (ir.Node, ir.Node) {
   204  			r := rn.(*ir.StructKeyExpr)
   205  			if r.Sym().IsBlank() || isBlank {
   206  				return ir.BlankNode, r.Value
   207  			}
   208  			ir.SetPos(r)
   209  			return ir.NewSelectorExpr(base.Pos, ir.OXDOT, var_, r.Sym()), r.Value
   210  		}
   211  	default:
   212  		base.Fatalf("fixedlit bad op: %v", n.Op())
   213  	}
   214  
   215  	for _, r := range n.List {
   216  		a, value := splitnode(r)
   217  		if a == ir.BlankNode && !staticinit.AnySideEffects(value) {
   218  			// Discard.
   219  			continue
   220  		}
   221  
   222  		switch value.Op() {
   223  		case ir.OSLICELIT:
   224  			value := value.(*ir.CompLitExpr)
   225  			if kind == initKindDynamic {
   226  				slicelit(value, a, init)
   227  				continue
   228  			}
   229  
   230  		case ir.OARRAYLIT, ir.OSTRUCTLIT:
   231  			value := value.(*ir.CompLitExpr)
   232  			fixedlit(kind, value, a, init)
   233  			continue
   234  		}
   235  
   236  		islit := isStaticLiteral(value)
   237  		if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
   238  			continue
   239  		}
   240  
   241  		// build list of assignments: var[index] = expr
   242  		ir.SetPos(a)
   243  		as := ir.NewAssignStmt(base.Pos, a, value)
   244  		as = typecheck.Stmt(as).(*ir.AssignStmt)
   245  		switch kind {
   246  		case initKindStatic:
   247  			genAsStatic(as)
   248  		case initKindDynamic, initKindLocalCode:
   249  			appendWalkStmt(init, orderStmtInPlace(as, map[string][]*ir.Name{}))
   250  		default:
   251  			base.Fatalf("fixedlit: bad kind %d", kind)
   252  		}
   253  
   254  	}
   255  }
   256  
   257  func isSmallSliceLit(n *ir.CompLitExpr) bool {
   258  	if n.Op() != ir.OSLICELIT {
   259  		return false
   260  	}
   261  
   262  	return n.Type().Elem().Size() == 0 || n.Len <= ir.MaxSmallArraySize/n.Type().Elem().Size()
   263  }
   264  
   265  func slicelit(n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
   266  	// make an array type corresponding the number of elements we have
   267  	t := types.NewArray(n.Type().Elem(), n.Len)
   268  	types.CalcSize(t)
   269  
   270  	// recipe for var = []t{...}
   271  	// 1. make a static array
   272  	//	var vstat [...]t
   273  	// 2. assign (data statements) the constant part
   274  	//	vstat = constpart{}
   275  	// 3. make an auto pointer to array and allocate heap to it
   276  	//	var vauto *[...]t = new([...]t)
   277  	// 4. copy the static array to the auto array
   278  	//	*vauto = vstat
   279  	// 5. for each dynamic part assign to the array
   280  	//	vauto[i] = dynamic part
   281  	// 6. assign slice of allocated heap to var
   282  	//	var = vauto[:]
   283  	//
   284  	// an optimization is done if there is no constant part
   285  	//	3. var vauto *[...]t = new([...]t)
   286  	//	5. vauto[i] = dynamic part
   287  	//	6. var = vauto[:]
   288  
   289  	// if the literal contains constants,
   290  	// make static initialized array (1),(2)
   291  	var vstat ir.Node
   292  
   293  	mode := getdyn(n, true)
   294  	if mode&initConst != 0 && !isSmallSliceLit(n) {
   295  		vstat = readonlystaticname(t)
   296  		fixedlit(initKindStatic, n, vstat, init)
   297  	}
   298  
   299  	// make new auto *array (3 declare)
   300  	vauto := typecheck.TempAt(base.Pos, ir.CurFunc, types.NewPtr(t))
   301  
   302  	// set auto to point at new temp or heap (3 assign)
   303  	var a ir.Node
   304  	if x := n.Prealloc; x != nil {
   305  		// temp allocated during order.go for dddarg
   306  		if !types.Identical(t, x.Type()) {
   307  			panic("dotdotdot base type does not match order's assigned type")
   308  		}
   309  		a = initStackTemp(init, x, vstat)
   310  	} else if n.Esc() == ir.EscNone {
   311  		a = initStackTemp(init, typecheck.TempAt(base.Pos, ir.CurFunc, t), vstat)
   312  	} else {
   313  		a = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(t))
   314  	}
   315  	appendWalkStmt(init, ir.NewAssignStmt(base.Pos, vauto, a))
   316  
   317  	if vstat != nil && n.Prealloc == nil && n.Esc() != ir.EscNone {
   318  		// If we allocated on the heap with ONEW, copy the static to the
   319  		// heap (4). We skip this for stack temporaries, because
   320  		// initStackTemp already handled the copy.
   321  		a = ir.NewStarExpr(base.Pos, vauto)
   322  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, a, vstat))
   323  	}
   324  
   325  	// put dynamics into array (5)
   326  	var index int64
   327  	for _, value := range n.List {
   328  		if value.Op() == ir.OKEY {
   329  			kv := value.(*ir.KeyExpr)
   330  			index = typecheck.IndexConst(kv.Key)
   331  			value = kv.Value
   332  		}
   333  		a := ir.NewIndexExpr(base.Pos, vauto, ir.NewInt(base.Pos, index))
   334  		a.SetBounded(true)
   335  		index++
   336  
   337  		// TODO need to check bounds?
   338  
   339  		switch value.Op() {
   340  		case ir.OSLICELIT:
   341  			break
   342  
   343  		case ir.OARRAYLIT, ir.OSTRUCTLIT:
   344  			value := value.(*ir.CompLitExpr)
   345  			k := initKindDynamic
   346  			if vstat == nil {
   347  				// Generate both static and dynamic initializations.
   348  				// See issue #31987.
   349  				k = initKindLocalCode
   350  			}
   351  			fixedlit(k, value, a, init)
   352  			continue
   353  		}
   354  
   355  		if vstat != nil && isStaticLiteral(value) { // already set by copy from static value
   356  			continue
   357  		}
   358  
   359  		// build list of vauto[c] = expr
   360  		ir.SetPos(value)
   361  		as := ir.NewAssignStmt(base.Pos, a, value)
   362  		appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(as), map[string][]*ir.Name{}))
   363  	}
   364  
   365  	// make slice out of heap (6)
   366  	a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto, nil, nil, nil))
   367  	appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(a), map[string][]*ir.Name{}))
   368  }
   369  
   370  func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) {
   371  	// make the map var
   372  	args := []ir.Node{ir.TypeNode(n.Type()), ir.NewInt(base.Pos, n.Len+int64(len(n.List)))}
   373  	a := typecheck.Expr(ir.NewCallExpr(base.Pos, ir.OMAKE, nil, args)).(*ir.MakeExpr)
   374  	a.RType = n.RType
   375  	a.SetEsc(n.Esc())
   376  	appendWalkStmt(init, ir.NewAssignStmt(base.Pos, m, a))
   377  
   378  	entries := n.List
   379  
   380  	// The order pass already removed any dynamic (runtime-computed) entries.
   381  	// All remaining entries are static. Double-check that.
   382  	for _, r := range entries {
   383  		r := r.(*ir.KeyExpr)
   384  		if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) {
   385  			base.Fatalf("maplit: entry is not a literal: %v", r)
   386  		}
   387  	}
   388  
   389  	if len(entries) > 25 {
   390  		// For a large number of entries, put them in an array and loop.
   391  
   392  		// build types [count]Tindex and [count]Tvalue
   393  		tk := types.NewArray(n.Type().Key(), int64(len(entries)))
   394  		te := types.NewArray(n.Type().Elem(), int64(len(entries)))
   395  
   396  		// TODO(#47904): mark tk and te NoAlg here once the
   397  		// compiler/linker can handle NoAlg types correctly.
   398  
   399  		types.CalcSize(tk)
   400  		types.CalcSize(te)
   401  
   402  		// make and initialize static arrays
   403  		vstatk := readonlystaticname(tk)
   404  		vstate := readonlystaticname(te)
   405  
   406  		datak := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
   407  		datae := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
   408  		for _, r := range entries {
   409  			r := r.(*ir.KeyExpr)
   410  			datak.List.Append(r.Key)
   411  			datae.List.Append(r.Value)
   412  		}
   413  		fixedlit(initKindStatic, datak, vstatk, init)
   414  		fixedlit(initKindStatic, datae, vstate, init)
   415  
   416  		// loop adding structure elements to map
   417  		// for i = 0; i < len(vstatk); i++ {
   418  		//	map[vstatk[i]] = vstate[i]
   419  		// }
   420  		i := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
   421  		rhs := ir.NewIndexExpr(base.Pos, vstate, i)
   422  		rhs.SetBounded(true)
   423  
   424  		kidx := ir.NewIndexExpr(base.Pos, vstatk, i)
   425  		kidx.SetBounded(true)
   426  
   427  		// typechecker rewrites OINDEX to OINDEXMAP
   428  		lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, kidx)).(*ir.IndexExpr)
   429  		base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
   430  		lhs.RType = n.RType
   431  
   432  		zero := ir.NewAssignStmt(base.Pos, i, ir.NewInt(base.Pos, 0))
   433  		cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(base.Pos, tk.NumElem()))
   434  		incr := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(base.Pos, 1)))
   435  
   436  		var body ir.Node = ir.NewAssignStmt(base.Pos, lhs, rhs)
   437  		body = typecheck.Stmt(body)
   438  		body = orderStmtInPlace(body, map[string][]*ir.Name{})
   439  
   440  		loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil, false)
   441  		loop.Body = []ir.Node{body}
   442  		loop.SetInit([]ir.Node{zero})
   443  
   444  		appendWalkStmt(init, loop)
   445  		return
   446  	}
   447  	// For a small number of entries, just add them directly.
   448  
   449  	// Build list of var[c] = expr.
   450  	// Use temporaries so that mapassign1 can have addressable key, elem.
   451  	// TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys.
   452  	// TODO(khr): assign these temps in order phase so we can reuse them across multiple maplits?
   453  	tmpkey := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Key())
   454  	tmpelem := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Elem())
   455  
   456  	for _, r := range entries {
   457  		r := r.(*ir.KeyExpr)
   458  		index, elem := r.Key, r.Value
   459  
   460  		ir.SetPos(index)
   461  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpkey, index))
   462  
   463  		ir.SetPos(elem)
   464  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpelem, elem))
   465  
   466  		ir.SetPos(tmpelem)
   467  
   468  		// typechecker rewrites OINDEX to OINDEXMAP
   469  		lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, tmpkey)).(*ir.IndexExpr)
   470  		base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
   471  		lhs.RType = n.RType
   472  
   473  		var a ir.Node = ir.NewAssignStmt(base.Pos, lhs, tmpelem)
   474  		a = typecheck.Stmt(a)
   475  		a = orderStmtInPlace(a, map[string][]*ir.Name{})
   476  		appendWalkStmt(init, a)
   477  	}
   478  }
   479  
   480  func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
   481  	t := n.Type()
   482  	switch n.Op() {
   483  	default:
   484  		base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n)
   485  
   486  	case ir.ONAME:
   487  		n := n.(*ir.Name)
   488  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
   489  
   490  	case ir.OMETHEXPR:
   491  		n := n.(*ir.SelectorExpr)
   492  		anylit(n.FuncName(), var_, init)
   493  
   494  	case ir.OPTRLIT:
   495  		n := n.(*ir.AddrExpr)
   496  		if !t.IsPtr() {
   497  			base.Fatalf("anylit: not ptr")
   498  		}
   499  
   500  		var r ir.Node
   501  		if n.Prealloc != nil {
   502  			// n.Prealloc is stack temporary used as backing store.
   503  			r = initStackTemp(init, n.Prealloc, nil)
   504  		} else {
   505  			r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
   506  			r.SetEsc(n.Esc())
   507  		}
   508  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r))
   509  
   510  		var_ = ir.NewStarExpr(base.Pos, var_)
   511  		var_ = typecheck.AssignExpr(var_)
   512  		anylit(n.X, var_, init)
   513  
   514  	case ir.OSTRUCTLIT, ir.OARRAYLIT:
   515  		n := n.(*ir.CompLitExpr)
   516  		if !t.IsStruct() && !t.IsArray() {
   517  			base.Fatalf("anylit: not struct/array")
   518  		}
   519  
   520  		if isSimpleName(var_) && len(n.List) > 4 {
   521  			// lay out static data
   522  			vstat := readonlystaticname(t)
   523  
   524  			fixedlit(initKindStatic, n, vstat, init)
   525  
   526  			// copy static to var
   527  			appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, vstat))
   528  
   529  			// add expressions to automatic
   530  			fixedlit(initKindDynamic, n, var_, init)
   531  			break
   532  		}
   533  
   534  		var components int64
   535  		if n.Op() == ir.OARRAYLIT {
   536  			components = t.NumElem()
   537  		} else {
   538  			components = int64(t.NumFields())
   539  		}
   540  		// initialization of an array or struct with unspecified components (missing fields or arrays)
   541  		if isSimpleName(var_) || int64(len(n.List)) < components {
   542  			appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))
   543  		}
   544  
   545  		fixedlit(initKindLocalCode, n, var_, init)
   546  
   547  	case ir.OSLICELIT:
   548  		n := n.(*ir.CompLitExpr)
   549  		slicelit(n, var_, init)
   550  
   551  	case ir.OMAPLIT:
   552  		n := n.(*ir.CompLitExpr)
   553  		if !t.IsMap() {
   554  			base.Fatalf("anylit: not map")
   555  		}
   556  		maplit(n, var_, init)
   557  	}
   558  }
   559  
   560  // oaslit handles special composite literal assignments.
   561  // It returns true if n's effects have been added to init,
   562  // in which case n should be dropped from the program by the caller.
   563  func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
   564  	if n.X == nil || n.Y == nil {
   565  		// not a special composite literal assignment
   566  		return false
   567  	}
   568  	if n.X.Type() == nil || n.Y.Type() == nil {
   569  		// not a special composite literal assignment
   570  		return false
   571  	}
   572  	if !isSimpleName(n.X) {
   573  		// not a special composite literal assignment
   574  		return false
   575  	}
   576  	x := n.X.(*ir.Name)
   577  	if !types.Identical(n.X.Type(), n.Y.Type()) {
   578  		// not a special composite literal assignment
   579  		return false
   580  	}
   581  	if x.Addrtaken() {
   582  		// If x is address-taken, the RHS may (implicitly) uses LHS.
   583  		// Not safe to do a special composite literal assignment
   584  		// (which may expand to multiple assignments).
   585  		return false
   586  	}
   587  
   588  	switch n.Y.Op() {
   589  	default:
   590  		// not a special composite literal assignment
   591  		return false
   592  
   593  	case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
   594  		if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) {
   595  			// not safe to do a special composite literal assignment if RHS uses LHS.
   596  			return false
   597  		}
   598  		anylit(n.Y, n.X, init)
   599  	}
   600  
   601  	return true
   602  }
   603  
   604  func genAsStatic(as *ir.AssignStmt) {
   605  	if as.X.Type() == nil {
   606  		base.Fatalf("genAsStatic as.Left not typechecked")
   607  	}
   608  
   609  	name, offset, ok := staticinit.StaticLoc(as.X)
   610  	if !ok || (name.Class != ir.PEXTERN && as.X != ir.BlankNode) {
   611  		base.Fatalf("genAsStatic: lhs %v", as.X)
   612  	}
   613  
   614  	switch r := as.Y; r.Op() {
   615  	case ir.OLITERAL:
   616  		staticdata.InitConst(name, offset, r, int(r.Type().Size()))
   617  		return
   618  	case ir.OMETHEXPR:
   619  		r := r.(*ir.SelectorExpr)
   620  		staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r.FuncName()))
   621  		return
   622  	case ir.ONAME:
   623  		r := r.(*ir.Name)
   624  		if r.Offset_ != 0 {
   625  			base.Fatalf("genAsStatic %+v", as)
   626  		}
   627  		if r.Class == ir.PFUNC {
   628  			staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r))
   629  			return
   630  		}
   631  	}
   632  	base.Fatalf("genAsStatic: rhs %v", as.Y)
   633  }
   634  

View as plain text