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

View as plain text