| |
| |
| |
|
|
| package walk |
|
|
| import ( |
| "cmd/compile/internal/base" |
| "cmd/compile/internal/ir" |
| "cmd/compile/internal/ssa" |
| "cmd/compile/internal/staticdata" |
| "cmd/compile/internal/staticinit" |
| "cmd/compile/internal/typecheck" |
| "cmd/compile/internal/types" |
| "cmd/internal/obj" |
| ) |
|
|
| |
| |
| func walkCompLit(n ir.Node, init *ir.Nodes) ir.Node { |
| if isStaticCompositeLiteral(n) && !ssa.CanSSA(n.Type()) { |
| n := n.(*ir.CompLitExpr) |
| |
| |
| vstat := readonlystaticname(n.Type()) |
| fixedlit(inInitFunction, initKindStatic, n, vstat, init) |
| return typecheck.Expr(vstat) |
| } |
| var_ := typecheck.TempAt(base.Pos, ir.CurFunc, n.Type()) |
| anylit(n, var_, init) |
| return var_ |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| type initContext uint8 |
|
|
| const ( |
| inInitFunction initContext = iota |
| inNonInitFunction |
| ) |
|
|
| func (c initContext) String() string { |
| if c == inInitFunction { |
| return "inInitFunction" |
| } |
| return "inNonInitFunction" |
| } |
|
|
| |
| func readonlystaticname(t *types.Type) *ir.Name { |
| n := staticinit.StaticName(t) |
| n.MarkReadonly() |
| n.Linksym().Set(obj.AttrContentAddressable, true) |
| n.Linksym().Set(obj.AttrLocal, true) |
| return n |
| } |
|
|
| func isSimpleName(nn ir.Node) bool { |
| if nn.Op() != ir.ONAME || ir.IsBlank(nn) { |
| return false |
| } |
| n := nn.(*ir.Name) |
| return n.OnStack() |
| } |
|
|
| |
| type initGenType uint8 |
|
|
| const ( |
| initDynamic initGenType = 1 << iota |
| initConst |
| ) |
|
|
| |
| |
| func getdyn(n ir.Node, top bool) initGenType { |
| switch n.Op() { |
| default: |
| |
| |
| if ir.IsConstNode(n) && (!n.Type().IsString() || !base.Ctxt.IsFIPS()) { |
| return initConst |
| } |
| return initDynamic |
|
|
| case ir.OSLICELIT: |
| n := n.(*ir.CompLitExpr) |
| if !top { |
| return initDynamic |
| } |
| if n.Len/4 > int64(len(n.List)) { |
| |
| |
| |
| |
| |
| |
| return initDynamic |
| } |
|
|
| case ir.OARRAYLIT, ir.OSTRUCTLIT: |
| } |
| lit := n.(*ir.CompLitExpr) |
|
|
| var mode initGenType |
| for _, n1 := range lit.List { |
| switch n1.Op() { |
| case ir.OKEY: |
| n1 = n1.(*ir.KeyExpr).Value |
| case ir.OSTRUCTKEY: |
| n1 = n1.(*ir.StructKeyExpr).Value |
| } |
| mode |= getdyn(n1, false) |
| if mode == initDynamic|initConst { |
| break |
| } |
| } |
| return mode |
| } |
|
|
| |
| func isStaticCompositeLiteral(n ir.Node) bool { |
| switch n.Op() { |
| case ir.OSLICELIT: |
| return false |
| case ir.OARRAYLIT: |
| n := n.(*ir.CompLitExpr) |
| for _, r := range n.List { |
| if r.Op() == ir.OKEY { |
| r = r.(*ir.KeyExpr).Value |
| } |
| if !isStaticCompositeLiteral(r) { |
| return false |
| } |
| } |
| return true |
| case ir.OSTRUCTLIT: |
| n := n.(*ir.CompLitExpr) |
| for _, r := range n.List { |
| r := r.(*ir.StructKeyExpr) |
| if !isStaticCompositeLiteral(r.Value) { |
| return false |
| } |
| } |
| return true |
| case ir.OLITERAL, ir.ONIL: |
| return true |
| case ir.OCONVIFACE: |
| |
| if base.Ctxt.IsFIPS() && base.Ctxt.Flag_shared { |
| return false |
| } |
| n := n.(*ir.ConvExpr) |
| val := ir.Node(n) |
| for val.Op() == ir.OCONVIFACE { |
| val = val.(*ir.ConvExpr).X |
| } |
| if val.Type().IsInterface() { |
| return val.Op() == ir.ONIL |
| } |
| if types.IsDirectIface(val.Type()) && val.Op() == ir.ONIL { |
| return true |
| } |
| return isStaticCompositeLiteral(val) |
| } |
| return false |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| type initKind uint8 |
|
|
| const ( |
| initKindStatic initKind = iota + 1 |
| initKindDynamic |
| initKindLocalCode |
| ) |
|
|
| |
| |
| func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) { |
| isBlank := var_ == ir.BlankNode |
| var splitnode func(ir.Node) (a ir.Node, value ir.Node) |
| switch n.Op() { |
| case ir.OARRAYLIT, ir.OSLICELIT: |
| var k int64 |
| splitnode = func(r ir.Node) (ir.Node, ir.Node) { |
| if r.Op() == ir.OKEY { |
| kv := r.(*ir.KeyExpr) |
| k = typecheck.IndexConst(kv.Key) |
| r = kv.Value |
| } |
| a := ir.NewIndexExpr(base.Pos, var_, ir.NewInt(base.Pos, k)) |
| k++ |
| if isBlank { |
| return ir.BlankNode, r |
| } |
| return a, r |
| } |
| case ir.OSTRUCTLIT: |
| splitnode = func(rn ir.Node) (ir.Node, ir.Node) { |
| r := rn.(*ir.StructKeyExpr) |
| if r.Sym().IsBlank() || isBlank { |
| return ir.BlankNode, r.Value |
| } |
| ir.SetPos(r) |
| return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Sym()), r.Value |
| } |
| default: |
| base.Fatalf("fixedlit bad op: %v", n.Op()) |
| } |
|
|
| for _, r := range n.List { |
| a, value := splitnode(r) |
| if a == ir.BlankNode && !staticinit.AnySideEffects(value) { |
| |
| continue |
| } |
|
|
| switch value.Op() { |
| case ir.OSLICELIT: |
| value := value.(*ir.CompLitExpr) |
| if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) { |
| var sinit ir.Nodes |
| slicelit(ctxt, value, a, &sinit) |
| if kind == initKindStatic { |
| |
| |
| |
| |
| orderBlock(&sinit, map[string][]*ir.Name{}) |
| typecheck.Stmts(sinit) |
| walkStmtList(sinit) |
| } |
| init.Append(sinit...) |
| continue |
| } |
|
|
| case ir.OARRAYLIT, ir.OSTRUCTLIT: |
| value := value.(*ir.CompLitExpr) |
| fixedlit(ctxt, kind, value, a, init) |
| continue |
| } |
|
|
| islit := ir.IsConstNode(value) |
| if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) { |
| continue |
| } |
|
|
| |
| ir.SetPos(a) |
| as := ir.NewAssignStmt(base.Pos, a, value) |
| as = typecheck.Stmt(as).(*ir.AssignStmt) |
| switch kind { |
| case initKindStatic: |
| genAsStatic(as) |
| case initKindDynamic, initKindLocalCode: |
| appendWalkStmt(init, orderStmtInPlace(as, map[string][]*ir.Name{})) |
| default: |
| base.Fatalf("fixedlit: bad kind %d", kind) |
| } |
|
|
| } |
| } |
|
|
| func isSmallSliceLit(n *ir.CompLitExpr) bool { |
| if n.Op() != ir.OSLICELIT { |
| return false |
| } |
|
|
| return n.Type().Elem().Size() == 0 || n.Len <= ir.MaxSmallArraySize/n.Type().Elem().Size() |
| } |
|
|
| func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) { |
| |
| t := types.NewArray(n.Type().Elem(), n.Len) |
| types.CalcSize(t) |
|
|
| if ctxt == inNonInitFunction { |
| |
| vstat := staticinit.StaticName(t) |
|
|
| fixedlit(ctxt, initKindStatic, n, vstat, init) |
| fixedlit(ctxt, initKindDynamic, n, vstat, init) |
|
|
| |
| var_ = typecheck.AssignExpr(var_) |
| name, offset, ok := staticinit.StaticLoc(var_) |
| if !ok || name.Class != ir.PEXTERN { |
| base.Fatalf("slicelit: %v", var_) |
| } |
| staticdata.InitSlice(name, offset, vstat.Linksym(), t.NumElem()) |
| return |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| var vstat ir.Node |
|
|
| mode := getdyn(n, true) |
| if mode&initConst != 0 && !isSmallSliceLit(n) { |
| if ctxt == inInitFunction { |
| vstat = readonlystaticname(t) |
| } else { |
| vstat = staticinit.StaticName(t) |
| } |
| fixedlit(ctxt, initKindStatic, n, vstat, init) |
| } |
|
|
| |
| vauto := typecheck.TempAt(base.Pos, ir.CurFunc, types.NewPtr(t)) |
|
|
| |
| var a ir.Node |
| if x := n.Prealloc; x != nil { |
| |
| if !types.Identical(t, x.Type()) { |
| panic("dotdotdot base type does not match order's assigned type") |
| } |
| a = initStackTemp(init, x, vstat) |
| } else if n.Esc() == ir.EscNone { |
| a = initStackTemp(init, typecheck.TempAt(base.Pos, ir.CurFunc, t), vstat) |
| } else { |
| a = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(t)) |
| } |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, vauto, a)) |
|
|
| if vstat != nil && n.Prealloc == nil && n.Esc() != ir.EscNone { |
| |
| |
| |
| a = ir.NewStarExpr(base.Pos, vauto) |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, a, vstat)) |
| } |
|
|
| |
| var index int64 |
| for _, value := range n.List { |
| if value.Op() == ir.OKEY { |
| kv := value.(*ir.KeyExpr) |
| index = typecheck.IndexConst(kv.Key) |
| value = kv.Value |
| } |
| a := ir.NewIndexExpr(base.Pos, vauto, ir.NewInt(base.Pos, index)) |
| a.SetBounded(true) |
| index++ |
|
|
| |
|
|
| switch value.Op() { |
| case ir.OSLICELIT: |
| break |
|
|
| case ir.OARRAYLIT, ir.OSTRUCTLIT: |
| value := value.(*ir.CompLitExpr) |
| k := initKindDynamic |
| if vstat == nil { |
| |
| |
| k = initKindLocalCode |
| } |
| fixedlit(ctxt, k, value, a, init) |
| continue |
| } |
|
|
| if vstat != nil && ir.IsConstNode(value) { |
| continue |
| } |
|
|
| |
| ir.SetPos(value) |
| as := ir.NewAssignStmt(base.Pos, a, value) |
| appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(as), map[string][]*ir.Name{})) |
| } |
|
|
| |
| a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto, nil, nil, nil)) |
| appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(a), map[string][]*ir.Name{})) |
| } |
|
|
| func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) { |
| |
| args := []ir.Node{ir.TypeNode(n.Type()), ir.NewInt(base.Pos, n.Len+int64(len(n.List)))} |
| a := typecheck.Expr(ir.NewCallExpr(base.Pos, ir.OMAKE, nil, args)).(*ir.MakeExpr) |
| a.RType = n.RType |
| a.SetEsc(n.Esc()) |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, m, a)) |
|
|
| entries := n.List |
|
|
| |
| |
| for _, r := range entries { |
| r := r.(*ir.KeyExpr) |
| if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) { |
| base.Fatalf("maplit: entry is not a literal: %v", r) |
| } |
| } |
|
|
| if len(entries) > 25 { |
| |
|
|
| |
| tk := types.NewArray(n.Type().Key(), int64(len(entries))) |
| te := types.NewArray(n.Type().Elem(), int64(len(entries))) |
|
|
| |
| |
|
|
| types.CalcSize(tk) |
| types.CalcSize(te) |
|
|
| |
| vstatk := readonlystaticname(tk) |
| vstate := readonlystaticname(te) |
|
|
| datak := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil) |
| datae := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil) |
| for _, r := range entries { |
| r := r.(*ir.KeyExpr) |
| datak.List.Append(r.Key) |
| datae.List.Append(r.Value) |
| } |
| fixedlit(inInitFunction, initKindStatic, datak, vstatk, init) |
| fixedlit(inInitFunction, initKindStatic, datae, vstate, init) |
|
|
| |
| |
| |
| |
| i := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT]) |
| rhs := ir.NewIndexExpr(base.Pos, vstate, i) |
| rhs.SetBounded(true) |
|
|
| kidx := ir.NewIndexExpr(base.Pos, vstatk, i) |
| kidx.SetBounded(true) |
|
|
| |
| lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, kidx)).(*ir.IndexExpr) |
| base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs) |
| lhs.RType = n.RType |
|
|
| zero := ir.NewAssignStmt(base.Pos, i, ir.NewInt(base.Pos, 0)) |
| cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(base.Pos, tk.NumElem())) |
| incr := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(base.Pos, 1))) |
|
|
| var body ir.Node = ir.NewAssignStmt(base.Pos, lhs, rhs) |
| body = typecheck.Stmt(body) |
| body = orderStmtInPlace(body, map[string][]*ir.Name{}) |
|
|
| loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil, false) |
| loop.Body = []ir.Node{body} |
| loop.SetInit([]ir.Node{zero}) |
|
|
| appendWalkStmt(init, loop) |
| return |
| } |
| |
|
|
| |
| |
| |
| |
| tmpkey := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Key()) |
| tmpelem := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Elem()) |
|
|
| for _, r := range entries { |
| r := r.(*ir.KeyExpr) |
| index, elem := r.Key, r.Value |
|
|
| ir.SetPos(index) |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpkey, index)) |
|
|
| ir.SetPos(elem) |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpelem, elem)) |
|
|
| ir.SetPos(tmpelem) |
|
|
| |
| lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, tmpkey)).(*ir.IndexExpr) |
| base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs) |
| lhs.RType = n.RType |
|
|
| var a ir.Node = ir.NewAssignStmt(base.Pos, lhs, tmpelem) |
| a = typecheck.Stmt(a) |
| a = orderStmtInPlace(a, map[string][]*ir.Name{}) |
| appendWalkStmt(init, a) |
| } |
| } |
|
|
| func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) { |
| t := n.Type() |
| switch n.Op() { |
| default: |
| base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n) |
|
|
| case ir.ONAME: |
| n := n.(*ir.Name) |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n)) |
|
|
| case ir.OMETHEXPR: |
| n := n.(*ir.SelectorExpr) |
| anylit(n.FuncName(), var_, init) |
|
|
| case ir.OPTRLIT: |
| n := n.(*ir.AddrExpr) |
| if !t.IsPtr() { |
| base.Fatalf("anylit: not ptr") |
| } |
|
|
| var r ir.Node |
| if n.Prealloc != nil { |
| |
| r = initStackTemp(init, n.Prealloc, nil) |
| } else { |
| r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type())) |
| r.SetEsc(n.Esc()) |
| } |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r)) |
|
|
| var_ = ir.NewStarExpr(base.Pos, var_) |
| var_ = typecheck.AssignExpr(var_) |
| anylit(n.X, var_, init) |
|
|
| case ir.OSTRUCTLIT, ir.OARRAYLIT: |
| n := n.(*ir.CompLitExpr) |
| if !t.IsStruct() && !t.IsArray() { |
| base.Fatalf("anylit: not struct/array") |
| } |
|
|
| if isSimpleName(var_) && len(n.List) > 4 { |
| |
| vstat := readonlystaticname(t) |
|
|
| ctxt := inInitFunction |
| if n.Op() == ir.OARRAYLIT { |
| ctxt = inNonInitFunction |
| } |
| fixedlit(ctxt, initKindStatic, n, vstat, init) |
|
|
| |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, vstat)) |
|
|
| |
| fixedlit(inInitFunction, initKindDynamic, n, var_, init) |
| break |
| } |
|
|
| var components int64 |
| if n.Op() == ir.OARRAYLIT { |
| components = t.NumElem() |
| } else { |
| components = int64(t.NumFields()) |
| } |
| |
| if isSimpleName(var_) || int64(len(n.List)) < components { |
| appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil)) |
| } |
|
|
| fixedlit(inInitFunction, initKindLocalCode, n, var_, init) |
|
|
| case ir.OSLICELIT: |
| n := n.(*ir.CompLitExpr) |
| slicelit(inInitFunction, n, var_, init) |
|
|
| case ir.OMAPLIT: |
| n := n.(*ir.CompLitExpr) |
| if !t.IsMap() { |
| base.Fatalf("anylit: not map") |
| } |
| maplit(n, var_, init) |
| } |
| } |
|
|
| |
| |
| |
| func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool { |
| if n.X == nil || n.Y == nil { |
| |
| return false |
| } |
| if n.X.Type() == nil || n.Y.Type() == nil { |
| |
| return false |
| } |
| if !isSimpleName(n.X) { |
| |
| return false |
| } |
| x := n.X.(*ir.Name) |
| if !types.Identical(n.X.Type(), n.Y.Type()) { |
| |
| return false |
| } |
| if x.Addrtaken() { |
| |
| |
| |
| return false |
| } |
|
|
| switch n.Y.Op() { |
| default: |
| |
| return false |
|
|
| case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT: |
| if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) { |
| |
| return false |
| } |
| anylit(n.Y, n.X, init) |
| } |
|
|
| return true |
| } |
|
|
| func genAsStatic(as *ir.AssignStmt) { |
| if as.X.Type() == nil { |
| base.Fatalf("genAsStatic as.Left not typechecked") |
| } |
|
|
| name, offset, ok := staticinit.StaticLoc(as.X) |
| if !ok || (name.Class != ir.PEXTERN && as.X != ir.BlankNode) { |
| base.Fatalf("genAsStatic: lhs %v", as.X) |
| } |
|
|
| switch r := as.Y; r.Op() { |
| case ir.OLITERAL: |
| staticdata.InitConst(name, offset, r, int(r.Type().Size())) |
| return |
| case ir.OMETHEXPR: |
| r := r.(*ir.SelectorExpr) |
| staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r.FuncName())) |
| return |
| case ir.ONAME: |
| r := r.(*ir.Name) |
| if r.Offset_ != 0 { |
| base.Fatalf("genAsStatic %+v", as) |
| } |
| if r.Class == ir.PFUNC { |
| staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r)) |
| return |
| } |
| } |
| base.Fatalf("genAsStatic: rhs %v", as.Y) |
| } |
|
|