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

View as plain text