github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/walk/complit.go (about) 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 "github.com/go-asm/go/cmd/compile/base" 9 "github.com/go-asm/go/cmd/compile/ir" 10 "github.com/go-asm/go/cmd/compile/ssa" 11 "github.com/go-asm/go/cmd/compile/staticdata" 12 "github.com/go-asm/go/cmd/compile/staticinit" 13 "github.com/go-asm/go/cmd/compile/typecheck" 14 "github.com/go-asm/go/cmd/compile/types" 15 "github.com/go-asm/go/cmd/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 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. 129 func 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. 182 type initKind uint8 183 184 const ( 185 initKindStatic initKind = iota + 1 186 initKindDynamic 187 initKindLocalCode 188 ) 189 190 // fixedlit handles struct, array, and slice literals. 191 // TODO: expand documentation. 192 func 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 280 func 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 288 func 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 417 func 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 527 func 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. 614 func 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 655 func 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 }