2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"fmt"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* static initialization
|
|
|
|
|
*/
|
|
|
|
|
const (
|
|
|
|
|
InitNotStarted = 0
|
|
|
|
|
InitDone = 1
|
|
|
|
|
InitPending = 2
|
|
|
|
|
)
|
|
|
|
|
|
2015-06-03 14:16:01 -04:00
|
|
|
var (
|
|
|
|
|
initlist *NodeList
|
|
|
|
|
initplans map[*Node]*InitPlan
|
|
|
|
|
inittemps = make(map[*Node]*Node)
|
|
|
|
|
)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// init1 walks the AST starting at n, and accumulates in out
|
|
|
|
|
// the list of definitions needing init code in dependency order.
|
|
|
|
|
func init1(n *Node, out **NodeList) {
|
|
|
|
|
if n == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
init1(n.Left, out)
|
|
|
|
|
init1(n.Right, out)
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
init1(l.N, out)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Left != nil && n.Type != nil && n.Left.Op == OTYPE && n.Class == PFUNC {
|
|
|
|
|
// Methods called as Type.Method(receiver, ...).
|
|
|
|
|
// Definitions for method expressions are stored in type->nname.
|
|
|
|
|
init1(n.Type.Nname, out)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Op != ONAME {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
switch n.Class {
|
2015-04-01 09:38:44 -07:00
|
|
|
case PEXTERN, PFUNC:
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
|
|
|
|
|
default:
|
2015-05-27 07:31:56 -04:00
|
|
|
if isblank(n) && n.Name.Curfn == nil && n.Name.Defn != nil && n.Name.Defn.Initorder == InitNotStarted {
|
2015-02-13 14:40:36 -05:00
|
|
|
// blank names initialization is part of init() but not
|
|
|
|
|
// when they are inside a function.
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Initorder == InitDone {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if n.Initorder == InitPending {
|
|
|
|
|
// Since mutually recursive sets of functions are allowed,
|
|
|
|
|
// we don't necessarily raise an error if n depends on a node
|
|
|
|
|
// which is already waiting for its dependencies to be visited.
|
|
|
|
|
//
|
|
|
|
|
// initlist contains a cycle of identifiers referring to each other.
|
|
|
|
|
// If this cycle contains a variable, then this variable refers to itself.
|
|
|
|
|
// Conversely, if there exists an initialization cycle involving
|
|
|
|
|
// a variable in the program, the tree walk will reach a cycle
|
|
|
|
|
// involving that variable.
|
2015-02-23 16:07:24 -05:00
|
|
|
var nv *Node
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Class != PFUNC {
|
|
|
|
|
nv = n
|
|
|
|
|
goto foundinitloop
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := initlist; l.N != n; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
if l.N.Class != PFUNC {
|
|
|
|
|
nv = l.N
|
|
|
|
|
goto foundinitloop
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The loop involves only functions, ok.
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// if there have already been errors printed,
|
|
|
|
|
// those errors probably confused us and
|
|
|
|
|
// there might not be a loop. let the user
|
|
|
|
|
// fix those first.
|
|
|
|
|
foundinitloop:
|
|
|
|
|
Flusherrors()
|
|
|
|
|
|
|
|
|
|
if nerrors > 0 {
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There is a loop involving nv. We know about
|
|
|
|
|
// n and initlist = n1 <- ... <- nv <- ... <- n <- ...
|
|
|
|
|
fmt.Printf("%v: initialization loop:\n", nv.Line())
|
|
|
|
|
|
|
|
|
|
// Build back pointers in initlist.
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := initlist; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
if l.Next != nil {
|
|
|
|
|
l.Next.End = l
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Print nv -> ... -> n1 -> n.
|
2015-02-23 16:07:24 -05:00
|
|
|
var l *NodeList
|
2015-02-13 14:40:36 -05:00
|
|
|
for l = initlist; l.N != nv; l = l.Next {
|
|
|
|
|
}
|
|
|
|
|
for ; l != nil; l = l.End {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("\t%v %v refers to\n", l.N.Line(), l.N.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Print n -> ... -> nv.
|
|
|
|
|
for l = initlist; l.N != n; l = l.Next {
|
|
|
|
|
}
|
|
|
|
|
for ; l.N != nv; l = l.End {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("\t%v %v refers to\n", l.N.Line(), l.N.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("\t%v %v\n", nv.Line(), nv.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// reached a new unvisited node.
|
|
|
|
|
n.Initorder = InitPending
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
l := new(NodeList)
|
2015-02-13 14:40:36 -05:00
|
|
|
if l == nil {
|
|
|
|
|
Flusherrors()
|
|
|
|
|
Yyerror("out of memory")
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l.Next = initlist
|
|
|
|
|
l.N = n
|
|
|
|
|
l.End = nil
|
|
|
|
|
initlist = l
|
|
|
|
|
|
|
|
|
|
// make sure that everything n depends on is initialized.
|
|
|
|
|
// n->defn is an assignment to n
|
2015-05-26 22:19:27 -04:00
|
|
|
if defn := n.Name.Defn; defn != nil {
|
|
|
|
|
switch defn.Op {
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
|
|
|
|
goto bad
|
|
|
|
|
|
|
|
|
|
case ODCLFUNC:
|
2015-05-26 22:19:27 -04:00
|
|
|
init2list(defn.Nbody, out)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OAS:
|
2015-05-26 22:19:27 -04:00
|
|
|
if defn.Left != n {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto bad
|
|
|
|
|
}
|
2015-05-26 22:19:27 -04:00
|
|
|
if isblank(defn.Left) && candiscard(defn.Right) {
|
|
|
|
|
defn.Op = OEMPTY
|
|
|
|
|
defn.Left = nil
|
|
|
|
|
defn.Right = nil
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-26 22:19:27 -04:00
|
|
|
init2(defn.Right, out)
|
2015-02-13 14:40:36 -05:00
|
|
|
if Debug['j'] != 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("%v\n", n.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if isblank(n) || !staticinit(n, out) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if Debug['%'] != 0 {
|
2015-05-26 22:19:27 -04:00
|
|
|
Dump("nonstatic", defn)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-26 22:19:27 -04:00
|
|
|
*out = list(*out, defn)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
|
2015-05-26 22:19:27 -04:00
|
|
|
if defn.Initorder != InitNotStarted {
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
2015-05-26 22:19:27 -04:00
|
|
|
defn.Initorder = InitDone
|
|
|
|
|
for l := defn.Rlist; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
init1(l.N, out)
|
|
|
|
|
}
|
|
|
|
|
if Debug['%'] != 0 {
|
2015-05-26 22:19:27 -04:00
|
|
|
Dump("nonstatic", defn)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-26 22:19:27 -04:00
|
|
|
*out = list(*out, defn)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l = initlist
|
|
|
|
|
initlist = l.Next
|
|
|
|
|
if l.N != n {
|
|
|
|
|
Fatal("bad initlist")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n.Initorder = InitDone
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
bad:
|
2015-05-26 22:19:27 -04:00
|
|
|
Dump("defn", n.Name.Defn)
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("init1: bad defn")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// recurse over n, doing init1 everywhere.
|
|
|
|
|
func init2(n *Node, out **NodeList) {
|
|
|
|
|
if n == nil || n.Initorder == InitDone {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Op == ONAME && n.Ninit != nil {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("name %v with ninit: %v\n", n.Sym, Nconv(n, obj.FmtSign))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init1(n, out)
|
|
|
|
|
init2(n.Left, out)
|
|
|
|
|
init2(n.Right, out)
|
|
|
|
|
init2list(n.Ninit, out)
|
|
|
|
|
init2list(n.List, out)
|
|
|
|
|
init2list(n.Rlist, out)
|
|
|
|
|
init2list(n.Nbody, out)
|
|
|
|
|
|
|
|
|
|
if n.Op == OCLOSURE {
|
2015-05-27 00:44:05 -04:00
|
|
|
init2list(n.Func.Closure.Nbody, out)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Op == ODOTMETH || n.Op == OCALLPART {
|
|
|
|
|
init2(n.Type.Nname, out)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func init2list(l *NodeList, out **NodeList) {
|
|
|
|
|
for ; l != nil; l = l.Next {
|
|
|
|
|
init2(l.N, out)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func initreorder(l *NodeList, out **NodeList) {
|
|
|
|
|
var n *Node
|
|
|
|
|
|
|
|
|
|
for ; l != nil; l = l.Next {
|
|
|
|
|
n = l.N
|
|
|
|
|
switch n.Op {
|
2015-04-01 09:38:44 -07:00
|
|
|
case ODCLFUNC, ODCLCONST, ODCLTYPE:
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initreorder(n.Ninit, out)
|
|
|
|
|
n.Ninit = nil
|
|
|
|
|
init1(n, out)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// initfix computes initialization order for a list l of top-level
|
|
|
|
|
// declarations and outputs the corresponding list of statements
|
|
|
|
|
// to include in the init() function body.
|
|
|
|
|
func initfix(l *NodeList) *NodeList {
|
2015-03-02 14:22:05 -05:00
|
|
|
var lout *NodeList
|
2015-06-03 14:16:01 -04:00
|
|
|
initplans = make(map[*Node]*InitPlan)
|
2015-02-23 16:07:24 -05:00
|
|
|
lno := int(lineno)
|
2015-02-13 14:40:36 -05:00
|
|
|
initreorder(l, &lout)
|
|
|
|
|
lineno = int32(lno)
|
2015-06-03 14:16:01 -04:00
|
|
|
initplans = nil
|
2015-02-13 14:40:36 -05:00
|
|
|
return lout
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* compilation of top-level (static) assignments
|
|
|
|
|
* into DATA statements if at all possible.
|
|
|
|
|
*/
|
2015-02-17 22:13:49 -05:00
|
|
|
func staticinit(n *Node, out **NodeList) bool {
|
2015-05-26 22:19:27 -04:00
|
|
|
if n.Op != ONAME || n.Class != PEXTERN || n.Name.Defn == nil || n.Name.Defn.Op != OAS {
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("staticinit")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lineno = n.Lineno
|
2015-05-26 22:19:27 -04:00
|
|
|
l := n.Name.Defn.Left
|
|
|
|
|
r := n.Name.Defn.Right
|
2015-02-13 14:40:36 -05:00
|
|
|
return staticassign(l, r, out)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// like staticassign but we are copying an already
|
|
|
|
|
// initialized value r.
|
2015-02-17 22:13:49 -05:00
|
|
|
func staticcopy(l *Node, r *Node, out **NodeList) bool {
|
2015-03-04 16:33:28 -08:00
|
|
|
if r.Op != ONAME {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if r.Class == PFUNC {
|
|
|
|
|
gdata(l, r, Widthptr)
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if r.Class != PEXTERN || r.Sym.Pkg != localpkg {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-26 22:19:27 -04:00
|
|
|
if r.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-26 22:19:27 -04:00
|
|
|
if r.Name.Defn.Op != OAS {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
orig := r
|
2015-05-26 22:19:27 -04:00
|
|
|
r = r.Name.Defn.Right
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-06-29 12:49:25 -04:00
|
|
|
for r.Op == OCONVNOP {
|
|
|
|
|
r = r.Left
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
switch r.Op {
|
|
|
|
|
case ONAME:
|
2015-02-17 22:13:49 -05:00
|
|
|
if staticcopy(l, r, out) {
|
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
*out = list(*out, Nod(OAS, l, r))
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OLITERAL:
|
2015-02-17 22:13:49 -05:00
|
|
|
if iszero(r) {
|
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
gdata(l, r, int(l.Type.Width))
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OADDR:
|
|
|
|
|
switch r.Left.Op {
|
|
|
|
|
case ONAME:
|
|
|
|
|
gdata(l, r, int(l.Type.Width))
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OPTRLIT:
|
|
|
|
|
switch r.Left.Op {
|
|
|
|
|
//dump("not static addr", r);
|
|
|
|
|
default:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
// copy pointer
|
2015-04-01 09:38:44 -07:00
|
|
|
case OARRAYLIT, OSTRUCTLIT, OMAPLIT:
|
2015-05-27 10:44:23 -04:00
|
|
|
gdata(l, Nod(OADDR, inittemps[r], nil), int(l.Type.Width))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OARRAYLIT:
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isslice(r.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// copy slice
|
2015-05-27 10:44:23 -04:00
|
|
|
a := inittemps[r]
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
n1 := *l
|
2015-02-13 14:40:36 -05:00
|
|
|
n1.Xoffset = l.Xoffset + int64(Array_array)
|
|
|
|
|
gdata(&n1, Nod(OADDR, a, nil), Widthptr)
|
|
|
|
|
n1.Xoffset = l.Xoffset + int64(Array_nel)
|
|
|
|
|
gdata(&n1, r.Right, Widthint)
|
|
|
|
|
n1.Xoffset = l.Xoffset + int64(Array_cap)
|
|
|
|
|
gdata(&n1, r.Right, Widthint)
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
|
|
// fall through
|
|
|
|
|
case OSTRUCTLIT:
|
2015-05-22 01:16:52 -04:00
|
|
|
p := initplans[r]
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
n1 := *l
|
|
|
|
|
var e *InitEntry
|
|
|
|
|
var ll *Node
|
|
|
|
|
var rr *Node
|
|
|
|
|
for i := 0; i < len(p.E); i++ {
|
2015-02-13 14:40:36 -05:00
|
|
|
e = &p.E[i]
|
|
|
|
|
n1.Xoffset = l.Xoffset + e.Xoffset
|
|
|
|
|
n1.Type = e.Expr.Type
|
|
|
|
|
if e.Expr.Op == OLITERAL {
|
|
|
|
|
gdata(&n1, e.Expr, int(n1.Type.Width))
|
|
|
|
|
} else {
|
|
|
|
|
ll = Nod(OXXX, nil, nil)
|
|
|
|
|
*ll = n1
|
|
|
|
|
ll.Orig = ll // completely separate copy
|
2015-02-17 22:13:49 -05:00
|
|
|
if !staticassign(ll, e.Expr, out) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// Requires computation, but we're
|
|
|
|
|
// copying someone else's computation.
|
|
|
|
|
rr = Nod(OXXX, nil, nil)
|
|
|
|
|
|
|
|
|
|
*rr = *orig
|
|
|
|
|
rr.Orig = rr // completely separate copy
|
|
|
|
|
rr.Type = ll.Type
|
|
|
|
|
rr.Xoffset += e.Xoffset
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(rr)
|
2015-02-13 14:40:36 -05:00
|
|
|
*out = list(*out, Nod(OAS, ll, rr))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func staticassign(l *Node, r *Node, out **NodeList) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
var n1 Node
|
|
|
|
|
|
2015-06-29 12:49:25 -04:00
|
|
|
for r.Op == OCONVNOP {
|
|
|
|
|
r = r.Left
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
switch r.Op {
|
|
|
|
|
//dump("not static", r);
|
|
|
|
|
default:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case ONAME:
|
2015-03-04 16:33:28 -08:00
|
|
|
return staticcopy(l, r, out)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OLITERAL:
|
2015-02-17 22:13:49 -05:00
|
|
|
if iszero(r) {
|
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
gdata(l, r, int(l.Type.Width))
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OADDR:
|
2015-02-23 16:07:24 -05:00
|
|
|
var nam Node
|
2015-02-17 22:13:49 -05:00
|
|
|
if stataddr(&nam, r.Left) {
|
2015-02-23 16:07:24 -05:00
|
|
|
n1 := *r
|
2015-02-13 14:40:36 -05:00
|
|
|
n1.Left = &nam
|
|
|
|
|
gdata(l, &n1, int(l.Type.Width))
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
|
|
case OPTRLIT:
|
|
|
|
|
switch r.Left.Op {
|
|
|
|
|
//dump("not static ptrlit", r);
|
|
|
|
|
default:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
// Init pointer.
|
2015-04-01 09:38:44 -07:00
|
|
|
case OARRAYLIT, OMAPLIT, OSTRUCTLIT:
|
2015-02-23 16:07:24 -05:00
|
|
|
a := staticname(r.Left.Type, 1)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-05-27 10:44:23 -04:00
|
|
|
inittemps[r] = a
|
2015-02-13 14:40:36 -05:00
|
|
|
gdata(l, Nod(OADDR, a, nil), int(l.Type.Width))
|
|
|
|
|
|
|
|
|
|
// Init underlying literal.
|
2015-02-17 22:13:49 -05:00
|
|
|
if !staticassign(a, r.Left, out) {
|
2015-02-13 14:40:36 -05:00
|
|
|
*out = list(*out, Nod(OAS, a, r.Left))
|
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OSTRARRAYBYTE:
|
|
|
|
|
if l.Class == PEXTERN && r.Left.Op == OLITERAL {
|
2015-05-27 00:47:05 -04:00
|
|
|
sval := r.Left.Val().U.(string)
|
2015-03-02 16:03:26 -05:00
|
|
|
slicebytes(l, sval, len(sval))
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OARRAYLIT:
|
|
|
|
|
initplan(r)
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isslice(r.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// Init slice.
|
2015-02-23 16:07:24 -05:00
|
|
|
ta := typ(TARRAY)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
ta.Type = r.Type.Type
|
2015-05-27 00:47:05 -04:00
|
|
|
ta.Bound = Mpgetfix(r.Right.Val().U.(*Mpint))
|
2015-02-23 16:07:24 -05:00
|
|
|
a := staticname(ta, 1)
|
2015-05-27 10:44:23 -04:00
|
|
|
inittemps[r] = a
|
2015-02-13 14:40:36 -05:00
|
|
|
n1 = *l
|
|
|
|
|
n1.Xoffset = l.Xoffset + int64(Array_array)
|
|
|
|
|
gdata(&n1, Nod(OADDR, a, nil), Widthptr)
|
|
|
|
|
n1.Xoffset = l.Xoffset + int64(Array_nel)
|
|
|
|
|
gdata(&n1, r.Right, Widthint)
|
|
|
|
|
n1.Xoffset = l.Xoffset + int64(Array_cap)
|
|
|
|
|
gdata(&n1, r.Right, Widthint)
|
|
|
|
|
|
|
|
|
|
// Fall through to init underlying array.
|
|
|
|
|
l = a
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
|
|
// fall through
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
|
initplan(r)
|
|
|
|
|
|
2015-05-22 01:16:52 -04:00
|
|
|
p := initplans[r]
|
2015-02-13 14:40:36 -05:00
|
|
|
n1 = *l
|
2015-02-23 16:07:24 -05:00
|
|
|
var e *InitEntry
|
|
|
|
|
var a *Node
|
|
|
|
|
for i := 0; i < len(p.E); i++ {
|
2015-02-13 14:40:36 -05:00
|
|
|
e = &p.E[i]
|
|
|
|
|
n1.Xoffset = l.Xoffset + e.Xoffset
|
|
|
|
|
n1.Type = e.Expr.Type
|
|
|
|
|
if e.Expr.Op == OLITERAL {
|
|
|
|
|
gdata(&n1, e.Expr, int(n1.Type.Width))
|
|
|
|
|
} else {
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(e.Expr)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nod(OXXX, nil, nil)
|
|
|
|
|
*a = n1
|
|
|
|
|
a.Orig = a // completely separate copy
|
2015-02-17 22:13:49 -05:00
|
|
|
if !staticassign(a, e.Expr, out) {
|
2015-02-13 14:40:36 -05:00
|
|
|
*out = list(*out, Nod(OAS, a, e.Expr))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// TODO: Table-driven map insert.
|
|
|
|
|
case OMAPLIT:
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* from here down is the walk analysis
|
|
|
|
|
* of composite literals.
|
|
|
|
|
* most of the work is to generate
|
|
|
|
|
* data statements for the constant
|
|
|
|
|
* part of the composite literal.
|
|
|
|
|
*/
|
|
|
|
|
func staticname(t *Type, ctxt int) *Node {
|
2015-03-06 12:02:24 -08:00
|
|
|
n := newname(Lookupf("statictmp_%.4d", statuniqgen))
|
2015-02-13 14:40:36 -05:00
|
|
|
statuniqgen++
|
2015-02-17 22:13:49 -05:00
|
|
|
if ctxt == 0 {
|
2015-05-15 10:02:19 -07:00
|
|
|
n.Name.Readonly = true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
addvar(n, t, PEXTERN)
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func isliteral(n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Op == OLITERAL {
|
2015-05-27 00:47:05 -04:00
|
|
|
if n.Val().Ctype() != CTNIL {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func simplename(n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Op != ONAME {
|
2015-03-02 12:35:15 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-04-02 19:58:37 -07:00
|
|
|
if !n.Addable {
|
2015-03-02 12:35:15 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Class&PHEAP != 0 {
|
2015-03-02 12:35:15 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Class == PPARAMREF {
|
2015-03-02 12:35:15 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func litas(l *Node, r *Node, init **NodeList) {
|
2015-02-23 16:07:24 -05:00
|
|
|
a := Nod(OAS, l, r)
|
2015-02-13 14:40:36 -05:00
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
MODEDYNAM = 1
|
|
|
|
|
MODECONST = 2
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func getdyn(n *Node, top int) int {
|
2015-02-23 16:07:24 -05:00
|
|
|
mode := 0
|
2015-02-13 14:40:36 -05:00
|
|
|
switch n.Op {
|
|
|
|
|
default:
|
2015-02-17 22:13:49 -05:00
|
|
|
if isliteral(n) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return MODECONST
|
|
|
|
|
}
|
|
|
|
|
return MODEDYNAM
|
|
|
|
|
|
|
|
|
|
case OARRAYLIT:
|
2015-02-17 22:13:49 -05:00
|
|
|
if top == 0 && n.Type.Bound < 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
return MODEDYNAM
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var value *Node
|
|
|
|
|
for nl := n.List; nl != nil; nl = nl.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
value = nl.N.Right
|
|
|
|
|
mode |= getdyn(value, 0)
|
|
|
|
|
if mode == MODEDYNAM|MODECONST {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
|
|
|
|
|
var r *Node
|
|
|
|
|
var a *Node
|
|
|
|
|
var index *Node
|
|
|
|
|
var value *Node
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for nl := n.List; nl != nil; nl = nl.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
r = nl.N
|
|
|
|
|
if r.Op != OKEY {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("structlit: rhs not OKEY: %v", r)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
index = r.Left
|
|
|
|
|
value = r.Right
|
|
|
|
|
|
|
|
|
|
switch value.Op {
|
|
|
|
|
case OARRAYLIT:
|
|
|
|
|
if value.Type.Bound < 0 {
|
|
|
|
|
if pass == 1 && ctxt != 0 {
|
|
|
|
|
a = Nod(ODOT, var_, newname(index.Sym))
|
|
|
|
|
slicelit(ctxt, value, a, init)
|
|
|
|
|
} else if pass == 2 && ctxt == 0 {
|
|
|
|
|
a = Nod(ODOT, var_, newname(index.Sym))
|
|
|
|
|
slicelit(ctxt, value, a, init)
|
|
|
|
|
} else if pass == 3 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a = Nod(ODOT, var_, newname(index.Sym))
|
|
|
|
|
arraylit(ctxt, pass, value, a, init)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
|
a = Nod(ODOT, var_, newname(index.Sym))
|
|
|
|
|
structlit(ctxt, pass, value, a, init)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isliteral(value) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if pass == 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
} else if pass == 1 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build list of var.field = expr
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(value)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nod(ODOT, var_, newname(index.Sym))
|
|
|
|
|
|
|
|
|
|
a = Nod(OAS, a, value)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
if pass == 1 {
|
|
|
|
|
walkexpr(&a, init) // add any assignments in r to top
|
|
|
|
|
if a.Op != OAS {
|
|
|
|
|
Fatal("structlit: not as")
|
|
|
|
|
}
|
|
|
|
|
a.Dodata = 2
|
|
|
|
|
} else {
|
|
|
|
|
orderstmtinplace(&a)
|
|
|
|
|
walkstmt(&a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
|
|
|
|
|
var r *Node
|
|
|
|
|
var a *Node
|
|
|
|
|
var index *Node
|
|
|
|
|
var value *Node
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
r = l.N
|
|
|
|
|
if r.Op != OKEY {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("arraylit: rhs not OKEY: %v", r)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
index = r.Left
|
|
|
|
|
value = r.Right
|
|
|
|
|
|
|
|
|
|
switch value.Op {
|
|
|
|
|
case OARRAYLIT:
|
|
|
|
|
if value.Type.Bound < 0 {
|
|
|
|
|
if pass == 1 && ctxt != 0 {
|
|
|
|
|
a = Nod(OINDEX, var_, index)
|
|
|
|
|
slicelit(ctxt, value, a, init)
|
|
|
|
|
} else if pass == 2 && ctxt == 0 {
|
|
|
|
|
a = Nod(OINDEX, var_, index)
|
|
|
|
|
slicelit(ctxt, value, a, init)
|
|
|
|
|
} else if pass == 3 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a = Nod(OINDEX, var_, index)
|
|
|
|
|
arraylit(ctxt, pass, value, a, init)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
|
a = Nod(OINDEX, var_, index)
|
|
|
|
|
structlit(ctxt, pass, value, a, init)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isliteral(index) && isliteral(value) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if pass == 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
} else if pass == 1 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build list of var[index] = value
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(value)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nod(OINDEX, var_, index)
|
|
|
|
|
|
|
|
|
|
a = Nod(OAS, a, value)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
if pass == 1 {
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
if a.Op != OAS {
|
|
|
|
|
Fatal("arraylit: not as")
|
|
|
|
|
}
|
|
|
|
|
a.Dodata = 2
|
|
|
|
|
} else {
|
|
|
|
|
orderstmtinplace(&a)
|
|
|
|
|
walkstmt(&a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
|
|
|
|
|
// make an array type
|
2015-02-23 16:07:24 -05:00
|
|
|
t := shallow(n.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-05-27 00:47:05 -04:00
|
|
|
t.Bound = Mpgetfix(n.Right.Val().U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
t.Width = 0
|
|
|
|
|
t.Sym = nil
|
|
|
|
|
t.Haspointers = 0
|
|
|
|
|
dowidth(t)
|
|
|
|
|
|
|
|
|
|
if ctxt != 0 {
|
|
|
|
|
// put everything into static array
|
2015-02-23 16:07:24 -05:00
|
|
|
vstat := staticname(t, ctxt)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
arraylit(ctxt, 1, n, vstat, init)
|
|
|
|
|
arraylit(ctxt, 2, n, vstat, init)
|
|
|
|
|
|
|
|
|
|
// copy static to slice
|
2015-02-23 16:07:24 -05:00
|
|
|
a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
a = Nod(OAS, var_, a)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
a.Dodata = 2
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// recipe for var = []t{...}
|
|
|
|
|
// 1. make a static array
|
|
|
|
|
// var vstat [...]t
|
|
|
|
|
// 2. assign (data statements) the constant part
|
|
|
|
|
// vstat = constpart{}
|
|
|
|
|
// 3. make an auto pointer to array and allocate heap to it
|
|
|
|
|
// var vauto *[...]t = new([...]t)
|
|
|
|
|
// 4. copy the static array to the auto array
|
|
|
|
|
// *vauto = vstat
|
|
|
|
|
// 5. assign slice of allocated heap to var
|
|
|
|
|
// var = [0:]*auto
|
|
|
|
|
// 6. for each dynamic part assign to the slice
|
|
|
|
|
// var[i] = dynamic part
|
|
|
|
|
//
|
|
|
|
|
// an optimization is done if there is no constant part
|
|
|
|
|
// 3. var vauto *[...]t = new([...]t)
|
|
|
|
|
// 5. var = [0:]*auto
|
|
|
|
|
// 6. var[i] = dynamic part
|
|
|
|
|
|
|
|
|
|
// if the literal contains constants,
|
|
|
|
|
// make static initialized array (1),(2)
|
2015-03-02 14:22:05 -05:00
|
|
|
var vstat *Node
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
mode := getdyn(n, 1)
|
2015-02-13 14:40:36 -05:00
|
|
|
if mode&MODECONST != 0 {
|
|
|
|
|
vstat = staticname(t, ctxt)
|
|
|
|
|
arraylit(ctxt, 1, n, vstat, init)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make new auto *array (3 declare)
|
2015-02-23 16:07:24 -05:00
|
|
|
vauto := temp(Ptrto(t))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// set auto to point at new temp or heap (3 assign)
|
2015-02-23 16:07:24 -05:00
|
|
|
var a *Node
|
2015-05-26 23:05:35 -04:00
|
|
|
if x := prealloc[n]; x != nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
// temp allocated during order.c for dddarg
|
2015-05-26 23:05:35 -04:00
|
|
|
x.Type = t
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if vstat == nil {
|
2015-05-26 23:05:35 -04:00
|
|
|
a = Nod(OAS, x, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
*init = list(*init, a) // zero new temp
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-26 23:05:35 -04:00
|
|
|
a = Nod(OADDR, x, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else if n.Esc == EscNone {
|
|
|
|
|
a = temp(t)
|
|
|
|
|
if vstat == nil {
|
|
|
|
|
a = Nod(OAS, temp(t), nil)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
*init = list(*init, a) // zero new temp
|
|
|
|
|
a = a.Left
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a = Nod(OADDR, a, nil)
|
|
|
|
|
} else {
|
|
|
|
|
a = Nod(ONEW, nil, nil)
|
|
|
|
|
a.List = list1(typenod(t))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a = Nod(OAS, vauto, a)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
|
|
|
|
if vstat != nil {
|
|
|
|
|
// copy static to heap (4)
|
|
|
|
|
a = Nod(OIND, vauto, nil)
|
|
|
|
|
|
|
|
|
|
a = Nod(OAS, a, vstat)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make slice out of heap (5)
|
|
|
|
|
a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil)))
|
|
|
|
|
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
orderstmtinplace(&a)
|
|
|
|
|
walkstmt(&a)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
|
|
|
|
// put dynamics into slice (6)
|
2015-02-23 16:07:24 -05:00
|
|
|
var value *Node
|
|
|
|
|
var r *Node
|
|
|
|
|
var index *Node
|
|
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
r = l.N
|
|
|
|
|
if r.Op != OKEY {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("slicelit: rhs not OKEY: %v", r)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
index = r.Left
|
|
|
|
|
value = r.Right
|
|
|
|
|
a = Nod(OINDEX, var_, index)
|
2015-02-17 22:13:49 -05:00
|
|
|
a.Bounded = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// TODO need to check bounds?
|
|
|
|
|
|
|
|
|
|
switch value.Op {
|
|
|
|
|
case OARRAYLIT:
|
|
|
|
|
if value.Type.Bound < 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
arraylit(ctxt, 2, value, a, init)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
|
structlit(ctxt, 2, value, a, init)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isliteral(index) && isliteral(value) {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build list of var[c] = expr
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(value)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nod(OAS, a, value)
|
|
|
|
|
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
orderstmtinplace(&a)
|
|
|
|
|
walkstmt(&a)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
|
|
|
|
|
var r *Node
|
|
|
|
|
var index *Node
|
|
|
|
|
var value *Node
|
|
|
|
|
|
|
|
|
|
ctxt = 0
|
|
|
|
|
|
|
|
|
|
// make the map var
|
2015-02-23 16:07:24 -05:00
|
|
|
nerr := nerrors
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
a := Nod(OMAKE, nil, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
a.List = list1(typenod(n.Type))
|
|
|
|
|
litas(var_, a, init)
|
|
|
|
|
|
|
|
|
|
// count the initializers
|
2015-02-23 16:07:24 -05:00
|
|
|
b := int64(0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
r = l.N
|
|
|
|
|
|
|
|
|
|
if r.Op != OKEY {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("maplit: rhs not OKEY: %v", r)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
index = r.Left
|
|
|
|
|
value = r.Right
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isliteral(index) && isliteral(value) {
|
2015-02-13 14:40:36 -05:00
|
|
|
b++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if b != 0 {
|
|
|
|
|
// build type [count]struct { a Tindex, b Tvalue }
|
2015-02-23 16:07:24 -05:00
|
|
|
t := n.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
tk := t.Down
|
|
|
|
|
tv := t.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
symb := Lookup("b")
|
2015-02-13 14:40:36 -05:00
|
|
|
t = typ(TFIELD)
|
|
|
|
|
t.Type = tv
|
|
|
|
|
t.Sym = symb
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
syma := Lookup("a")
|
|
|
|
|
t1 := t
|
2015-02-13 14:40:36 -05:00
|
|
|
t = typ(TFIELD)
|
|
|
|
|
t.Type = tk
|
|
|
|
|
t.Sym = syma
|
|
|
|
|
t.Down = t1
|
|
|
|
|
|
|
|
|
|
t1 = t
|
|
|
|
|
t = typ(TSTRUCT)
|
|
|
|
|
t.Type = t1
|
|
|
|
|
|
|
|
|
|
t1 = t
|
|
|
|
|
t = typ(TARRAY)
|
|
|
|
|
t.Bound = b
|
|
|
|
|
t.Type = t1
|
|
|
|
|
|
|
|
|
|
dowidth(t)
|
|
|
|
|
|
|
|
|
|
// make and initialize static array
|
2015-02-23 16:07:24 -05:00
|
|
|
vstat := staticname(t, ctxt)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
b := int64(0)
|
|
|
|
|
var index *Node
|
|
|
|
|
var r *Node
|
|
|
|
|
var value *Node
|
|
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
r = l.N
|
|
|
|
|
|
|
|
|
|
if r.Op != OKEY {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("maplit: rhs not OKEY: %v", r)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
index = r.Left
|
|
|
|
|
value = r.Right
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isliteral(index) && isliteral(value) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// build vstat[b].a = key;
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(index)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nodintconst(b)
|
|
|
|
|
|
|
|
|
|
a = Nod(OINDEX, vstat, a)
|
|
|
|
|
a = Nod(ODOT, a, newname(syma))
|
|
|
|
|
a = Nod(OAS, a, index)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
a.Dodata = 2
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
|
|
|
|
// build vstat[b].b = value;
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(value)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nodintconst(b)
|
|
|
|
|
|
|
|
|
|
a = Nod(OINDEX, vstat, a)
|
|
|
|
|
a = Nod(ODOT, a, newname(symb))
|
|
|
|
|
a = Nod(OAS, a, value)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
a.Dodata = 2
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
|
|
|
|
b++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// loop adding structure elements to map
|
|
|
|
|
// for i = 0; i < len(vstat); i++ {
|
|
|
|
|
// map[vstat[i].a] = vstat[i].b
|
|
|
|
|
// }
|
|
|
|
|
index = temp(Types[TINT])
|
|
|
|
|
|
|
|
|
|
a = Nod(OINDEX, vstat, index)
|
2015-02-17 22:13:49 -05:00
|
|
|
a.Bounded = true
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nod(ODOT, a, newname(symb))
|
|
|
|
|
|
|
|
|
|
r = Nod(OINDEX, vstat, index)
|
2015-02-17 22:13:49 -05:00
|
|
|
r.Bounded = true
|
2015-02-13 14:40:36 -05:00
|
|
|
r = Nod(ODOT, r, newname(syma))
|
|
|
|
|
r = Nod(OINDEX, var_, r)
|
|
|
|
|
|
|
|
|
|
r = Nod(OAS, r, a)
|
|
|
|
|
|
|
|
|
|
a = Nod(OFOR, nil, nil)
|
|
|
|
|
a.Nbody = list1(r)
|
|
|
|
|
|
|
|
|
|
a.Ninit = list1(Nod(OAS, index, Nodintconst(0)))
|
2015-05-26 21:30:20 -04:00
|
|
|
a.Left = Nod(OLT, index, Nodintconst(t.Bound))
|
2015-05-22 01:16:52 -04:00
|
|
|
a.Right = Nod(OAS, index, Nod(OADD, index, Nodintconst(1)))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkstmt(&a)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// put in dynamic entries one-at-a-time
|
2015-03-02 14:22:05 -05:00
|
|
|
var key *Node
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-02 14:22:05 -05:00
|
|
|
var val *Node
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
r = l.N
|
|
|
|
|
|
|
|
|
|
if r.Op != OKEY {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("maplit: rhs not OKEY: %v", r)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
index = r.Left
|
|
|
|
|
value = r.Right
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isliteral(index) && isliteral(value) {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build list of var[c] = expr.
|
|
|
|
|
// use temporary so that mapassign1 can have addressable key, val.
|
|
|
|
|
if key == nil {
|
|
|
|
|
key = temp(var_.Type.Down)
|
|
|
|
|
val = temp(var_.Type.Type)
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(r.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nod(OAS, key, r.Left)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkstmt(&a)
|
|
|
|
|
*init = list(*init, a)
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(r.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nod(OAS, val, r.Right)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkstmt(&a)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
2015-06-29 16:30:19 -04:00
|
|
|
setlineno(val)
|
2015-02-13 14:40:36 -05:00
|
|
|
a = Nod(OAS, Nod(OINDEX, var_, key), val)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkstmt(&a)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
|
|
|
|
if nerr != nerrors {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if key != nil {
|
|
|
|
|
a = Nod(OVARKILL, key, nil)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
a = Nod(OVARKILL, val, nil)
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
|
2015-02-23 16:07:24 -05:00
|
|
|
t := n.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
switch n.Op {
|
|
|
|
|
default:
|
|
|
|
|
Fatal("anylit: not lit")
|
|
|
|
|
|
|
|
|
|
case OPTRLIT:
|
2015-03-01 07:54:01 +00:00
|
|
|
if !Isptr[t.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("anylit: not ptr")
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var r *Node
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Right != nil {
|
|
|
|
|
r = Nod(OADDR, n.Right, nil)
|
|
|
|
|
typecheck(&r, Erv)
|
|
|
|
|
} else {
|
|
|
|
|
r = Nod(ONEW, nil, nil)
|
|
|
|
|
r.Typecheck = 1
|
|
|
|
|
r.Type = t
|
|
|
|
|
r.Esc = n.Esc
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
walkexpr(&r, init)
|
2015-02-23 16:07:24 -05:00
|
|
|
a := Nod(OAS, var_, r)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
|
|
|
|
var_ = Nod(OIND, var_, nil)
|
|
|
|
|
typecheck(&var_, Erv|Easgn)
|
|
|
|
|
anylit(ctxt, n.Left, var_, init)
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
|
if t.Etype != TSTRUCT {
|
|
|
|
|
Fatal("anylit: not struct")
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if simplename(var_) && count(n.List) > 4 {
|
2015-02-13 14:40:36 -05:00
|
|
|
if ctxt == 0 {
|
|
|
|
|
// lay out static data
|
2015-02-23 16:07:24 -05:00
|
|
|
vstat := staticname(t, ctxt)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
structlit(ctxt, 1, n, vstat, init)
|
|
|
|
|
|
|
|
|
|
// copy static to var
|
2015-02-23 16:07:24 -05:00
|
|
|
a := Nod(OAS, var_, vstat)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
|
|
|
|
// add expressions to automatic
|
|
|
|
|
structlit(ctxt, 2, n, var_, init)
|
|
|
|
|
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
structlit(ctxt, 1, n, var_, init)
|
|
|
|
|
structlit(ctxt, 2, n, var_, init)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// initialize of not completely specified
|
2015-02-17 22:13:49 -05:00
|
|
|
if simplename(var_) || count(n.List) < structcount(t) {
|
2015-02-23 16:07:24 -05:00
|
|
|
a := Nod(OAS, var_, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
structlit(ctxt, 3, n, var_, init)
|
|
|
|
|
|
|
|
|
|
case OARRAYLIT:
|
|
|
|
|
if t.Etype != TARRAY {
|
|
|
|
|
Fatal("anylit: not array")
|
|
|
|
|
}
|
|
|
|
|
if t.Bound < 0 {
|
|
|
|
|
slicelit(ctxt, n, var_, init)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if simplename(var_) && count(n.List) > 4 {
|
2015-02-13 14:40:36 -05:00
|
|
|
if ctxt == 0 {
|
|
|
|
|
// lay out static data
|
2015-02-23 16:07:24 -05:00
|
|
|
vstat := staticname(t, ctxt)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
arraylit(1, 1, n, vstat, init)
|
|
|
|
|
|
|
|
|
|
// copy static to automatic
|
2015-02-23 16:07:24 -05:00
|
|
|
a := Nod(OAS, var_, vstat)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
|
|
|
|
|
// add expressions to automatic
|
|
|
|
|
arraylit(ctxt, 2, n, var_, init)
|
|
|
|
|
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arraylit(ctxt, 1, n, var_, init)
|
|
|
|
|
arraylit(ctxt, 2, n, var_, init)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// initialize of not completely specified
|
2015-02-17 22:13:49 -05:00
|
|
|
if simplename(var_) || int64(count(n.List)) < t.Bound {
|
2015-02-23 16:07:24 -05:00
|
|
|
a := Nod(OAS, var_, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
typecheck(&a, Etop)
|
|
|
|
|
walkexpr(&a, init)
|
|
|
|
|
*init = list(*init, a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arraylit(ctxt, 3, n, var_, init)
|
|
|
|
|
|
|
|
|
|
case OMAPLIT:
|
|
|
|
|
if t.Etype != TMAP {
|
|
|
|
|
Fatal("anylit: not map")
|
|
|
|
|
}
|
|
|
|
|
maplit(ctxt, n, var_, init)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func oaslit(n *Node, init **NodeList) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Left == nil || n.Right == nil {
|
2015-03-02 12:35:15 -05:00
|
|
|
// not a special composit literal assignment
|
|
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Left.Type == nil || n.Right.Type == nil {
|
2015-03-02 12:35:15 -05:00
|
|
|
// not a special composit literal assignment
|
|
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if !simplename(n.Left) {
|
2015-03-02 12:35:15 -05:00
|
|
|
// not a special composit literal assignment
|
|
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if !Eqtype(n.Left.Type, n.Right.Type) {
|
2015-03-02 12:35:15 -05:00
|
|
|
// not a special composit literal assignment
|
|
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// context is init() function.
|
|
|
|
|
// implies generated data executed
|
|
|
|
|
// exactly once and not subject to races.
|
2015-03-02 12:35:15 -05:00
|
|
|
ctxt := 0
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// if(n->dodata == 1)
|
|
|
|
|
// ctxt = 1;
|
|
|
|
|
|
|
|
|
|
switch n.Right.Op {
|
|
|
|
|
default:
|
2015-03-02 12:35:15 -05:00
|
|
|
// not a special composit literal assignment
|
|
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OSTRUCTLIT, OARRAYLIT, OMAPLIT:
|
2015-02-17 22:13:49 -05:00
|
|
|
if vmatch1(n.Left, n.Right) {
|
2015-03-02 12:35:15 -05:00
|
|
|
// not a special composit literal assignment
|
|
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
anylit(ctxt, n.Right, n.Left, init)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n.Op = OEMPTY
|
2015-05-26 21:30:20 -04:00
|
|
|
n.Right = nil
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getlit(lit *Node) int {
|
2015-02-17 22:13:49 -05:00
|
|
|
if Smallintconst(lit) {
|
2015-05-27 00:47:05 -04:00
|
|
|
return int(Mpgetfix(lit.Val().U.(*Mpint)))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func stataddr(nam *Node, n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
2015-03-02 12:35:15 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
|
case ONAME:
|
|
|
|
|
*nam = *n
|
2015-04-02 19:58:37 -07:00
|
|
|
return n.Addable
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ODOT:
|
2015-02-17 22:13:49 -05:00
|
|
|
if !stataddr(nam, n.Left) {
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
nam.Xoffset += n.Xoffset
|
|
|
|
|
nam.Type = n.Type
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OINDEX:
|
|
|
|
|
if n.Left.Type.Bound < 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if !stataddr(nam, n.Left) {
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
l := getlit(n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
if l < 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for overflow.
|
|
|
|
|
if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
nam.Xoffset += int64(l) * n.Type.Width
|
|
|
|
|
nam.Type = n.Type
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func initplan(n *Node) {
|
2015-05-22 01:16:52 -04:00
|
|
|
if initplans[n] != nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
p := new(InitPlan)
|
2015-05-22 01:16:52 -04:00
|
|
|
initplans[n] = p
|
2015-02-13 14:40:36 -05:00
|
|
|
switch n.Op {
|
|
|
|
|
default:
|
|
|
|
|
Fatal("initplan")
|
|
|
|
|
|
|
|
|
|
case OARRAYLIT:
|
2015-02-23 16:07:24 -05:00
|
|
|
var a *Node
|
|
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
a = l.N
|
2015-02-17 22:13:49 -05:00
|
|
|
if a.Op != OKEY || !Smallintconst(a.Left) {
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("initplan arraylit")
|
|
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val().U.(*Mpint)), nil, a.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
2015-02-23 16:07:24 -05:00
|
|
|
var a *Node
|
|
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
a = l.N
|
|
|
|
|
if a.Op != OKEY || a.Left.Type == nil {
|
|
|
|
|
Fatal("initplan structlit")
|
|
|
|
|
}
|
|
|
|
|
addvalue(p, a.Left.Type.Width, nil, a.Right)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OMAPLIT:
|
2015-02-23 16:07:24 -05:00
|
|
|
var a *Node
|
|
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
a = l.N
|
|
|
|
|
if a.Op != OKEY {
|
|
|
|
|
Fatal("initplan maplit")
|
|
|
|
|
}
|
|
|
|
|
addvalue(p, -1, a.Left, a.Right)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func addvalue(p *InitPlan, xoffset int64, key *Node, n *Node) {
|
|
|
|
|
// special case: zero can be dropped entirely
|
2015-02-17 22:13:49 -05:00
|
|
|
if iszero(n) {
|
2015-02-13 14:40:36 -05:00
|
|
|
p.Zero += n.Type.Width
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// special case: inline struct and array (not slice) literals
|
2015-02-17 22:13:49 -05:00
|
|
|
if isvaluelit(n) {
|
2015-02-13 14:40:36 -05:00
|
|
|
initplan(n)
|
2015-05-22 01:16:52 -04:00
|
|
|
q := initplans[n]
|
2015-02-23 16:07:24 -05:00
|
|
|
var e *InitEntry
|
|
|
|
|
for i := 0; i < len(q.E); i++ {
|
2015-02-13 14:40:36 -05:00
|
|
|
e = entry(p)
|
|
|
|
|
*e = q.E[i]
|
|
|
|
|
e.Xoffset += xoffset
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add to plan
|
|
|
|
|
if n.Op == OLITERAL {
|
|
|
|
|
p.Lit += n.Type.Width
|
|
|
|
|
} else {
|
|
|
|
|
p.Expr += n.Type.Width
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
e := entry(p)
|
2015-02-13 14:40:36 -05:00
|
|
|
e.Xoffset = xoffset
|
|
|
|
|
e.Expr = n
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func iszero(n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch n.Op {
|
|
|
|
|
case OLITERAL:
|
2015-05-27 00:47:05 -04:00
|
|
|
switch n.Val().Ctype() {
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
|
|
|
|
Dump("unexpected literal", n)
|
|
|
|
|
Fatal("iszero")
|
|
|
|
|
|
|
|
|
|
case CTNIL:
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case CTSTR:
|
2015-05-27 00:47:05 -04:00
|
|
|
return n.Val().U.(string) == ""
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case CTBOOL:
|
2015-05-27 00:47:05 -04:00
|
|
|
return !n.Val().U.(bool)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE:
|
2015-05-27 00:47:05 -04:00
|
|
|
return mpcmpfixc(n.Val().U.(*Mpint), 0) == 0
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case CTFLT:
|
2015-05-27 00:47:05 -04:00
|
|
|
return mpcmpfltc(n.Val().U.(*Mpflt), 0) == 0
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case CTCPLX:
|
2015-05-27 00:47:05 -04:00
|
|
|
return mpcmpfltc(&n.Val().U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&n.Val().U.(*Mpcplx).Imag, 0) == 0
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OARRAYLIT:
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isslice(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
|
|
// fall through
|
|
|
|
|
case OSTRUCTLIT:
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-17 22:13:49 -05:00
|
|
|
if !iszero(l.N.Right) {
|
|
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func isvaluelit(n *Node) bool {
|
|
|
|
|
return (n.Op == OARRAYLIT && Isfixedarray(n.Type)) || n.Op == OSTRUCTLIT
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func entry(p *InitPlan) *InitEntry {
|
|
|
|
|
p.E = append(p.E, InitEntry{})
|
|
|
|
|
return &p.E[len(p.E)-1]
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func gen_as_init(n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
var nr *Node
|
|
|
|
|
var nl *Node
|
|
|
|
|
var nam Node
|
|
|
|
|
|
|
|
|
|
if n.Dodata == 0 {
|
|
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nr = n.Right
|
|
|
|
|
nl = n.Left
|
|
|
|
|
if nr == nil {
|
2015-02-23 16:07:24 -05:00
|
|
|
var nam Node
|
2015-02-17 22:13:49 -05:00
|
|
|
if !stataddr(&nam, nl) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
if nam.Class != PEXTERN {
|
|
|
|
|
goto no
|
|
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nr.Type == nil || !Eqtype(nl.Type, nr.Type) {
|
|
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if !stataddr(&nam, nl) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nam.Class != PEXTERN {
|
|
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch nr.Op {
|
|
|
|
|
default:
|
|
|
|
|
goto no
|
|
|
|
|
|
|
|
|
|
case OCONVNOP:
|
|
|
|
|
nr = nr.Left
|
|
|
|
|
if nr == nil || nr.Op != OSLICEARR {
|
|
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
|
|
// fall through
|
|
|
|
|
case OSLICEARR:
|
|
|
|
|
if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil {
|
|
|
|
|
nr = nr.Left
|
2015-03-02 12:35:15 -05:00
|
|
|
gused(nil) // in case the data is the dest of a goto
|
|
|
|
|
nl := nr
|
|
|
|
|
if nr == nil || nr.Op != OADDR {
|
|
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
nr = nr.Left
|
|
|
|
|
if nr == nil || nr.Op != ONAME {
|
|
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// nr is the array being converted to a slice
|
|
|
|
|
if nr.Type == nil || nr.Type.Etype != TARRAY || nr.Type.Bound < 0 {
|
|
|
|
|
goto no
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nam.Xoffset += int64(Array_array)
|
|
|
|
|
gdata(&nam, nl, int(Types[Tptr].Width))
|
|
|
|
|
|
|
|
|
|
nam.Xoffset += int64(Array_nel) - int64(Array_array)
|
|
|
|
|
var nod1 Node
|
|
|
|
|
Nodconst(&nod1, Types[TINT], nr.Type.Bound)
|
|
|
|
|
gdata(&nam, &nod1, Widthint)
|
|
|
|
|
|
|
|
|
|
nam.Xoffset += int64(Array_cap) - int64(Array_nel)
|
|
|
|
|
gdata(&nam, &nod1, Widthint)
|
|
|
|
|
|
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto no
|
|
|
|
|
|
|
|
|
|
case OLITERAL:
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch nr.Type.Etype {
|
|
|
|
|
default:
|
|
|
|
|
goto no
|
|
|
|
|
|
|
|
|
|
case TBOOL,
|
|
|
|
|
TINT8,
|
|
|
|
|
TUINT8,
|
|
|
|
|
TINT16,
|
|
|
|
|
TUINT16,
|
|
|
|
|
TINT32,
|
|
|
|
|
TUINT32,
|
|
|
|
|
TINT64,
|
|
|
|
|
TUINT64,
|
|
|
|
|
TINT,
|
|
|
|
|
TUINT,
|
|
|
|
|
TUINTPTR,
|
|
|
|
|
TPTR32,
|
|
|
|
|
TPTR64,
|
|
|
|
|
TFLOAT32,
|
|
|
|
|
TFLOAT64:
|
|
|
|
|
gdata(&nam, nr, int(nr.Type.Width))
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case TCOMPLEX64, TCOMPLEX128:
|
2015-05-27 00:47:05 -04:00
|
|
|
gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TSTRING:
|
2015-05-27 00:47:05 -04:00
|
|
|
gdatastring(&nam, nr.Val().U.(string))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
no:
|
|
|
|
|
if n.Dodata == 2 {
|
|
|
|
|
Dump("\ngen_as_init", n)
|
|
|
|
|
Fatal("gen_as_init couldnt make data statement")
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|