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

View as plain text