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