var knownFormats = map[string]string{
"*bytes.Buffer %s": "",
"*cmd/compile/internal/gc.EscLocation %v": "",
- "*cmd/compile/internal/gc.Node %#v": "",
- "*cmd/compile/internal/gc.Node %+S": "",
- "*cmd/compile/internal/gc.Node %+v": "",
- "*cmd/compile/internal/gc.Node %L": "",
- "*cmd/compile/internal/gc.Node %S": "",
- "*cmd/compile/internal/gc.Node %j": "",
- "*cmd/compile/internal/gc.Node %p": "",
- "*cmd/compile/internal/gc.Node %v": "",
+ "*cmd/compile/internal/ir.Node %#v": "",
+ "*cmd/compile/internal/ir.Node %+S": "",
+ "*cmd/compile/internal/ir.Node %+v": "",
+ "*cmd/compile/internal/ir.Node %L": "",
+ "*cmd/compile/internal/ir.Node %S": "",
+ "*cmd/compile/internal/ir.Node %j": "",
+ "*cmd/compile/internal/ir.Node %p": "",
+ "*cmd/compile/internal/ir.Node %v": "",
"*cmd/compile/internal/ssa.Block %s": "",
"*cmd/compile/internal/ssa.Block %v": "",
"*cmd/compile/internal/ssa.Func %s": "",
"byte %q": "",
"byte %v": "",
"cmd/compile/internal/arm.shift %d": "",
- "cmd/compile/internal/gc.Class %d": "",
- "cmd/compile/internal/gc.Class %s": "",
- "cmd/compile/internal/gc.Class %v": "",
- "cmd/compile/internal/gc.Nodes %#v": "",
- "cmd/compile/internal/gc.Nodes %+v": "",
- "cmd/compile/internal/gc.Nodes %.v": "",
- "cmd/compile/internal/gc.Nodes %v": "",
- "cmd/compile/internal/gc.Op %#v": "",
- "cmd/compile/internal/gc.Op %v": "",
- "cmd/compile/internal/gc.fmtMode %d": "",
"cmd/compile/internal/gc.initKind %d": "",
"cmd/compile/internal/gc.itag %v": "",
+ "cmd/compile/internal/ir.Class %d": "",
+ "cmd/compile/internal/ir.Class %s": "",
+ "cmd/compile/internal/ir.Class %v": "",
+ "cmd/compile/internal/ir.FmtMode %d": "",
+ "cmd/compile/internal/ir.Nodes %#v": "",
+ "cmd/compile/internal/ir.Nodes %+v": "",
+ "cmd/compile/internal/ir.Nodes %.v": "",
+ "cmd/compile/internal/ir.Nodes %v": "",
+ "cmd/compile/internal/ir.Op %#v": "",
+ "cmd/compile/internal/ir.Op %v": "",
"cmd/compile/internal/ssa.BranchPrediction %d": "",
"cmd/compile/internal/ssa.Edge %v": "",
"cmd/compile/internal/ssa.GCNode %v": "",
"interface{} %q": "",
"interface{} %s": "",
"interface{} %v": "",
- "map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
- "map[*cmd/compile/internal/gc.Node][]*cmd/compile/internal/gc.Node %v": "",
+ "map[*cmd/compile/internal/ir.Node]*cmd/compile/internal/ssa.Value %v": "",
+ "map[*cmd/compile/internal/ir.Node][]*cmd/compile/internal/ir.Node %v": "",
"map[cmd/compile/internal/ssa.ID]uint32 %v": "",
"map[int64]uint32 %v": "",
"math/big.Accuracy %s": "",
"cmd/compile/internal/base"
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
case *obj.LSym:
wantreg = "SB"
gc.AddAux(&p.From, v)
- case *gc.Node:
+ case *ir.Node:
wantreg = "SP"
gc.AddAux(&p.From, v)
case nil:
"cmd/compile/internal/base"
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
case *obj.LSym:
wantreg = "SB"
gc.AddAux(&p.From, v)
- case *gc.Node:
+ case *ir.Node:
wantreg = "SP"
gc.AddAux(&p.From, v)
case nil:
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/obj"
"fmt"
switch t.Etype {
default:
return false
- case TINTER:
+ case types.TINTER:
return true
- case TARRAY:
+ case types.TARRAY:
return EqCanPanic(t.Elem())
- case TSTRUCT:
+ case types.TSTRUCT:
for _, f := range t.FieldSlice() {
if !f.Sym.IsBlank() && EqCanPanic(f.Type) {
return true
}
switch t.Etype {
- case TANY, TFORW:
+ case types.TANY, types.TFORW:
// will be defined later.
return ANOEQ, t
- case TINT8, TUINT8, TINT16, TUINT16,
- TINT32, TUINT32, TINT64, TUINT64,
- TINT, TUINT, TUINTPTR,
- TBOOL, TPTR,
- TCHAN, TUNSAFEPTR:
+ case types.TINT8, types.TUINT8, types.TINT16, types.TUINT16,
+ types.TINT32, types.TUINT32, types.TINT64, types.TUINT64,
+ types.TINT, types.TUINT, types.TUINTPTR,
+ types.TBOOL, types.TPTR,
+ types.TCHAN, types.TUNSAFEPTR:
return AMEM, nil
- case TFUNC, TMAP:
+ case types.TFUNC, types.TMAP:
return ANOEQ, t
- case TFLOAT32:
+ case types.TFLOAT32:
return AFLOAT32, nil
- case TFLOAT64:
+ case types.TFLOAT64:
return AFLOAT64, nil
- case TCOMPLEX64:
+ case types.TCOMPLEX64:
return ACPLX64, nil
- case TCOMPLEX128:
+ case types.TCOMPLEX128:
return ACPLX128, nil
- case TSTRING:
+ case types.TSTRING:
return ASTRING, nil
- case TINTER:
+ case types.TINTER:
if t.IsEmptyInterface() {
return ANILINTER, nil
}
return AINTER, nil
- case TSLICE:
+ case types.TSLICE:
return ANOEQ, t
- case TARRAY:
+ case types.TARRAY:
a, bad := algtype1(t.Elem())
switch a {
case AMEM:
return ASPECIAL, nil
- case TSTRUCT:
+ case types.TSTRUCT:
fields := t.FieldSlice()
// One-field struct is same as that one field alone.
}
base.Pos = autogeneratedPos // less confusing than end of input
- dclcontext = PEXTERN
+ dclcontext = ir.PEXTERN
// func sym(p *T, h uintptr) uintptr
- tfn := nod(OTFUNC, nil, nil)
+ tfn := ir.Nod(ir.OTFUNC, nil, nil)
tfn.List.Set2(
namedfield("p", types.NewPtr(t)),
- namedfield("h", types.Types[TUINTPTR]),
+ namedfield("h", types.Types[types.TUINTPTR]),
)
- tfn.Rlist.Set1(anonfield(types.Types[TUINTPTR]))
+ tfn.Rlist.Set1(anonfield(types.Types[types.TUINTPTR]))
fn := dclfunc(sym, tfn)
- np := asNode(tfn.Type.Params().Field(0).Nname)
- nh := asNode(tfn.Type.Params().Field(1).Nname)
+ np := ir.AsNode(tfn.Type.Params().Field(0).Nname)
+ nh := ir.AsNode(tfn.Type.Params().Field(1).Nname)
switch t.Etype {
case types.TARRAY:
// pure memory.
hashel := hashfor(t.Elem())
- n := nod(ORANGE, nil, nod(ODEREF, np, nil))
- ni := newname(lookup("i"))
- ni.Type = types.Types[TINT]
+ n := ir.Nod(ir.ORANGE, nil, ir.Nod(ir.ODEREF, np, nil))
+ ni := NewName(lookup("i"))
+ ni.Type = types.Types[types.TINT]
n.List.Set1(ni)
n.SetColas(true)
colasdefn(n.List.Slice(), n)
ni = n.List.First()
// h = hashel(&p[i], h)
- call := nod(OCALL, hashel, nil)
+ call := ir.Nod(ir.OCALL, hashel, nil)
- nx := nod(OINDEX, np, ni)
+ nx := ir.Nod(ir.OINDEX, np, ni)
nx.SetBounded(true)
- na := nod(OADDR, nx, nil)
+ na := ir.Nod(ir.OADDR, nx, nil)
call.List.Append(na)
call.List.Append(nh)
- n.Nbody.Append(nod(OAS, nh, call))
+ n.Nbody.Append(ir.Nod(ir.OAS, nh, call))
fn.Nbody.Append(n)
// Hash non-memory fields with appropriate hash function.
if !IsRegularMemory(f.Type) {
hashel := hashfor(f.Type)
- call := nod(OCALL, hashel, nil)
- nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
- na := nod(OADDR, nx, nil)
+ call := ir.Nod(ir.OCALL, hashel, nil)
+ nx := nodSym(ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
+ na := ir.Nod(ir.OADDR, nx, nil)
call.List.Append(na)
call.List.Append(nh)
- fn.Nbody.Append(nod(OAS, nh, call))
+ fn.Nbody.Append(ir.Nod(ir.OAS, nh, call))
i++
continue
}
// h = hashel(&p.first, size, h)
hashel := hashmem(f.Type)
- call := nod(OCALL, hashel, nil)
- nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
- na := nod(OADDR, nx, nil)
+ call := ir.Nod(ir.OCALL, hashel, nil)
+ nx := nodSym(ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
+ na := ir.Nod(ir.OADDR, nx, nil)
call.List.Append(na)
call.List.Append(nh)
call.List.Append(nodintconst(size))
- fn.Nbody.Append(nod(OAS, nh, call))
+ fn.Nbody.Append(ir.Nod(ir.OAS, nh, call))
i = next
}
}
- r := nod(ORETURN, nil, nil)
+ r := ir.Nod(ir.ORETURN, nil, nil)
r.List.Append(nh)
fn.Nbody.Append(r)
if base.Flag.LowerR != 0 {
- dumplist("genhash body", fn.Nbody)
+ ir.DumpList("genhash body", fn.Nbody)
}
funcbody()
return closure
}
-func hashfor(t *types.Type) *Node {
+func hashfor(t *types.Type) *ir.Node {
var sym *types.Sym
switch a, _ := algtype1(t); a {
sym = typesymprefix(".hash", t)
}
- n := newname(sym)
+ n := NewName(sym)
setNodeNameFunc(n)
- n.Type = functype(nil, []*Node{
+ n.Type = functype(nil, []*ir.Node{
anonfield(types.NewPtr(t)),
- anonfield(types.Types[TUINTPTR]),
- }, []*Node{
- anonfield(types.Types[TUINTPTR]),
+ anonfield(types.Types[types.TUINTPTR]),
+ }, []*ir.Node{
+ anonfield(types.Types[types.TUINTPTR]),
})
return n
}
// Autogenerate code for equality of structs and arrays.
base.Pos = autogeneratedPos // less confusing than end of input
- dclcontext = PEXTERN
+ dclcontext = ir.PEXTERN
// func sym(p, q *T) bool
- tfn := nod(OTFUNC, nil, nil)
+ tfn := ir.Nod(ir.OTFUNC, nil, nil)
tfn.List.Set2(
namedfield("p", types.NewPtr(t)),
namedfield("q", types.NewPtr(t)),
)
- tfn.Rlist.Set1(namedfield("r", types.Types[TBOOL]))
+ tfn.Rlist.Set1(namedfield("r", types.Types[types.TBOOL]))
fn := dclfunc(sym, tfn)
- np := asNode(tfn.Type.Params().Field(0).Nname)
- nq := asNode(tfn.Type.Params().Field(1).Nname)
- nr := asNode(tfn.Type.Results().Field(0).Nname)
+ np := ir.AsNode(tfn.Type.Params().Field(0).Nname)
+ nq := ir.AsNode(tfn.Type.Params().Field(1).Nname)
+ nr := ir.AsNode(tfn.Type.Results().Field(0).Nname)
// Label to jump to if an equality test fails.
neq := autolabel(".neq")
default:
base.Fatalf("geneq %v", t)
- case TARRAY:
+ case types.TARRAY:
nelem := t.NumElem()
// checkAll generates code to check the equality of all array elements.
//
// TODO(josharian): consider doing some loop unrolling
// for larger nelem as well, processing a few elements at a time in a loop.
- checkAll := func(unroll int64, last bool, eq func(pi, qi *Node) *Node) {
+ checkAll := func(unroll int64, last bool, eq func(pi, qi *ir.Node) *ir.Node) {
// checkIdx generates a node to check for equality at index i.
- checkIdx := func(i *Node) *Node {
+ checkIdx := func(i *ir.Node) *ir.Node {
// pi := p[i]
- pi := nod(OINDEX, np, i)
+ pi := ir.Nod(ir.OINDEX, np, i)
pi.SetBounded(true)
pi.Type = t.Elem()
// qi := q[i]
- qi := nod(OINDEX, nq, i)
+ qi := ir.Nod(ir.OINDEX, nq, i)
qi.SetBounded(true)
qi.Type = t.Elem()
return eq(pi, qi)
// Generate a series of checks.
for i := int64(0); i < nelem; i++ {
// if check {} else { goto neq }
- nif := nod(OIF, checkIdx(nodintconst(i)), nil)
- nif.Rlist.Append(nodSym(OGOTO, nil, neq))
+ nif := ir.Nod(ir.OIF, checkIdx(nodintconst(i)), nil)
+ nif.Rlist.Append(nodSym(ir.OGOTO, nil, neq))
fn.Nbody.Append(nif)
}
if last {
- fn.Nbody.Append(nod(OAS, nr, checkIdx(nodintconst(nelem))))
+ fn.Nbody.Append(ir.Nod(ir.OAS, nr, checkIdx(nodintconst(nelem))))
}
} else {
// Generate a for loop.
// for i := 0; i < nelem; i++
- i := temp(types.Types[TINT])
- init := nod(OAS, i, nodintconst(0))
- cond := nod(OLT, i, nodintconst(nelem))
- post := nod(OAS, i, nod(OADD, i, nodintconst(1)))
- loop := nod(OFOR, cond, post)
+ i := temp(types.Types[types.TINT])
+ init := ir.Nod(ir.OAS, i, nodintconst(0))
+ cond := ir.Nod(ir.OLT, i, nodintconst(nelem))
+ post := ir.Nod(ir.OAS, i, ir.Nod(ir.OADD, i, nodintconst(1)))
+ loop := ir.Nod(ir.OFOR, cond, post)
loop.Ninit.Append(init)
// if eq(pi, qi) {} else { goto neq }
- nif := nod(OIF, checkIdx(i), nil)
- nif.Rlist.Append(nodSym(OGOTO, nil, neq))
+ nif := ir.Nod(ir.OIF, checkIdx(i), nil)
+ nif.Rlist.Append(nodSym(ir.OGOTO, nil, neq))
loop.Nbody.Append(nif)
fn.Nbody.Append(loop)
if last {
- fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
+ fn.Nbody.Append(ir.Nod(ir.OAS, nr, nodbool(true)))
}
}
}
switch t.Elem().Etype {
- case TSTRING:
+ case types.TSTRING:
// Do two loops. First, check that all the lengths match (cheap).
// Second, check that all the contents match (expensive).
// TODO: when the array size is small, unroll the length match checks.
- checkAll(3, false, func(pi, qi *Node) *Node {
+ checkAll(3, false, func(pi, qi *ir.Node) *ir.Node {
// Compare lengths.
eqlen, _ := eqstring(pi, qi)
return eqlen
})
- checkAll(1, true, func(pi, qi *Node) *Node {
+ checkAll(1, true, func(pi, qi *ir.Node) *ir.Node {
// Compare contents.
_, eqmem := eqstring(pi, qi)
return eqmem
})
- case TFLOAT32, TFLOAT64:
- checkAll(2, true, func(pi, qi *Node) *Node {
+ case types.TFLOAT32, types.TFLOAT64:
+ checkAll(2, true, func(pi, qi *ir.Node) *ir.Node {
// p[i] == q[i]
- return nod(OEQ, pi, qi)
+ return ir.Nod(ir.OEQ, pi, qi)
})
// TODO: pick apart structs, do them piecemeal too
default:
- checkAll(1, true, func(pi, qi *Node) *Node {
+ checkAll(1, true, func(pi, qi *ir.Node) *ir.Node {
// p[i] == q[i]
- return nod(OEQ, pi, qi)
+ return ir.Nod(ir.OEQ, pi, qi)
})
}
- case TSTRUCT:
+ case types.TSTRUCT:
// Build a list of conditions to satisfy.
// The conditions are a list-of-lists. Conditions are reorderable
// within each inner list. The outer lists must be evaluated in order.
- var conds [][]*Node
- conds = append(conds, []*Node{})
- and := func(n *Node) {
+ var conds [][]*ir.Node
+ conds = append(conds, []*ir.Node{})
+ and := func(n *ir.Node) {
i := len(conds) - 1
conds[i] = append(conds[i], n)
}
if !IsRegularMemory(f.Type) {
if EqCanPanic(f.Type) {
// Enforce ordering by starting a new set of reorderable conditions.
- conds = append(conds, []*Node{})
+ conds = append(conds, []*ir.Node{})
}
- p := nodSym(OXDOT, np, f.Sym)
- q := nodSym(OXDOT, nq, f.Sym)
+ p := nodSym(ir.OXDOT, np, f.Sym)
+ q := nodSym(ir.OXDOT, nq, f.Sym)
switch {
case f.Type.IsString():
eqlen, eqmem := eqstring(p, q)
and(eqlen)
and(eqmem)
default:
- and(nod(OEQ, p, q))
+ and(ir.Nod(ir.OEQ, p, q))
}
if EqCanPanic(f.Type) {
// Also enforce ordering after something that can panic.
- conds = append(conds, []*Node{})
+ conds = append(conds, []*ir.Node{})
}
i++
continue
// Sort conditions to put runtime calls last.
// Preserve the rest of the ordering.
- var flatConds []*Node
+ var flatConds []*ir.Node
for _, c := range conds {
- isCall := func(n *Node) bool {
- return n.Op == OCALL || n.Op == OCALLFUNC
+ isCall := func(n *ir.Node) bool {
+ return n.Op == ir.OCALL || n.Op == ir.OCALLFUNC
}
sort.SliceStable(c, func(i, j int) bool {
return !isCall(c[i]) && isCall(c[j])
}
if len(flatConds) == 0 {
- fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
+ fn.Nbody.Append(ir.Nod(ir.OAS, nr, nodbool(true)))
} else {
for _, c := range flatConds[:len(flatConds)-1] {
// if cond {} else { goto neq }
- n := nod(OIF, c, nil)
- n.Rlist.Append(nodSym(OGOTO, nil, neq))
+ n := ir.Nod(ir.OIF, c, nil)
+ n.Rlist.Append(nodSym(ir.OGOTO, nil, neq))
fn.Nbody.Append(n)
}
- fn.Nbody.Append(nod(OAS, nr, flatConds[len(flatConds)-1]))
+ fn.Nbody.Append(ir.Nod(ir.OAS, nr, flatConds[len(flatConds)-1]))
}
}
// ret:
// return
ret := autolabel(".ret")
- fn.Nbody.Append(nodSym(OLABEL, nil, ret))
- fn.Nbody.Append(nod(ORETURN, nil, nil))
+ fn.Nbody.Append(nodSym(ir.OLABEL, nil, ret))
+ fn.Nbody.Append(ir.Nod(ir.ORETURN, nil, nil))
// neq:
// r = false
// return (or goto ret)
- fn.Nbody.Append(nodSym(OLABEL, nil, neq))
- fn.Nbody.Append(nod(OAS, nr, nodbool(false)))
+ fn.Nbody.Append(nodSym(ir.OLABEL, nil, neq))
+ fn.Nbody.Append(ir.Nod(ir.OAS, nr, nodbool(false)))
if EqCanPanic(t) || hasCall(fn) {
// Epilogue is large, so share it with the equal case.
- fn.Nbody.Append(nodSym(OGOTO, nil, ret))
+ fn.Nbody.Append(nodSym(ir.OGOTO, nil, ret))
} else {
// Epilogue is small, so don't bother sharing.
- fn.Nbody.Append(nod(ORETURN, nil, nil))
+ fn.Nbody.Append(ir.Nod(ir.ORETURN, nil, nil))
}
// TODO(khr): the epilogue size detection condition above isn't perfect.
// We should really do a generic CL that shares epilogues across
// the board. See #24936.
if base.Flag.LowerR != 0 {
- dumplist("geneq body", fn.Nbody)
+ ir.DumpList("geneq body", fn.Nbody)
}
funcbody()
return closure
}
-func hasCall(n *Node) bool {
- if n.Op == OCALL || n.Op == OCALLFUNC {
+func hasCall(n *ir.Node) bool {
+ if n.Op == ir.OCALL || n.Op == ir.OCALLFUNC {
return true
}
if n.Left != nil && hasCall(n.Left) {
// eqfield returns the node
// p.field == q.field
-func eqfield(p *Node, q *Node, field *types.Sym) *Node {
- nx := nodSym(OXDOT, p, field)
- ny := nodSym(OXDOT, q, field)
- ne := nod(OEQ, nx, ny)
+func eqfield(p *ir.Node, q *ir.Node, field *types.Sym) *ir.Node {
+ nx := nodSym(ir.OXDOT, p, field)
+ ny := nodSym(ir.OXDOT, q, field)
+ ne := ir.Nod(ir.OEQ, nx, ny)
return ne
}
// memequal(s.ptr, t.ptr, len(s))
// which can be used to construct string equality comparison.
// eqlen must be evaluated before eqmem, and shortcircuiting is required.
-func eqstring(s, t *Node) (eqlen, eqmem *Node) {
- s = conv(s, types.Types[TSTRING])
- t = conv(t, types.Types[TSTRING])
- sptr := nod(OSPTR, s, nil)
- tptr := nod(OSPTR, t, nil)
- slen := conv(nod(OLEN, s, nil), types.Types[TUINTPTR])
- tlen := conv(nod(OLEN, t, nil), types.Types[TUINTPTR])
+func eqstring(s, t *ir.Node) (eqlen, eqmem *ir.Node) {
+ s = conv(s, types.Types[types.TSTRING])
+ t = conv(t, types.Types[types.TSTRING])
+ sptr := ir.Nod(ir.OSPTR, s, nil)
+ tptr := ir.Nod(ir.OSPTR, t, nil)
+ slen := conv(ir.Nod(ir.OLEN, s, nil), types.Types[types.TUINTPTR])
+ tlen := conv(ir.Nod(ir.OLEN, t, nil), types.Types[types.TUINTPTR])
fn := syslook("memequal")
- fn = substArgTypes(fn, types.Types[TUINT8], types.Types[TUINT8])
- call := nod(OCALL, fn, nil)
- call.List.Append(sptr, tptr, slen.copy())
+ fn = substArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
+ call := ir.Nod(ir.OCALL, fn, nil)
+ call.List.Append(sptr, tptr, ir.Copy(slen))
call = typecheck(call, ctxExpr|ctxMultiOK)
- cmp := nod(OEQ, slen, tlen)
+ cmp := ir.Nod(ir.OEQ, slen, tlen)
cmp = typecheck(cmp, ctxExpr)
- cmp.Type = types.Types[TBOOL]
+ cmp.Type = types.Types[types.TBOOL]
return cmp, call
}
// ifaceeq(s.tab, s.data, t.data) (or efaceeq(s.typ, s.data, t.data), as appropriate)
// which can be used to construct interface equality comparison.
// eqtab must be evaluated before eqdata, and shortcircuiting is required.
-func eqinterface(s, t *Node) (eqtab, eqdata *Node) {
+func eqinterface(s, t *ir.Node) (eqtab, eqdata *ir.Node) {
if !types.Identical(s.Type, t.Type) {
base.Fatalf("eqinterface %v %v", s.Type, t.Type)
}
// func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
// func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
- var fn *Node
+ var fn *ir.Node
if s.Type.IsEmptyInterface() {
fn = syslook("efaceeq")
} else {
fn = syslook("ifaceeq")
}
- stab := nod(OITAB, s, nil)
- ttab := nod(OITAB, t, nil)
- sdata := nod(OIDATA, s, nil)
- tdata := nod(OIDATA, t, nil)
- sdata.Type = types.Types[TUNSAFEPTR]
- tdata.Type = types.Types[TUNSAFEPTR]
+ stab := ir.Nod(ir.OITAB, s, nil)
+ ttab := ir.Nod(ir.OITAB, t, nil)
+ sdata := ir.Nod(ir.OIDATA, s, nil)
+ tdata := ir.Nod(ir.OIDATA, t, nil)
+ sdata.Type = types.Types[types.TUNSAFEPTR]
+ tdata.Type = types.Types[types.TUNSAFEPTR]
sdata.SetTypecheck(1)
tdata.SetTypecheck(1)
- call := nod(OCALL, fn, nil)
+ call := ir.Nod(ir.OCALL, fn, nil)
call.List.Append(stab, sdata, tdata)
call = typecheck(call, ctxExpr|ctxMultiOK)
- cmp := nod(OEQ, stab, ttab)
+ cmp := ir.Nod(ir.OEQ, stab, ttab)
cmp = typecheck(cmp, ctxExpr)
- cmp.Type = types.Types[TBOOL]
+ cmp.Type = types.Types[types.TBOOL]
return cmp, call
}
// eqmem returns the node
// memequal(&p.field, &q.field [, size])
-func eqmem(p *Node, q *Node, field *types.Sym, size int64) *Node {
- nx := nod(OADDR, nodSym(OXDOT, p, field), nil)
- ny := nod(OADDR, nodSym(OXDOT, q, field), nil)
+func eqmem(p *ir.Node, q *ir.Node, field *types.Sym, size int64) *ir.Node {
+ nx := ir.Nod(ir.OADDR, nodSym(ir.OXDOT, p, field), nil)
+ ny := ir.Nod(ir.OADDR, nodSym(ir.OXDOT, q, field), nil)
nx = typecheck(nx, ctxExpr)
ny = typecheck(ny, ctxExpr)
fn, needsize := eqmemfunc(size, nx.Type.Elem())
- call := nod(OCALL, fn, nil)
+ call := ir.Nod(ir.OCALL, fn, nil)
call.List.Append(nx)
call.List.Append(ny)
if needsize {
return call
}
-func eqmemfunc(size int64, t *types.Type) (fn *Node, needsize bool) {
+func eqmemfunc(size int64, t *types.Type) (fn *ir.Node, needsize bool) {
switch size {
default:
fn = syslook("memequal")
import (
"bytes"
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"fmt"
"sort"
o = Rnd(o, int64(f.Type.Align))
}
f.Offset = o
- if n := asNode(f.Nname); n != nil {
+ if n := ir.AsNode(f.Nname); n != nil {
// addrescapes has similar code to update these offsets.
// Usually addrescapes runs after widstruct,
// in which case we could drop this,
}
*path = append(*path, t)
- if p := asNode(t.Nod).Name.Param; p != nil && findTypeLoop(p.Ntype.Type, path) {
+ if p := ir.AsNode(t.Nod).Name.Param; p != nil && findTypeLoop(p.Ntype.Type, path) {
return true
}
*path = (*path)[:len(*path)-1]
// Anonymous type. Recurse on contained types.
switch t.Etype {
- case TARRAY:
+ case types.TARRAY:
if findTypeLoop(t.Elem(), path) {
return true
}
- case TSTRUCT:
+ case types.TSTRUCT:
for _, f := range t.Fields().Slice() {
if findTypeLoop(f.Type, path) {
return true
}
}
- case TINTER:
+ case types.TINTER:
for _, m := range t.Methods().Slice() {
if m.Type.IsInterface() { // embedded interface
if findTypeLoop(m.Type, path) {
defercheckwidth()
lno := base.Pos
- if asNode(t.Nod) != nil {
- base.Pos = asNode(t.Nod).Pos
+ if ir.AsNode(t.Nod) != nil {
+ base.Pos = ir.AsNode(t.Nod).Pos
}
t.Width = -2
et := t.Etype
switch et {
- case TFUNC, TCHAN, TMAP, TSTRING:
+ case types.TFUNC, types.TCHAN, types.TMAP, types.TSTRING:
break
// simtype == 0 during bootstrap
base.Fatalf("dowidth: unknown type: %v", t)
// compiler-specific stuff
- case TINT8, TUINT8, TBOOL:
+ case types.TINT8, types.TUINT8, types.TBOOL:
// bool is int8
w = 1
- case TINT16, TUINT16:
+ case types.TINT16, types.TUINT16:
w = 2
- case TINT32, TUINT32, TFLOAT32:
+ case types.TINT32, types.TUINT32, types.TFLOAT32:
w = 4
- case TINT64, TUINT64, TFLOAT64:
+ case types.TINT64, types.TUINT64, types.TFLOAT64:
w = 8
t.Align = uint8(Widthreg)
- case TCOMPLEX64:
+ case types.TCOMPLEX64:
w = 8
t.Align = 4
- case TCOMPLEX128:
+ case types.TCOMPLEX128:
w = 16
t.Align = uint8(Widthreg)
- case TPTR:
+ case types.TPTR:
w = int64(Widthptr)
checkwidth(t.Elem())
- case TUNSAFEPTR:
+ case types.TUNSAFEPTR:
w = int64(Widthptr)
- case TINTER: // implemented as 2 pointers
+ case types.TINTER: // implemented as 2 pointers
w = 2 * int64(Widthptr)
t.Align = uint8(Widthptr)
expandiface(t)
- case TCHAN: // implemented as pointer
+ case types.TCHAN: // implemented as pointer
w = int64(Widthptr)
checkwidth(t.Elem())
t1 := types.NewChanArgs(t)
checkwidth(t1)
- case TCHANARGS:
+ case types.TCHANARGS:
t1 := t.ChanArgs()
dowidth(t1) // just in case
if t1.Elem().Width >= 1<<16 {
}
w = 1 // anything will do
- case TMAP: // implemented as pointer
+ case types.TMAP: // implemented as pointer
w = int64(Widthptr)
checkwidth(t.Elem())
checkwidth(t.Key())
- case TFORW: // should have been filled in
+ case types.TFORW: // should have been filled in
reportTypeLoop(t)
w = 1 // anything will do
- case TANY:
+ case types.TANY:
// not a real type; should be replaced before use.
base.Fatalf("dowidth any")
- case TSTRING:
+ case types.TSTRING:
if sizeofString == 0 {
base.Fatalf("early dowidth string")
}
w = sizeofString
t.Align = uint8(Widthptr)
- case TARRAY:
+ case types.TARRAY:
if t.Elem() == nil {
break
}
w = t.NumElem() * t.Elem().Width
t.Align = t.Elem().Align
- case TSLICE:
+ case types.TSLICE:
if t.Elem() == nil {
break
}
checkwidth(t.Elem())
t.Align = uint8(Widthptr)
- case TSTRUCT:
+ case types.TSTRUCT:
if t.IsFuncArgStruct() {
base.Fatalf("dowidth fn struct %v", t)
}
// make fake type to check later to
// trigger function argument computation.
- case TFUNC:
+ case types.TFUNC:
t1 := types.NewFuncArgs(t)
checkwidth(t1)
w = int64(Widthptr) // width of func type is pointer
// function is 3 cated structures;
// compute their widths as side-effect.
- case TFUNCARGS:
+ case types.TFUNCARGS:
t1 := t.FuncArgs()
w = widstruct(t1, t1.Recvs(), 0, 0)
w = widstruct(t1, t1.Params(), w, Widthreg)
package gc
import (
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
)
}
// markObject visits a reachable object.
-func (p *exporter) markObject(n *Node) {
- if n.Op == ONAME && n.Class() == PFUNC {
+func (p *exporter) markObject(n *ir.Node) {
+ if n.Op == ir.ONAME && n.Class() == ir.PFUNC {
inlFlood(n)
}
// only their unexpanded method set (i.e., exclusive of
// interface embeddings), and the switch statement below
// handles their full method set.
- if t.Sym != nil && t.Etype != TINTER {
+ if t.Sym != nil && t.Etype != types.TINTER {
for _, m := range t.Methods().Slice() {
if types.IsExported(m.Sym.Name) {
- p.markObject(asNode(m.Nname))
+ p.markObject(ir.AsNode(m.Nname))
}
}
}
// the user already needs some way to construct values of
// those types.
switch t.Etype {
- case TPTR, TARRAY, TSLICE:
+ case types.TPTR, types.TARRAY, types.TSLICE:
p.markType(t.Elem())
- case TCHAN:
+ case types.TCHAN:
if t.ChanDir().CanRecv() {
p.markType(t.Elem())
}
- case TMAP:
+ case types.TMAP:
p.markType(t.Key())
p.markType(t.Elem())
- case TSTRUCT:
+ case types.TSTRUCT:
for _, f := range t.FieldSlice() {
if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
p.markType(f.Type)
}
}
- case TFUNC:
+ case types.TFUNC:
for _, f := range t.Results().FieldSlice() {
p.markType(f.Type)
}
- case TINTER:
+ case types.TINTER:
for _, f := range t.FieldSlice() {
if types.IsExported(f.Sym.Name) {
p.markType(f.Type)
// elements have been initialized before
predecl = []*types.Type{
// basic types
- types.Types[TBOOL],
- types.Types[TINT],
- types.Types[TINT8],
- types.Types[TINT16],
- types.Types[TINT32],
- types.Types[TINT64],
- types.Types[TUINT],
- types.Types[TUINT8],
- types.Types[TUINT16],
- types.Types[TUINT32],
- types.Types[TUINT64],
- types.Types[TUINTPTR],
- types.Types[TFLOAT32],
- types.Types[TFLOAT64],
- types.Types[TCOMPLEX64],
- types.Types[TCOMPLEX128],
- types.Types[TSTRING],
+ types.Types[types.TBOOL],
+ types.Types[types.TINT],
+ types.Types[types.TINT8],
+ types.Types[types.TINT16],
+ types.Types[types.TINT32],
+ types.Types[types.TINT64],
+ types.Types[types.TUINT],
+ types.Types[types.TUINT8],
+ types.Types[types.TUINT16],
+ types.Types[types.TUINT32],
+ types.Types[types.TUINT64],
+ types.Types[types.TUINTPTR],
+ types.Types[types.TFLOAT32],
+ types.Types[types.TFLOAT64],
+ types.Types[types.TCOMPLEX64],
+ types.Types[types.TCOMPLEX128],
+ types.Types[types.TSTRING],
// basic type aliases
types.Bytetype,
types.UntypedFloat,
types.UntypedComplex,
types.UntypedString,
- types.Types[TNIL],
+ types.Types[types.TNIL],
// package unsafe
- types.Types[TUNSAFEPTR],
+ types.Types[types.TUNSAFEPTR],
// invalid type (package contains errors)
- types.Types[Txxx],
+ types.Types[types.Txxx],
// any type, for builtin export data
- types.Types[TANY],
+ types.Types[types.TANY],
}
}
return predecl
package gc
import (
+ "cmd/compile/internal/ir"
"cmd/internal/src"
)
-// numImport tracks how often a package with a given name is imported.
-// It is used to provide a better error message (by using the package
-// path to disambiguate) if a package that appears multiple times with
-// the same name appears in an error message.
-var numImport = make(map[string]int)
-
-func npos(pos src.XPos, n *Node) *Node {
+func npos(pos src.XPos, n *ir.Node) *ir.Node {
n.Pos = pos
return n
}
-func builtinCall(op Op) *Node {
- return nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil)
+func builtinCall(op ir.Op) *ir.Node {
+ return ir.Nod(ir.OCALL, mkname(ir.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
}
package gc
-import "cmd/compile/internal/types"
+import (
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+)
var runtimeDecls = [...]struct {
name string
var typs [131]*types.Type
typs[0] = types.Bytetype
typs[1] = types.NewPtr(typs[0])
- typs[2] = types.Types[TANY]
+ typs[2] = types.Types[types.TANY]
typs[3] = types.NewPtr(typs[2])
- typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
- typs[5] = types.Types[TUINTPTR]
- typs[6] = types.Types[TBOOL]
- typs[7] = types.Types[TUNSAFEPTR]
- typs[8] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*Node{anonfield(typs[7])})
+ typs[4] = functype(nil, []*ir.Node{anonfield(typs[1])}, []*ir.Node{anonfield(typs[3])})
+ typs[5] = types.Types[types.TUINTPTR]
+ typs[6] = types.Types[types.TBOOL]
+ typs[7] = types.Types[types.TUNSAFEPTR]
+ typs[8] = functype(nil, []*ir.Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*ir.Node{anonfield(typs[7])})
typs[9] = functype(nil, nil, nil)
- typs[10] = types.Types[TINTER]
- typs[11] = functype(nil, []*Node{anonfield(typs[10])}, nil)
- typs[12] = types.Types[TINT32]
+ typs[10] = types.Types[types.TINTER]
+ typs[11] = functype(nil, []*ir.Node{anonfield(typs[10])}, nil)
+ typs[12] = types.Types[types.TINT32]
typs[13] = types.NewPtr(typs[12])
- typs[14] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[10])})
- typs[15] = types.Types[TINT]
- typs[16] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
- typs[17] = types.Types[TUINT]
- typs[18] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
- typs[19] = functype(nil, []*Node{anonfield(typs[6])}, nil)
- typs[20] = types.Types[TFLOAT64]
- typs[21] = functype(nil, []*Node{anonfield(typs[20])}, nil)
- typs[22] = types.Types[TINT64]
- typs[23] = functype(nil, []*Node{anonfield(typs[22])}, nil)
- typs[24] = types.Types[TUINT64]
- typs[25] = functype(nil, []*Node{anonfield(typs[24])}, nil)
- typs[26] = types.Types[TCOMPLEX128]
- typs[27] = functype(nil, []*Node{anonfield(typs[26])}, nil)
- typs[28] = types.Types[TSTRING]
- typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
- typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
- typs[31] = functype(nil, []*Node{anonfield(typs[5])}, nil)
+ typs[14] = functype(nil, []*ir.Node{anonfield(typs[13])}, []*ir.Node{anonfield(typs[10])})
+ typs[15] = types.Types[types.TINT]
+ typs[16] = functype(nil, []*ir.Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
+ typs[17] = types.Types[types.TUINT]
+ typs[18] = functype(nil, []*ir.Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
+ typs[19] = functype(nil, []*ir.Node{anonfield(typs[6])}, nil)
+ typs[20] = types.Types[types.TFLOAT64]
+ typs[21] = functype(nil, []*ir.Node{anonfield(typs[20])}, nil)
+ typs[22] = types.Types[types.TINT64]
+ typs[23] = functype(nil, []*ir.Node{anonfield(typs[22])}, nil)
+ typs[24] = types.Types[types.TUINT64]
+ typs[25] = functype(nil, []*ir.Node{anonfield(typs[24])}, nil)
+ typs[26] = types.Types[types.TCOMPLEX128]
+ typs[27] = functype(nil, []*ir.Node{anonfield(typs[26])}, nil)
+ typs[28] = types.Types[types.TSTRING]
+ typs[29] = functype(nil, []*ir.Node{anonfield(typs[28])}, nil)
+ typs[30] = functype(nil, []*ir.Node{anonfield(typs[2])}, nil)
+ typs[31] = functype(nil, []*ir.Node{anonfield(typs[5])}, nil)
typs[32] = types.NewArray(typs[0], 32)
typs[33] = types.NewPtr(typs[32])
- typs[34] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
- typs[35] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
- typs[36] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
- typs[37] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[34] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28])}, []*ir.Node{anonfield(typs[28])})
+ typs[35] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*ir.Node{anonfield(typs[28])})
+ typs[36] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*ir.Node{anonfield(typs[28])})
+ typs[37] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*ir.Node{anonfield(typs[28])})
typs[38] = types.NewSlice(typs[28])
- typs[39] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[38])}, []*Node{anonfield(typs[28])})
- typs[40] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
+ typs[39] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[38])}, []*ir.Node{anonfield(typs[28])})
+ typs[40] = functype(nil, []*ir.Node{anonfield(typs[28]), anonfield(typs[28])}, []*ir.Node{anonfield(typs[15])})
typs[41] = types.NewArray(typs[0], 4)
typs[42] = types.NewPtr(typs[41])
- typs[43] = functype(nil, []*Node{anonfield(typs[42]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
- typs[44] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
- typs[45] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
+ typs[43] = functype(nil, []*ir.Node{anonfield(typs[42]), anonfield(typs[22])}, []*ir.Node{anonfield(typs[28])})
+ typs[44] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[1]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[28])})
+ typs[45] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[28])})
typs[46] = types.Runetype
typs[47] = types.NewSlice(typs[46])
- typs[48] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[47])}, []*Node{anonfield(typs[28])})
+ typs[48] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[47])}, []*ir.Node{anonfield(typs[28])})
typs[49] = types.NewSlice(typs[0])
- typs[50] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28])}, []*Node{anonfield(typs[49])})
+ typs[50] = functype(nil, []*ir.Node{anonfield(typs[33]), anonfield(typs[28])}, []*ir.Node{anonfield(typs[49])})
typs[51] = types.NewArray(typs[46], 32)
typs[52] = types.NewPtr(typs[51])
- typs[53] = functype(nil, []*Node{anonfield(typs[52]), anonfield(typs[28])}, []*Node{anonfield(typs[47])})
- typs[54] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
- typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[46]), anonfield(typs[15])})
- typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
- typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
- typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
- typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
- typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
- typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
- typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
+ typs[53] = functype(nil, []*ir.Node{anonfield(typs[52]), anonfield(typs[28])}, []*ir.Node{anonfield(typs[47])})
+ typs[54] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*ir.Node{anonfield(typs[15])})
+ typs[55] = functype(nil, []*ir.Node{anonfield(typs[28]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[46]), anonfield(typs[15])})
+ typs[56] = functype(nil, []*ir.Node{anonfield(typs[28])}, []*ir.Node{anonfield(typs[15])})
+ typs[57] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[2])}, []*ir.Node{anonfield(typs[2])})
+ typs[58] = functype(nil, []*ir.Node{anonfield(typs[2])}, []*ir.Node{anonfield(typs[7])})
+ typs[59] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[2])})
+ typs[60] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[2])}, []*ir.Node{anonfield(typs[2]), anonfield(typs[6])})
+ typs[61] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
+ typs[62] = functype(nil, []*ir.Node{anonfield(typs[1])}, nil)
typs[63] = types.NewPtr(typs[5])
- typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
- typs[65] = types.Types[TUINT32]
- typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
+ typs[64] = functype(nil, []*ir.Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*ir.Node{anonfield(typs[6])})
+ typs[65] = types.Types[types.TUINT32]
+ typs[66] = functype(nil, nil, []*ir.Node{anonfield(typs[65])})
typs[67] = types.NewMap(typs[2], typs[2])
- typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
- typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
- typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
- typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
- typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
- typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
- typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
- typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
- typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
- typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
- typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
- typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
- typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
+ typs[68] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[67])})
+ typs[69] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[67])})
+ typs[70] = functype(nil, nil, []*ir.Node{anonfield(typs[67])})
+ typs[71] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[3])})
+ typs[72] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*ir.Node{anonfield(typs[3])})
+ typs[73] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*ir.Node{anonfield(typs[3])})
+ typs[74] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[75] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*ir.Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[76] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*ir.Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[77] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
+ typs[78] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
+ typs[79] = functype(nil, []*ir.Node{anonfield(typs[3])}, nil)
+ typs[80] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
typs[81] = types.NewChan(typs[2], types.Cboth)
- typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
- typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
+ typs[82] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[22])}, []*ir.Node{anonfield(typs[81])})
+ typs[83] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[81])})
typs[84] = types.NewChan(typs[2], types.Crecv)
- typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
- typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[85] = functype(nil, []*ir.Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
+ typs[86] = functype(nil, []*ir.Node{anonfield(typs[84]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[6])})
typs[87] = types.NewChan(typs[2], types.Csend)
- typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
+ typs[88] = functype(nil, []*ir.Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
typs[89] = types.NewArray(typs[0], 3)
- typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
- typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
- typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
- typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
- typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
- typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
+ typs[90] = tostruct([]*ir.Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
+ typs[91] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
+ typs[92] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
+ typs[93] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[15])})
+ typs[94] = functype(nil, []*ir.Node{anonfield(typs[87]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[6])})
+ typs[95] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[84])}, []*ir.Node{anonfield(typs[6])})
typs[96] = types.NewPtr(typs[6])
- typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
- typs[98] = functype(nil, []*Node{anonfield(typs[63])}, nil)
- typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
- typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
- typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
- typs[102] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
+ typs[97] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*ir.Node{anonfield(typs[6])})
+ typs[98] = functype(nil, []*ir.Node{anonfield(typs[63])}, nil)
+ typs[99] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*ir.Node{anonfield(typs[15]), anonfield(typs[6])})
+ typs[100] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[7])})
+ typs[101] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*ir.Node{anonfield(typs[7])})
+ typs[102] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*ir.Node{anonfield(typs[7])})
typs[103] = types.NewSlice(typs[2])
- typs[104] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[103]), anonfield(typs[15])}, []*Node{anonfield(typs[103])})
- typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
- typs[106] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
- typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
- typs[108] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
- typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
- typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
- typs[111] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
- typs[112] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
- typs[113] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
- typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
- typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
- typs[116] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
- typs[117] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
- typs[118] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
- typs[119] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
- typs[120] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
- typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
- typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
+ typs[104] = functype(nil, []*ir.Node{anonfield(typs[1]), anonfield(typs[103]), anonfield(typs[15])}, []*ir.Node{anonfield(typs[103])})
+ typs[105] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
+ typs[106] = functype(nil, []*ir.Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
+ typs[107] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*ir.Node{anonfield(typs[6])})
+ typs[108] = functype(nil, []*ir.Node{anonfield(typs[3]), anonfield(typs[3])}, []*ir.Node{anonfield(typs[6])})
+ typs[109] = functype(nil, []*ir.Node{anonfield(typs[7]), anonfield(typs[7])}, []*ir.Node{anonfield(typs[6])})
+ typs[110] = functype(nil, []*ir.Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*ir.Node{anonfield(typs[5])})
+ typs[111] = functype(nil, []*ir.Node{anonfield(typs[7]), anonfield(typs[5])}, []*ir.Node{anonfield(typs[5])})
+ typs[112] = functype(nil, []*ir.Node{anonfield(typs[22]), anonfield(typs[22])}, []*ir.Node{anonfield(typs[22])})
+ typs[113] = functype(nil, []*ir.Node{anonfield(typs[24]), anonfield(typs[24])}, []*ir.Node{anonfield(typs[24])})
+ typs[114] = functype(nil, []*ir.Node{anonfield(typs[20])}, []*ir.Node{anonfield(typs[22])})
+ typs[115] = functype(nil, []*ir.Node{anonfield(typs[20])}, []*ir.Node{anonfield(typs[24])})
+ typs[116] = functype(nil, []*ir.Node{anonfield(typs[20])}, []*ir.Node{anonfield(typs[65])})
+ typs[117] = functype(nil, []*ir.Node{anonfield(typs[22])}, []*ir.Node{anonfield(typs[20])})
+ typs[118] = functype(nil, []*ir.Node{anonfield(typs[24])}, []*ir.Node{anonfield(typs[20])})
+ typs[119] = functype(nil, []*ir.Node{anonfield(typs[65])}, []*ir.Node{anonfield(typs[20])})
+ typs[120] = functype(nil, []*ir.Node{anonfield(typs[26]), anonfield(typs[26])}, []*ir.Node{anonfield(typs[26])})
+ typs[121] = functype(nil, []*ir.Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
+ typs[122] = functype(nil, []*ir.Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
typs[123] = types.NewSlice(typs[7])
- typs[124] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
- typs[125] = types.Types[TUINT8]
- typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
- typs[127] = types.Types[TUINT16]
- typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
- typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
- typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
+ typs[124] = functype(nil, []*ir.Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
+ typs[125] = types.Types[types.TUINT8]
+ typs[126] = functype(nil, []*ir.Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
+ typs[127] = types.Types[types.TUINT16]
+ typs[128] = functype(nil, []*ir.Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
+ typs[129] = functype(nil, []*ir.Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
+ typs[130] = functype(nil, []*ir.Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
return typs[:]
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
)
-func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
+func (p *noder) funcLit(expr *syntax.FuncLit) *ir.Node {
xtype := p.typeExpr(expr.Type)
ntype := p.typeExpr(expr.Type)
- dcl := p.nod(expr, ODCLFUNC, nil, nil)
+ dcl := p.nod(expr, ir.ODCLFUNC, nil, nil)
fn := dcl.Func
fn.SetIsHiddenClosure(Curfn != nil)
- fn.Nname = newfuncnamel(p.pos(expr), nblank.Sym, fn) // filled in by typecheckclosure
+ fn.Nname = newfuncnamel(p.pos(expr), ir.BlankNode.Sym, fn) // filled in by typecheckclosure
fn.Nname.Name.Param.Ntype = xtype
fn.Nname.Name.Defn = dcl
- clo := p.nod(expr, OCLOSURE, nil, nil)
+ clo := p.nod(expr, ir.OCLOSURE, nil, nil)
clo.Func = fn
fn.ClosureType = ntype
fn.OClosure = clo
// function associated with the closure.
// TODO: This creation of the named function should probably really be done in a
// separate pass from type-checking.
-func typecheckclosure(clo *Node, top int) {
+func typecheckclosure(clo *ir.Node, top int) {
fn := clo.Func
dcl := fn.Decl
// Set current associated iota value, so iota can be used inside
// closurename generates a new unique name for a closure within
// outerfunc.
-func closurename(outerfunc *Node) *types.Sym {
+func closurename(outerfunc *ir.Node) *types.Sym {
outer := "glob."
prefix := "func"
gen := &globClosgen
prefix = ""
}
- outer = outerfunc.funcname()
+ outer = ir.FuncName(outerfunc)
// There may be multiple functions named "_". In those
// cases, we can't use their individual Closgens as it
// would lead to name clashes.
- if !outerfunc.Func.Nname.isBlank() {
+ if !ir.IsBlank(outerfunc.Func.Nname) {
gen = &outerfunc.Func.Closgen
}
}
// by value or by reference.
// We use value capturing for values <= 128 bytes that are never reassigned
// after capturing (effectively constant).
-func capturevars(dcl *Node) {
+func capturevars(dcl *ir.Node) {
lno := base.Pos
base.Pos = dcl.Pos
fn := dcl.Func
outermost := v.Name.Defn
// out parameters will be assigned to implicitly upon return.
- if outermost.Class() != PPARAMOUT && !outermost.Name.Addrtaken() && !outermost.Name.Assigned() && v.Type.Width <= 128 {
+ if outermost.Class() != ir.PPARAMOUT && !outermost.Name.Addrtaken() && !outermost.Name.Assigned() && v.Type.Width <= 128 {
v.Name.SetByval(true)
} else {
outermost.Name.SetAddrtaken(true)
- outer = nod(OADDR, outer, nil)
+ outer = ir.Nod(ir.OADDR, outer, nil)
}
if base.Flag.LowerM > 1 {
// transformclosure is called in a separate phase after escape analysis.
// It transform closure bodies to properly reference captured variables.
-func transformclosure(dcl *Node) {
+func transformclosure(dcl *ir.Node) {
lno := base.Pos
base.Pos = dcl.Pos
fn := dcl.Func
// We are going to insert captured variables before input args.
var params []*types.Field
- var decls []*Node
+ var decls []*ir.Node
for _, v := range fn.ClosureVars.Slice() {
if !v.Name.Byval() {
// If v of type T is captured by reference,
// we introduce function param &v *T
// and v remains PAUTOHEAP with &v heapaddr
// (accesses will implicitly deref &v).
- addr := newname(lookup("&" + v.Sym.Name))
+ addr := NewName(lookup("&" + v.Sym.Name))
addr.Type = types.NewPtr(v.Type)
v.Name.Param.Heapaddr = addr
v = addr
}
- v.SetClass(PPARAM)
+ v.SetClass(ir.PPARAM)
decls = append(decls, v)
fld := types.NewField(src.NoXPos, v.Sym, v.Type)
- fld.Nname = asTypesNode(v)
+ fld.Nname = ir.AsTypesNode(v)
params = append(params, fld)
}
dcl.Type = f.Type // update type of ODCLFUNC
} else {
// The closure is not called, so it is going to stay as closure.
- var body []*Node
+ var body []*ir.Node
offset := int64(Widthptr)
for _, v := range fn.ClosureVars.Slice() {
// cv refers to the field inside of closure OSTRUCTLIT.
- cv := nod(OCLOSUREVAR, nil, nil)
+ cv := ir.Nod(ir.OCLOSUREVAR, nil, nil)
cv.Type = v.Type
if !v.Name.Byval() {
if v.Name.Byval() && v.Type.Width <= int64(2*Widthptr) {
// If it is a small variable captured by value, downgrade it to PAUTO.
- v.SetClass(PAUTO)
+ v.SetClass(ir.PAUTO)
fn.Dcl = append(fn.Dcl, v)
- body = append(body, nod(OAS, v, cv))
+ body = append(body, ir.Nod(ir.OAS, v, cv))
} else {
// Declare variable holding addresses taken from closure
// and initialize in entry prologue.
- addr := newname(lookup("&" + v.Sym.Name))
+ addr := NewName(lookup("&" + v.Sym.Name))
addr.Type = types.NewPtr(v.Type)
- addr.SetClass(PAUTO)
+ addr.SetClass(ir.PAUTO)
addr.Name.SetUsed(true)
addr.Name.Curfn = dcl
fn.Dcl = append(fn.Dcl, addr)
v.Name.Param.Heapaddr = addr
if v.Name.Byval() {
- cv = nod(OADDR, cv, nil)
+ cv = ir.Nod(ir.OADDR, cv, nil)
}
- body = append(body, nod(OAS, addr, cv))
+ body = append(body, ir.Nod(ir.OAS, addr, cv))
}
}
// hasemptycvars reports whether closure clo has an
// empty list of captured vars.
-func hasemptycvars(clo *Node) bool {
+func hasemptycvars(clo *ir.Node) bool {
return clo.Func.ClosureVars.Len() == 0
}
// closuredebugruntimecheck applies boilerplate checks for debug flags
// and compiling runtime
-func closuredebugruntimecheck(clo *Node) {
+func closuredebugruntimecheck(clo *ir.Node) {
if base.Debug.Closure > 0 {
if clo.Esc == EscHeap {
base.WarnfAt(clo.Pos, "heap closure, captured vars = %v", clo.Func.ClosureVars)
// closureType returns the struct type used to hold all the information
// needed in the closure for clo (clo must be a OCLOSURE node).
// The address of a variable of the returned type can be cast to a func.
-func closureType(clo *Node) *types.Type {
+func closureType(clo *ir.Node) *types.Type {
// Create closure in the form of a composite literal.
// supposing the closure captures an int i and a string s
// and has one float64 argument and no results,
// The information appears in the binary in the form of type descriptors;
// the struct is unnamed so that closures in multiple packages with the
// same struct type can share the descriptor.
- fields := []*Node{
- namedfield(".F", types.Types[TUINTPTR]),
+ fields := []*ir.Node{
+ namedfield(".F", types.Types[types.TUINTPTR]),
}
for _, v := range clo.Func.ClosureVars.Slice() {
typ := v.Type
return typ
}
-func walkclosure(clo *Node, init *Nodes) *Node {
+func walkclosure(clo *ir.Node, init *ir.Nodes) *ir.Node {
fn := clo.Func
// If no closure vars, don't bother wrapping.
typ := closureType(clo)
- clos := nod(OCOMPLIT, nil, typenod(typ))
+ clos := ir.Nod(ir.OCOMPLIT, nil, typenod(typ))
clos.Esc = clo.Esc
- clos.List.Set(append([]*Node{nod(OCFUNC, fn.Nname, nil)}, fn.ClosureEnter.Slice()...))
+ clos.List.Set(append([]*ir.Node{ir.Nod(ir.OCFUNC, fn.Nname, nil)}, fn.ClosureEnter.Slice()...))
- clos = nod(OADDR, clos, nil)
+ clos = ir.Nod(ir.OADDR, clos, nil)
clos.Esc = clo.Esc
// Force type conversion from *struct to the func type.
return walkexpr(clos, init)
}
-func typecheckpartialcall(dot *Node, sym *types.Sym) {
+func typecheckpartialcall(dot *ir.Node, sym *types.Sym) {
switch dot.Op {
- case ODOTINTER, ODOTMETH:
+ case ir.ODOTINTER, ir.ODOTMETH:
break
default:
// Create top-level function.
dcl := makepartialcall(dot, dot.Type, sym)
dcl.Func.SetWrapper(true)
- dot.Op = OCALLPART
- dot.Right = newname(sym)
+ dot.Op = ir.OCALLPART
+ dot.Right = NewName(sym)
dot.Type = dcl.Type
dot.Func = dcl.Func
dot.SetOpt(nil) // clear types.Field from ODOTMETH
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
// for partial calls.
-func makepartialcall(dot *Node, t0 *types.Type, meth *types.Sym) *Node {
+func makepartialcall(dot *ir.Node, t0 *types.Type, meth *types.Sym) *ir.Node {
rcvrtype := dot.Left.Type
sym := methodSymSuffix(rcvrtype, meth, "-fm")
if sym.Uniq() {
- return asNode(sym.Def)
+ return ir.AsNode(sym.Def)
}
sym.SetUniq(true)
// number at the use of the method expression in this
// case. See issue 29389.
- tfn := nod(OTFUNC, nil, nil)
+ tfn := ir.Nod(ir.OTFUNC, nil, nil)
tfn.List.Set(structargs(t0.Params(), true))
tfn.Rlist.Set(structargs(t0.Results(), false))
// Declare and initialize variable holding receiver.
- cv := nod(OCLOSUREVAR, nil, nil)
+ cv := ir.Nod(ir.OCLOSUREVAR, nil, nil)
cv.Type = rcvrtype
cv.Xoffset = Rnd(int64(Widthptr), int64(cv.Type.Align))
- ptr := newname(lookup(".this"))
- declare(ptr, PAUTO)
+ ptr := NewName(lookup(".this"))
+ declare(ptr, ir.PAUTO)
ptr.Name.SetUsed(true)
- var body []*Node
+ var body []*ir.Node
if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
ptr.Type = rcvrtype
- body = append(body, nod(OAS, ptr, cv))
+ body = append(body, ir.Nod(ir.OAS, ptr, cv))
} else {
ptr.Type = types.NewPtr(rcvrtype)
- body = append(body, nod(OAS, ptr, nod(OADDR, cv, nil)))
+ body = append(body, ir.Nod(ir.OAS, ptr, ir.Nod(ir.OADDR, cv, nil)))
}
- call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil)
+ call := ir.Nod(ir.OCALL, nodSym(ir.OXDOT, ptr, meth), nil)
call.List.Set(paramNnames(tfn.Type))
call.SetIsDDD(tfn.Type.IsVariadic())
if t0.NumResults() != 0 {
- n := nod(ORETURN, nil, nil)
+ n := ir.Nod(ir.ORETURN, nil, nil)
n.List.Set1(call)
call = n
}
// typecheckslice() requires that Curfn is set when processing an ORETURN.
Curfn = dcl
typecheckslice(dcl.Nbody.Slice(), ctxStmt)
- sym.Def = asTypesNode(dcl)
+ sym.Def = ir.AsTypesNode(dcl)
xtop = append(xtop, dcl)
Curfn = savecurfn
base.Pos = saveLineNo
// partialCallType returns the struct type used to hold all the information
// needed in the closure for n (n must be a OCALLPART node).
// The address of a variable of the returned type can be cast to a func.
-func partialCallType(n *Node) *types.Type {
- t := tostruct([]*Node{
- namedfield("F", types.Types[TUINTPTR]),
+func partialCallType(n *ir.Node) *types.Type {
+ t := tostruct([]*ir.Node{
+ namedfield("F", types.Types[types.TUINTPTR]),
namedfield("R", n.Left.Type),
})
t.SetNoalg(true)
return t
}
-func walkpartialcall(n *Node, init *Nodes) *Node {
+func walkpartialcall(n *ir.Node, init *ir.Nodes) *ir.Node {
// Create closure in the form of a composite literal.
// For x.M with receiver (x) type T, the generated code looks like:
//
n.Left = cheapexpr(n.Left, init)
n.Left = walkexpr(n.Left, nil)
- tab := nod(OITAB, n.Left, nil)
+ tab := ir.Nod(ir.OITAB, n.Left, nil)
tab = typecheck(tab, ctxExpr)
- c := nod(OCHECKNIL, tab, nil)
+ c := ir.Nod(ir.OCHECKNIL, tab, nil)
c.SetTypecheck(1)
init.Append(c)
}
typ := partialCallType(n)
- clos := nod(OCOMPLIT, nil, typenod(typ))
+ clos := ir.Nod(ir.OCOMPLIT, nil, typenod(typ))
clos.Esc = n.Esc
- clos.List.Set2(nod(OCFUNC, n.Func.Nname, nil), n.Left)
+ clos.List.Set2(ir.Nod(ir.OCFUNC, n.Func.Nname, nil), n.Left)
- clos = nod(OADDR, clos, nil)
+ clos = ir.Nod(ir.OADDR, clos, nil)
clos.Esc = n.Esc
// Force type conversion from *struct to the func type.
// callpartMethod returns the *types.Field representing the method
// referenced by method value n.
-func callpartMethod(n *Node) *types.Field {
- if n.Op != OCALLPART {
+func callpartMethod(n *ir.Node) *types.Field {
+ if n.Op != ir.OCALLPART {
base.Fatalf("expected OCALLPART, got %v", n)
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
Mpprec = 512
)
-// ValueInterface returns the constant value stored in n as an interface{}.
-// It returns int64s for ints and runes, float64s for floats,
-// and complex128s for complex values.
-func (n *Node) ValueInterface() interface{} {
- switch v := n.Val(); v.Kind() {
- default:
- base.Fatalf("unexpected constant: %v", v)
- panic("unreachable")
- case constant.Bool:
- return constant.BoolVal(v)
- case constant.String:
- return constant.StringVal(v)
- case constant.Int:
- return int64Val(n.Type, v)
- case constant.Float:
- return float64Val(v)
- case constant.Complex:
- return complex(float64Val(constant.Real(v)), float64Val(constant.Imag(v)))
- }
-}
-
-// int64Val returns v converted to int64.
-// Note: if t is uint64, very large values will be converted to negative int64.
-func int64Val(t *types.Type, v constant.Value) int64 {
- if t.IsUnsigned() {
- if x, ok := constant.Uint64Val(v); ok {
- return int64(x)
- }
- } else {
- if x, ok := constant.Int64Val(v); ok {
- return x
- }
- }
- base.Fatalf("%v out of range for %v", v, t)
- panic("unreachable")
-}
-
-func float64Val(v constant.Value) float64 {
- if x, _ := constant.Float64Val(v); !math.IsInf(x, 0) {
- return x + 0 // avoid -0 (should not be needed, but be conservative)
- }
- base.Fatalf("bad float64 value: %v", v)
- panic("unreachable")
-}
-
func bigFloatVal(v constant.Value) *big.Float {
f := new(big.Float)
f.SetPrec(Mpprec)
return f
}
-// Int64Val returns n as an int64.
-// n must be an integer or rune constant.
-func (n *Node) Int64Val() int64 {
- if !Isconst(n, constant.Int) {
- base.Fatalf("Int64Val(%v)", n)
- }
- x, ok := constant.Int64Val(n.Val())
- if !ok {
- base.Fatalf("Int64Val(%v)", n)
- }
- return x
-}
-
-// CanInt64 reports whether it is safe to call Int64Val() on n.
-func (n *Node) CanInt64() bool {
- if !Isconst(n, constant.Int) {
- return false
- }
-
- // if the value inside n cannot be represented as an int64, the
- // return value of Int64 is undefined
- _, ok := constant.Int64Val(n.Val())
- return ok
-}
-
-// Uint64Val returns n as an uint64.
-// n must be an integer or rune constant.
-func (n *Node) Uint64Val() uint64 {
- if !Isconst(n, constant.Int) {
- base.Fatalf("Uint64Val(%v)", n)
- }
- x, ok := constant.Uint64Val(n.Val())
- if !ok {
- base.Fatalf("Uint64Val(%v)", n)
- }
- return x
-}
-
-// BoolVal returns n as a bool.
-// n must be a boolean constant.
-func (n *Node) BoolVal() bool {
- if !Isconst(n, constant.Bool) {
- base.Fatalf("BoolVal(%v)", n)
- }
- return constant.BoolVal(n.Val())
-}
-
-// StringVal returns the value of a literal string Node as a string.
-// n must be a string constant.
-func (n *Node) StringVal() string {
- if !Isconst(n, constant.String) {
- base.Fatalf("StringVal(%v)", n)
- }
- return constant.StringVal(n.Val())
-}
-
func roundFloat(v constant.Value, sz int64) constant.Value {
switch sz {
case 4:
}
// TODO(mdempsky): Replace these with better APIs.
-func convlit(n *Node, t *types.Type) *Node { return convlit1(n, t, false, nil) }
-func defaultlit(n *Node, t *types.Type) *Node { return convlit1(n, t, false, nil) }
+func convlit(n *ir.Node, t *types.Type) *ir.Node { return convlit1(n, t, false, nil) }
+func defaultlit(n *ir.Node, t *types.Type) *ir.Node { return convlit1(n, t, false, nil) }
// convlit1 converts an untyped expression n to type t. If n already
// has a type, convlit1 has no effect.
//
// If there's an error converting n to t, context is used in the error
// message.
-func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Node {
+func convlit1(n *ir.Node, t *types.Type, explicit bool, context func() string) *ir.Node {
if explicit && t == nil {
base.Fatalf("explicit conversion missing type")
}
return n
}
- if n.Op == OLITERAL || n.Op == ONIL {
+ if n.Op == ir.OLITERAL || n.Op == ir.ONIL {
// Can't always set n.Type directly on OLITERAL nodes.
// See discussion on CL 20813.
- n = n.rawcopy()
+ n = n.RawCopy()
}
// Nil is technically not a constant, so handle it specially.
- if n.Type.Etype == TNIL {
- if n.Op != ONIL {
+ if n.Type.Etype == types.TNIL {
+ if n.Op != ir.ONIL {
base.Fatalf("unexpected op: %v (%v)", n, n.Op)
}
if t == nil {
return n
}
- if t == nil || !okforconst[t.Etype] {
+ if t == nil || !ir.OKForConst[t.Etype] {
t = defaultType(n.Type)
}
default:
base.Fatalf("unexpected untyped expression: %v", n)
- case OLITERAL:
+ case ir.OLITERAL:
v := convertVal(n.Val(), t, explicit)
if v.Kind() == constant.Unknown {
break
n.SetVal(v)
return n
- case OPLUS, ONEG, OBITNOT, ONOT, OREAL, OIMAG:
+ case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.OREAL, ir.OIMAG:
ot := operandType(n.Op, t)
if ot == nil {
n = defaultlit(n, nil)
n.Type = t
return n
- case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND, OCOMPLEX:
+ case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT, ir.OOROR, ir.OANDAND, ir.OCOMPLEX:
ot := operandType(n.Op, t)
if ot == nil {
n = defaultlit(n, nil)
n.Type = t
return n
- case OEQ, ONE, OLT, OLE, OGT, OGE:
+ case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
if !t.IsBoolean() {
break
}
n.Type = t
return n
- case OLSH, ORSH:
+ case ir.OLSH, ir.ORSH:
n.Left = convlit1(n.Left, t, explicit, nil)
n.Type = n.Left.Type
if n.Type != nil && !n.Type.IsInteger() {
return n
}
-func operandType(op Op, t *types.Type) *types.Type {
+func operandType(op ir.Op, t *types.Type) *types.Type {
switch op {
- case OCOMPLEX:
+ case ir.OCOMPLEX:
if t.IsComplex() {
return floatForComplex(t)
}
- case OREAL, OIMAG:
+ case ir.OREAL, ir.OIMAG:
if t.IsFloat() {
return complexForFloat(t)
}
return true
}
if doesoverflow(v, t) {
- base.Errorf("constant %v overflows %v", vconv(v, 0), t)
+ base.Errorf("constant %v overflows %v", ir.FmtConst(v, 0), t)
return true
}
return false
return v
}
-func consttype(n *Node) constant.Kind {
- if n == nil || n.Op != OLITERAL {
- return constant.Unknown
- }
- return n.Val().Kind()
-}
-
-func Isconst(n *Node, ct constant.Kind) bool {
- return consttype(n) == ct
-}
-
var tokenForOp = [...]token.Token{
- OPLUS: token.ADD,
- ONEG: token.SUB,
- ONOT: token.NOT,
- OBITNOT: token.XOR,
-
- OADD: token.ADD,
- OSUB: token.SUB,
- OMUL: token.MUL,
- ODIV: token.QUO,
- OMOD: token.REM,
- OOR: token.OR,
- OXOR: token.XOR,
- OAND: token.AND,
- OANDNOT: token.AND_NOT,
- OOROR: token.LOR,
- OANDAND: token.LAND,
-
- OEQ: token.EQL,
- ONE: token.NEQ,
- OLT: token.LSS,
- OLE: token.LEQ,
- OGT: token.GTR,
- OGE: token.GEQ,
-
- OLSH: token.SHL,
- ORSH: token.SHR,
+ ir.OPLUS: token.ADD,
+ ir.ONEG: token.SUB,
+ ir.ONOT: token.NOT,
+ ir.OBITNOT: token.XOR,
+
+ ir.OADD: token.ADD,
+ ir.OSUB: token.SUB,
+ ir.OMUL: token.MUL,
+ ir.ODIV: token.QUO,
+ ir.OMOD: token.REM,
+ ir.OOR: token.OR,
+ ir.OXOR: token.XOR,
+ ir.OAND: token.AND,
+ ir.OANDNOT: token.AND_NOT,
+ ir.OOROR: token.LOR,
+ ir.OANDAND: token.LAND,
+
+ ir.OEQ: token.EQL,
+ ir.ONE: token.NEQ,
+ ir.OLT: token.LSS,
+ ir.OLE: token.LEQ,
+ ir.OGT: token.GTR,
+ ir.OGE: token.GEQ,
+
+ ir.OLSH: token.SHL,
+ ir.ORSH: token.SHR,
}
// evalConst returns a constant-evaluated expression equivalent to n.
// If n is not a constant, evalConst returns n.
// Otherwise, evalConst returns a new OLITERAL with the same value as n,
// and with .Orig pointing back to n.
-func evalConst(n *Node) *Node {
+func evalConst(n *ir.Node) *ir.Node {
nl, nr := n.Left, n.Right
// Pick off just the opcodes that can be constant evaluated.
switch op := n.Op; op {
- case OPLUS, ONEG, OBITNOT, ONOT:
- if nl.Op == OLITERAL {
+ case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
+ if nl.Op == ir.OLITERAL {
var prec uint
if n.Type.IsUnsigned() {
prec = uint(n.Type.Size() * 8)
return origConst(n, constant.UnaryOp(tokenForOp[op], nl.Val(), prec))
}
- case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND:
- if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT, ir.OOROR, ir.OANDAND:
+ if nl.Op == ir.OLITERAL && nr.Op == ir.OLITERAL {
rval := nr.Val()
// check for divisor underflow in complex division (see issue 20227)
- if op == ODIV && n.Type.IsComplex() && constant.Sign(square(constant.Real(rval))) == 0 && constant.Sign(square(constant.Imag(rval))) == 0 {
+ if op == ir.ODIV && n.Type.IsComplex() && constant.Sign(square(constant.Real(rval))) == 0 && constant.Sign(square(constant.Imag(rval))) == 0 {
base.Errorf("complex division by zero")
n.Type = nil
return n
}
- if (op == ODIV || op == OMOD) && constant.Sign(rval) == 0 {
+ if (op == ir.ODIV || op == ir.OMOD) && constant.Sign(rval) == 0 {
base.Errorf("division by zero")
n.Type = nil
return n
}
tok := tokenForOp[op]
- if op == ODIV && n.Type.IsInteger() {
+ if op == ir.ODIV && n.Type.IsInteger() {
tok = token.QUO_ASSIGN // integer division
}
return origConst(n, constant.BinaryOp(nl.Val(), tok, rval))
}
- case OEQ, ONE, OLT, OLE, OGT, OGE:
- if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
+ if nl.Op == ir.OLITERAL && nr.Op == ir.OLITERAL {
return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[op], nr.Val()))
}
- case OLSH, ORSH:
- if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ case ir.OLSH, ir.ORSH:
+ if nl.Op == ir.OLITERAL && nr.Op == ir.OLITERAL {
// shiftBound from go/types; "so we can express smallestFloat64"
const shiftBound = 1023 - 1 + 52
s, ok := constant.Uint64Val(nr.Val())
return origConst(n, constant.Shift(toint(nl.Val()), tokenForOp[op], uint(s)))
}
- case OCONV, ORUNESTR:
- if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
+ case ir.OCONV, ir.ORUNESTR:
+ if ir.OKForConst[n.Type.Etype] && nl.Op == ir.OLITERAL {
return origConst(n, convertVal(nl.Val(), n.Type, true))
}
- case OCONVNOP:
- if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
+ case ir.OCONVNOP:
+ if ir.OKForConst[n.Type.Etype] && nl.Op == ir.OLITERAL {
// set so n.Orig gets OCONV instead of OCONVNOP
- n.Op = OCONV
+ n.Op = ir.OCONV
return origConst(n, nl.Val())
}
- case OADDSTR:
+ case ir.OADDSTR:
// Merge adjacent constants in the argument list.
s := n.List.Slice()
need := 0
for i := 0; i < len(s); i++ {
- if i == 0 || !Isconst(s[i-1], constant.String) || !Isconst(s[i], constant.String) {
+ if i == 0 || !ir.IsConst(s[i-1], constant.String) || !ir.IsConst(s[i], constant.String) {
// Can't merge s[i] into s[i-1]; need a slot in the list.
need++
}
}
return origConst(n, constant.MakeString(strings.Join(strs, "")))
}
- newList := make([]*Node, 0, need)
+ newList := make([]*ir.Node, 0, need)
for i := 0; i < len(s); i++ {
- if Isconst(s[i], constant.String) && i+1 < len(s) && Isconst(s[i+1], constant.String) {
+ if ir.IsConst(s[i], constant.String) && i+1 < len(s) && ir.IsConst(s[i+1], constant.String) {
// merge from i up to but not including i2
var strs []string
i2 := i
- for i2 < len(s) && Isconst(s[i2], constant.String) {
+ for i2 < len(s) && ir.IsConst(s[i2], constant.String) {
strs = append(strs, s[i2].StringVal())
i2++
}
}
}
- n = n.copy()
+ n = ir.Copy(n)
n.List.Set(newList)
return n
- case OCAP, OLEN:
+ case ir.OCAP, ir.OLEN:
switch nl.Type.Etype {
- case TSTRING:
- if Isconst(nl, constant.String) {
+ case types.TSTRING:
+ if ir.IsConst(nl, constant.String) {
return origIntConst(n, int64(len(nl.StringVal())))
}
- case TARRAY:
+ case types.TARRAY:
if !hascallchan(nl) {
return origIntConst(n, nl.Type.NumElem())
}
}
- case OALIGNOF, OOFFSETOF, OSIZEOF:
+ case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
return origIntConst(n, evalunsafe(n))
- case OREAL:
- if nl.Op == OLITERAL {
+ case ir.OREAL:
+ if nl.Op == ir.OLITERAL {
return origConst(n, constant.Real(nl.Val()))
}
- case OIMAG:
- if nl.Op == OLITERAL {
+ case ir.OIMAG:
+ if nl.Op == ir.OLITERAL {
return origConst(n, constant.Imag(nl.Val()))
}
- case OCOMPLEX:
- if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ case ir.OCOMPLEX:
+ if nl.Op == ir.OLITERAL && nr.Op == ir.OLITERAL {
return origConst(n, makeComplex(nl.Val(), nr.Val()))
}
}
// For matching historical "constant OP overflow" error messages.
// TODO(mdempsky): Replace with error messages like go/types uses.
var overflowNames = [...]string{
- OADD: "addition",
- OSUB: "subtraction",
- OMUL: "multiplication",
- OLSH: "shift",
- OXOR: "bitwise XOR",
- OBITNOT: "bitwise complement",
+ ir.OADD: "addition",
+ ir.OSUB: "subtraction",
+ ir.OMUL: "multiplication",
+ ir.OLSH: "shift",
+ ir.OXOR: "bitwise XOR",
+ ir.OBITNOT: "bitwise complement",
}
// origConst returns an OLITERAL with orig n and value v.
-func origConst(n *Node, v constant.Value) *Node {
+func origConst(n *ir.Node, v constant.Value) *ir.Node {
lno := setlineno(n)
v = convertVal(v, n.Type, false)
base.Pos = lno
}
orig := n
- n = nodl(orig.Pos, OLITERAL, nil, nil)
+ n = ir.NodAt(orig.Pos, ir.OLITERAL, nil, nil)
n.Orig = orig
n.Type = orig.Type
n.SetVal(v)
return n
}
-func assertRepresents(t *types.Type, v constant.Value) {
- if !represents(t, v) {
- base.Fatalf("%v does not represent %v", t, v)
- }
-}
-
-func represents(t *types.Type, v constant.Value) bool {
- switch v.Kind() {
- case constant.Unknown:
- return okforconst[t.Etype]
- case constant.Bool:
- return t.IsBoolean()
- case constant.String:
- return t.IsString()
- case constant.Int:
- return t.IsInteger()
- case constant.Float:
- return t.IsFloat()
- case constant.Complex:
- return t.IsComplex()
- }
-
- base.Fatalf("unexpected constant kind: %v", v)
- panic("unreachable")
-}
-
-func origBoolConst(n *Node, v bool) *Node {
+func origBoolConst(n *ir.Node, v bool) *ir.Node {
return origConst(n, constant.MakeBool(v))
}
-func origIntConst(n *Node, v int64) *Node {
+func origIntConst(n *ir.Node, v int64) *ir.Node {
return origConst(n, constant.MakeInt64(v))
}
-// nodlit returns a new untyped constant with value v.
-func nodlit(v constant.Value) *Node {
- n := nod(OLITERAL, nil, nil)
- if k := v.Kind(); k != constant.Unknown {
- n.Type = idealType(k)
- n.SetVal(v)
- }
- return n
-}
-
-func idealType(ct constant.Kind) *types.Type {
- switch ct {
- case constant.String:
- return types.UntypedString
- case constant.Bool:
- return types.UntypedBool
- case constant.Int:
- return types.UntypedInt
- case constant.Float:
- return types.UntypedFloat
- case constant.Complex:
- return types.UntypedComplex
- }
- base.Fatalf("unexpected Ctype: %v", ct)
- return nil
-}
-
// defaultlit on both nodes simultaneously;
// if they're both ideal going in they better
// get the same type going out.
// force means must assign concrete (non-ideal) type.
// The results of defaultlit2 MUST be assigned back to l and r, e.g.
// n.Left, n.Right = defaultlit2(n.Left, n.Right, force)
-func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
+func defaultlit2(l *ir.Node, r *ir.Node, force bool) (*ir.Node, *ir.Node) {
if l.Type == nil || r.Type == nil {
return l, r
}
if l.Type.IsString() != r.Type.IsString() {
return l, r
}
- if l.isNil() || r.isNil() {
+ if ir.IsNil(l) || ir.IsNil(r) {
return l, r
}
}
func defaultType(t *types.Type) *types.Type {
- if !t.IsUntyped() || t.Etype == TNIL {
+ if !t.IsUntyped() || t.Etype == types.TNIL {
return t
}
switch t {
case types.UntypedBool:
- return types.Types[TBOOL]
+ return types.Types[types.TBOOL]
case types.UntypedString:
- return types.Types[TSTRING]
+ return types.Types[types.TSTRING]
case types.UntypedInt:
- return types.Types[TINT]
+ return types.Types[types.TINT]
case types.UntypedRune:
return types.Runetype
case types.UntypedFloat:
- return types.Types[TFLOAT64]
+ return types.Types[types.TFLOAT64]
case types.UntypedComplex:
- return types.Types[TCOMPLEX128]
+ return types.Types[types.TCOMPLEX128]
}
base.Fatalf("bad type %v", t)
return nil
}
-func smallintconst(n *Node) bool {
- if n.Op == OLITERAL {
+func smallintconst(n *ir.Node) bool {
+ if n.Op == ir.OLITERAL {
v, ok := constant.Int64Val(n.Val())
return ok && int64(int32(v)) == v
}
// If n is not a constant expression, not representable as an
// integer, or negative, it returns -1. If n is too large, it
// returns -2.
-func indexconst(n *Node) int64 {
- if n.Op != OLITERAL {
+func indexconst(n *ir.Node) int64 {
+ if n.Op != ir.OLITERAL {
return -1
}
- if !n.Type.IsInteger() && n.Type.Etype != TIDEAL {
+ if !n.Type.IsInteger() && n.Type.Etype != types.TIDEAL {
return -1
}
if v.Kind() != constant.Int || constant.Sign(v) < 0 {
return -1
}
- if doesoverflow(v, types.Types[TINT]) {
+ if doesoverflow(v, types.Types[types.TINT]) {
return -2
}
- return int64Val(types.Types[TINT], v)
+ return ir.Int64Val(types.Types[types.TINT], v)
}
// isGoConst reports whether n is a Go language constant (as opposed to a
//
// Expressions derived from nil, like string([]byte(nil)), while they
// may be known at compile time, are not Go language constants.
-func (n *Node) isGoConst() bool {
- return n.Op == OLITERAL
+func isGoConst(n *ir.Node) bool {
+ return n.Op == ir.OLITERAL
}
-func hascallchan(n *Node) bool {
+func hascallchan(n *ir.Node) bool {
if n == nil {
return false
}
switch n.Op {
- case OAPPEND,
- OCALL,
- OCALLFUNC,
- OCALLINTER,
- OCALLMETH,
- OCAP,
- OCLOSE,
- OCOMPLEX,
- OCOPY,
- ODELETE,
- OIMAG,
- OLEN,
- OMAKE,
- ONEW,
- OPANIC,
- OPRINT,
- OPRINTN,
- OREAL,
- ORECOVER,
- ORECV:
+ case ir.OAPPEND,
+ ir.OCALL,
+ ir.OCALLFUNC,
+ ir.OCALLINTER,
+ ir.OCALLMETH,
+ ir.OCAP,
+ ir.OCLOSE,
+ ir.OCOMPLEX,
+ ir.OCOPY,
+ ir.ODELETE,
+ ir.OIMAG,
+ ir.OLEN,
+ ir.OMAKE,
+ ir.ONEW,
+ ir.OPANIC,
+ ir.OPRINT,
+ ir.OPRINTN,
+ ir.OREAL,
+ ir.ORECOVER,
+ ir.ORECV:
return true
}
// where are used in the error message.
//
// n must not be an untyped constant.
-func (s *constSet) add(pos src.XPos, n *Node, what, where string) {
- if n.Op == OCONVIFACE && n.Implicit() {
+func (s *constSet) add(pos src.XPos, n *ir.Node, what, where string) {
+ if n.Op == ir.OCONVIFACE && n.Implicit() {
n = n.Left
}
- if !n.isGoConst() {
+ if !isGoConst(n) {
return
}
if n.Type.IsUntyped() {
typ := n.Type
switch typ {
case types.Bytetype:
- typ = types.Types[TUINT8]
+ typ = types.Types[types.TUINT8]
case types.Runetype:
- typ = types.Types[TINT32]
+ typ = types.Types[types.TINT32]
}
- k := constSetKey{typ, n.ValueInterface()}
+ k := constSetKey{typ, ir.ConstValue(n)}
if hasUniquePos(n) {
pos = n.Pos
// the latter is non-obvious.
//
// TODO(mdempsky): This could probably be a fmt.go flag.
-func nodeAndVal(n *Node) string {
+func nodeAndVal(n *ir.Node) string {
show := n.String()
- val := n.ValueInterface()
+ val := ir.ConstValue(n)
if s := fmt.Sprintf("%#v", val); show != s {
show += " (value " + s + ")"
}
import (
"bytes"
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src"
// Declaration stack & operations
-var externdcl []*Node
+var externdcl []*ir.Node
func testdclstack() {
if !types.IsDclstackValid() {
// declare records that Node n declares symbol n.Sym in the specified
// declaration context.
-func declare(n *Node, ctxt Class) {
- if n.isBlank() {
+func declare(n *ir.Node, ctxt ir.Class) {
+ if ir.IsBlank(n) {
return
}
if n.Name == nil {
// named OLITERAL needs Name; most OLITERALs don't.
- n.Name = new(Name)
+ n.Name = new(ir.Name)
}
s := n.Sym
// kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
- if !inimport && !typecheckok && s.Pkg != localpkg {
+ if !inimport && !typecheckok && s.Pkg != ir.LocalPkg {
base.ErrorfAt(n.Pos, "cannot declare name %v", s)
}
gen := 0
- if ctxt == PEXTERN {
+ if ctxt == ir.PEXTERN {
if s.Name == "init" {
base.ErrorfAt(n.Pos, "cannot declare init - must be func")
}
}
externdcl = append(externdcl, n)
} else {
- if Curfn == nil && ctxt == PAUTO {
+ if Curfn == nil && ctxt == ir.PAUTO {
base.Pos = n.Pos
base.Fatalf("automatic outside function")
}
- if Curfn != nil && ctxt != PFUNC {
+ if Curfn != nil && ctxt != ir.PFUNC {
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
}
- if n.Op == OTYPE {
+ if n.Op == ir.OTYPE {
declare_typegen++
gen = declare_typegen
- } else if n.Op == ONAME && ctxt == PAUTO && !strings.Contains(s.Name, "·") {
+ } else if n.Op == ir.ONAME && ctxt == ir.PAUTO && !strings.Contains(s.Name, "·") {
vargen++
gen = vargen
}
n.Name.Curfn = Curfn
}
- if ctxt == PAUTO {
+ if ctxt == ir.PAUTO {
n.Xoffset = 0
}
if s.Block == types.Block {
// functype will print errors about duplicate function arguments.
// Don't repeat the error here.
- if ctxt != PPARAM && ctxt != PPARAMOUT {
+ if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT {
redeclare(n.Pos, s, "in this block")
}
}
s.Block = types.Block
s.Lastlineno = base.Pos
- s.Def = asTypesNode(n)
+ s.Def = ir.AsTypesNode(n)
n.Name.Vargen = int32(gen)
n.SetClass(ctxt)
- if ctxt == PFUNC {
+ if ctxt == ir.PFUNC {
n.Sym.SetFunc(true)
}
autoexport(n, ctxt)
}
-func addvar(n *Node, t *types.Type, ctxt Class) {
- if n == nil || n.Sym == nil || (n.Op != ONAME && n.Op != ONONAME) || t == nil {
+func addvar(n *ir.Node, t *types.Type, ctxt ir.Class) {
+ if n == nil || n.Sym == nil || (n.Op != ir.ONAME && n.Op != ir.ONONAME) || t == nil {
base.Fatalf("addvar: n=%v t=%v nil", n, t)
}
- n.Op = ONAME
+ n.Op = ir.ONAME
declare(n, ctxt)
n.Type = t
}
// declare variables from grammar
// new_name_list (type | [type] = expr_list)
-func variter(vl []*Node, t *Node, el []*Node) []*Node {
- var init []*Node
+func variter(vl []*ir.Node, t *ir.Node, el []*ir.Node) []*ir.Node {
+ var init []*ir.Node
doexpr := len(el) > 0
if len(el) == 1 && len(vl) > 1 {
e := el[0]
- as2 := nod(OAS2, nil, nil)
+ as2 := ir.Nod(ir.OAS2, nil, nil)
as2.List.Set(vl)
as2.Rlist.Set1(e)
for _, v := range vl {
- v.Op = ONAME
+ v.Op = ir.ONAME
declare(v, dclcontext)
v.Name.Param.Ntype = t
v.Name.Defn = as2
if Curfn != nil {
- init = append(init, nod(ODCL, v, nil))
+ init = append(init, ir.Nod(ir.ODCL, v, nil))
}
}
nel := len(el)
for _, v := range vl {
- var e *Node
+ var e *ir.Node
if doexpr {
if len(el) == 0 {
base.Errorf("assignment mismatch: %d variables but %d values", len(vl), nel)
el = el[1:]
}
- v.Op = ONAME
+ v.Op = ir.ONAME
declare(v, dclcontext)
v.Name.Param.Ntype = t
- if e != nil || Curfn != nil || v.isBlank() {
+ if e != nil || Curfn != nil || ir.IsBlank(v) {
if Curfn != nil {
- init = append(init, nod(ODCL, v, nil))
+ init = append(init, ir.Nod(ir.ODCL, v, nil))
}
- e = nod(OAS, v, e)
+ e = ir.Nod(ir.OAS, v, e)
init = append(init, e)
if e.Right != nil {
v.Name.Defn = e
}
// newnoname returns a new ONONAME Node associated with symbol s.
-func newnoname(s *types.Sym) *Node {
+func newnoname(s *types.Sym) *ir.Node {
if s == nil {
base.Fatalf("newnoname nil")
}
- n := nod(ONONAME, nil, nil)
+ n := ir.Nod(ir.ONONAME, nil, nil)
n.Sym = s
n.Xoffset = 0
return n
}
// newfuncnamel generates a new name node for a function or method.
-func newfuncnamel(pos src.XPos, s *types.Sym, fn *Func) *Node {
+func newfuncnamel(pos src.XPos, s *types.Sym, fn *ir.Func) *ir.Node {
if fn.Nname != nil {
base.Fatalf("newfuncnamel - already have name")
}
- n := newnamel(pos, s)
+ n := ir.NewNameAt(pos, s)
n.Func = fn
fn.Nname = n
return n
// this generates a new name node for a name
// being declared.
-func dclname(s *types.Sym) *Node {
- n := newname(s)
- n.Op = ONONAME // caller will correct it
+func dclname(s *types.Sym) *ir.Node {
+ n := NewName(s)
+ n.Op = ir.ONONAME // caller will correct it
return n
}
-func typenod(t *types.Type) *Node {
+func typenod(t *types.Type) *ir.Node {
return typenodl(src.NoXPos, t)
}
-func typenodl(pos src.XPos, t *types.Type) *Node {
+func typenodl(pos src.XPos, t *types.Type) *ir.Node {
// if we copied another type with *t = *u
// then t->nod might be out of date, so
// check t->nod->type too
- if asNode(t.Nod) == nil || asNode(t.Nod).Type != t {
- t.Nod = asTypesNode(nodl(pos, OTYPE, nil, nil))
- asNode(t.Nod).Type = t
- asNode(t.Nod).Sym = t.Sym
+ if ir.AsNode(t.Nod) == nil || ir.AsNode(t.Nod).Type != t {
+ t.Nod = ir.AsTypesNode(ir.NodAt(pos, ir.OTYPE, nil, nil))
+ ir.AsNode(t.Nod).Type = t
+ ir.AsNode(t.Nod).Sym = t.Sym
}
- return asNode(t.Nod)
+ return ir.AsNode(t.Nod)
}
-func anonfield(typ *types.Type) *Node {
+func anonfield(typ *types.Type) *ir.Node {
return symfield(nil, typ)
}
-func namedfield(s string, typ *types.Type) *Node {
+func namedfield(s string, typ *types.Type) *ir.Node {
return symfield(lookup(s), typ)
}
-func symfield(s *types.Sym, typ *types.Type) *Node {
- n := nodSym(ODCLFIELD, nil, s)
+func symfield(s *types.Sym, typ *types.Type) *ir.Node {
+ n := nodSym(ir.ODCLFIELD, nil, s)
n.Type = typ
return n
}
// If no such Node currently exists, an ONONAME Node is returned instead.
// Automatically creates a new closure variable if the referenced symbol was
// declared in a different (containing) function.
-func oldname(s *types.Sym) *Node {
- n := asNode(s.Def)
+func oldname(s *types.Sym) *ir.Node {
+ n := ir.AsNode(s.Def)
if n == nil {
// Maybe a top-level declaration will come along later to
// define s. resolve will check s.Def again once all input
return newnoname(s)
}
- if Curfn != nil && n.Op == ONAME && n.Name.Curfn != nil && n.Name.Curfn != Curfn {
+ if Curfn != nil && n.Op == ir.ONAME && n.Name.Curfn != nil && n.Name.Curfn != Curfn {
// Inner func is referring to var in outer func.
//
// TODO(rsc): If there is an outer variable x and we
c := n.Name.Param.Innermost
if c == nil || c.Name.Curfn != Curfn {
// Do not have a closure var for the active closure yet; make one.
- c = newname(s)
- c.SetClass(PAUTOHEAP)
+ c = NewName(s)
+ c.SetClass(ir.PAUTOHEAP)
c.Name.SetIsClosureVar(true)
c.SetIsDDD(n.IsDDD())
c.Name.Defn = n
}
// importName is like oldname, but it reports an error if sym is from another package and not exported.
-func importName(sym *types.Sym) *Node {
+func importName(sym *types.Sym) *ir.Node {
n := oldname(sym)
- if !types.IsExported(sym.Name) && sym.Pkg != localpkg {
+ if !types.IsExported(sym.Name) && sym.Pkg != ir.LocalPkg {
n.SetDiag(true)
base.Errorf("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name)
}
}
// := declarations
-func colasname(n *Node) bool {
+func colasname(n *ir.Node) bool {
switch n.Op {
- case ONAME,
- ONONAME,
- OPACK,
- OTYPE,
- OLITERAL:
+ case ir.ONAME,
+ ir.ONONAME,
+ ir.OPACK,
+ ir.OTYPE,
+ ir.OLITERAL:
return n.Sym != nil
}
return false
}
-func colasdefn(left []*Node, defn *Node) {
+func colasdefn(left []*ir.Node, defn *ir.Node) {
for _, n := range left {
if n.Sym != nil {
n.Sym.SetUniq(true)
var nnew, nerr int
for i, n := range left {
- if n.isBlank() {
+ if ir.IsBlank(n) {
continue
}
if !colasname(n) {
}
nnew++
- n = newname(n.Sym)
+ n = NewName(n.Sym)
declare(n, dclcontext)
n.Name.Defn = defn
- defn.Ninit.Append(nod(ODCL, n, nil))
+ defn.Ninit.Append(ir.Nod(ir.ODCL, n, nil))
left[i] = n
}
// declare the arguments in an
// interface field declaration.
-func ifacedcl(n *Node) {
- if n.Op != ODCLFIELD || n.Left == nil {
+func ifacedcl(n *ir.Node) {
+ if n.Op != ir.ODCLFIELD || n.Left == nil {
base.Fatalf("ifacedcl")
}
// and declare the arguments.
// called in extern-declaration context
// returns in auto-declaration context.
-func funchdr(n *Node) {
+func funchdr(n *ir.Node) {
// change the declaration context from extern to auto
funcStack = append(funcStack, funcStackEnt{Curfn, dclcontext})
Curfn = n
- dclcontext = PAUTO
+ dclcontext = ir.PAUTO
types.Markdcl()
}
}
-func funcargs(nt *Node) {
- if nt.Op != OTFUNC {
+func funcargs(nt *ir.Node) {
+ if nt.Op != ir.OTFUNC {
base.Fatalf("funcargs %v", nt.Op)
}
// declare the receiver and in arguments.
if nt.Left != nil {
- funcarg(nt.Left, PPARAM)
+ funcarg(nt.Left, ir.PPARAM)
}
for _, n := range nt.List.Slice() {
- funcarg(n, PPARAM)
+ funcarg(n, ir.PPARAM)
}
oldvargen := vargen
gen++
}
- funcarg(n, PPARAMOUT)
+ funcarg(n, ir.PPARAMOUT)
}
vargen = oldvargen
}
-func funcarg(n *Node, ctxt Class) {
- if n.Op != ODCLFIELD {
+func funcarg(n *ir.Node, ctxt ir.Class) {
+ if n.Op != ir.ODCLFIELD {
base.Fatalf("funcarg %v", n.Op)
}
if n.Sym == nil {
return
}
- n.Right = newnamel(n.Pos, n.Sym)
+ n.Right = ir.NewNameAt(n.Pos, n.Sym)
n.Right.Name.Param.Ntype = n.Left
n.Right.SetIsDDD(n.IsDDD())
declare(n.Right, ctxt)
// This happens during import, where the hidden_fndcl rule has
// used functype directly to parse the function's type.
func funcargs2(t *types.Type) {
- if t.Etype != TFUNC {
+ if t.Etype != types.TFUNC {
base.Fatalf("funcargs2 %v", t)
}
for _, f := range t.Recvs().Fields().Slice() {
- funcarg2(f, PPARAM)
+ funcarg2(f, ir.PPARAM)
}
for _, f := range t.Params().Fields().Slice() {
- funcarg2(f, PPARAM)
+ funcarg2(f, ir.PPARAM)
}
for _, f := range t.Results().Fields().Slice() {
- funcarg2(f, PPARAMOUT)
+ funcarg2(f, ir.PPARAMOUT)
}
}
-func funcarg2(f *types.Field, ctxt Class) {
+func funcarg2(f *types.Field, ctxt ir.Class) {
if f.Sym == nil {
return
}
- n := newnamel(f.Pos, f.Sym)
- f.Nname = asTypesNode(n)
+ n := ir.NewNameAt(f.Pos, f.Sym)
+ f.Nname = ir.AsTypesNode(n)
n.Type = f.Type
n.SetIsDDD(f.IsDDD())
declare(n, ctxt)
var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
type funcStackEnt struct {
- curfn *Node
- dclcontext Class
+ curfn *ir.Node
+ dclcontext ir.Class
}
// finish the body.
if t.IsPtr() || t.IsUnsafePtr() {
base.Errorf("embedded type cannot be a pointer")
- } else if t.Etype == TFORW && !t.ForwardType().Embedlineno.IsKnown() {
+ } else if t.Etype == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
t.ForwardType().Embedlineno = base.Pos
}
}
-func structfield(n *Node) *types.Field {
+func structfield(n *ir.Node) *types.Field {
lno := base.Pos
base.Pos = n.Pos
- if n.Op != ODCLFIELD {
+ if n.Op != ir.ODCLFIELD {
base.Fatalf("structfield: oops %v\n", n)
}
// convert a parsed id/type list into
// a type for struct/interface/arglist
-func tostruct(l []*Node) *types.Type {
- t := types.New(TSTRUCT)
+func tostruct(l []*ir.Node) *types.Type {
+ t := types.New(types.TSTRUCT)
fields := make([]*types.Field, len(l))
for i, n := range l {
return t
}
-func tofunargs(l []*Node, funarg types.Funarg) *types.Type {
- t := types.New(TSTRUCT)
+func tofunargs(l []*ir.Node, funarg types.Funarg) *types.Type {
+ t := types.New(types.TSTRUCT)
t.StructType().Funarg = funarg
fields := make([]*types.Field, len(l))
f.SetIsDDD(n.IsDDD())
if n.Right != nil {
n.Right.Type = f.Type
- f.Nname = asTypesNode(n.Right)
+ f.Nname = ir.AsTypesNode(n.Right)
}
if f.Broke() {
t.SetBroke(true)
}
func tofunargsfield(fields []*types.Field, funarg types.Funarg) *types.Type {
- t := types.New(TSTRUCT)
+ t := types.New(types.TSTRUCT)
t.StructType().Funarg = funarg
t.SetFields(fields)
return t
}
-func interfacefield(n *Node) *types.Field {
+func interfacefield(n *ir.Node) *types.Field {
lno := base.Pos
base.Pos = n.Pos
- if n.Op != ODCLFIELD {
+ if n.Op != ir.ODCLFIELD {
base.Fatalf("interfacefield: oops %v\n", n)
}
return f
}
-func tointerface(l []*Node) *types.Type {
+func tointerface(l []*ir.Node) *types.Type {
if len(l) == 0 {
- return types.Types[TINTER]
+ return types.Types[types.TINTER]
}
- t := types.New(TINTER)
+ t := types.New(types.TINTER)
var fields []*types.Field
for _, n := range l {
f := interfacefield(n)
return t
}
-func fakeRecv() *Node {
+func fakeRecv() *ir.Node {
return anonfield(types.FakeRecvType())
}
}
// turn a parsed function declaration into a type
-func functype(this *Node, in, out []*Node) *types.Type {
- t := types.New(TFUNC)
+func functype(this *ir.Node, in, out []*ir.Node) *types.Type {
+ t := types.New(types.TFUNC)
- var rcvr []*Node
+ var rcvr []*ir.Node
if this != nil {
- rcvr = []*Node{this}
+ rcvr = []*ir.Node{this}
}
t.FuncType().Receiver = tofunargs(rcvr, types.FunargRcvr)
t.FuncType().Params = tofunargs(in, types.FunargParams)
t.SetBroke(true)
}
- t.FuncType().Outnamed = t.NumResults() > 0 && origSym(t.Results().Field(0).Sym) != nil
+ t.FuncType().Outnamed = t.NumResults() > 0 && ir.OrigSym(t.Results().Field(0).Sym) != nil
return t
}
func functypefield(this *types.Field, in, out []*types.Field) *types.Type {
- t := types.New(TFUNC)
+ t := types.New(types.TFUNC)
var rcvr []*types.Field
if this != nil {
t.FuncType().Params = tofunargsfield(in, types.FunargParams)
t.FuncType().Results = tofunargsfield(out, types.FunargResults)
- t.FuncType().Outnamed = t.NumResults() > 0 && origSym(t.Results().Field(0).Sym) != nil
+ t.FuncType().Outnamed = t.NumResults() > 0 && ir.OrigSym(t.Results().Field(0).Sym) != nil
return t
}
-// origSym returns the original symbol written by the user.
-func origSym(s *types.Sym) *types.Sym {
- if s == nil {
- return nil
- }
-
- if len(s.Name) > 1 && s.Name[0] == '~' {
- switch s.Name[1] {
- case 'r': // originally an unnamed result
- return nil
- case 'b': // originally the blank identifier _
- // TODO(mdempsky): Does s.Pkg matter here?
- return nblank.Sym
- }
- return s
- }
-
- if strings.HasPrefix(s.Name, ".anon") {
- // originally an unnamed or _ name (see subr.go: structargs)
- return nil
- }
-
- return s
-}
-
// methodSym returns the method symbol representing a method name
// associated with a specific receiver type.
//
// - msym is the method symbol
// - t is function type (with receiver)
// Returns a pointer to the existing or added Field; or nil if there's an error.
-func addmethod(n *Node, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
+func addmethod(n *ir.Node, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
if msym == nil {
base.Fatalf("no method symbol")
}
return nil
}
- if local && mt.Sym.Pkg != localpkg {
+ if local && mt.Sym.Pkg != ir.LocalPkg {
base.Errorf("cannot define new methods on non-local type %v", mt)
return nil
}
}
f := types.NewField(base.Pos, msym, t)
- f.Nname = asTypesNode(n.Func.Nname)
+ f.Nname = ir.AsTypesNode(n.Func.Nname)
f.SetNointerface(nointerface)
mt.Methods().Append(f)
}
// setNodeNameFunc marks a node as a function.
-func setNodeNameFunc(n *Node) {
- if n.Op != ONAME || n.Class() != Pxxx {
+func setNodeNameFunc(n *ir.Node) {
+ if n.Op != ir.ONAME || n.Class() != ir.Pxxx {
base.Fatalf("expected ONAME/Pxxx node, got %v", n)
}
- n.SetClass(PFUNC)
+ n.SetClass(ir.PFUNC)
n.Sym.SetFunc(true)
}
-func dclfunc(sym *types.Sym, tfn *Node) *Node {
- if tfn.Op != OTFUNC {
+func dclfunc(sym *types.Sym, tfn *ir.Node) *ir.Node {
+ if tfn.Op != ir.OTFUNC {
base.Fatalf("expected OTFUNC node, got %v", tfn)
}
- fn := nod(ODCLFUNC, nil, nil)
+ fn := ir.Nod(ir.ODCLFUNC, nil, nil)
fn.Func.Nname = newfuncnamel(base.Pos, sym, fn.Func)
fn.Func.Nname.Name.Defn = fn
fn.Func.Nname.Name.Param.Ntype = tfn
// extraCalls contains extra function calls that may not be
// visible during later analysis. It maps from the ODCLFUNC of
// the caller to a list of callees.
- extraCalls map[*Node][]nowritebarrierrecCall
+ extraCalls map[*ir.Node][]nowritebarrierrecCall
// curfn is the current function during AST walks.
- curfn *Node
+ curfn *ir.Node
}
type nowritebarrierrecCall struct {
- target *Node // ODCLFUNC of caller or callee
+ target *ir.Node // ODCLFUNC of caller or callee
lineno src.XPos // line of call
}
-type nowritebarrierrecCallSym struct {
- target *obj.LSym // LSym of callee
- lineno src.XPos // line of call
-}
-
// newNowritebarrierrecChecker creates a nowritebarrierrecChecker. It
// must be called before transformclosure and walk.
func newNowritebarrierrecChecker() *nowritebarrierrecChecker {
c := &nowritebarrierrecChecker{
- extraCalls: make(map[*Node][]nowritebarrierrecCall),
+ extraCalls: make(map[*ir.Node][]nowritebarrierrecCall),
}
// Find all systemstack calls and record their targets. In
// directly. This has to happen before transformclosure since
// it's a lot harder to work out the argument after.
for _, n := range xtop {
- if n.Op != ODCLFUNC {
+ if n.Op != ir.ODCLFUNC {
continue
}
c.curfn = n
- inspect(n, c.findExtraCalls)
+ ir.Inspect(n, c.findExtraCalls)
}
c.curfn = nil
return c
}
-func (c *nowritebarrierrecChecker) findExtraCalls(n *Node) bool {
- if n.Op != OCALLFUNC {
+func (c *nowritebarrierrecChecker) findExtraCalls(n *ir.Node) bool {
+ if n.Op != ir.OCALLFUNC {
return true
}
fn := n.Left
- if fn == nil || fn.Op != ONAME || fn.Class() != PFUNC || fn.Name.Defn == nil {
+ if fn == nil || fn.Op != ir.ONAME || fn.Class() != ir.PFUNC || fn.Name.Defn == nil {
return true
}
if !isRuntimePkg(fn.Sym.Pkg) || fn.Sym.Name != "systemstack" {
return true
}
- var callee *Node
+ var callee *ir.Node
arg := n.List.First()
switch arg.Op {
- case ONAME:
+ case ir.ONAME:
callee = arg.Name.Defn
- case OCLOSURE:
+ case ir.OCLOSURE:
callee = arg.Func.Decl
default:
base.Fatalf("expected ONAME or OCLOSURE node, got %+v", arg)
}
- if callee.Op != ODCLFUNC {
+ if callee.Op != ir.ODCLFUNC {
base.Fatalf("expected ODCLFUNC node, got %+v", callee)
}
c.extraCalls[c.curfn] = append(c.extraCalls[c.curfn], nowritebarrierrecCall{callee, n.Pos})
// because that's all we know after we start SSA.
//
// This can be called concurrently for different from Nodes.
-func (c *nowritebarrierrecChecker) recordCall(from *Node, to *obj.LSym, pos src.XPos) {
- if from.Op != ODCLFUNC {
+func (c *nowritebarrierrecChecker) recordCall(from *ir.Node, to *obj.LSym, pos src.XPos) {
+ if from.Op != ir.ODCLFUNC {
base.Fatalf("expected ODCLFUNC, got %v", from)
}
// We record this information on the *Func so this is
// concurrent-safe.
fn := from.Func
- if fn.nwbrCalls == nil {
- fn.nwbrCalls = new([]nowritebarrierrecCallSym)
+ if fn.NWBRCalls == nil {
+ fn.NWBRCalls = new([]ir.SymAndPos)
}
- *fn.nwbrCalls = append(*fn.nwbrCalls, nowritebarrierrecCallSym{to, pos})
+ *fn.NWBRCalls = append(*fn.NWBRCalls, ir.SymAndPos{Sym: to, Pos: pos})
}
func (c *nowritebarrierrecChecker) check() {
// capture all calls created by lowering, but this means we
// only get to see the obj.LSyms of calls. symToFunc lets us
// get back to the ODCLFUNCs.
- symToFunc := make(map[*obj.LSym]*Node)
+ symToFunc := make(map[*obj.LSym]*ir.Node)
// funcs records the back-edges of the BFS call graph walk. It
// maps from the ODCLFUNC of each function that must not have
// write barriers to the call that inhibits them. Functions
// that are directly marked go:nowritebarrierrec are in this
// map with a zero-valued nowritebarrierrecCall. This also
// acts as the set of marks for the BFS of the call graph.
- funcs := make(map[*Node]nowritebarrierrecCall)
+ funcs := make(map[*ir.Node]nowritebarrierrecCall)
// q is the queue of ODCLFUNC Nodes to visit in BFS order.
- var q nodeQueue
+ var q ir.NodeQueue
for _, n := range xtop {
- if n.Op != ODCLFUNC {
+ if n.Op != ir.ODCLFUNC {
continue
}
- symToFunc[n.Func.lsym] = n
+ symToFunc[n.Func.LSym] = n
// Make nowritebarrierrec functions BFS roots.
- if n.Func.Pragma&Nowritebarrierrec != 0 {
+ if n.Func.Pragma&ir.Nowritebarrierrec != 0 {
funcs[n] = nowritebarrierrecCall{}
- q.pushRight(n)
+ q.PushRight(n)
}
// Check go:nowritebarrier functions.
- if n.Func.Pragma&Nowritebarrier != 0 && n.Func.WBPos.IsKnown() {
+ if n.Func.Pragma&ir.Nowritebarrier != 0 && n.Func.WBPos.IsKnown() {
base.ErrorfAt(n.Func.WBPos, "write barrier prohibited")
}
}
// Perform a BFS of the call graph from all
// go:nowritebarrierrec functions.
- enqueue := func(src, target *Node, pos src.XPos) {
- if target.Func.Pragma&Yeswritebarrierrec != 0 {
+ enqueue := func(src, target *ir.Node, pos src.XPos) {
+ if target.Func.Pragma&ir.Yeswritebarrierrec != 0 {
// Don't flow into this function.
return
}
// Record the path.
funcs[target] = nowritebarrierrecCall{target: src, lineno: pos}
- q.pushRight(target)
+ q.PushRight(target)
}
- for !q.empty() {
- fn := q.popLeft()
+ for !q.Empty() {
+ fn := q.PopLeft()
// Check fn.
if fn.Func.WBPos.IsKnown() {
for _, callee := range c.extraCalls[fn] {
enqueue(fn, callee.target, callee.lineno)
}
- if fn.Func.nwbrCalls == nil {
+ if fn.Func.NWBRCalls == nil {
continue
}
- for _, callee := range *fn.Func.nwbrCalls {
- target := symToFunc[callee.target]
+ for _, callee := range *fn.Func.NWBRCalls {
+ target := symToFunc[callee.Sym]
if target != nil {
- enqueue(fn, target, callee.lineno)
+ enqueue(fn, target, callee.Pos)
}
}
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
"cmd/compile/internal/types"
"cmd/internal/obj"
"strings"
)
-var embedlist []*Node
+var embedlist []*ir.Node
const (
embedUnknown = iota
var numLocalEmbed int
-func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []PragmaEmbed) (newExprs []*Node) {
+func varEmbed(p *noder, names []*ir.Node, typ *ir.Node, exprs []*ir.Node, embeds []PragmaEmbed) (newExprs []*ir.Node) {
haveEmbed := false
for _, decl := range p.file.DeclList {
imp, ok := decl.(*syntax.ImportDecl)
}
v := names[0]
- if dclcontext != PEXTERN {
+ if dclcontext != ir.PEXTERN {
numLocalEmbed++
- v = newnamel(v.Pos, lookupN("embed.", numLocalEmbed))
- v.Sym.Def = asTypesNode(v)
+ v = ir.NewNameAt(v.Pos, lookupN("embed.", numLocalEmbed))
+ v.Sym.Def = ir.AsTypesNode(v)
v.Name.Param.Ntype = typ
- v.SetClass(PEXTERN)
+ v.SetClass(ir.PEXTERN)
externdcl = append(externdcl, v)
- exprs = []*Node{v}
+ exprs = []*ir.Node{v}
}
v.Name.Param.SetEmbedFiles(list)
// The match is approximate because we haven't done scope resolution yet and
// can't tell whether "string" and "byte" really mean "string" and "byte".
// The result must be confirmed later, after type checking, using embedKind.
-func embedKindApprox(typ *Node) int {
- if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && base.Ctxt.Pkgpath == "embed")) {
+func embedKindApprox(typ *ir.Node) int {
+ if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == ir.LocalPkg && base.Ctxt.Pkgpath == "embed")) {
return embedFiles
}
// These are not guaranteed to match only string and []byte -
// maybe the local package has redefined one of those words.
// But it's the best we can do now during the noder.
// The stricter check happens later, in initEmbed calling embedKind.
- if typ.Sym != nil && typ.Sym.Name == "string" && typ.Sym.Pkg == localpkg {
+ if typ.Sym != nil && typ.Sym.Name == "string" && typ.Sym.Pkg == ir.LocalPkg {
return embedString
}
- if typ.Op == OTARRAY && typ.Left == nil && typ.Right.Sym != nil && typ.Right.Sym.Name == "byte" && typ.Right.Sym.Pkg == localpkg {
+ if typ.Op == ir.OTARRAY && typ.Left == nil && typ.Right.Sym != nil && typ.Right.Sym.Name == "byte" && typ.Right.Sym.Pkg == ir.LocalPkg {
return embedBytes
}
return embedUnknown
// embedKind determines the kind of embedding variable.
func embedKind(typ *types.Type) int {
- if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && base.Ctxt.Pkgpath == "embed")) {
+ if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == ir.LocalPkg && base.Ctxt.Pkgpath == "embed")) {
return embedFiles
}
- if typ == types.Types[TSTRING] {
+ if typ == types.Types[types.TSTRING] {
return embedString
}
if typ.Sym == nil && typ.IsSlice() && typ.Elem() == types.Bytetype {
// initEmbed emits the init data for a //go:embed variable,
// which is either a string, a []byte, or an embed.FS.
-func initEmbed(v *Node) {
+func initEmbed(v *ir.Node) {
files := v.Name.Param.EmbedFiles()
switch kind := embedKind(v.Type); kind {
case embedUnknown:
+++ /dev/null
-// Copyright 2011 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/compile/internal/base"
- "cmd/compile/internal/types"
- "fmt"
-)
-
-func escapes(all []*Node) {
- visitBottomUp(all, escapeFuncs)
-}
-
-const (
- EscFuncUnknown = 0 + iota
- EscFuncPlanned
- EscFuncStarted
- EscFuncTagged
-)
-
-func min8(a, b int8) int8 {
- if a < b {
- return a
- }
- return b
-}
-
-func max8(a, b int8) int8 {
- if a > b {
- return a
- }
- return b
-}
-
-const (
- EscUnknown = iota
- EscNone // Does not escape to heap, result, or parameters.
- EscHeap // Reachable from the heap
- EscNever // By construction will not escape.
-)
-
-// funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way.
-func funcSym(fn *Node) *types.Sym {
- if fn == nil || fn.Func.Nname == nil {
- return nil
- }
- return fn.Func.Nname.Sym
-}
-
-// Mark labels that have no backjumps to them as not increasing e.loopdepth.
-// Walk hasn't generated (goto|label).Left.Sym.Label yet, so we'll cheat
-// and set it to one of the following two. Then in esc we'll clear it again.
-var (
- looping = nod(OXXX, nil, nil)
- nonlooping = nod(OXXX, nil, nil)
-)
-
-func isSliceSelfAssign(dst, src *Node) bool {
- // Detect the following special case.
- //
- // func (b *Buffer) Foo() {
- // n, m := ...
- // b.buf = b.buf[n:m]
- // }
- //
- // This assignment is a no-op for escape analysis,
- // it does not store any new pointers into b that were not already there.
- // However, without this special case b will escape, because we assign to OIND/ODOTPTR.
- // Here we assume that the statement will not contain calls,
- // that is, that order will move any calls to init.
- // Otherwise base ONAME value could change between the moments
- // when we evaluate it for dst and for src.
-
- // dst is ONAME dereference.
- if dst.Op != ODEREF && dst.Op != ODOTPTR || dst.Left.Op != ONAME {
- return false
- }
- // src is a slice operation.
- switch src.Op {
- case OSLICE, OSLICE3, OSLICESTR:
- // OK.
- case OSLICEARR, OSLICE3ARR:
- // Since arrays are embedded into containing object,
- // slice of non-pointer array will introduce a new pointer into b that was not already there
- // (pointer to b itself). After such assignment, if b contents escape,
- // b escapes as well. If we ignore such OSLICEARR, we will conclude
- // that b does not escape when b contents do.
- //
- // Pointer to an array is OK since it's not stored inside b directly.
- // For slicing an array (not pointer to array), there is an implicit OADDR.
- // We check that to determine non-pointer array slicing.
- if src.Left.Op == OADDR {
- return false
- }
- default:
- return false
- }
- // slice is applied to ONAME dereference.
- if src.Left.Op != ODEREF && src.Left.Op != ODOTPTR || src.Left.Left.Op != ONAME {
- return false
- }
- // dst and src reference the same base ONAME.
- return dst.Left == src.Left.Left
-}
-
-// isSelfAssign reports whether assignment from src to dst can
-// be ignored by the escape analysis as it's effectively a self-assignment.
-func isSelfAssign(dst, src *Node) bool {
- if isSliceSelfAssign(dst, src) {
- return true
- }
-
- // Detect trivial assignments that assign back to the same object.
- //
- // It covers these cases:
- // val.x = val.y
- // val.x[i] = val.y[j]
- // val.x1.x2 = val.x1.y2
- // ... etc
- //
- // These assignments do not change assigned object lifetime.
-
- if dst == nil || src == nil || dst.Op != src.Op {
- return false
- }
-
- switch dst.Op {
- case ODOT, ODOTPTR:
- // Safe trailing accessors that are permitted to differ.
- case OINDEX:
- if mayAffectMemory(dst.Right) || mayAffectMemory(src.Right) {
- return false
- }
- default:
- return false
- }
-
- // The expression prefix must be both "safe" and identical.
- return samesafeexpr(dst.Left, src.Left)
-}
-
-// mayAffectMemory reports whether evaluation of n may affect the program's
-// memory state. If the expression can't affect memory state, then it can be
-// safely ignored by the escape analysis.
-func mayAffectMemory(n *Node) bool {
- // We may want to use a list of "memory safe" ops instead of generally
- // "side-effect free", which would include all calls and other ops that can
- // allocate or change global state. For now, it's safer to start with the latter.
- //
- // We're ignoring things like division by zero, index out of range,
- // and nil pointer dereference here.
- switch n.Op {
- case ONAME, OCLOSUREVAR, OLITERAL, ONIL:
- return false
-
- // Left+Right group.
- case OINDEX, OADD, OSUB, OOR, OXOR, OMUL, OLSH, ORSH, OAND, OANDNOT, ODIV, OMOD:
- return mayAffectMemory(n.Left) || mayAffectMemory(n.Right)
-
- // Left group.
- case ODOT, ODOTPTR, ODEREF, OCONVNOP, OCONV, OLEN, OCAP,
- ONOT, OBITNOT, OPLUS, ONEG, OALIGNOF, OOFFSETOF, OSIZEOF:
- return mayAffectMemory(n.Left)
-
- default:
- return true
- }
-}
-
-// heapAllocReason returns the reason the given Node must be heap
-// allocated, or the empty string if it doesn't.
-func heapAllocReason(n *Node) string {
- if n.Type == nil {
- return ""
- }
-
- // Parameters are always passed via the stack.
- if n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) {
- return ""
- }
-
- if n.Type.Width > maxStackVarSize {
- return "too large for stack"
- }
-
- if (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize {
- return "too large for stack"
- }
-
- if n.Op == OCLOSURE && closureType(n).Size() >= maxImplicitStackVarSize {
- return "too large for stack"
- }
- if n.Op == OCALLPART && partialCallType(n).Size() >= maxImplicitStackVarSize {
- return "too large for stack"
- }
-
- if n.Op == OMAKESLICE {
- r := n.Right
- if r == nil {
- r = n.Left
- }
- if !smallintconst(r) {
- return "non-constant size"
- }
- if t := n.Type; t.Elem().Width != 0 && r.Int64Val() >= maxImplicitStackVarSize/t.Elem().Width {
- return "too large for stack"
- }
- }
-
- return ""
-}
-
-// addrescapes tags node n as having had its address taken
-// by "increasing" the "value" of n.Esc to EscHeap.
-// Storage is allocated as necessary to allow the address
-// to be taken.
-func addrescapes(n *Node) {
- switch n.Op {
- default:
- // Unexpected Op, probably due to a previous type error. Ignore.
-
- case ODEREF, ODOTPTR:
- // Nothing to do.
-
- case ONAME:
- if n == nodfp {
- break
- }
-
- // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
- // on PPARAM it means something different.
- if n.Class() == PAUTO && n.Esc == EscNever {
- break
- }
-
- // If a closure reference escapes, mark the outer variable as escaping.
- if n.Name.IsClosureVar() {
- addrescapes(n.Name.Defn)
- break
- }
-
- if n.Class() != PPARAM && n.Class() != PPARAMOUT && n.Class() != PAUTO {
- break
- }
-
- // This is a plain parameter or local variable that needs to move to the heap,
- // but possibly for the function outside the one we're compiling.
- // That is, if we have:
- //
- // func f(x int) {
- // func() {
- // global = &x
- // }
- // }
- //
- // then we're analyzing the inner closure but we need to move x to the
- // heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
- oldfn := Curfn
- Curfn = n.Name.Curfn
- if Curfn.Op == OCLOSURE {
- Curfn = Curfn.Func.Decl
- panic("can't happen")
- }
- ln := base.Pos
- base.Pos = Curfn.Pos
- moveToHeap(n)
- Curfn = oldfn
- base.Pos = ln
-
- // ODOTPTR has already been introduced,
- // so these are the non-pointer ODOT and OINDEX.
- // In &x[0], if x is a slice, then x does not
- // escape--the pointer inside x does, but that
- // is always a heap pointer anyway.
- case ODOT, OINDEX, OPAREN, OCONVNOP:
- if !n.Left.Type.IsSlice() {
- addrescapes(n.Left)
- }
- }
-}
-
-// moveToHeap records the parameter or local variable n as moved to the heap.
-func moveToHeap(n *Node) {
- if base.Flag.LowerR != 0 {
- Dump("MOVE", n)
- }
- if base.Flag.CompilingRuntime {
- base.Errorf("%v escapes to heap, not allowed in runtime", n)
- }
- if n.Class() == PAUTOHEAP {
- Dump("n", n)
- base.Fatalf("double move to heap")
- }
-
- // Allocate a local stack variable to hold the pointer to the heap copy.
- // temp will add it to the function declaration list automatically.
- heapaddr := temp(types.NewPtr(n.Type))
- heapaddr.Sym = lookup("&" + n.Sym.Name)
- heapaddr.Orig.Sym = heapaddr.Sym
- heapaddr.Pos = n.Pos
-
- // Unset AutoTemp to persist the &foo variable name through SSA to
- // liveness analysis.
- // TODO(mdempsky/drchase): Cleaner solution?
- heapaddr.Name.SetAutoTemp(false)
-
- // Parameters have a local stack copy used at function start/end
- // in addition to the copy in the heap that may live longer than
- // the function.
- if n.Class() == PPARAM || n.Class() == PPARAMOUT {
- if n.Xoffset == BADWIDTH {
- base.Fatalf("addrescapes before param assignment")
- }
-
- // We rewrite n below to be a heap variable (indirection of heapaddr).
- // Preserve a copy so we can still write code referring to the original,
- // and substitute that copy into the function declaration list
- // so that analyses of the local (on-stack) variables use it.
- stackcopy := newname(n.Sym)
- stackcopy.Type = n.Type
- stackcopy.Xoffset = n.Xoffset
- stackcopy.SetClass(n.Class())
- stackcopy.Name.Param.Heapaddr = heapaddr
- if n.Class() == PPARAMOUT {
- // Make sure the pointer to the heap copy is kept live throughout the function.
- // The function could panic at any point, and then a defer could recover.
- // Thus, we need the pointer to the heap copy always available so the
- // post-deferreturn code can copy the return value back to the stack.
- // See issue 16095.
- heapaddr.Name.SetIsOutputParamHeapAddr(true)
- }
- n.Name.Param.Stackcopy = stackcopy
-
- // Substitute the stackcopy into the function variable list so that
- // liveness and other analyses use the underlying stack slot
- // and not the now-pseudo-variable n.
- found := false
- for i, d := range Curfn.Func.Dcl {
- if d == n {
- Curfn.Func.Dcl[i] = stackcopy
- found = true
- break
- }
- // Parameters are before locals, so can stop early.
- // This limits the search even in functions with many local variables.
- if d.Class() == PAUTO {
- break
- }
- }
- if !found {
- base.Fatalf("cannot find %v in local variable list", n)
- }
- Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
- }
-
- // Modify n in place so that uses of n now mean indirection of the heapaddr.
- n.SetClass(PAUTOHEAP)
- n.Xoffset = 0
- n.Name.Param.Heapaddr = heapaddr
- n.Esc = EscHeap
- if base.Flag.LowerM != 0 {
- base.WarnfAt(n.Pos, "moved to heap: %v", n)
- }
-}
-
-// This special tag is applied to uintptr variables
-// that we believe may hold unsafe.Pointers for
-// calls into assembly functions.
-const unsafeUintptrTag = "unsafe-uintptr"
-
-// This special tag is applied to uintptr parameters of functions
-// marked go:uintptrescapes.
-const uintptrEscapesTag = "uintptr-escapes"
-
-func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
- name := func() string {
- if f.Sym != nil {
- return f.Sym.Name
- }
- return fmt.Sprintf("arg#%d", narg)
- }
-
- if fn.Nbody.Len() == 0 {
- // Assume that uintptr arguments must be held live across the call.
- // This is most important for syscall.Syscall.
- // See golang.org/issue/13372.
- // This really doesn't have much to do with escape analysis per se,
- // but we are reusing the ability to annotate an individual function
- // argument and pass those annotations along to importing code.
- if f.Type.IsUintptr() {
- if base.Flag.LowerM != 0 {
- base.WarnfAt(f.Pos, "assuming %v is unsafe uintptr", name())
- }
- return unsafeUintptrTag
- }
-
- if !f.Type.HasPointers() { // don't bother tagging for scalars
- return ""
- }
-
- var esc EscLeaks
-
- // External functions are assumed unsafe, unless
- // //go:noescape is given before the declaration.
- if fn.Func.Pragma&Noescape != 0 {
- if base.Flag.LowerM != 0 && f.Sym != nil {
- base.WarnfAt(f.Pos, "%v does not escape", name())
- }
- } else {
- if base.Flag.LowerM != 0 && f.Sym != nil {
- base.WarnfAt(f.Pos, "leaking param: %v", name())
- }
- esc.AddHeap(0)
- }
-
- return esc.Encode()
- }
-
- if fn.Func.Pragma&UintptrEscapes != 0 {
- if f.Type.IsUintptr() {
- if base.Flag.LowerM != 0 {
- base.WarnfAt(f.Pos, "marking %v as escaping uintptr", name())
- }
- return uintptrEscapesTag
- }
- if f.IsDDD() && f.Type.Elem().IsUintptr() {
- // final argument is ...uintptr.
- if base.Flag.LowerM != 0 {
- base.WarnfAt(f.Pos, "marking %v as escaping ...uintptr", name())
- }
- return uintptrEscapesTag
- }
- }
-
- if !f.Type.HasPointers() { // don't bother tagging for scalars
- return ""
- }
-
- // Unnamed parameters are unused and therefore do not escape.
- if f.Sym == nil || f.Sym.IsBlank() {
- var esc EscLeaks
- return esc.Encode()
- }
-
- n := asNode(f.Nname)
- loc := e.oldLoc(n)
- esc := loc.paramEsc
- esc.Optimize()
-
- if base.Flag.LowerM != 0 && !loc.escapes {
- if esc.Empty() {
- base.WarnfAt(f.Pos, "%v does not escape", name())
- }
- if x := esc.Heap(); x >= 0 {
- if x == 0 {
- base.WarnfAt(f.Pos, "leaking param: %v", name())
- } else {
- // TODO(mdempsky): Mention level=x like below?
- base.WarnfAt(f.Pos, "leaking param content: %v", name())
- }
- }
- for i := 0; i < numEscResults; i++ {
- if x := esc.Result(i); x >= 0 {
- res := fn.Type.Results().Field(i).Sym
- base.WarnfAt(f.Pos, "leaking param: %v to result %v level=%d", name(), res, x)
- }
- }
- }
-
- return esc.Encode()
-}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/types"
"cmd/internal/src"
type Escape struct {
allLocs []*EscLocation
- curfn *Node
+ curfn *ir.Node
// loopDepth counts the current loop nesting depth within
// curfn. It increments within each "for" loop and at each
// An EscLocation represents an abstract location that stores a Go
// variable.
type EscLocation struct {
- n *Node // represented variable or expression, if any
- curfn *Node // enclosing function
+ n *ir.Node // represented variable or expression, if any
+ curfn *ir.Node // enclosing function
edges []EscEdge // incoming edges
loopDepth int // loopDepth at declaration
}
func init() {
- EscFmt = escFmt
+ ir.EscFmt = escFmt
}
// escFmt is called from node printing to print information about escape analysis results.
-func escFmt(n *Node, short bool) string {
+func escFmt(n *ir.Node, short bool) string {
text := ""
switch n.Esc {
case EscUnknown:
// escapeFuncs performs escape analysis on a minimal batch of
// functions.
-func escapeFuncs(fns []*Node, recursive bool) {
+func escapeFuncs(fns []*ir.Node, recursive bool) {
for _, fn := range fns {
- if fn.Op != ODCLFUNC {
+ if fn.Op != ir.ODCLFUNC {
base.Fatalf("unexpected node: %v", fn)
}
}
e.finish(fns)
}
-func (e *Escape) initFunc(fn *Node) {
- if fn.Op != ODCLFUNC || fn.Esc != EscFuncUnknown {
+func (e *Escape) initFunc(fn *ir.Node) {
+ if fn.Op != ir.ODCLFUNC || fn.Esc != EscFuncUnknown {
base.Fatalf("unexpected node: %v", fn)
}
fn.Esc = EscFuncPlanned
if base.Flag.LowerM > 3 {
- Dump("escAnalyze", fn)
+ ir.Dump("escAnalyze", fn)
}
e.curfn = fn
// Allocate locations for local variables.
for _, dcl := range fn.Func.Dcl {
- if dcl.Op == ONAME {
+ if dcl.Op == ir.ONAME {
e.newLoc(dcl, false)
}
}
}
-func (e *Escape) walkFunc(fn *Node) {
+func (e *Escape) walkFunc(fn *ir.Node) {
fn.Esc = EscFuncStarted
// Identify labels that mark the head of an unstructured loop.
- inspectList(fn.Nbody, func(n *Node) bool {
+ ir.InspectList(fn.Nbody, func(n *ir.Node) bool {
switch n.Op {
- case OLABEL:
- n.Sym.Label = asTypesNode(nonlooping)
+ case ir.OLABEL:
+ n.Sym.Label = ir.AsTypesNode(nonlooping)
- case OGOTO:
+ case ir.OGOTO:
// If we visited the label before the goto,
// then this is a looping label.
- if n.Sym.Label == asTypesNode(nonlooping) {
- n.Sym.Label = asTypesNode(looping)
+ if n.Sym.Label == ir.AsTypesNode(nonlooping) {
+ n.Sym.Label = ir.AsTypesNode(looping)
}
}
// }
// stmt evaluates a single Go statement.
-func (e *Escape) stmt(n *Node) {
+func (e *Escape) stmt(n *ir.Node) {
if n == nil {
return
}
default:
base.Fatalf("unexpected stmt: %v", n)
- case ODCLCONST, ODCLTYPE, OEMPTY, OFALL, OINLMARK:
+ case ir.ODCLCONST, ir.ODCLTYPE, ir.OEMPTY, ir.OFALL, ir.OINLMARK:
// nop
- case OBREAK, OCONTINUE, OGOTO:
+ case ir.OBREAK, ir.OCONTINUE, ir.OGOTO:
// TODO(mdempsky): Handle dead code?
- case OBLOCK:
+ case ir.OBLOCK:
e.stmts(n.List)
- case ODCL:
+ case ir.ODCL:
// Record loop depth at declaration.
- if !n.Left.isBlank() {
+ if !ir.IsBlank(n.Left) {
e.dcl(n.Left)
}
- case OLABEL:
- switch asNode(n.Sym.Label) {
+ case ir.OLABEL:
+ switch ir.AsNode(n.Sym.Label) {
case nonlooping:
if base.Flag.LowerM > 2 {
fmt.Printf("%v:%v non-looping label\n", base.FmtPos(base.Pos), n)
}
n.Sym.Label = nil
- case OIF:
+ case ir.OIF:
e.discard(n.Left)
e.block(n.Nbody)
e.block(n.Rlist)
- case OFOR, OFORUNTIL:
+ case ir.OFOR, ir.OFORUNTIL:
e.loopDepth++
e.discard(n.Left)
e.stmt(n.Right)
e.block(n.Nbody)
e.loopDepth--
- case ORANGE:
+ case ir.ORANGE:
// for List = range Right { Nbody }
e.loopDepth++
ks := e.addrs(n.List)
}
e.expr(e.later(k), n.Right)
- case OSWITCH:
- typesw := n.Left != nil && n.Left.Op == OTYPESW
+ case ir.OSWITCH:
+ typesw := n.Left != nil && n.Left.Op == ir.OTYPESW
var ks []EscHole
for _, cas := range n.List.Slice() { // cases
e.discard(n.Left)
}
- case OSELECT:
+ case ir.OSELECT:
for _, cas := range n.List.Slice() {
e.stmt(cas.Left)
e.block(cas.Nbody)
}
- case OSELRECV:
+ case ir.OSELRECV:
e.assign(n.Left, n.Right, "selrecv", n)
- case OSELRECV2:
+ case ir.OSELRECV2:
e.assign(n.Left, n.Right, "selrecv", n)
e.assign(n.List.First(), nil, "selrecv", n)
- case ORECV:
+ case ir.ORECV:
// TODO(mdempsky): Consider e.discard(n.Left).
e.exprSkipInit(e.discardHole(), n) // already visited n.Ninit
- case OSEND:
+ case ir.OSEND:
e.discard(n.Left)
e.assignHeap(n.Right, "send", n)
- case OAS, OASOP:
+ case ir.OAS, ir.OASOP:
e.assign(n.Left, n.Right, "assign", n)
- case OAS2:
+ case ir.OAS2:
for i, nl := range n.List.Slice() {
e.assign(nl, n.Rlist.Index(i), "assign-pair", n)
}
- case OAS2DOTTYPE: // v, ok = x.(type)
+ case ir.OAS2DOTTYPE: // v, ok = x.(type)
e.assign(n.List.First(), n.Right, "assign-pair-dot-type", n)
e.assign(n.List.Second(), nil, "assign-pair-dot-type", n)
- case OAS2MAPR: // v, ok = m[k]
+ case ir.OAS2MAPR: // v, ok = m[k]
e.assign(n.List.First(), n.Right, "assign-pair-mapr", n)
e.assign(n.List.Second(), nil, "assign-pair-mapr", n)
- case OAS2RECV: // v, ok = <-ch
+ case ir.OAS2RECV: // v, ok = <-ch
e.assign(n.List.First(), n.Right, "assign-pair-receive", n)
e.assign(n.List.Second(), nil, "assign-pair-receive", n)
- case OAS2FUNC:
+ case ir.OAS2FUNC:
e.stmts(n.Right.Ninit)
e.call(e.addrs(n.List), n.Right, nil)
- case ORETURN:
+ case ir.ORETURN:
results := e.curfn.Type.Results().FieldSlice()
for i, v := range n.List.Slice() {
- e.assign(asNode(results[i].Nname), v, "return", n)
+ e.assign(ir.AsNode(results[i].Nname), v, "return", n)
}
- case OCALLFUNC, OCALLMETH, OCALLINTER, OCLOSE, OCOPY, ODELETE, OPANIC, OPRINT, OPRINTN, ORECOVER:
+ case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
e.call(nil, n, nil)
- case OGO, ODEFER:
+ case ir.OGO, ir.ODEFER:
e.stmts(n.Left.Ninit)
e.call(nil, n.Left, n)
- case ORETJMP:
+ case ir.ORETJMP:
// TODO(mdempsky): What do? esc.go just ignores it.
}
}
-func (e *Escape) stmts(l Nodes) {
+func (e *Escape) stmts(l ir.Nodes) {
for _, n := range l.Slice() {
e.stmt(n)
}
}
// block is like stmts, but preserves loopDepth.
-func (e *Escape) block(l Nodes) {
+func (e *Escape) block(l ir.Nodes) {
old := e.loopDepth
e.stmts(l)
e.loopDepth = old
// expr models evaluating an expression n and flowing the result into
// hole k.
-func (e *Escape) expr(k EscHole, n *Node) {
+func (e *Escape) expr(k EscHole, n *ir.Node) {
if n == nil {
return
}
e.exprSkipInit(k, n)
}
-func (e *Escape) exprSkipInit(k EscHole, n *Node) {
+func (e *Escape) exprSkipInit(k EscHole, n *ir.Node) {
if n == nil {
return
}
uintptrEscapesHack := k.uintptrEscapesHack
k.uintptrEscapesHack = false
- if uintptrEscapesHack && n.Op == OCONVNOP && n.Left.Type.IsUnsafePtr() {
+ if uintptrEscapesHack && n.Op == ir.OCONVNOP && n.Left.Type.IsUnsafePtr() {
// nop
} else if k.derefs >= 0 && !n.Type.HasPointers() {
k = e.discardHole()
default:
base.Fatalf("unexpected expr: %v", n)
- case OLITERAL, ONIL, OGETG, OCLOSUREVAR, OTYPE, OMETHEXPR:
+ case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OCLOSUREVAR, ir.OTYPE, ir.OMETHEXPR:
// nop
- case ONAME:
- if n.Class() == PFUNC || n.Class() == PEXTERN {
+ case ir.ONAME:
+ if n.Class() == ir.PFUNC || n.Class() == ir.PEXTERN {
return
}
e.flow(k, e.oldLoc(n))
- case OPLUS, ONEG, OBITNOT, ONOT:
+ case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
e.discard(n.Left)
- case OADD, OSUB, OOR, OXOR, OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT, OEQ, ONE, OLT, OLE, OGT, OGE, OANDAND, OOROR:
+ case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE, ir.OANDAND, ir.OOROR:
e.discard(n.Left)
e.discard(n.Right)
- case OADDR:
+ case ir.OADDR:
e.expr(k.addr(n, "address-of"), n.Left) // "address-of"
- case ODEREF:
+ case ir.ODEREF:
e.expr(k.deref(n, "indirection"), n.Left) // "indirection"
- case ODOT, ODOTMETH, ODOTINTER:
+ case ir.ODOT, ir.ODOTMETH, ir.ODOTINTER:
e.expr(k.note(n, "dot"), n.Left)
- case ODOTPTR:
+ case ir.ODOTPTR:
e.expr(k.deref(n, "dot of pointer"), n.Left) // "dot of pointer"
- case ODOTTYPE, ODOTTYPE2:
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
e.expr(k.dotType(n.Type, n, "dot"), n.Left)
- case OINDEX:
+ case ir.OINDEX:
if n.Left.Type.IsArray() {
e.expr(k.note(n, "fixed-array-index-of"), n.Left)
} else {
e.expr(k.deref(n, "dot of pointer"), n.Left)
}
e.discard(n.Right)
- case OINDEXMAP:
+ case ir.OINDEXMAP:
e.discard(n.Left)
e.discard(n.Right)
- case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
+ case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR:
e.expr(k.note(n, "slice"), n.Left)
low, high, max := n.SliceBounds()
e.discard(low)
e.discard(high)
e.discard(max)
- case OCONV, OCONVNOP:
+ case ir.OCONV, ir.OCONVNOP:
if checkPtr(e.curfn, 2) && n.Type.IsUnsafePtr() && n.Left.Type.IsPtr() {
// When -d=checkptr=2 is enabled, treat
// conversions to unsafe.Pointer as an
} else {
e.expr(k, n.Left)
}
- case OCONVIFACE:
+ case ir.OCONVIFACE:
if !n.Left.Type.IsInterface() && !isdirectiface(n.Left.Type) {
k = e.spill(k, n)
}
e.expr(k.note(n, "interface-converted"), n.Left)
- case ORECV:
+ case ir.ORECV:
e.discard(n.Left)
- case OCALLMETH, OCALLFUNC, OCALLINTER, OLEN, OCAP, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCOPY:
+ case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY:
e.call([]EscHole{k}, n, nil)
- case ONEW:
+ case ir.ONEW:
e.spill(k, n)
- case OMAKESLICE:
+ case ir.OMAKESLICE:
e.spill(k, n)
e.discard(n.Left)
e.discard(n.Right)
- case OMAKECHAN:
+ case ir.OMAKECHAN:
e.discard(n.Left)
- case OMAKEMAP:
+ case ir.OMAKEMAP:
e.spill(k, n)
e.discard(n.Left)
- case ORECOVER:
+ case ir.ORECOVER:
// nop
- case OCALLPART:
+ case ir.OCALLPART:
// Flow the receiver argument to both the closure and
// to the receiver parameter.
for i := m.Type.NumResults(); i > 0; i-- {
ks = append(ks, e.heapHole())
}
- paramK := e.tagHole(ks, asNode(m.Nname), m.Type.Recv())
+ paramK := e.tagHole(ks, ir.AsNode(m.Nname), m.Type.Recv())
e.expr(e.teeHole(paramK, closureK), n.Left)
- case OPTRLIT:
+ case ir.OPTRLIT:
e.expr(e.spill(k, n), n.Left)
- case OARRAYLIT:
+ case ir.OARRAYLIT:
for _, elt := range n.List.Slice() {
- if elt.Op == OKEY {
+ if elt.Op == ir.OKEY {
elt = elt.Right
}
e.expr(k.note(n, "array literal element"), elt)
}
- case OSLICELIT:
+ case ir.OSLICELIT:
k = e.spill(k, n)
k.uintptrEscapesHack = uintptrEscapesHack // for ...uintptr parameters
for _, elt := range n.List.Slice() {
- if elt.Op == OKEY {
+ if elt.Op == ir.OKEY {
elt = elt.Right
}
e.expr(k.note(n, "slice-literal-element"), elt)
}
- case OSTRUCTLIT:
+ case ir.OSTRUCTLIT:
for _, elt := range n.List.Slice() {
e.expr(k.note(n, "struct literal element"), elt.Left)
}
- case OMAPLIT:
+ case ir.OMAPLIT:
e.spill(k, n)
// Map keys and values are always stored in the heap.
e.assignHeap(elt.Right, "map literal value", n)
}
- case OCLOSURE:
+ case ir.OCLOSURE:
k = e.spill(k, n)
// Link addresses of captured variables to closure.
for _, v := range n.Func.ClosureVars.Slice() {
- if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
+ if v.Op == ir.OXXX { // unnamed out argument; see dcl.go:/^funcargs
continue
}
e.expr(k.note(n, "captured by a closure"), v.Name.Defn)
}
- case ORUNES2STR, OBYTES2STR, OSTR2RUNES, OSTR2BYTES, ORUNESTR:
+ case ir.ORUNES2STR, ir.OBYTES2STR, ir.OSTR2RUNES, ir.OSTR2BYTES, ir.ORUNESTR:
e.spill(k, n)
e.discard(n.Left)
- case OADDSTR:
+ case ir.OADDSTR:
e.spill(k, n)
// Arguments of OADDSTR never escape;
// unsafeValue evaluates a uintptr-typed arithmetic expression looking
// for conversions from an unsafe.Pointer.
-func (e *Escape) unsafeValue(k EscHole, n *Node) {
- if n.Type.Etype != TUINTPTR {
+func (e *Escape) unsafeValue(k EscHole, n *ir.Node) {
+ if n.Type.Etype != types.TUINTPTR {
base.Fatalf("unexpected type %v for %v", n.Type, n)
}
e.stmts(n.Ninit)
switch n.Op {
- case OCONV, OCONVNOP:
+ case ir.OCONV, ir.OCONVNOP:
if n.Left.Type.IsUnsafePtr() {
e.expr(k, n.Left)
} else {
e.discard(n.Left)
}
- case ODOTPTR:
+ case ir.ODOTPTR:
if isReflectHeaderDataField(n) {
e.expr(k.deref(n, "reflect.Header.Data"), n.Left)
} else {
e.discard(n.Left)
}
- case OPLUS, ONEG, OBITNOT:
+ case ir.OPLUS, ir.ONEG, ir.OBITNOT:
e.unsafeValue(k, n.Left)
- case OADD, OSUB, OOR, OXOR, OMUL, ODIV, OMOD, OAND, OANDNOT:
+ case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OAND, ir.OANDNOT:
e.unsafeValue(k, n.Left)
e.unsafeValue(k, n.Right)
- case OLSH, ORSH:
+ case ir.OLSH, ir.ORSH:
e.unsafeValue(k, n.Left)
// RHS need not be uintptr-typed (#32959) and can't meaningfully
// flow pointers anyway.
// discard evaluates an expression n for side-effects, but discards
// its value.
-func (e *Escape) discard(n *Node) {
+func (e *Escape) discard(n *ir.Node) {
e.expr(e.discardHole(), n)
}
-func (e *Escape) discards(l Nodes) {
+func (e *Escape) discards(l ir.Nodes) {
for _, n := range l.Slice() {
e.discard(n)
}
// addr evaluates an addressable expression n and returns an EscHole
// that represents storing into the represented location.
-func (e *Escape) addr(n *Node) EscHole {
- if n == nil || n.isBlank() {
+func (e *Escape) addr(n *ir.Node) EscHole {
+ if n == nil || ir.IsBlank(n) {
// Can happen at least in OSELRECV.
// TODO(mdempsky): Anywhere else?
return e.discardHole()
switch n.Op {
default:
base.Fatalf("unexpected addr: %v", n)
- case ONAME:
- if n.Class() == PEXTERN {
+ case ir.ONAME:
+ if n.Class() == ir.PEXTERN {
break
}
k = e.oldLoc(n).asHole()
- case ODOT:
+ case ir.ODOT:
k = e.addr(n.Left)
- case OINDEX:
+ case ir.OINDEX:
e.discard(n.Right)
if n.Left.Type.IsArray() {
k = e.addr(n.Left)
} else {
e.discard(n.Left)
}
- case ODEREF, ODOTPTR:
+ case ir.ODEREF, ir.ODOTPTR:
e.discard(n)
- case OINDEXMAP:
+ case ir.OINDEXMAP:
e.discard(n.Left)
e.assignHeap(n.Right, "key of map put", n)
}
return k
}
-func (e *Escape) addrs(l Nodes) []EscHole {
+func (e *Escape) addrs(l ir.Nodes) []EscHole {
var ks []EscHole
for _, n := range l.Slice() {
ks = append(ks, e.addr(n))
}
// assign evaluates the assignment dst = src.
-func (e *Escape) assign(dst, src *Node, why string, where *Node) {
+func (e *Escape) assign(dst, src *ir.Node, why string, where *ir.Node) {
// Filter out some no-op assignments for escape analysis.
ignore := dst != nil && src != nil && isSelfAssign(dst, src)
if ignore && base.Flag.LowerM != 0 {
}
k := e.addr(dst)
- if dst != nil && dst.Op == ODOTPTR && isReflectHeaderDataField(dst) {
+ if dst != nil && dst.Op == ir.ODOTPTR && isReflectHeaderDataField(dst) {
e.unsafeValue(e.heapHole().note(where, why), src)
} else {
if ignore {
}
}
-func (e *Escape) assignHeap(src *Node, why string, where *Node) {
+func (e *Escape) assignHeap(src *ir.Node, why string, where *ir.Node) {
e.expr(e.heapHole().note(where, why), src)
}
// call evaluates a call expressions, including builtin calls. ks
// should contain the holes representing where the function callee's
// results flows; where is the OGO/ODEFER context of the call, if any.
-func (e *Escape) call(ks []EscHole, call, where *Node) {
- topLevelDefer := where != nil && where.Op == ODEFER && e.loopDepth == 1
+func (e *Escape) call(ks []EscHole, call, where *ir.Node) {
+ topLevelDefer := where != nil && where.Op == ir.ODEFER && e.loopDepth == 1
if topLevelDefer {
// force stack allocation of defer record, unless
// open-coded defers are used (see ssa.go)
where.Esc = EscNever
}
- argument := func(k EscHole, arg *Node) {
+ argument := func(k EscHole, arg *ir.Node) {
if topLevelDefer {
// Top level defers arguments don't escape to
// heap, but they do need to last until end of
default:
base.Fatalf("unexpected call op: %v", call.Op)
- case OCALLFUNC, OCALLMETH, OCALLINTER:
+ case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
fixVariadicCall(call)
// Pick out the function callee, if statically known.
- var fn *Node
+ var fn *ir.Node
switch call.Op {
- case OCALLFUNC:
+ case ir.OCALLFUNC:
switch v := staticValue(call.Left); {
- case v.Op == ONAME && v.Class() == PFUNC:
+ case v.Op == ir.ONAME && v.Class() == ir.PFUNC:
fn = v
- case v.Op == OCLOSURE:
+ case v.Op == ir.OCLOSURE:
fn = v.Func.Nname
}
- case OCALLMETH:
- fn = call.Left.MethodName()
+ case ir.OCALLMETH:
+ fn = methodExprName(call.Left)
}
fntype := call.Left.Type
if ks != nil && fn != nil && e.inMutualBatch(fn) {
for i, result := range fn.Type.Results().FieldSlice() {
- e.expr(ks[i], asNode(result.Nname))
+ e.expr(ks[i], ir.AsNode(result.Nname))
}
}
argument(e.tagHole(ks, fn, param), args[i])
}
- case OAPPEND:
+ case ir.OAPPEND:
args := call.List.Slice()
// Appendee slice may flow directly to the result, if
}
}
- case OCOPY:
+ case ir.OCOPY:
argument(e.discardHole(), call.Left)
copiedK := e.discardHole()
}
argument(copiedK, call.Right)
- case OPANIC:
+ case ir.OPANIC:
argument(e.heapHole(), call.Left)
- case OCOMPLEX:
+ case ir.OCOMPLEX:
argument(e.discardHole(), call.Left)
argument(e.discardHole(), call.Right)
- case ODELETE, OPRINT, OPRINTN, ORECOVER:
+ case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
for _, arg := range call.List.Slice() {
argument(e.discardHole(), arg)
}
- case OLEN, OCAP, OREAL, OIMAG, OCLOSE:
+ case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
argument(e.discardHole(), call.Left)
}
}
// ks should contain the holes representing where the function
// callee's results flows. fn is the statically-known callee function,
// if any.
-func (e *Escape) tagHole(ks []EscHole, fn *Node, param *types.Field) EscHole {
+func (e *Escape) tagHole(ks []EscHole, fn *ir.Node, param *types.Field) EscHole {
// If this is a dynamic call, we can't rely on param.Note.
if fn == nil {
return e.heapHole()
}
if e.inMutualBatch(fn) {
- return e.addr(asNode(param.Nname))
+ return e.addr(ir.AsNode(param.Nname))
}
// Call to previously tagged function.
// fn has not yet been analyzed, so its parameters and results
// should be incorporated directly into the flow graph instead of
// relying on its escape analysis tagging.
-func (e *Escape) inMutualBatch(fn *Node) bool {
+func (e *Escape) inMutualBatch(fn *ir.Node) bool {
if fn.Name.Defn != nil && fn.Name.Defn.Esc < EscFuncTagged {
if fn.Name.Defn.Esc == EscFuncUnknown {
base.Fatalf("graph inconsistency")
type EscNote struct {
next *EscNote
- where *Node
+ where *ir.Node
why string
}
-func (k EscHole) note(where *Node, why string) EscHole {
+func (k EscHole) note(where *ir.Node, why string) EscHole {
if where == nil || why == "" {
base.Fatalf("note: missing where/why")
}
return k
}
-func (k EscHole) deref(where *Node, why string) EscHole { return k.shift(1).note(where, why) }
-func (k EscHole) addr(where *Node, why string) EscHole { return k.shift(-1).note(where, why) }
+func (k EscHole) deref(where *ir.Node, why string) EscHole { return k.shift(1).note(where, why) }
+func (k EscHole) addr(where *ir.Node, why string) EscHole { return k.shift(-1).note(where, why) }
-func (k EscHole) dotType(t *types.Type, where *Node, why string) EscHole {
+func (k EscHole) dotType(t *types.Type, where *ir.Node, why string) EscHole {
if !t.IsInterface() && !isdirectiface(t) {
k = k.shift(1)
}
return loc.asHole()
}
-func (e *Escape) dcl(n *Node) EscHole {
+func (e *Escape) dcl(n *ir.Node) EscHole {
loc := e.oldLoc(n)
loc.loopDepth = e.loopDepth
return loc.asHole()
// spill allocates a new location associated with expression n, flows
// its address to k, and returns a hole that flows values to it. It's
// intended for use with most expressions that allocate storage.
-func (e *Escape) spill(k EscHole, n *Node) EscHole {
+func (e *Escape) spill(k EscHole, n *ir.Node) EscHole {
loc := e.newLoc(n, true)
e.flow(k.addr(n, "spill"), loc)
return loc.asHole()
// canonicalNode returns the canonical *Node that n logically
// represents.
-func canonicalNode(n *Node) *Node {
- if n != nil && n.Op == ONAME && n.Name.IsClosureVar() {
+func canonicalNode(n *ir.Node) *ir.Node {
+ if n != nil && n.Op == ir.ONAME && n.Name.IsClosureVar() {
n = n.Name.Defn
if n.Name.IsClosureVar() {
base.Fatalf("still closure var")
return n
}
-func (e *Escape) newLoc(n *Node, transient bool) *EscLocation {
+func (e *Escape) newLoc(n *ir.Node, transient bool) *EscLocation {
if e.curfn == nil {
base.Fatalf("e.curfn isn't set")
}
}
e.allLocs = append(e.allLocs, loc)
if n != nil {
- if n.Op == ONAME && n.Name.Curfn != e.curfn {
+ if n.Op == ir.ONAME && n.Name.Curfn != e.curfn {
base.Fatalf("curfn mismatch: %v != %v", n.Name.Curfn, e.curfn)
}
return loc
}
-func (e *Escape) oldLoc(n *Node) *EscLocation {
+func (e *Escape) oldLoc(n *ir.Node) *EscLocation {
n = canonicalNode(n)
return n.Opt().(*EscLocation)
}
}
explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{})
if logopt.Enabled() {
- logopt.LogOpt(src.n.Pos, "escapes", "escape", e.curfn.funcname(), fmt.Sprintf("%v escapes to heap", src.n), explanation)
+ logopt.LogOpt(src.n.Pos, "escapes", "escape", ir.FuncName(e.curfn), fmt.Sprintf("%v escapes to heap", src.n), explanation)
}
}
// corresponding result parameter, then record
// that value flow for tagging the function
// later.
- if l.isName(PPARAM) {
+ if l.isName(ir.PPARAM) {
if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.escapes {
if base.Flag.LowerM >= 2 {
fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", base.FmtPos(l.n.Pos), l.n, e.explainLoc(root), derefs)
}
explanation := e.explainPath(root, l)
if logopt.Enabled() {
- logopt.LogOpt(l.n.Pos, "leak", "escape", e.curfn.funcname(),
+ logopt.LogOpt(l.n.Pos, "leak", "escape", ir.FuncName(e.curfn),
fmt.Sprintf("parameter %v leaks to %s with derefs=%d", l.n, e.explainLoc(root), derefs), explanation)
}
}
}
explanation := e.explainPath(root, l)
if logopt.Enabled() {
- logopt.LogOpt(l.n.Pos, "escape", "escape", e.curfn.funcname(), fmt.Sprintf("%v escapes to heap", l.n), explanation)
+ logopt.LogOpt(l.n.Pos, "escape", "escape", ir.FuncName(e.curfn), fmt.Sprintf("%v escapes to heap", l.n), explanation)
}
}
l.escapes = true
} else if srcloc != nil && srcloc.n != nil {
epos = srcloc.n.Pos
}
- explanation = append(explanation, logopt.NewLoggedOpt(epos, "escflow", "escape", e.curfn.funcname(), flow))
+ explanation = append(explanation, logopt.NewLoggedOpt(epos, "escflow", "escape", ir.FuncName(e.curfn), flow))
}
for note := notes; note != nil; note = note.next {
fmt.Printf("%s: from %v (%v) at %s\n", pos, note.where, note.why, base.FmtPos(note.where.Pos))
}
if logopt.Enabled() {
- explanation = append(explanation, logopt.NewLoggedOpt(note.where.Pos, "escflow", "escape", e.curfn.funcname(),
+ explanation = append(explanation, logopt.NewLoggedOpt(note.where.Pos, "escflow", "escape", ir.FuncName(e.curfn),
fmt.Sprintf(" from %v (%v)", note.where, note.why)))
}
}
// TODO(mdempsky): Omit entirely.
return "{temp}"
}
- if l.n.Op == ONAME {
+ if l.n.Op == ir.ONAME {
return fmt.Sprintf("%v", l.n)
}
return fmt.Sprintf("{storage for %v}", l.n)
// We don't know what callers do with returned values, so
// pessimistically we need to assume they flow to the heap and
// outlive everything too.
- if l.isName(PPARAMOUT) {
+ if l.isName(ir.PPARAMOUT) {
// Exception: Directly called closures can return
// locations allocated outside of them without forcing
// them to the heap. For example:
}
// containsClosure reports whether c is a closure contained within f.
-func containsClosure(f, c *Node) bool {
- if f.Op != ODCLFUNC || c.Op != ODCLFUNC {
+func containsClosure(f, c *ir.Node) bool {
+ if f.Op != ir.ODCLFUNC || c.Op != ir.ODCLFUNC {
base.Fatalf("bad containsClosure: %v, %v", f, c)
}
func (l *EscLocation) leakTo(sink *EscLocation, derefs int) {
// If sink is a result parameter and we can fit return bits
// into the escape analysis tag, then record a return leak.
- if sink.isName(PPARAMOUT) && sink.curfn == l.curfn {
+ if sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn {
// TODO(mdempsky): Eliminate dependency on Vargen here.
ri := int(sink.n.Name.Vargen) - 1
if ri < numEscResults {
l.paramEsc.AddHeap(derefs)
}
-func (e *Escape) finish(fns []*Node) {
+func (e *Escape) finish(fns []*ir.Node) {
// Record parameter tags for package export data.
for _, fn := range fns {
fn.Esc = EscFuncTagged
// Update n.Esc based on escape analysis results.
if loc.escapes {
- if n.Op != ONAME {
+ if n.Op != ir.ONAME {
if base.Flag.LowerM != 0 {
base.WarnfAt(n.Pos, "%S escapes to heap", n)
}
if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "escape", "escape", e.curfn.funcname())
+ logopt.LogOpt(n.Pos, "escape", "escape", ir.FuncName(e.curfn))
}
}
n.Esc = EscHeap
addrescapes(n)
} else {
- if base.Flag.LowerM != 0 && n.Op != ONAME {
+ if base.Flag.LowerM != 0 && n.Op != ir.ONAME {
base.WarnfAt(n.Pos, "%S does not escape", n)
}
n.Esc = EscNone
}
}
-func (l *EscLocation) isName(c Class) bool {
- return l.n != nil && l.n.Op == ONAME && l.n.Class() == c
+func (l *EscLocation) isName(c ir.Class) bool {
+ return l.n != nil && l.n.Op == ir.ONAME && l.n.Class() == c
}
const numEscResults = 7
copy(l[:], s[4:])
return l
}
+
+func escapes(all []*ir.Node) {
+ visitBottomUp(all, escapeFuncs)
+}
+
+const (
+ EscFuncUnknown = 0 + iota
+ EscFuncPlanned
+ EscFuncStarted
+ EscFuncTagged
+)
+
+func min8(a, b int8) int8 {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func max8(a, b int8) int8 {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+const (
+ EscUnknown = iota
+ EscNone // Does not escape to heap, result, or parameters.
+ EscHeap // Reachable from the heap
+ EscNever // By construction will not escape.
+)
+
+// funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way.
+func funcSym(fn *ir.Node) *types.Sym {
+ if fn == nil || fn.Func.Nname == nil {
+ return nil
+ }
+ return fn.Func.Nname.Sym
+}
+
+// Mark labels that have no backjumps to them as not increasing e.loopdepth.
+// Walk hasn't generated (goto|label).Left.Sym.Label yet, so we'll cheat
+// and set it to one of the following two. Then in esc we'll clear it again.
+var (
+ looping = ir.Nod(ir.OXXX, nil, nil)
+ nonlooping = ir.Nod(ir.OXXX, nil, nil)
+)
+
+func isSliceSelfAssign(dst, src *ir.Node) bool {
+ // Detect the following special case.
+ //
+ // func (b *Buffer) Foo() {
+ // n, m := ...
+ // b.buf = b.buf[n:m]
+ // }
+ //
+ // This assignment is a no-op for escape analysis,
+ // it does not store any new pointers into b that were not already there.
+ // However, without this special case b will escape, because we assign to OIND/ODOTPTR.
+ // Here we assume that the statement will not contain calls,
+ // that is, that order will move any calls to init.
+ // Otherwise base ONAME value could change between the moments
+ // when we evaluate it for dst and for src.
+
+ // dst is ONAME dereference.
+ if dst.Op != ir.ODEREF && dst.Op != ir.ODOTPTR || dst.Left.Op != ir.ONAME {
+ return false
+ }
+ // src is a slice operation.
+ switch src.Op {
+ case ir.OSLICE, ir.OSLICE3, ir.OSLICESTR:
+ // OK.
+ case ir.OSLICEARR, ir.OSLICE3ARR:
+ // Since arrays are embedded into containing object,
+ // slice of non-pointer array will introduce a new pointer into b that was not already there
+ // (pointer to b itself). After such assignment, if b contents escape,
+ // b escapes as well. If we ignore such OSLICEARR, we will conclude
+ // that b does not escape when b contents do.
+ //
+ // Pointer to an array is OK since it's not stored inside b directly.
+ // For slicing an array (not pointer to array), there is an implicit OADDR.
+ // We check that to determine non-pointer array slicing.
+ if src.Left.Op == ir.OADDR {
+ return false
+ }
+ default:
+ return false
+ }
+ // slice is applied to ONAME dereference.
+ if src.Left.Op != ir.ODEREF && src.Left.Op != ir.ODOTPTR || src.Left.Left.Op != ir.ONAME {
+ return false
+ }
+ // dst and src reference the same base ONAME.
+ return dst.Left == src.Left.Left
+}
+
+// isSelfAssign reports whether assignment from src to dst can
+// be ignored by the escape analysis as it's effectively a self-assignment.
+func isSelfAssign(dst, src *ir.Node) bool {
+ if isSliceSelfAssign(dst, src) {
+ return true
+ }
+
+ // Detect trivial assignments that assign back to the same object.
+ //
+ // It covers these cases:
+ // val.x = val.y
+ // val.x[i] = val.y[j]
+ // val.x1.x2 = val.x1.y2
+ // ... etc
+ //
+ // These assignments do not change assigned object lifetime.
+
+ if dst == nil || src == nil || dst.Op != src.Op {
+ return false
+ }
+
+ switch dst.Op {
+ case ir.ODOT, ir.ODOTPTR:
+ // Safe trailing accessors that are permitted to differ.
+ case ir.OINDEX:
+ if mayAffectMemory(dst.Right) || mayAffectMemory(src.Right) {
+ return false
+ }
+ default:
+ return false
+ }
+
+ // The expression prefix must be both "safe" and identical.
+ return samesafeexpr(dst.Left, src.Left)
+}
+
+// mayAffectMemory reports whether evaluation of n may affect the program's
+// memory state. If the expression can't affect memory state, then it can be
+// safely ignored by the escape analysis.
+func mayAffectMemory(n *ir.Node) bool {
+ // We may want to use a list of "memory safe" ops instead of generally
+ // "side-effect free", which would include all calls and other ops that can
+ // allocate or change global state. For now, it's safer to start with the latter.
+ //
+ // We're ignoring things like division by zero, index out of range,
+ // and nil pointer dereference here.
+ switch n.Op {
+ case ir.ONAME, ir.OCLOSUREVAR, ir.OLITERAL, ir.ONIL:
+ return false
+
+ // Left+Right group.
+ case ir.OINDEX, ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD:
+ return mayAffectMemory(n.Left) || mayAffectMemory(n.Right)
+
+ // Left group.
+ case ir.ODOT, ir.ODOTPTR, ir.ODEREF, ir.OCONVNOP, ir.OCONV, ir.OLEN, ir.OCAP,
+ ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+ return mayAffectMemory(n.Left)
+
+ default:
+ return true
+ }
+}
+
+// heapAllocReason returns the reason the given Node must be heap
+// allocated, or the empty string if it doesn't.
+func heapAllocReason(n *ir.Node) string {
+ if n.Type == nil {
+ return ""
+ }
+
+ // Parameters are always passed via the stack.
+ if n.Op == ir.ONAME && (n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT) {
+ return ""
+ }
+
+ if n.Type.Width > maxStackVarSize {
+ return "too large for stack"
+ }
+
+ if (n.Op == ir.ONEW || n.Op == ir.OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize {
+ return "too large for stack"
+ }
+
+ if n.Op == ir.OCLOSURE && closureType(n).Size() >= maxImplicitStackVarSize {
+ return "too large for stack"
+ }
+ if n.Op == ir.OCALLPART && partialCallType(n).Size() >= maxImplicitStackVarSize {
+ return "too large for stack"
+ }
+
+ if n.Op == ir.OMAKESLICE {
+ r := n.Right
+ if r == nil {
+ r = n.Left
+ }
+ if !smallintconst(r) {
+ return "non-constant size"
+ }
+ if t := n.Type; t.Elem().Width != 0 && r.Int64Val() >= maxImplicitStackVarSize/t.Elem().Width {
+ return "too large for stack"
+ }
+ }
+
+ return ""
+}
+
+// addrescapes tags node n as having had its address taken
+// by "increasing" the "value" of n.Esc to EscHeap.
+// Storage is allocated as necessary to allow the address
+// to be taken.
+func addrescapes(n *ir.Node) {
+ switch n.Op {
+ default:
+ // Unexpected Op, probably due to a previous type error. Ignore.
+
+ case ir.ODEREF, ir.ODOTPTR:
+ // Nothing to do.
+
+ case ir.ONAME:
+ if n == nodfp {
+ break
+ }
+
+ // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
+ // on PPARAM it means something different.
+ if n.Class() == ir.PAUTO && n.Esc == EscNever {
+ break
+ }
+
+ // If a closure reference escapes, mark the outer variable as escaping.
+ if n.Name.IsClosureVar() {
+ addrescapes(n.Name.Defn)
+ break
+ }
+
+ if n.Class() != ir.PPARAM && n.Class() != ir.PPARAMOUT && n.Class() != ir.PAUTO {
+ break
+ }
+
+ // This is a plain parameter or local variable that needs to move to the heap,
+ // but possibly for the function outside the one we're compiling.
+ // That is, if we have:
+ //
+ // func f(x int) {
+ // func() {
+ // global = &x
+ // }
+ // }
+ //
+ // then we're analyzing the inner closure but we need to move x to the
+ // heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
+ oldfn := Curfn
+ Curfn = n.Name.Curfn
+ if Curfn.Op == ir.OCLOSURE {
+ Curfn = Curfn.Func.Decl
+ panic("can't happen")
+ }
+ ln := base.Pos
+ base.Pos = Curfn.Pos
+ moveToHeap(n)
+ Curfn = oldfn
+ base.Pos = ln
+
+ // ODOTPTR has already been introduced,
+ // so these are the non-pointer ODOT and OINDEX.
+ // In &x[0], if x is a slice, then x does not
+ // escape--the pointer inside x does, but that
+ // is always a heap pointer anyway.
+ case ir.ODOT, ir.OINDEX, ir.OPAREN, ir.OCONVNOP:
+ if !n.Left.Type.IsSlice() {
+ addrescapes(n.Left)
+ }
+ }
+}
+
+// moveToHeap records the parameter or local variable n as moved to the heap.
+func moveToHeap(n *ir.Node) {
+ if base.Flag.LowerR != 0 {
+ ir.Dump("MOVE", n)
+ }
+ if base.Flag.CompilingRuntime {
+ base.Errorf("%v escapes to heap, not allowed in runtime", n)
+ }
+ if n.Class() == ir.PAUTOHEAP {
+ ir.Dump("n", n)
+ base.Fatalf("double move to heap")
+ }
+
+ // Allocate a local stack variable to hold the pointer to the heap copy.
+ // temp will add it to the function declaration list automatically.
+ heapaddr := temp(types.NewPtr(n.Type))
+ heapaddr.Sym = lookup("&" + n.Sym.Name)
+ heapaddr.Orig.Sym = heapaddr.Sym
+ heapaddr.Pos = n.Pos
+
+ // Unset AutoTemp to persist the &foo variable name through SSA to
+ // liveness analysis.
+ // TODO(mdempsky/drchase): Cleaner solution?
+ heapaddr.Name.SetAutoTemp(false)
+
+ // Parameters have a local stack copy used at function start/end
+ // in addition to the copy in the heap that may live longer than
+ // the function.
+ if n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT {
+ if n.Xoffset == types.BADWIDTH {
+ base.Fatalf("addrescapes before param assignment")
+ }
+
+ // We rewrite n below to be a heap variable (indirection of heapaddr).
+ // Preserve a copy so we can still write code referring to the original,
+ // and substitute that copy into the function declaration list
+ // so that analyses of the local (on-stack) variables use it.
+ stackcopy := NewName(n.Sym)
+ stackcopy.Type = n.Type
+ stackcopy.Xoffset = n.Xoffset
+ stackcopy.SetClass(n.Class())
+ stackcopy.Name.Param.Heapaddr = heapaddr
+ if n.Class() == ir.PPARAMOUT {
+ // Make sure the pointer to the heap copy is kept live throughout the function.
+ // The function could panic at any point, and then a defer could recover.
+ // Thus, we need the pointer to the heap copy always available so the
+ // post-deferreturn code can copy the return value back to the stack.
+ // See issue 16095.
+ heapaddr.Name.SetIsOutputParamHeapAddr(true)
+ }
+ n.Name.Param.Stackcopy = stackcopy
+
+ // Substitute the stackcopy into the function variable list so that
+ // liveness and other analyses use the underlying stack slot
+ // and not the now-pseudo-variable n.
+ found := false
+ for i, d := range Curfn.Func.Dcl {
+ if d == n {
+ Curfn.Func.Dcl[i] = stackcopy
+ found = true
+ break
+ }
+ // Parameters are before locals, so can stop early.
+ // This limits the search even in functions with many local variables.
+ if d.Class() == ir.PAUTO {
+ break
+ }
+ }
+ if !found {
+ base.Fatalf("cannot find %v in local variable list", n)
+ }
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+ }
+
+ // Modify n in place so that uses of n now mean indirection of the heapaddr.
+ n.SetClass(ir.PAUTOHEAP)
+ n.Xoffset = 0
+ n.Name.Param.Heapaddr = heapaddr
+ n.Esc = EscHeap
+ if base.Flag.LowerM != 0 {
+ base.WarnfAt(n.Pos, "moved to heap: %v", n)
+ }
+}
+
+// This special tag is applied to uintptr variables
+// that we believe may hold unsafe.Pointers for
+// calls into assembly functions.
+const unsafeUintptrTag = "unsafe-uintptr"
+
+// This special tag is applied to uintptr parameters of functions
+// marked go:uintptrescapes.
+const uintptrEscapesTag = "uintptr-escapes"
+
+func (e *Escape) paramTag(fn *ir.Node, narg int, f *types.Field) string {
+ name := func() string {
+ if f.Sym != nil {
+ return f.Sym.Name
+ }
+ return fmt.Sprintf("arg#%d", narg)
+ }
+
+ if fn.Nbody.Len() == 0 {
+ // Assume that uintptr arguments must be held live across the call.
+ // This is most important for syscall.Syscall.
+ // See golang.org/issue/13372.
+ // This really doesn't have much to do with escape analysis per se,
+ // but we are reusing the ability to annotate an individual function
+ // argument and pass those annotations along to importing code.
+ if f.Type.IsUintptr() {
+ if base.Flag.LowerM != 0 {
+ base.WarnfAt(f.Pos, "assuming %v is unsafe uintptr", name())
+ }
+ return unsafeUintptrTag
+ }
+
+ if !f.Type.HasPointers() { // don't bother tagging for scalars
+ return ""
+ }
+
+ var esc EscLeaks
+
+ // External functions are assumed unsafe, unless
+ // //go:noescape is given before the declaration.
+ if fn.Func.Pragma&ir.Noescape != 0 {
+ if base.Flag.LowerM != 0 && f.Sym != nil {
+ base.WarnfAt(f.Pos, "%v does not escape", name())
+ }
+ } else {
+ if base.Flag.LowerM != 0 && f.Sym != nil {
+ base.WarnfAt(f.Pos, "leaking param: %v", name())
+ }
+ esc.AddHeap(0)
+ }
+
+ return esc.Encode()
+ }
+
+ if fn.Func.Pragma&ir.UintptrEscapes != 0 {
+ if f.Type.IsUintptr() {
+ if base.Flag.LowerM != 0 {
+ base.WarnfAt(f.Pos, "marking %v as escaping uintptr", name())
+ }
+ return uintptrEscapesTag
+ }
+ if f.IsDDD() && f.Type.Elem().IsUintptr() {
+ // final argument is ...uintptr.
+ if base.Flag.LowerM != 0 {
+ base.WarnfAt(f.Pos, "marking %v as escaping ...uintptr", name())
+ }
+ return uintptrEscapesTag
+ }
+ }
+
+ if !f.Type.HasPointers() { // don't bother tagging for scalars
+ return ""
+ }
+
+ // Unnamed parameters are unused and therefore do not escape.
+ if f.Sym == nil || f.Sym.IsBlank() {
+ var esc EscLeaks
+ return esc.Encode()
+ }
+
+ n := ir.AsNode(f.Nname)
+ loc := e.oldLoc(n)
+ esc := loc.paramEsc
+ esc.Optimize()
+
+ if base.Flag.LowerM != 0 && !loc.escapes {
+ if esc.Empty() {
+ base.WarnfAt(f.Pos, "%v does not escape", name())
+ }
+ if x := esc.Heap(); x >= 0 {
+ if x == 0 {
+ base.WarnfAt(f.Pos, "leaking param: %v", name())
+ } else {
+ // TODO(mdempsky): Mention level=x like below?
+ base.WarnfAt(f.Pos, "leaking param content: %v", name())
+ }
+ }
+ for i := 0; i < numEscResults; i++ {
+ if x := esc.Result(i); x >= 0 {
+ res := fn.Type.Results().Field(i).Sym
+ base.WarnfAt(f.Pos, "leaking param: %v to result %v level=%d", name(), res, x)
+ }
+ }
+ }
+
+ return esc.Encode()
+}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/bio"
"cmd/internal/src"
}
}
-var asmlist []*Node
+var asmlist []*ir.Node
// exportsym marks n for export (or reexport).
-func exportsym(n *Node) {
+func exportsym(n *ir.Node) {
if n.Sym.OnExportList() {
return
}
return s == "init"
}
-func autoexport(n *Node, ctxt Class) {
- if n.Sym.Pkg != localpkg {
+func autoexport(n *ir.Node, ctxt ir.Class) {
+ if n.Sym.Pkg != ir.LocalPkg {
return
}
- if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
+ if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || dclcontext != ir.PEXTERN {
return
}
- if n.Type != nil && n.Type.IsKind(TFUNC) && n.IsMethod() {
+ if n.Type != nil && n.Type.IsKind(types.TFUNC) && ir.IsMethod(n) {
return
}
}
}
-func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node {
- n := asNode(s.PkgDef())
+func importsym(ipkg *types.Pkg, s *types.Sym, op ir.Op) *ir.Node {
+ n := ir.AsNode(s.PkgDef())
if n == nil {
// iimport should have created a stub ONONAME
// declaration for all imported symbols. The exception
}
n = dclname(s)
- s.SetPkgDef(asTypesNode(n))
+ s.SetPkgDef(ir.AsTypesNode(n))
s.Importdef = ipkg
}
- if n.Op != ONONAME && n.Op != op {
+ if n.Op != ir.ONONAME && n.Op != op {
redeclare(base.Pos, s, fmt.Sprintf("during import %q", ipkg.Path))
}
return n
// If no such type has been declared yet, a forward declaration is returned.
// ipkg is the package being imported
func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type {
- n := importsym(ipkg, s, OTYPE)
- if n.Op != OTYPE {
- t := types.New(TFORW)
+ n := importsym(ipkg, s, ir.OTYPE)
+ if n.Op != ir.OTYPE {
+ t := types.New(types.TFORW)
t.Sym = s
- t.Nod = asTypesNode(n)
+ t.Nod = ir.AsTypesNode(n)
- n.Op = OTYPE
+ n.Op = ir.OTYPE
n.Pos = pos
n.Type = t
- n.SetClass(PEXTERN)
+ n.SetClass(ir.PEXTERN)
}
t := n.Type
// importobj declares symbol s as an imported object representable by op.
// ipkg is the package being imported
-func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op, ctxt Class, t *types.Type) *Node {
+func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class, t *types.Type) *ir.Node {
n := importsym(ipkg, s, op)
- if n.Op != ONONAME {
+ if n.Op != ir.ONONAME {
if n.Op == op && (n.Class() != ctxt || !types.Identical(n.Type, t)) {
redeclare(base.Pos, s, fmt.Sprintf("during import %q", ipkg.Path))
}
n.Op = op
n.Pos = pos
n.SetClass(ctxt)
- if ctxt == PFUNC {
+ if ctxt == ir.PFUNC {
n.Sym.SetFunc(true)
}
n.Type = t
// importconst declares symbol s as an imported constant with type t and value val.
// ipkg is the package being imported
func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) {
- n := importobj(ipkg, pos, s, OLITERAL, PEXTERN, t)
+ n := importobj(ipkg, pos, s, ir.OLITERAL, ir.PEXTERN, t)
if n == nil { // TODO: Check that value matches.
return
}
// importfunc declares symbol s as an imported function with type t.
// ipkg is the package being imported
func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
- n := importobj(ipkg, pos, s, ONAME, PFUNC, t)
+ n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t)
if n == nil {
return
}
- n.Func = new(Func)
+ n.Func = new(ir.Func)
if base.Flag.E != 0 {
fmt.Printf("import func %v%S\n", s, t)
// importvar declares symbol s as an imported variable with type t.
// ipkg is the package being imported
func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
- n := importobj(ipkg, pos, s, ONAME, PEXTERN, t)
+ n := importobj(ipkg, pos, s, ir.ONAME, ir.PEXTERN, t)
if n == nil {
return
}
// importalias declares symbol s as an imported type alias with type t.
// ipkg is the package being imported
func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
- n := importobj(ipkg, pos, s, OTYPE, PEXTERN, t)
+ n := importobj(ipkg, pos, s, ir.OTYPE, ir.PEXTERN, t)
if n == nil {
return
}
if err != nil {
base.Fatalf("%v", err)
}
- fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
+ fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", ir.LocalPkg.Name)
for _, n := range asmlist {
if n.Sym.IsBlank() {
continue
}
switch n.Op {
- case OLITERAL:
+ case ir.OLITERAL:
t := n.Val().Kind()
if t == constant.Float || t == constant.Complex {
break
}
fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
- case OTYPE:
+ case ir.OTYPE:
t := n.Type
if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
break
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src"
// isParamStackCopy reports whether this is the on-stack copy of a
// function parameter that moved to the heap.
-func (n *Node) isParamStackCopy() bool {
- return n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) && n.Name.Param.Heapaddr != nil
+func isParamStackCopy(n *ir.Node) bool {
+ return n.Op == ir.ONAME && (n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT) && n.Name.Param.Heapaddr != nil
}
// isParamHeapCopy reports whether this is the on-heap copy of
// a function parameter that moved to the heap.
-func (n *Node) isParamHeapCopy() bool {
- return n.Op == ONAME && n.Class() == PAUTOHEAP && n.Name.Param.Stackcopy != nil
+func isParamHeapCopy(n *ir.Node) bool {
+ return n.Op == ir.ONAME && n.Class() == ir.PAUTOHEAP && n.Name.Param.Stackcopy != nil
}
// autotmpname returns the name for an autotmp variable numbered n.
}
// make a new Node off the books
-func tempAt(pos src.XPos, curfn *Node, t *types.Type) *Node {
+func tempAt(pos src.XPos, curfn *ir.Node, t *types.Type) *ir.Node {
if curfn == nil {
base.Fatalf("no curfn for tempAt")
}
- if curfn.Op == OCLOSURE {
- Dump("tempAt", curfn)
+ if curfn.Op == ir.OCLOSURE {
+ ir.Dump("tempAt", curfn)
base.Fatalf("adding tempAt to wrong closure function")
}
if t == nil {
s := &types.Sym{
Name: autotmpname(len(curfn.Func.Dcl)),
- Pkg: localpkg,
+ Pkg: ir.LocalPkg,
}
- n := newnamel(pos, s)
- s.Def = asTypesNode(n)
+ n := ir.NewNameAt(pos, s)
+ s.Def = ir.AsTypesNode(n)
n.Type = t
- n.SetClass(PAUTO)
+ n.SetClass(ir.PAUTO)
n.Esc = EscNever
n.Name.Curfn = curfn
n.Name.SetUsed(true)
return n.Orig
}
-func temp(t *types.Type) *Node {
+func temp(t *types.Type) *ir.Node {
return tempAt(base.Pos, Curfn, t)
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/obj"
"sync"
)
-const (
- BADWIDTH = types.BADWIDTH
-)
-
var (
// maximum size variable which we will allocate on the stack.
// This limit is for explicit variable declarations like "var x T" or "x := ...".
// isRuntimePkg reports whether p is package runtime.
func isRuntimePkg(p *types.Pkg) bool {
- if base.Flag.CompilingRuntime && p == localpkg {
+ if base.Flag.CompilingRuntime && p == ir.LocalPkg {
return true
}
return p.Path == "runtime"
// isReflectPkg reports whether p is package reflect.
func isReflectPkg(p *types.Pkg) bool {
- if p == localpkg {
+ if p == ir.LocalPkg {
return base.Ctxt.Pkgpath == "reflect"
}
return p.Path == "reflect"
}
-// The Class of a variable/function describes the "storage class"
-// of a variable or function. During parsing, storage classes are
-// called declaration contexts.
-type Class uint8
-
-//go:generate stringer -type=Class
-const (
- Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
- PEXTERN // global variables
- PAUTO // local variables
- PAUTOHEAP // local variables or parameters moved to heap
- PPARAM // input arguments
- PPARAMOUT // output results
- PFUNC // global functions
-
- // Careful: Class is stored in three bits in Node.flags.
- _ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
-)
-
// Slices in the runtime are represented by three components:
//
// type slice struct {
var decldepth int32
-var localpkg *types.Pkg // package being compiled
-
var inimport bool // set during import
var itabpkg *types.Pkg // fake pkg for itab entries
var zerosize int64
-var simtype [NTYPE]types.EType
+var simtype [types.NTYPE]types.EType
var (
- isInt [NTYPE]bool
- isFloat [NTYPE]bool
- isComplex [NTYPE]bool
- issimple [NTYPE]bool
+ isInt [types.NTYPE]bool
+ isFloat [types.NTYPE]bool
+ isComplex [types.NTYPE]bool
+ issimple [types.NTYPE]bool
)
var (
- okforeq [NTYPE]bool
- okforadd [NTYPE]bool
- okforand [NTYPE]bool
- okfornone [NTYPE]bool
- okforcmp [NTYPE]bool
- okforbool [NTYPE]bool
- okforcap [NTYPE]bool
- okforlen [NTYPE]bool
- okforarith [NTYPE]bool
+ okforeq [types.NTYPE]bool
+ okforadd [types.NTYPE]bool
+ okforand [types.NTYPE]bool
+ okfornone [types.NTYPE]bool
+ okforcmp [types.NTYPE]bool
+ okforbool [types.NTYPE]bool
+ okforcap [types.NTYPE]bool
+ okforlen [types.NTYPE]bool
+ okforarith [types.NTYPE]bool
)
-var okforconst [NTYPE]bool
-
var (
- okfor [OEND][]bool
- iscmp [OEND]bool
+ okfor [ir.OEND][]bool
+ iscmp [ir.OEND]bool
)
-var xtop []*Node
+var xtop []*ir.Node
-var exportlist []*Node
+var exportlist []*ir.Node
-var importlist []*Node // imported functions and methods with inlinable bodies
+var importlist []*ir.Node // imported functions and methods with inlinable bodies
var (
funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
funcsyms []*types.Sym
)
-var dclcontext Class // PEXTERN/PAUTO
+var dclcontext ir.Class // PEXTERN/PAUTO
-var Curfn *Node
+var Curfn *ir.Node
var Widthptr int
var Widthreg int
-var nblank *Node
-
var typecheckok bool
// Whether we are adding any sort of code instrumentation, such as
// Whether we are tracking lexical scopes for DWARF.
var trackScopes bool
-var nodfp *Node
+var nodfp *ir.Node
var autogeneratedPos src.XPos
var (
staticuint64s,
- zerobase *Node
+ zerobase *ir.Node
assertE2I,
assertE2I2,
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/objabi"
next *obj.Prog // next Prog
pc int64 // virtual PC; count of Progs
pos src.XPos // position to use for new Progs
- curfn *Node // fn these Progs are for
+ curfn *ir.Node // fn these Progs are for
progcache []obj.Prog // local progcache
cacheidx int // first free element of progcache
// newProgs returns a new Progs for fn.
// worker indicates which of the backend workers will use the Progs.
-func newProgs(fn *Node, worker int) *Progs {
+func newProgs(fn *ir.Node, worker int) *Progs {
pp := new(Progs)
if base.Ctxt.CanReuseProgs() {
sz := len(sharedProgArray) / base.Flag.LowerC
return q
}
-func (pp *Progs) settext(fn *Node) {
+func (pp *Progs) settext(fn *ir.Node) {
if pp.Text != nil {
base.Fatalf("Progs.settext called twice")
}
ptxt := pp.Prog(obj.ATEXT)
pp.Text = ptxt
- fn.Func.lsym.Func().Text = ptxt
+ fn.Func.LSym.Func().Text = ptxt
ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN
- ptxt.From.Sym = fn.Func.lsym
+ ptxt.From.Sym = fn.Func.LSym
}
// initLSym defines f's obj.LSym and initializes it based on the
//
// initLSym must be called exactly once per function and must be
// called for both functions with bodies and functions without bodies.
-func (f *Func) initLSym(hasBody bool) {
- if f.lsym != nil {
+func initLSym(f *ir.Func, hasBody bool) {
+ if f.LSym != nil {
base.Fatalf("Func.initLSym called twice")
}
- if nam := f.Nname; !nam.isBlank() {
- f.lsym = nam.Sym.Linksym()
- if f.Pragma&Systemstack != 0 {
- f.lsym.Set(obj.AttrCFunc, true)
+ if nam := f.Nname; !ir.IsBlank(nam) {
+ f.LSym = nam.Sym.Linksym()
+ if f.Pragma&ir.Systemstack != 0 {
+ f.LSym.Set(obj.AttrCFunc, true)
}
var aliasABI obj.ABI
needABIAlias := false
- defABI, hasDefABI := symabiDefs[f.lsym.Name]
+ defABI, hasDefABI := symabiDefs[f.LSym.Name]
if hasDefABI && defABI == obj.ABI0 {
// Symbol is defined as ABI0. Create an
// Internal -> ABI0 wrapper.
- f.lsym.SetABI(obj.ABI0)
+ f.LSym.SetABI(obj.ABI0)
needABIAlias, aliasABI = true, obj.ABIInternal
} else {
// No ABI override. Check that the symbol is
// using the expected ABI.
want := obj.ABIInternal
- if f.lsym.ABI() != want {
- base.Fatalf("function symbol %s has the wrong ABI %v, expected %v", f.lsym.Name, f.lsym.ABI(), want)
+ if f.LSym.ABI() != want {
+ base.Fatalf("function symbol %s has the wrong ABI %v, expected %v", f.LSym.Name, f.LSym.ABI(), want)
}
}
isLinknameExported := nam.Sym.Linkname != "" && (hasBody || hasDefABI)
- if abi, ok := symabiRefs[f.lsym.Name]; (ok && abi == obj.ABI0) || isLinknameExported {
+ if abi, ok := symabiRefs[f.LSym.Name]; (ok && abi == obj.ABI0) || isLinknameExported {
// Either 1) this symbol is definitely
// referenced as ABI0 from this package; or 2)
// this symbol is defined in this package but
// since other packages may "pull" symbols
// using linkname and we don't want to create
// duplicate ABI wrappers.
- if f.lsym.ABI() != obj.ABI0 {
+ if f.LSym.ABI() != obj.ABI0 {
needABIAlias, aliasABI = true, obj.ABI0
}
}
// rather than looking them up. The uniqueness
// of f.lsym ensures uniqueness of asym.
asym := &obj.LSym{
- Name: f.lsym.Name,
+ Name: f.LSym.Name,
Type: objabi.SABIALIAS,
- R: []obj.Reloc{{Sym: f.lsym}}, // 0 size, so "informational"
+ R: []obj.Reloc{{Sym: f.LSym}}, // 0 size, so "informational"
}
asym.SetABI(aliasABI)
asym.Set(obj.AttrDuplicateOK, true)
if f.Needctxt() {
flag |= obj.NEEDCTXT
}
- if f.Pragma&Nosplit != 0 {
+ if f.Pragma&ir.Nosplit != 0 {
flag |= obj.NOSPLIT
}
if f.ReflectMethod() {
}
}
- base.Ctxt.InitTextSym(f.lsym, flag)
+ base.Ctxt.InitTextSym(f.LSym, flag)
}
-func ggloblnod(nam *Node) {
+func ggloblnod(nam *ir.Node) {
s := nam.Sym.Linksym()
s.Gotype = ngotype(nam).Linksym()
flags := 0
"bufio"
"bytes"
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/goobj"
"cmd/internal/src"
p := iexporter{
allPkgs: map[*types.Pkg]bool{},
stringIndex: map[string]uint64{},
- declIndex: map[*Node]uint64{},
- inlineIndex: map[*Node]uint64{},
+ declIndex: map[*ir.Node]uint64{},
+ inlineIndex: map[*ir.Node]uint64{},
typIndex: map[*types.Type]uint64{},
}
// Loop until no more work. We use a queue because while
// writing out inline bodies, we may discover additional
// declarations that are needed.
- for !p.declTodo.empty() {
- p.doDecl(p.declTodo.popLeft())
+ for !p.declTodo.Empty() {
+ p.doDecl(p.declTodo.PopLeft())
}
// Append indices to data0 section.
// we're writing out the main index, which is also read by
// non-compiler tools and includes a complete package description
// (i.e., name and height).
-func (w *exportWriter) writeIndex(index map[*Node]uint64, mainIndex bool) {
+func (w *exportWriter) writeIndex(index map[*ir.Node]uint64, mainIndex bool) {
// Build a map from packages to objects from that package.
- pkgObjs := map[*types.Pkg][]*Node{}
+ pkgObjs := map[*types.Pkg][]*ir.Node{}
// For the main index, make sure to include every package that
// we reference, even if we're not exporting (or reexporting)
// any symbols from it.
if mainIndex {
- pkgObjs[localpkg] = nil
+ pkgObjs[ir.LocalPkg] = nil
for pkg := range w.p.allPkgs {
pkgObjs[pkg] = nil
}
// main index.
allPkgs map[*types.Pkg]bool
- declTodo nodeQueue
+ declTodo ir.NodeQueue
strings intWriter
stringIndex map[string]uint64
data0 intWriter
- declIndex map[*Node]uint64
- inlineIndex map[*Node]uint64
+ declIndex map[*ir.Node]uint64
+ inlineIndex map[*ir.Node]uint64
typIndex map[*types.Type]uint64
}
}
// pushDecl adds n to the declaration work queue, if not already present.
-func (p *iexporter) pushDecl(n *Node) {
- if n.Sym == nil || asNode(n.Sym.Def) != n && n.Op != OTYPE {
+func (p *iexporter) pushDecl(n *ir.Node) {
+ if n.Sym == nil || ir.AsNode(n.Sym.Def) != n && n.Op != ir.OTYPE {
base.Fatalf("weird Sym: %v, %v", n, n.Sym)
}
// Don't export predeclared declarations.
- if n.Sym.Pkg == builtinpkg || n.Sym.Pkg == unsafepkg {
+ if n.Sym.Pkg == ir.BuiltinPkg || n.Sym.Pkg == unsafepkg {
return
}
}
p.declIndex[n] = ^uint64(0) // mark n present in work queue
- p.declTodo.pushRight(n)
+ p.declTodo.PushRight(n)
}
// exportWriter handles writing out individual data section chunks.
prevColumn int64
}
-func (p *iexporter) doDecl(n *Node) {
+func (p *iexporter) doDecl(n *ir.Node) {
w := p.newWriter()
w.setPkg(n.Sym.Pkg, false)
switch n.Op {
- case ONAME:
+ case ir.ONAME:
switch n.Class() {
- case PEXTERN:
+ case ir.PEXTERN:
// Variable.
w.tag('V')
w.pos(n.Pos)
w.typ(n.Type)
w.varExt(n)
- case PFUNC:
- if n.IsMethod() {
+ case ir.PFUNC:
+ if ir.IsMethod(n) {
base.Fatalf("unexpected method: %v", n)
}
base.Fatalf("unexpected class: %v, %v", n, n.Class())
}
- case OLITERAL:
+ case ir.OLITERAL:
// Constant.
n = typecheck(n, ctxExpr)
w.tag('C')
w.pos(n.Pos)
w.value(n.Type, n.Val())
- case OTYPE:
+ case ir.OTYPE:
if IsAlias(n.Sym) {
// Alias.
w.tag('A')
w.data.WriteByte(tag)
}
-func (p *iexporter) doInline(f *Node) {
+func (p *iexporter) doInline(f *ir.Node) {
w := p.newWriter()
w.setPkg(fnpkg(f), false)
- w.stmtList(asNodes(f.Func.Inl.Body))
+ w.stmtList(ir.AsNodes(f.Func.Inl.Body))
p.inlineIndex[f] = w.flush()
}
w.string(pkg.Path)
}
-func (w *exportWriter) qualifiedIdent(n *Node) {
+func (w *exportWriter) qualifiedIdent(n *ir.Node) {
// Ensure any referenced declarations are written out too.
w.p.pushDecl(n)
} else {
pkg := w.currPkg
if types.IsExported(name) {
- pkg = localpkg
+ pkg = ir.LocalPkg
}
if s.Pkg != pkg {
base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
func (w *exportWriter) doTyp(t *types.Type) {
if t.Sym != nil {
- if t.Sym.Pkg == builtinpkg || t.Sym.Pkg == unsafepkg {
+ if t.Sym.Pkg == ir.BuiltinPkg || t.Sym.Pkg == unsafepkg {
base.Fatalf("builtin type missing from typIndex: %v", t)
}
}
switch t.Etype {
- case TPTR:
+ case types.TPTR:
w.startType(pointerType)
w.typ(t.Elem())
- case TSLICE:
+ case types.TSLICE:
w.startType(sliceType)
w.typ(t.Elem())
- case TARRAY:
+ case types.TARRAY:
w.startType(arrayType)
w.uint64(uint64(t.NumElem()))
w.typ(t.Elem())
- case TCHAN:
+ case types.TCHAN:
w.startType(chanType)
w.uint64(uint64(t.ChanDir()))
w.typ(t.Elem())
- case TMAP:
+ case types.TMAP:
w.startType(mapType)
w.typ(t.Key())
w.typ(t.Elem())
- case TFUNC:
+ case types.TFUNC:
w.startType(signatureType)
w.setPkg(t.Pkg(), true)
w.signature(t)
- case TSTRUCT:
+ case types.TSTRUCT:
w.startType(structType)
w.setPkg(t.Pkg(), true)
w.string(f.Note)
}
- case TINTER:
+ case types.TINTER:
var embeddeds, methods []*types.Field
for _, m := range t.Methods().Slice() {
if m.Sym != nil {
if pkg == nil {
// TODO(mdempsky): Proactively set Pkg for types and
// remove this fallback logic.
- pkg = localpkg
+ pkg = ir.LocalPkg
}
if write {
func (w *exportWriter) param(f *types.Field) {
w.pos(f.Pos)
- w.localIdent(origSym(f.Sym), 0)
+ w.localIdent(ir.OrigSym(f.Sym), 0)
w.typ(f.Type)
}
}
switch typ.Etype {
- case TBOOL:
+ case types.TBOOL:
return constant.Bool
- case TSTRING:
+ case types.TSTRING:
return constant.String
- case TINT, TINT8, TINT16, TINT32, TINT64,
- TUINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINTPTR:
+ case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64,
+ types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
return constant.Int
- case TFLOAT32, TFLOAT64:
+ case types.TFLOAT32, types.TFLOAT64:
return constant.Float
- case TCOMPLEX64, TCOMPLEX128:
+ case types.TCOMPLEX64, types.TCOMPLEX128:
return constant.Complex
}
}
func (w *exportWriter) value(typ *types.Type, v constant.Value) {
- assertRepresents(typ, v)
+ ir.AssertValidTypeForConst(typ, v)
w.typ(typ)
// Each type has only one admissible constant representation,
}
switch typ.Etype {
- case TFLOAT32, TCOMPLEX64:
+ case types.TFLOAT32, types.TCOMPLEX64:
return true, 3
- case TFLOAT64, TCOMPLEX128:
+ case types.TFLOAT64, types.TCOMPLEX128:
return true, 7
}
// The go/types API doesn't expose sizes to importers, so they
// don't know how big these types are.
switch typ.Etype {
- case TINT, TUINT, TUINTPTR:
+ case types.TINT, types.TUINT, types.TUINTPTR:
maxBytes = 8
}
// Compiler-specific extensions.
-func (w *exportWriter) varExt(n *Node) {
+func (w *exportWriter) varExt(n *ir.Node) {
w.linkname(n.Sym)
w.symIdx(n.Sym)
}
-func (w *exportWriter) funcExt(n *Node) {
+func (w *exportWriter) funcExt(n *ir.Node) {
w.linkname(n.Sym)
w.symIdx(n.Sym)
func (w *exportWriter) methExt(m *types.Field) {
w.bool(m.Nointerface())
- w.funcExt(asNode(m.Nname))
+ w.funcExt(ir.AsNode(m.Nname))
}
func (w *exportWriter) linkname(s *types.Sym) {
// Inline bodies.
-func (w *exportWriter) stmtList(list Nodes) {
+func (w *exportWriter) stmtList(list ir.Nodes) {
for _, n := range list.Slice() {
w.node(n)
}
- w.op(OEND)
+ w.op(ir.OEND)
}
-func (w *exportWriter) node(n *Node) {
- if opprec[n.Op] < 0 {
+func (w *exportWriter) node(n *ir.Node) {
+ if ir.OpPrec[n.Op] < 0 {
w.stmt(n)
} else {
w.expr(n)
// Caution: stmt will emit more than one node for statement nodes n that have a non-empty
// n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
-func (w *exportWriter) stmt(n *Node) {
- if n.Ninit.Len() > 0 && !stmtwithinit(n.Op) {
+func (w *exportWriter) stmt(n *ir.Node) {
+ if n.Ninit.Len() > 0 && !ir.StmtWithInit(n.Op) {
// can't use stmtList here since we don't want the final OEND
for _, n := range n.Ninit.Slice() {
w.stmt(n)
}
switch op := n.Op; op {
- case ODCL:
- w.op(ODCL)
+ case ir.ODCL:
+ w.op(ir.ODCL)
w.pos(n.Left.Pos)
w.localName(n.Left)
w.typ(n.Left.Type)
// case ODCLFIELD:
// unimplemented - handled by default case
- case OAS:
+ case ir.OAS:
// Don't export "v = <N>" initializing statements, hope they're always
// preceded by the DCL which will be re-parsed and typecheck to reproduce
// the "v = <N>" again.
if n.Right != nil {
- w.op(OAS)
+ w.op(ir.OAS)
w.pos(n.Pos)
w.expr(n.Left)
w.expr(n.Right)
}
- case OASOP:
- w.op(OASOP)
+ case ir.OASOP:
+ w.op(ir.OASOP)
w.pos(n.Pos)
w.op(n.SubOp())
w.expr(n.Left)
w.expr(n.Right)
}
- case OAS2:
- w.op(OAS2)
+ case ir.OAS2:
+ w.op(ir.OAS2)
w.pos(n.Pos)
w.exprList(n.List)
w.exprList(n.Rlist)
- case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
- w.op(OAS2)
+ case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
+ w.op(ir.OAS2)
w.pos(n.Pos)
w.exprList(n.List)
- w.exprList(asNodes([]*Node{n.Right}))
+ w.exprList(ir.AsNodes([]*ir.Node{n.Right}))
- case ORETURN:
- w.op(ORETURN)
+ case ir.ORETURN:
+ w.op(ir.ORETURN)
w.pos(n.Pos)
w.exprList(n.List)
// case ORETJMP:
// unreachable - generated by compiler for trampolin routines
- case OGO, ODEFER:
+ case ir.OGO, ir.ODEFER:
w.op(op)
w.pos(n.Pos)
w.expr(n.Left)
- case OIF:
- w.op(OIF)
+ case ir.OIF:
+ w.op(ir.OIF)
w.pos(n.Pos)
w.stmtList(n.Ninit)
w.expr(n.Left)
w.stmtList(n.Nbody)
w.stmtList(n.Rlist)
- case OFOR:
- w.op(OFOR)
+ case ir.OFOR:
+ w.op(ir.OFOR)
w.pos(n.Pos)
w.stmtList(n.Ninit)
w.exprsOrNil(n.Left, n.Right)
w.stmtList(n.Nbody)
- case ORANGE:
- w.op(ORANGE)
+ case ir.ORANGE:
+ w.op(ir.ORANGE)
w.pos(n.Pos)
w.stmtList(n.List)
w.expr(n.Right)
w.stmtList(n.Nbody)
- case OSELECT, OSWITCH:
+ case ir.OSELECT, ir.OSWITCH:
w.op(op)
w.pos(n.Pos)
w.stmtList(n.Ninit)
// case OCASE:
// handled by caseList
- case OFALL:
- w.op(OFALL)
+ case ir.OFALL:
+ w.op(ir.OFALL)
w.pos(n.Pos)
- case OBREAK, OCONTINUE:
+ case ir.OBREAK, ir.OCONTINUE:
w.op(op)
w.pos(n.Pos)
w.exprsOrNil(n.Left, nil)
- case OEMPTY:
+ case ir.OEMPTY:
// nothing to emit
- case OGOTO, OLABEL:
+ case ir.OGOTO, ir.OLABEL:
w.op(op)
w.pos(n.Pos)
w.string(n.Sym.Name)
}
}
-func (w *exportWriter) caseList(sw *Node) {
- namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil
+func (w *exportWriter) caseList(sw *ir.Node) {
+ namedTypeSwitch := sw.Op == ir.OSWITCH && sw.Left != nil && sw.Left.Op == ir.OTYPESW && sw.Left.Left != nil
cases := sw.List.Slice()
w.uint64(uint64(len(cases)))
for _, cas := range cases {
- if cas.Op != OCASE {
+ if cas.Op != ir.OCASE {
base.Fatalf("expected OCASE, got %v", cas)
}
w.pos(cas.Pos)
}
}
-func (w *exportWriter) exprList(list Nodes) {
+func (w *exportWriter) exprList(list ir.Nodes) {
for _, n := range list.Slice() {
w.expr(n)
}
- w.op(OEND)
+ w.op(ir.OEND)
}
-func (w *exportWriter) expr(n *Node) {
+func (w *exportWriter) expr(n *ir.Node) {
// from nodefmt (fmt.go)
//
// nodefmt reverts nodes back to their original - we don't need to do
// }
// from exprfmt (fmt.go)
- for n.Op == OPAREN || n.Implicit() && (n.Op == ODEREF || n.Op == OADDR || n.Op == ODOT || n.Op == ODOTPTR) {
+ for n.Op == ir.OPAREN || n.Implicit() && (n.Op == ir.ODEREF || n.Op == ir.OADDR || n.Op == ir.ODOT || n.Op == ir.ODOTPTR) {
n = n.Left
}
switch op := n.Op; op {
// expressions
// (somewhat closely following the structure of exprfmt in fmt.go)
- case ONIL:
+ case ir.ONIL:
if !n.Type.HasNil() {
base.Fatalf("unexpected type for nil: %v", n.Type)
}
w.expr(n.Orig)
break
}
- w.op(OLITERAL)
+ w.op(ir.OLITERAL)
w.pos(n.Pos)
w.typ(n.Type)
- case OLITERAL:
- w.op(OLITERAL)
+ case ir.OLITERAL:
+ w.op(ir.OLITERAL)
w.pos(n.Pos)
w.value(n.Type, n.Val())
- case OMETHEXPR:
+ case ir.OMETHEXPR:
// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
// but for export, this should be rendered as (*pkg.T).meth.
// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
- w.op(OXDOT)
+ w.op(ir.OXDOT)
w.pos(n.Pos)
w.expr(n.Left) // n.Left.Op == OTYPE
w.selector(n.Right.Sym)
- case ONAME:
+ case ir.ONAME:
// Package scope name.
- if (n.Class() == PEXTERN || n.Class() == PFUNC) && !n.isBlank() {
- w.op(ONONAME)
+ if (n.Class() == ir.PEXTERN || n.Class() == ir.PFUNC) && !ir.IsBlank(n) {
+ w.op(ir.ONONAME)
w.qualifiedIdent(n)
break
}
// Function scope name.
- w.op(ONAME)
+ w.op(ir.ONAME)
w.localName(n)
// case OPACK, ONONAME:
// should have been resolved by typechecking - handled by default case
- case OTYPE:
- w.op(OTYPE)
+ case ir.OTYPE:
+ w.op(ir.OTYPE)
w.typ(n.Type)
- case OTYPESW:
- w.op(OTYPESW)
+ case ir.OTYPESW:
+ w.op(ir.OTYPESW)
w.pos(n.Pos)
var s *types.Sym
if n.Left != nil {
- if n.Left.Op != ONONAME {
+ if n.Left.Op != ir.ONONAME {
base.Fatalf("expected ONONAME, got %v", n.Left)
}
s = n.Left.Sym
// case OCOMPLIT:
// should have been resolved by typechecking - handled by default case
- case OPTRLIT:
- w.op(OADDR)
+ case ir.OPTRLIT:
+ w.op(ir.OADDR)
w.pos(n.Pos)
w.expr(n.Left)
- case OSTRUCTLIT:
- w.op(OSTRUCTLIT)
+ case ir.OSTRUCTLIT:
+ w.op(ir.OSTRUCTLIT)
w.pos(n.Pos)
w.typ(n.Type)
w.elemList(n.List) // special handling of field names
- case OARRAYLIT, OSLICELIT, OMAPLIT:
- w.op(OCOMPLIT)
+ case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
+ w.op(ir.OCOMPLIT)
w.pos(n.Pos)
w.typ(n.Type)
w.exprList(n.List)
- case OKEY:
- w.op(OKEY)
+ case ir.OKEY:
+ w.op(ir.OKEY)
w.pos(n.Pos)
w.exprsOrNil(n.Left, n.Right)
// case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList
- case OCALLPART:
+ case ir.OCALLPART:
// An OCALLPART is an OXDOT before type checking.
- w.op(OXDOT)
+ w.op(ir.OXDOT)
w.pos(n.Pos)
w.expr(n.Left)
// Right node should be ONAME
w.selector(n.Right.Sym)
- case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
- w.op(OXDOT)
+ case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH:
+ w.op(ir.OXDOT)
w.pos(n.Pos)
w.expr(n.Left)
w.selector(n.Sym)
- case ODOTTYPE, ODOTTYPE2:
- w.op(ODOTTYPE)
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
+ w.op(ir.ODOTTYPE)
w.pos(n.Pos)
w.expr(n.Left)
w.typ(n.Type)
- case OINDEX, OINDEXMAP:
- w.op(OINDEX)
+ case ir.OINDEX, ir.OINDEXMAP:
+ w.op(ir.OINDEX)
w.pos(n.Pos)
w.expr(n.Left)
w.expr(n.Right)
- case OSLICE, OSLICESTR, OSLICEARR:
- w.op(OSLICE)
+ case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR:
+ w.op(ir.OSLICE)
w.pos(n.Pos)
w.expr(n.Left)
low, high, _ := n.SliceBounds()
w.exprsOrNil(low, high)
- case OSLICE3, OSLICE3ARR:
- w.op(OSLICE3)
+ case ir.OSLICE3, ir.OSLICE3ARR:
+ w.op(ir.OSLICE3)
w.pos(n.Pos)
w.expr(n.Left)
low, high, max := n.SliceBounds()
w.exprsOrNil(low, high)
w.expr(max)
- case OCOPY, OCOMPLEX:
+ case ir.OCOPY, ir.OCOMPLEX:
// treated like other builtin calls (see e.g., OREAL)
w.op(op)
w.pos(n.Pos)
w.expr(n.Left)
w.expr(n.Right)
- w.op(OEND)
+ w.op(ir.OEND)
- case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
- w.op(OCONV)
+ case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR:
+ w.op(ir.OCONV)
w.pos(n.Pos)
w.expr(n.Left)
w.typ(n.Type)
- case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
+ case ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
w.op(op)
w.pos(n.Pos)
if n.Left != nil {
w.expr(n.Left)
- w.op(OEND)
+ w.op(ir.OEND)
} else {
w.exprList(n.List) // emits terminating OEND
}
// only append() calls may contain '...' arguments
- if op == OAPPEND {
+ if op == ir.OAPPEND {
w.bool(n.IsDDD())
} else if n.IsDDD() {
base.Fatalf("exporter: unexpected '...' with %v call", op)
}
- case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
- w.op(OCALL)
+ case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
+ w.op(ir.OCALL)
w.pos(n.Pos)
w.stmtList(n.Ninit)
w.expr(n.Left)
w.exprList(n.List)
w.bool(n.IsDDD())
- case OMAKEMAP, OMAKECHAN, OMAKESLICE:
+ case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
w.op(op) // must keep separate from OMAKE for importer
w.pos(n.Pos)
w.typ(n.Type)
switch {
default:
// empty list
- w.op(OEND)
+ w.op(ir.OEND)
case n.List.Len() != 0: // pre-typecheck
w.exprList(n.List) // emits terminating OEND
case n.Right != nil:
w.expr(n.Left)
w.expr(n.Right)
- w.op(OEND)
- case n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()):
+ w.op(ir.OEND)
+ case n.Left != nil && (n.Op == ir.OMAKESLICE || !n.Left.Type.IsUntyped()):
w.expr(n.Left)
- w.op(OEND)
+ w.op(ir.OEND)
}
// unary expressions
- case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
+ case ir.OPLUS, ir.ONEG, ir.OADDR, ir.OBITNOT, ir.ODEREF, ir.ONOT, ir.ORECV:
w.op(op)
w.pos(n.Pos)
w.expr(n.Left)
// binary expressions
- case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
- OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
+ case ir.OADD, ir.OAND, ir.OANDAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
+ ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR:
w.op(op)
w.pos(n.Pos)
w.expr(n.Left)
w.expr(n.Right)
- case OADDSTR:
- w.op(OADDSTR)
+ case ir.OADDSTR:
+ w.op(ir.OADDSTR)
w.pos(n.Pos)
w.exprList(n.List)
- case ODCLCONST:
+ case ir.ODCLCONST:
// if exporting, DCLCONST should just be removed as its usage
// has already been replaced with literals
}
}
-func (w *exportWriter) op(op Op) {
+func (w *exportWriter) op(op ir.Op) {
w.uint64(uint64(op))
}
-func (w *exportWriter) exprsOrNil(a, b *Node) {
+func (w *exportWriter) exprsOrNil(a, b *ir.Node) {
ab := 0
if a != nil {
ab |= 1
}
}
-func (w *exportWriter) elemList(list Nodes) {
+func (w *exportWriter) elemList(list ir.Nodes) {
w.uint64(uint64(list.Len()))
for _, n := range list.Slice() {
w.selector(n.Sym)
}
}
-func (w *exportWriter) localName(n *Node) {
+func (w *exportWriter) localName(n *ir.Node) {
// Escape analysis happens after inline bodies are saved, but
// we're using the same ONAME nodes, so we might still see
// PAUTOHEAP here.
// PPARAM/PPARAMOUT, because we only want to include vargen in
// non-param names.
var v int32
- if n.Class() == PAUTO || (n.Class() == PAUTOHEAP && n.Name.Param.Stackcopy == nil) {
+ if n.Class() == ir.PAUTO || (n.Class() == ir.PAUTOHEAP && n.Name.Param.Stackcopy == nil) {
v = n.Name.Vargen
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/bio"
"cmd/internal/goobj"
inlineImporter = map[*types.Sym]iimporterAndOffset{}
)
-func expandDecl(n *Node) {
- if n.Op != ONONAME {
+func expandDecl(n *ir.Node) {
+ if n.Op != ir.ONONAME {
return
}
r.doDecl(n)
}
-func expandInline(fn *Node) {
+func expandInline(fn *ir.Node) {
if fn.Func.Inl.Body != nil {
return
}
r.doInline(fn)
}
-func importReaderFor(n *Node, importers map[*types.Sym]iimporterAndOffset) *importReader {
+func importReaderFor(n *ir.Node, importers map[*types.Sym]iimporterAndOffset) *importReader {
x, ok := importers[n.Sym]
if !ok {
return nil
if pkg.Name == "" {
pkg.Name = pkgName
pkg.Height = pkgHeight
- numImport[pkgName]++
+ ir.NumImport[pkgName]++
// TODO(mdempsky): This belongs somewhere else.
- pkg.Lookup("_").Def = asTypesNode(nblank)
+ pkg.Lookup("_").Def = ir.AsTypesNode(ir.BlankNode)
} else {
if pkg.Name != pkgName {
base.Fatalf("conflicting package names %v and %v for path %q", pkg.Name, pkgName, pkg.Path)
// Create stub declaration. If used, this will
// be overwritten by expandDecl.
if s.Def != nil {
- base.Fatalf("unexpected definition for %v: %v", s, asNode(s.Def))
+ base.Fatalf("unexpected definition for %v: %v", s, ir.AsNode(s.Def))
}
- s.Def = asTypesNode(npos(src.NoXPos, dclname(s)))
+ s.Def = ir.AsTypesNode(npos(src.NoXPos, dclname(s)))
}
}
r.currPkg = r.pkg()
}
-func (r *importReader) doDecl(n *Node) {
- if n.Op != ONONAME {
+func (r *importReader) doDecl(n *ir.Node) {
+ if n.Op != ir.ONONAME {
base.Fatalf("doDecl: unexpected Op for %v: %v", n.Sym, n.Op)
}
recv := r.param()
mtyp := r.signature(recv)
- m := newfuncnamel(mpos, methodSym(recv.Type, msym), new(Func))
+ m := newfuncnamel(mpos, methodSym(recv.Type, msym), new(ir.Func))
m.Type = mtyp
- m.SetClass(PFUNC)
+ m.SetClass(ir.PFUNC)
// methodSym already marked m.Sym as a function.
f := types.NewField(mpos, msym, mtyp)
- f.Nname = asTypesNode(m)
+ f.Nname = ir.AsTypesNode(m)
ms[i] = f
}
t.Methods().Set(ms)
}
pkg := r.currPkg
if types.IsExported(name) {
- pkg = localpkg
+ pkg = ir.LocalPkg
}
return pkg.Lookup(name)
}
// support inlining functions with local defined
// types. Therefore, this must be a package-scope
// type.
- n := asNode(r.qualifiedIdent().PkgDef())
- if n.Op == ONONAME {
+ n := ir.AsNode(r.qualifiedIdent().PkgDef())
+ if n.Op == ir.ONONAME {
expandDecl(n)
}
- if n.Op != OTYPE {
+ if n.Op != ir.OTYPE {
base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op, n.Sym, n)
}
return n.Type
fs[i] = f
}
- t := types.New(TSTRUCT)
+ t := types.New(types.TSTRUCT)
t.SetPkg(r.currPkg)
t.SetFields(fs)
return t
methods[i] = types.NewField(pos, sym, typ)
}
- t := types.New(TINTER)
+ t := types.New(types.TINTER)
t.SetPkg(r.currPkg)
t.SetInterface(append(embeddeds, methods...))
// Compiler-specific extensions.
-func (r *importReader) varExt(n *Node) {
+func (r *importReader) varExt(n *ir.Node) {
r.linkname(n.Sym)
r.symIdx(n.Sym)
}
-func (r *importReader) funcExt(n *Node) {
+func (r *importReader) funcExt(n *ir.Node) {
r.linkname(n.Sym)
r.symIdx(n.Sym)
// Inline body.
if u := r.uint64(); u > 0 {
- n.Func.Inl = &Inline{
+ n.Func.Inl = &ir.Inline{
Cost: int32(u - 1),
}
n.Func.Endlineno = r.pos()
if r.bool() {
m.SetNointerface(true)
}
- r.funcExt(asNode(m.Nname))
+ r.funcExt(ir.AsNode(m.Nname))
}
func (r *importReader) linkname(s *types.Sym) {
// so we can use index to reference the symbol.
var typeSymIdx = make(map[*types.Type][2]int64)
-func (r *importReader) doInline(n *Node) {
+func (r *importReader) doInline(n *ir.Node) {
if len(n.Func.Inl.Body) != 0 {
base.Fatalf("%v already has inline body", n)
}
// (not doing so can cause significant performance
// degradation due to unnecessary calls to empty
// functions).
- body = []*Node{}
+ body = []*ir.Node{}
}
n.Func.Inl.Body = body
if base.Flag.E > 0 && base.Flag.LowerM > 2 {
if base.Flag.LowerM > 3 {
- fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body))
+ fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, ir.AsNodes(n.Func.Inl.Body))
} else {
- fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body))
+ fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, ir.AsNodes(n.Func.Inl.Body))
}
}
}
// unrefined nodes (since this is what the importer uses). The respective case
// entries are unreachable in the importer.
-func (r *importReader) stmtList() []*Node {
- var list []*Node
+func (r *importReader) stmtList() []*ir.Node {
+ var list []*ir.Node
for {
n := r.node()
if n == nil {
break
}
// OBLOCK nodes may be created when importing ODCL nodes - unpack them
- if n.Op == OBLOCK {
+ if n.Op == ir.OBLOCK {
list = append(list, n.List.Slice()...)
} else {
list = append(list, n)
return list
}
-func (r *importReader) caseList(sw *Node) []*Node {
- namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil
+func (r *importReader) caseList(sw *ir.Node) []*ir.Node {
+ namedTypeSwitch := sw.Op == ir.OSWITCH && sw.Left != nil && sw.Left.Op == ir.OTYPESW && sw.Left.Left != nil
- cases := make([]*Node, r.uint64())
+ cases := make([]*ir.Node, r.uint64())
for i := range cases {
- cas := nodl(r.pos(), OCASE, nil, nil)
+ cas := ir.NodAt(r.pos(), ir.OCASE, nil, nil)
cas.List.Set(r.stmtList())
if namedTypeSwitch {
// Note: per-case variables will have distinct, dotted
// names after import. That's okay: swt.go only needs
// Sym for diagnostics anyway.
- caseVar := newnamel(cas.Pos, r.ident())
+ caseVar := ir.NewNameAt(cas.Pos, r.ident())
declare(caseVar, dclcontext)
cas.Rlist.Set1(caseVar)
caseVar.Name.Defn = sw.Left
return cases
}
-func (r *importReader) exprList() []*Node {
- var list []*Node
+func (r *importReader) exprList() []*ir.Node {
+ var list []*ir.Node
for {
n := r.expr()
if n == nil {
return list
}
-func (r *importReader) expr() *Node {
+func (r *importReader) expr() *ir.Node {
n := r.node()
- if n != nil && n.Op == OBLOCK {
+ if n != nil && n.Op == ir.OBLOCK {
base.Fatalf("unexpected block node: %v", n)
}
return n
}
// TODO(gri) split into expr and stmt
-func (r *importReader) node() *Node {
+func (r *importReader) node() *ir.Node {
switch op := r.op(); op {
// expressions
// case OPAREN:
// case ONIL:
// unreachable - mapped to OLITERAL
- case OLITERAL:
+ case ir.OLITERAL:
pos := r.pos()
typ := r.typ()
- var n *Node
+ var n *ir.Node
if typ.HasNil() {
n = nodnil()
} else {
- n = nodlit(r.value(typ))
+ n = ir.NewLiteral(r.value(typ))
}
n = npos(pos, n)
n.Type = typ
return n
- case ONONAME:
+ case ir.ONONAME:
return mkname(r.qualifiedIdent())
- case ONAME:
+ case ir.ONAME:
return mkname(r.ident())
// case OPACK, ONONAME:
// unreachable - should have been resolved by typechecking
- case OTYPE:
+ case ir.OTYPE:
return typenod(r.typ())
- case OTYPESW:
- n := nodl(r.pos(), OTYPESW, nil, nil)
+ case ir.OTYPESW:
+ n := ir.NodAt(r.pos(), ir.OTYPESW, nil, nil)
if s := r.ident(); s != nil {
n.Left = npos(n.Pos, newnoname(s))
}
// case OPTRLIT:
// unreachable - mapped to case OADDR below by exporter
- case OSTRUCTLIT:
+ case ir.OSTRUCTLIT:
// TODO(mdempsky): Export position information for OSTRUCTKEY nodes.
savedlineno := base.Pos
base.Pos = r.pos()
- n := nodl(base.Pos, OCOMPLIT, nil, typenod(r.typ()))
+ n := ir.NodAt(base.Pos, ir.OCOMPLIT, nil, typenod(r.typ()))
n.List.Set(r.elemList()) // special handling of field names
base.Pos = savedlineno
return n
// case OARRAYLIT, OSLICELIT, OMAPLIT:
// unreachable - mapped to case OCOMPLIT below by exporter
- case OCOMPLIT:
- n := nodl(r.pos(), OCOMPLIT, nil, typenod(r.typ()))
+ case ir.OCOMPLIT:
+ n := ir.NodAt(r.pos(), ir.OCOMPLIT, nil, typenod(r.typ()))
n.List.Set(r.exprList())
return n
- case OKEY:
+ case ir.OKEY:
pos := r.pos()
left, right := r.exprsOrNil()
- return nodl(pos, OKEY, left, right)
+ return ir.NodAt(pos, ir.OKEY, left, right)
// case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
// unreachable - mapped to case OXDOT below by exporter
- case OXDOT:
+ case ir.OXDOT:
// see parser.new_dotname
- return npos(r.pos(), nodSym(OXDOT, r.expr(), r.ident()))
+ return npos(r.pos(), nodSym(ir.OXDOT, r.expr(), r.ident()))
// case ODOTTYPE, ODOTTYPE2:
// unreachable - mapped to case ODOTTYPE below by exporter
- case ODOTTYPE:
- n := nodl(r.pos(), ODOTTYPE, r.expr(), nil)
+ case ir.ODOTTYPE:
+ n := ir.NodAt(r.pos(), ir.ODOTTYPE, r.expr(), nil)
n.Type = r.typ()
return n
// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
// unreachable - mapped to cases below by exporter
- case OINDEX:
- return nodl(r.pos(), op, r.expr(), r.expr())
+ case ir.OINDEX:
+ return ir.NodAt(r.pos(), op, r.expr(), r.expr())
- case OSLICE, OSLICE3:
- n := nodl(r.pos(), op, r.expr(), nil)
+ case ir.OSLICE, ir.OSLICE3:
+ n := ir.NodAt(r.pos(), op, r.expr(), nil)
low, high := r.exprsOrNil()
- var max *Node
+ var max *ir.Node
if n.Op.IsSlice3() {
max = r.expr()
}
// case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
// unreachable - mapped to OCONV case below by exporter
- case OCONV:
- n := nodl(r.pos(), OCONV, r.expr(), nil)
+ case ir.OCONV:
+ n := ir.NodAt(r.pos(), ir.OCONV, r.expr(), nil)
n.Type = r.typ()
return n
- case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
+ case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
n := npos(r.pos(), builtinCall(op))
n.List.Set(r.exprList())
- if op == OAPPEND {
+ if op == ir.OAPPEND {
n.SetIsDDD(r.bool())
}
return n
// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
// unreachable - mapped to OCALL case below by exporter
- case OCALL:
- n := nodl(r.pos(), OCALL, nil, nil)
+ case ir.OCALL:
+ n := ir.NodAt(r.pos(), ir.OCALL, nil, nil)
n.Ninit.Set(r.stmtList())
n.Left = r.expr()
n.List.Set(r.exprList())
n.SetIsDDD(r.bool())
return n
- case OMAKEMAP, OMAKECHAN, OMAKESLICE:
- n := npos(r.pos(), builtinCall(OMAKE))
+ case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
+ n := npos(r.pos(), builtinCall(ir.OMAKE))
n.List.Append(typenod(r.typ()))
n.List.Append(r.exprList()...)
return n
// unary expressions
- case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
- return nodl(r.pos(), op, r.expr(), nil)
+ case ir.OPLUS, ir.ONEG, ir.OADDR, ir.OBITNOT, ir.ODEREF, ir.ONOT, ir.ORECV:
+ return ir.NodAt(r.pos(), op, r.expr(), nil)
// binary expressions
- case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
- OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
- return nodl(r.pos(), op, r.expr(), r.expr())
+ case ir.OADD, ir.OAND, ir.OANDAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
+ ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR:
+ return ir.NodAt(r.pos(), op, r.expr(), r.expr())
- case OADDSTR:
+ case ir.OADDSTR:
pos := r.pos()
list := r.exprList()
x := npos(pos, list[0])
for _, y := range list[1:] {
- x = nodl(pos, OADD, x, y)
+ x = ir.NodAt(pos, ir.OADD, x, y)
}
return x
// --------------------------------------------------------------------
// statements
- case ODCL:
+ case ir.ODCL:
pos := r.pos()
lhs := npos(pos, dclname(r.ident()))
typ := typenod(r.typ())
- return npos(pos, liststmt(variter([]*Node{lhs}, typ, nil))) // TODO(gri) avoid list creation
+ return npos(pos, liststmt(variter([]*ir.Node{lhs}, typ, nil))) // TODO(gri) avoid list creation
// case ODCLFIELD:
// unimplemented
// case OAS, OASWB:
// unreachable - mapped to OAS case below by exporter
- case OAS:
- return nodl(r.pos(), OAS, r.expr(), r.expr())
+ case ir.OAS:
+ return ir.NodAt(r.pos(), ir.OAS, r.expr(), r.expr())
- case OASOP:
- n := nodl(r.pos(), OASOP, nil, nil)
+ case ir.OASOP:
+ n := ir.NodAt(r.pos(), ir.OASOP, nil, nil)
n.SetSubOp(r.op())
n.Left = r.expr()
if !r.bool() {
// case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
// unreachable - mapped to OAS2 case below by exporter
- case OAS2:
- n := nodl(r.pos(), OAS2, nil, nil)
+ case ir.OAS2:
+ n := ir.NodAt(r.pos(), ir.OAS2, nil, nil)
n.List.Set(r.exprList())
n.Rlist.Set(r.exprList())
return n
- case ORETURN:
- n := nodl(r.pos(), ORETURN, nil, nil)
+ case ir.ORETURN:
+ n := ir.NodAt(r.pos(), ir.ORETURN, nil, nil)
n.List.Set(r.exprList())
return n
// case ORETJMP:
// unreachable - generated by compiler for trampolin routines (not exported)
- case OGO, ODEFER:
- return nodl(r.pos(), op, r.expr(), nil)
+ case ir.OGO, ir.ODEFER:
+ return ir.NodAt(r.pos(), op, r.expr(), nil)
- case OIF:
- n := nodl(r.pos(), OIF, nil, nil)
+ case ir.OIF:
+ n := ir.NodAt(r.pos(), ir.OIF, nil, nil)
n.Ninit.Set(r.stmtList())
n.Left = r.expr()
n.Nbody.Set(r.stmtList())
n.Rlist.Set(r.stmtList())
return n
- case OFOR:
- n := nodl(r.pos(), OFOR, nil, nil)
+ case ir.OFOR:
+ n := ir.NodAt(r.pos(), ir.OFOR, nil, nil)
n.Ninit.Set(r.stmtList())
left, right := r.exprsOrNil()
n.Left = left
n.Nbody.Set(r.stmtList())
return n
- case ORANGE:
- n := nodl(r.pos(), ORANGE, nil, nil)
+ case ir.ORANGE:
+ n := ir.NodAt(r.pos(), ir.ORANGE, nil, nil)
n.List.Set(r.stmtList())
n.Right = r.expr()
n.Nbody.Set(r.stmtList())
return n
- case OSELECT, OSWITCH:
- n := nodl(r.pos(), op, nil, nil)
+ case ir.OSELECT, ir.OSWITCH:
+ n := ir.NodAt(r.pos(), op, nil, nil)
n.Ninit.Set(r.stmtList())
left, _ := r.exprsOrNil()
n.Left = left
// case OCASE:
// handled by caseList
- case OFALL:
- n := nodl(r.pos(), OFALL, nil, nil)
+ case ir.OFALL:
+ n := ir.NodAt(r.pos(), ir.OFALL, nil, nil)
return n
- case OBREAK, OCONTINUE:
+ case ir.OBREAK, ir.OCONTINUE:
pos := r.pos()
left, _ := r.exprsOrNil()
if left != nil {
- left = newname(left.Sym)
+ left = NewName(left.Sym)
}
- return nodl(pos, op, left, nil)
+ return ir.NodAt(pos, op, left, nil)
// case OEMPTY:
// unreachable - not emitted by exporter
- case OGOTO, OLABEL:
- n := nodl(r.pos(), op, nil, nil)
+ case ir.OGOTO, ir.OLABEL:
+ n := ir.NodAt(r.pos(), op, nil, nil)
n.Sym = lookup(r.string())
return n
- case OEND:
+ case ir.OEND:
return nil
default:
}
}
-func (r *importReader) op() Op {
- return Op(r.uint64())
+func (r *importReader) op() ir.Op {
+ return ir.Op(r.uint64())
}
-func (r *importReader) elemList() []*Node {
+func (r *importReader) elemList() []*ir.Node {
c := r.uint64()
- list := make([]*Node, c)
+ list := make([]*ir.Node, c)
for i := range list {
s := r.ident()
- list[i] = nodSym(OSTRUCTKEY, r.expr(), s)
+ list[i] = nodSym(ir.OSTRUCTKEY, r.expr(), s)
}
return list
}
-func (r *importReader) exprsOrNil() (a, b *Node) {
+func (r *importReader) exprsOrNil() (a, b *ir.Node) {
ab := r.uint64()
if ab&1 != 0 {
a = r.expr()
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/obj"
)
// Function collecting autotmps generated during typechecking,
// to be included in the package-level init function.
-var initTodo = nod(ODCLFUNC, nil, nil)
+var initTodo = ir.Nod(ir.ODCLFUNC, nil, nil)
func renameinit() *types.Sym {
s := lookupN("init.", renameinitgen)
// 1) Initialize all of the packages the current package depends on.
// 2) Initialize all the variables that have initializers.
// 3) Run any init functions.
-func fninit(n []*Node) {
+func fninit(n []*ir.Node) {
nf := initOrder(n)
var deps []*obj.LSym // initTask records for packages the current package depends on
if len(nf) > 0 {
base.Pos = nf[0].Pos // prolog/epilog gets line number of first init stmt
initializers := lookup("init")
- fn := dclfunc(initializers, nod(OTFUNC, nil, nil))
+ fn := dclfunc(initializers, ir.Nod(ir.OTFUNC, nil, nil))
for _, dcl := range initTodo.Func.Dcl {
dcl.Name.Curfn = fn
}
// Record user init functions.
for i := 0; i < renameinitgen; i++ {
s := lookupN("init.", i)
- fn := asNode(s.Def).Name.Defn
+ fn := ir.AsNode(s.Def).Name.Defn
// Skip init functions with empty bodies.
- if fn.Nbody.Len() == 1 && fn.Nbody.First().Op == OEMPTY {
+ if fn.Nbody.Len() == 1 && fn.Nbody.First().Op == ir.OEMPTY {
continue
}
fns = append(fns, s.Linksym())
}
- if len(deps) == 0 && len(fns) == 0 && localpkg.Name != "main" && localpkg.Name != "runtime" {
+ if len(deps) == 0 && len(fns) == 0 && ir.LocalPkg.Name != "main" && ir.LocalPkg.Name != "runtime" {
return // nothing to initialize
}
// Make an .inittask structure.
sym := lookup(".inittask")
- nn := newname(sym)
- nn.Type = types.Types[TUINT8] // fake type
- nn.SetClass(PEXTERN)
- sym.Def = asTypesNode(nn)
+ nn := NewName(sym)
+ nn.Type = types.Types[types.TUINT8] // fake type
+ nn.SetClass(ir.PEXTERN)
+ sym.Def = ir.AsTypesNode(nn)
exportsym(nn)
lsym := sym.Linksym()
ot := 0
"fmt"
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
)
// Package initialization
type InitOrder struct {
// blocking maps initialization assignments to the assignments
// that depend on it.
- blocking map[*Node][]*Node
+ blocking map[*ir.Node][]*ir.Node
// ready is the queue of Pending initialization assignments
// that are ready for initialization.
// package-level declarations (in declaration order) and outputs the
// corresponding list of statements to include in the init() function
// body.
-func initOrder(l []*Node) []*Node {
+func initOrder(l []*ir.Node) []*ir.Node {
s := InitSchedule{
- initplans: make(map[*Node]*InitPlan),
- inittemps: make(map[*Node]*Node),
+ initplans: make(map[*ir.Node]*InitPlan),
+ inittemps: make(map[*ir.Node]*ir.Node),
}
o := InitOrder{
- blocking: make(map[*Node][]*Node),
+ blocking: make(map[*ir.Node][]*ir.Node),
}
// Process all package-level assignment in declaration order.
for _, n := range l {
switch n.Op {
- case OAS, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ case ir.OAS, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
o.processAssign(n)
o.flushReady(s.staticInit)
- case ODCLCONST, ODCLFUNC, ODCLTYPE:
+ case ir.ODCLCONST, ir.ODCLFUNC, ir.ODCLTYPE:
// nop
default:
base.Fatalf("unexpected package-level statement: %v", n)
// have been a dependency cycle.
for _, n := range l {
switch n.Op {
- case OAS, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ case ir.OAS, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
if n.Initorder() != InitDone {
// If there have already been errors
// printed, those errors may have
// first.
base.ExitIfErrors()
- findInitLoopAndExit(firstLHS(n), new([]*Node))
+ findInitLoopAndExit(firstLHS(n), new([]*ir.Node))
base.Fatalf("initialization unfinished, but failed to identify loop")
}
}
return s.out
}
-func (o *InitOrder) processAssign(n *Node) {
- if n.Initorder() != InitNotStarted || n.Xoffset != BADWIDTH {
+func (o *InitOrder) processAssign(n *ir.Node) {
+ if n.Initorder() != InitNotStarted || n.Xoffset != types.BADWIDTH {
base.Fatalf("unexpected state: %v, %v, %v", n, n.Initorder(), n.Xoffset)
}
defn := dep.Name.Defn
// Skip dependencies on functions (PFUNC) and
// variables already initialized (InitDone).
- if dep.Class() != PEXTERN || defn.Initorder() == InitDone {
+ if dep.Class() != ir.PEXTERN || defn.Initorder() == InitDone {
continue
}
n.Xoffset++
// flushReady repeatedly applies initialize to the earliest (in
// declaration order) assignment ready for initialization and updates
// the inverse dependency ("blocking") graph.
-func (o *InitOrder) flushReady(initialize func(*Node)) {
+func (o *InitOrder) flushReady(initialize func(*ir.Node)) {
for o.ready.Len() != 0 {
- n := heap.Pop(&o.ready).(*Node)
+ n := heap.Pop(&o.ready).(*ir.Node)
if n.Initorder() != InitPending || n.Xoffset != 0 {
base.Fatalf("unexpected state: %v, %v, %v", n, n.Initorder(), n.Xoffset)
}
initialize(n)
n.SetInitorder(InitDone)
- n.Xoffset = BADWIDTH
+ n.Xoffset = types.BADWIDTH
blocked := o.blocking[n]
delete(o.blocking, n)
// path points to a slice used for tracking the sequence of
// variables/functions visited. Using a pointer to a slice allows the
// slice capacity to grow and limit reallocations.
-func findInitLoopAndExit(n *Node, path *[]*Node) {
+func findInitLoopAndExit(n *ir.Node, path *[]*ir.Node) {
// We implement a simple DFS loop-finding algorithm. This
// could be faster, but initialization cycles are rare.
// There might be multiple loops involving n; by sorting
// references, we deterministically pick the one reported.
- refers := collectDeps(n.Name.Defn, false).Sorted(func(ni, nj *Node) bool {
+ refers := collectDeps(n.Name.Defn, false).Sorted(func(ni, nj *ir.Node) bool {
return ni.Pos.Before(nj.Pos)
})
*path = append(*path, n)
for _, ref := range refers {
// Short-circuit variables that were initialized.
- if ref.Class() == PEXTERN && ref.Name.Defn.Initorder() == InitDone {
+ if ref.Class() == ir.PEXTERN && ref.Name.Defn.Initorder() == InitDone {
continue
}
// reportInitLoopAndExit reports and initialization loop as an error
// and exits. However, if l is not actually an initialization loop, it
// simply returns instead.
-func reportInitLoopAndExit(l []*Node) {
+func reportInitLoopAndExit(l []*ir.Node) {
// Rotate loop so that the earliest variable declaration is at
// the start.
i := -1
for j, n := range l {
- if n.Class() == PEXTERN && (i == -1 || n.Pos.Before(l[i].Pos)) {
+ if n.Class() == ir.PEXTERN && (i == -1 || n.Pos.Before(l[i].Pos)) {
i = j
}
}
var msg bytes.Buffer
fmt.Fprintf(&msg, "initialization loop:\n")
for _, n := range l {
- fmt.Fprintf(&msg, "\t%v: %v refers to\n", n.Line(), n)
+ fmt.Fprintf(&msg, "\t%v: %v refers to\n", ir.Line(n), n)
}
- fmt.Fprintf(&msg, "\t%v: %v", l[0].Line(), l[0])
+ fmt.Fprintf(&msg, "\t%v: %v", ir.Line(l[0]), l[0])
base.ErrorfAt(l[0].Pos, msg.String())
base.ErrorExit()
// variables that declaration n depends on. If transitive is true,
// then it also includes the transitive dependencies of any depended
// upon functions (but not variables).
-func collectDeps(n *Node, transitive bool) NodeSet {
+func collectDeps(n *ir.Node, transitive bool) ir.NodeSet {
d := initDeps{transitive: transitive}
switch n.Op {
- case OAS:
+ case ir.OAS:
d.inspect(n.Right)
- case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
d.inspect(n.Right)
- case ODCLFUNC:
+ case ir.ODCLFUNC:
d.inspectList(n.Nbody)
default:
base.Fatalf("unexpected Op: %v", n.Op)
type initDeps struct {
transitive bool
- seen NodeSet
+ seen ir.NodeSet
}
-func (d *initDeps) inspect(n *Node) { inspect(n, d.visit) }
-func (d *initDeps) inspectList(l Nodes) { inspectList(l, d.visit) }
+func (d *initDeps) inspect(n *ir.Node) { ir.Inspect(n, d.visit) }
+func (d *initDeps) inspectList(l ir.Nodes) { ir.InspectList(l, d.visit) }
// visit calls foundDep on any package-level functions or variables
// referenced by n, if any.
-func (d *initDeps) visit(n *Node) bool {
+func (d *initDeps) visit(n *ir.Node) bool {
switch n.Op {
- case OMETHEXPR:
- d.foundDep(n.MethodName())
+ case ir.OMETHEXPR:
+ d.foundDep(methodExprName(n))
return false
- case ONAME:
+ case ir.ONAME:
switch n.Class() {
- case PEXTERN, PFUNC:
+ case ir.PEXTERN, ir.PFUNC:
d.foundDep(n)
}
- case OCLOSURE:
+ case ir.OCLOSURE:
d.inspectList(n.Func.Decl.Nbody)
- case ODOTMETH, OCALLPART:
- d.foundDep(n.MethodName())
+ case ir.ODOTMETH, ir.OCALLPART:
+ d.foundDep(methodExprName(n))
}
return true
// foundDep records that we've found a dependency on n by adding it to
// seen.
-func (d *initDeps) foundDep(n *Node) {
+func (d *initDeps) foundDep(n *ir.Node) {
// Can happen with method expressions involving interface
// types; e.g., fixedbugs/issue4495.go.
if n == nil {
return
}
d.seen.Add(n)
- if d.transitive && n.Class() == PFUNC {
+ if d.transitive && n.Class() == ir.PFUNC {
d.inspectList(n.Name.Defn.Nbody)
}
}
// an OAS node's Pos may not be unique. For example, given the
// declaration "var a, b = f(), g()", "a" must be ordered before "b",
// but both OAS nodes use the "=" token's position as their Pos.
-type declOrder []*Node
+type declOrder []*ir.Node
func (s declOrder) Len() int { return len(s) }
func (s declOrder) Less(i, j int) bool { return firstLHS(s[i]).Pos.Before(firstLHS(s[j]).Pos) }
func (s declOrder) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s *declOrder) Push(x interface{}) { *s = append(*s, x.(*Node)) }
+func (s *declOrder) Push(x interface{}) { *s = append(*s, x.(*ir.Node)) }
func (s *declOrder) Pop() interface{} {
n := (*s)[len(*s)-1]
*s = (*s)[:len(*s)-1]
// firstLHS returns the first expression on the left-hand side of
// assignment n.
-func firstLHS(n *Node) *Node {
+func firstLHS(n *ir.Node) *ir.Node {
switch n.Op {
- case OAS:
+ case ir.OAS:
return n.Left
- case OAS2DOTTYPE, OAS2FUNC, OAS2RECV, OAS2MAPR:
+ case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2RECV, ir.OAS2MAPR:
return n.List.First()
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/types"
"cmd/internal/obj"
// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
// the ->sym can be re-used in the local package, so peel it off the receiver's type.
-func fnpkg(fn *Node) *types.Pkg {
- if fn.IsMethod() {
+func fnpkg(fn *ir.Node) *types.Pkg {
+ if ir.IsMethod(fn) {
// method
rcvr := fn.Type.Recv().Type
// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
// because they're a copy of an already checked body.
-func typecheckinl(fn *Node) {
+func typecheckinl(fn *ir.Node) {
lno := setlineno(fn)
expandInline(fn)
// the ->inl of a local function has been typechecked before caninl copied it.
pkg := fnpkg(fn)
- if pkg == localpkg || pkg == nil {
+ if pkg == ir.LocalPkg || pkg == nil {
return // typecheckinl on local function
}
if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
- fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
+ fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, ir.AsNodes(fn.Func.Inl.Body))
}
savefn := Curfn
// Caninl determines whether fn is inlineable.
// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
// fn and ->nbody will already have been typechecked.
-func caninl(fn *Node) {
- if fn.Op != ODCLFUNC {
+func caninl(fn *ir.Node) {
+ if fn.Op != ir.ODCLFUNC {
base.Fatalf("caninl %v", fn)
}
if fn.Func.Nname == nil {
defer func() {
if reason != "" {
if base.Flag.LowerM > 1 {
- fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
+ fmt.Printf("%v: cannot inline %v: %s\n", ir.Line(fn), fn.Func.Nname, reason)
}
if logopt.Enabled() {
- logopt.LogOpt(fn.Pos, "cannotInlineFunction", "inline", fn.funcname(), reason)
+ logopt.LogOpt(fn.Pos, "cannotInlineFunction", "inline", ir.FuncName(fn), reason)
}
}
}()
}
// If marked "go:noinline", don't inline
- if fn.Func.Pragma&Noinline != 0 {
+ if fn.Func.Pragma&ir.Noinline != 0 {
reason = "marked go:noinline"
return
}
// If marked "go:norace" and -race compilation, don't inline.
- if base.Flag.Race && fn.Func.Pragma&Norace != 0 {
+ if base.Flag.Race && fn.Func.Pragma&ir.Norace != 0 {
reason = "marked go:norace with -race compilation"
return
}
// If marked "go:nocheckptr" and -d checkptr compilation, don't inline.
- if base.Debug.Checkptr != 0 && fn.Func.Pragma&NoCheckPtr != 0 {
+ if base.Debug.Checkptr != 0 && fn.Func.Pragma&ir.NoCheckPtr != 0 {
reason = "marked go:nocheckptr"
return
}
// If marked "go:cgo_unsafe_args", don't inline, since the
// function makes assumptions about its argument frame layout.
- if fn.Func.Pragma&CgoUnsafeArgs != 0 {
+ if fn.Func.Pragma&ir.CgoUnsafeArgs != 0 {
reason = "marked go:cgo_unsafe_args"
return
}
// If marked as "go:uintptrescapes", don't inline, since the
// escape information is lost during inlining.
- if fn.Func.Pragma&UintptrEscapes != 0 {
+ if fn.Func.Pragma&ir.UintptrEscapes != 0 {
reason = "marked as having an escaping uintptr argument"
return
}
// granularity, so inlining yeswritebarrierrec functions can
// confuse it (#22342). As a workaround, disallow inlining
// them for now.
- if fn.Func.Pragma&Yeswritebarrierrec != 0 {
+ if fn.Func.Pragma&ir.Yeswritebarrierrec != 0 {
reason = "marked go:yeswritebarrierrec"
return
}
visitor := hairyVisitor{
budget: inlineMaxBudget,
extraCallCost: cc,
- usedLocals: make(map[*Node]bool),
+ usedLocals: make(map[*ir.Node]bool),
}
if visitor.visitList(fn.Nbody) {
reason = visitor.reason
return
}
- n.Func.Inl = &Inline{
+ n.Func.Inl = &ir.Inline{
Cost: inlineMaxBudget - visitor.budget,
Dcl: inlcopylist(pruneUnusedAutos(n.Name.Defn.Func.Dcl, &visitor)),
Body: inlcopylist(fn.Nbody.Slice()),
}
if base.Flag.LowerM > 1 {
- fmt.Printf("%v: can inline %#v with cost %d as: %#v { %#v }\n", fn.Line(), n, inlineMaxBudget-visitor.budget, fn.Type, asNodes(n.Func.Inl.Body))
+ fmt.Printf("%v: can inline %#v with cost %d as: %#v { %#v }\n", ir.Line(fn), n, inlineMaxBudget-visitor.budget, fn.Type, ir.AsNodes(n.Func.Inl.Body))
} else if base.Flag.LowerM != 0 {
- fmt.Printf("%v: can inline %v\n", fn.Line(), n)
+ fmt.Printf("%v: can inline %v\n", ir.Line(fn), n)
}
if logopt.Enabled() {
- logopt.LogOpt(fn.Pos, "canInlineFunction", "inline", fn.funcname(), fmt.Sprintf("cost: %d", inlineMaxBudget-visitor.budget))
+ logopt.LogOpt(fn.Pos, "canInlineFunction", "inline", ir.FuncName(fn), fmt.Sprintf("cost: %d", inlineMaxBudget-visitor.budget))
}
}
// inlFlood marks n's inline body for export and recursively ensures
// all called functions are marked too.
-func inlFlood(n *Node) {
+func inlFlood(n *ir.Node) {
if n == nil {
return
}
- if n.Op != ONAME || n.Class() != PFUNC {
+ if n.Op != ir.ONAME || n.Class() != ir.PFUNC {
base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op, n.Class())
}
if n.Func == nil {
// Recursively identify all referenced functions for
// reexport. We want to include even non-called functions,
// because after inlining they might be callable.
- inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
+ ir.InspectList(ir.AsNodes(n.Func.Inl.Body), func(n *ir.Node) bool {
switch n.Op {
- case OMETHEXPR:
- inlFlood(n.MethodName())
+ case ir.OMETHEXPR:
+ inlFlood(methodExprName(n))
- case ONAME:
+ case ir.ONAME:
switch n.Class() {
- case PFUNC:
+ case ir.PFUNC:
inlFlood(n)
exportsym(n)
- case PEXTERN:
+ case ir.PEXTERN:
exportsym(n)
}
- case ODOTMETH:
- fn := n.MethodName()
+ case ir.ODOTMETH:
+ fn := methodExprName(n)
inlFlood(fn)
- case OCALLPART:
+ case ir.OCALLPART:
// Okay, because we don't yet inline indirect
// calls to method values.
- case OCLOSURE:
+ case ir.OCLOSURE:
// If the closure is inlinable, we'll need to
// flood it too. But today we don't support
// inlining functions that contain closures.
budget int32
reason string
extraCallCost int32
- usedLocals map[*Node]bool
+ usedLocals map[*ir.Node]bool
}
// Look for anything we want to punt on.
-func (v *hairyVisitor) visitList(ll Nodes) bool {
+func (v *hairyVisitor) visitList(ll ir.Nodes) bool {
for _, n := range ll.Slice() {
if v.visit(n) {
return true
return false
}
-func (v *hairyVisitor) visit(n *Node) bool {
+func (v *hairyVisitor) visit(n *ir.Node) bool {
if n == nil {
return false
}
switch n.Op {
// Call is okay if inlinable and we have the budget for the body.
- case OCALLFUNC:
+ case ir.OCALLFUNC:
// Functions that call runtime.getcaller{pc,sp} can not be inlined
// because getcaller{pc,sp} expect a pointer to the caller's first argument.
//
// runtime.throw is a "cheap call" like panic in normal code.
- if n.Left.Op == ONAME && n.Left.Class() == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
+ if n.Left.Op == ir.ONAME && n.Left.Class() == ir.PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
fn := n.Left.Sym.Name
if fn == "getcallerpc" || fn == "getcallersp" {
v.reason = "call to " + fn
v.budget -= v.extraCallCost
// Call is okay if inlinable and we have the budget for the body.
- case OCALLMETH:
+ case ir.OCALLMETH:
t := n.Left.Type
if t == nil {
base.Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
break
}
}
- if inlfn := n.Left.MethodName().Func; inlfn.Inl != nil {
+ if inlfn := methodExprName(n.Left).Func; inlfn.Inl != nil {
v.budget -= inlfn.Inl.Cost
break
}
v.budget -= v.extraCallCost
// Things that are too hairy, irrespective of the budget
- case OCALL, OCALLINTER:
+ case ir.OCALL, ir.OCALLINTER:
// Call cost for non-leaf inlining.
v.budget -= v.extraCallCost
- case OPANIC:
+ case ir.OPANIC:
v.budget -= inlineExtraPanicCost
- case ORECOVER:
+ case ir.ORECOVER:
// recover matches the argument frame pointer to find
// the right panic value, so it needs an argument frame.
v.reason = "call to recover"
return true
- case OCLOSURE,
- ORANGE,
- OSELECT,
- OGO,
- ODEFER,
- ODCLTYPE, // can't print yet
- ORETJMP:
+ case ir.OCLOSURE,
+ ir.ORANGE,
+ ir.OSELECT,
+ ir.OGO,
+ ir.ODEFER,
+ ir.ODCLTYPE, // can't print yet
+ ir.ORETJMP:
v.reason = "unhandled op " + n.Op.String()
return true
- case OAPPEND:
+ case ir.OAPPEND:
v.budget -= inlineExtraAppendCost
- case ODCLCONST, OEMPTY, OFALL:
+ case ir.ODCLCONST, ir.OEMPTY, ir.OFALL:
// These nodes don't produce code; omit from inlining budget.
return false
- case OLABEL:
+ case ir.OLABEL:
// TODO(mdempsky): Add support for inlining labeled control statements.
- if n.labeledControl() != nil {
+ if labeledControl(n) != nil {
v.reason = "labeled control"
return true
}
- case OBREAK, OCONTINUE:
+ case ir.OBREAK, ir.OCONTINUE:
if n.Sym != nil {
// Should have short-circuited due to labeledControl above.
base.Fatalf("unexpected labeled break/continue: %v", n)
}
- case OIF:
- if Isconst(n.Left, constant.Bool) {
+ case ir.OIF:
+ if ir.IsConst(n.Left, constant.Bool) {
// This if and the condition cost nothing.
return v.visitList(n.Ninit) || v.visitList(n.Nbody) ||
v.visitList(n.Rlist)
}
- case ONAME:
- if n.Class() == PAUTO {
+ case ir.ONAME:
+ if n.Class() == ir.PAUTO {
v.usedLocals[n] = true
}
// inlcopylist (together with inlcopy) recursively copies a list of nodes, except
// that it keeps the same ONAME, OTYPE, and OLITERAL nodes. It is used for copying
// the body and dcls of an inlineable function.
-func inlcopylist(ll []*Node) []*Node {
- s := make([]*Node, 0, len(ll))
+func inlcopylist(ll []*ir.Node) []*ir.Node {
+ s := make([]*ir.Node, 0, len(ll))
for _, n := range ll {
s = append(s, inlcopy(n))
}
return s
}
-func inlcopy(n *Node) *Node {
+func inlcopy(n *ir.Node) *ir.Node {
if n == nil {
return nil
}
switch n.Op {
- case ONAME, OTYPE, OLITERAL, ONIL:
+ case ir.ONAME, ir.OTYPE, ir.OLITERAL, ir.ONIL:
return n
}
- m := n.copy()
- if n.Op != OCALLPART && m.Func != nil {
+ m := ir.Copy(n)
+ if n.Op != ir.OCALLPART && m.Func != nil {
base.Fatalf("unexpected Func: %v", m)
}
m.Left = inlcopy(n.Left)
return m
}
-func countNodes(n *Node) int {
+func countNodes(n *ir.Node) int {
if n == nil {
return 0
}
// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
// calls made to inlineable functions. This is the external entry point.
-func inlcalls(fn *Node) {
+func inlcalls(fn *ir.Node) {
savefn := Curfn
Curfn = fn
maxCost := int32(inlineMaxBudget)
// but allow inlining if there is a recursion cycle of many functions.
// Most likely, the inlining will stop before we even hit the beginning of
// the cycle again, but the map catches the unusual case.
- inlMap := make(map[*Node]bool)
+ inlMap := make(map[*ir.Node]bool)
fn = inlnode(fn, maxCost, inlMap)
if fn != Curfn {
base.Fatalf("inlnode replaced curfn")
}
// Turn an OINLCALL into a statement.
-func inlconv2stmt(n *Node) {
- n.Op = OBLOCK
+func inlconv2stmt(n *ir.Node) {
+ n.Op = ir.OBLOCK
// n->ninit stays
n.List.Set(n.Nbody.Slice())
// Turn an OINLCALL into a single valued expression.
// The result of inlconv2expr MUST be assigned back to n, e.g.
// n.Left = inlconv2expr(n.Left)
-func inlconv2expr(n *Node) *Node {
+func inlconv2expr(n *ir.Node) *ir.Node {
r := n.Rlist.First()
return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
}
// containing the inlined statements on the first list element so
// order will be preserved Used in return, oas2func and call
// statements.
-func inlconv2list(n *Node) []*Node {
- if n.Op != OINLCALL || n.Rlist.Len() == 0 {
+func inlconv2list(n *ir.Node) []*ir.Node {
+ if n.Op != ir.OINLCALL || n.Rlist.Len() == 0 {
base.Fatalf("inlconv2list %+v\n", n)
}
return s
}
-func inlnodelist(l Nodes, maxCost int32, inlMap map[*Node]bool) {
+func inlnodelist(l ir.Nodes, maxCost int32, inlMap map[*ir.Node]bool) {
s := l.Slice()
for i := range s {
s[i] = inlnode(s[i], maxCost, inlMap)
// shorter and less complicated.
// The result of inlnode MUST be assigned back to n, e.g.
// n.Left = inlnode(n.Left)
-func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
+func inlnode(n *ir.Node, maxCost int32, inlMap map[*ir.Node]bool) *ir.Node {
if n == nil {
return n
}
switch n.Op {
- case ODEFER, OGO:
+ case ir.ODEFER, ir.OGO:
switch n.Left.Op {
- case OCALLFUNC, OCALLMETH:
+ case ir.OCALLFUNC, ir.OCALLMETH:
n.Left.SetNoInline(true)
}
// TODO do them here (or earlier),
// so escape analysis can avoid more heapmoves.
- case OCLOSURE:
+ case ir.OCLOSURE:
return n
- case OCALLMETH:
+ case ir.OCALLMETH:
// Prevent inlining some reflect.Value methods when using checkptr,
// even when package reflect was compiled without it (#35073).
if s := n.Left.Sym; base.Debug.Checkptr != 0 && isReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
inlnodelist(n.Ninit, maxCost, inlMap)
for _, n1 := range n.Ninit.Slice() {
- if n1.Op == OINLCALL {
+ if n1.Op == ir.OINLCALL {
inlconv2stmt(n1)
}
}
n.Left = inlnode(n.Left, maxCost, inlMap)
- if n.Left != nil && n.Left.Op == OINLCALL {
+ if n.Left != nil && n.Left.Op == ir.OINLCALL {
n.Left = inlconv2expr(n.Left)
}
n.Right = inlnode(n.Right, maxCost, inlMap)
- if n.Right != nil && n.Right.Op == OINLCALL {
- if n.Op == OFOR || n.Op == OFORUNTIL {
+ if n.Right != nil && n.Right.Op == ir.OINLCALL {
+ if n.Op == ir.OFOR || n.Op == ir.OFORUNTIL {
inlconv2stmt(n.Right)
- } else if n.Op == OAS2FUNC {
+ } else if n.Op == ir.OAS2FUNC {
n.Rlist.Set(inlconv2list(n.Right))
n.Right = nil
- n.Op = OAS2
+ n.Op = ir.OAS2
n.SetTypecheck(0)
n = typecheck(n, ctxStmt)
} else {
}
inlnodelist(n.List, maxCost, inlMap)
- if n.Op == OBLOCK {
+ if n.Op == ir.OBLOCK {
for _, n2 := range n.List.Slice() {
- if n2.Op == OINLCALL {
+ if n2.Op == ir.OINLCALL {
inlconv2stmt(n2)
}
}
} else {
s := n.List.Slice()
for i1, n1 := range s {
- if n1 != nil && n1.Op == OINLCALL {
+ if n1 != nil && n1.Op == ir.OINLCALL {
s[i1] = inlconv2expr(s[i1])
}
}
inlnodelist(n.Rlist, maxCost, inlMap)
s := n.Rlist.Slice()
for i1, n1 := range s {
- if n1.Op == OINLCALL {
- if n.Op == OIF {
+ if n1.Op == ir.OINLCALL {
+ if n.Op == ir.OIF {
inlconv2stmt(n1)
} else {
s[i1] = inlconv2expr(s[i1])
inlnodelist(n.Nbody, maxCost, inlMap)
for _, n := range n.Nbody.Slice() {
- if n.Op == OINLCALL {
+ if n.Op == ir.OINLCALL {
inlconv2stmt(n)
}
}
// transmogrify this node itself unless inhibited by the
// switch at the top of this function.
switch n.Op {
- case OCALLFUNC, OCALLMETH:
+ case ir.OCALLFUNC, ir.OCALLMETH:
if n.NoInline() {
return n
}
}
switch n.Op {
- case OCALLFUNC:
+ case ir.OCALLFUNC:
if base.Flag.LowerM > 3 {
- fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
+ fmt.Printf("%v:call to func %+v\n", ir.Line(n), n.Left)
}
if isIntrinsicCall(n) {
break
n = mkinlcall(n, fn, maxCost, inlMap)
}
- case OCALLMETH:
+ case ir.OCALLMETH:
if base.Flag.LowerM > 3 {
- fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
+ fmt.Printf("%v:call to meth %L\n", ir.Line(n), n.Left.Right)
}
// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
base.Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
}
- n = mkinlcall(n, n.Left.MethodName(), maxCost, inlMap)
+ n = mkinlcall(n, methodExprName(n.Left), maxCost, inlMap)
}
base.Pos = lno
// inlCallee takes a function-typed expression and returns the underlying function ONAME
// that it refers to if statically known. Otherwise, it returns nil.
-func inlCallee(fn *Node) *Node {
+func inlCallee(fn *ir.Node) *ir.Node {
fn = staticValue(fn)
switch {
- case fn.Op == OMETHEXPR:
- n := fn.MethodName()
+ case fn.Op == ir.OMETHEXPR:
+ n := methodExprName(fn)
// Check that receiver type matches fn.Left.
// TODO(mdempsky): Handle implicit dereference
// of pointer receiver argument?
return nil
}
return n
- case fn.Op == ONAME && fn.Class() == PFUNC:
+ case fn.Op == ir.ONAME && fn.Class() == ir.PFUNC:
return fn
- case fn.Op == OCLOSURE:
+ case fn.Op == ir.OCLOSURE:
c := fn.Func.Decl
caninl(c)
return c.Func.Nname
return nil
}
-func staticValue(n *Node) *Node {
+func staticValue(n *ir.Node) *ir.Node {
for {
- if n.Op == OCONVNOP {
+ if n.Op == ir.OCONVNOP {
n = n.Left
continue
}
// staticValue1 implements a simple SSA-like optimization. If n is a local variable
// that is initialized and never reassigned, staticValue1 returns the initializer
// expression. Otherwise, it returns nil.
-func staticValue1(n *Node) *Node {
- if n.Op != ONAME || n.Class() != PAUTO || n.Name.Addrtaken() {
+func staticValue1(n *ir.Node) *ir.Node {
+ if n.Op != ir.ONAME || n.Class() != ir.PAUTO || n.Name.Addrtaken() {
return nil
}
return nil
}
- var rhs *Node
+ var rhs *ir.Node
FindRHS:
switch defn.Op {
- case OAS:
+ case ir.OAS:
rhs = defn.Right
- case OAS2:
+ case ir.OAS2:
for i, lhs := range defn.List.Slice() {
if lhs == n {
rhs = defn.Rlist.Index(i)
// useful for -m output documenting the reason for inhibited optimizations.
// NB: global variables are always considered to be re-assigned.
// TODO: handle initial declaration not including an assignment and followed by a single assignment?
-func reassigned(n *Node) (bool, *Node) {
- if n.Op != ONAME {
+func reassigned(n *ir.Node) (bool, *ir.Node) {
+ if n.Op != ir.ONAME {
base.Fatalf("reassigned %v", n)
}
// no way to reliably check for no-reassignment of globals, assume it can be
// of the corresponding ODCLFUNC.
// We need to walk the function body to check for reassignments so we follow the
// linkage to the ODCLFUNC node as that is where body is held.
- if f.Op == OCLOSURE {
+ if f.Op == ir.OCLOSURE {
f = f.Func.Decl
}
v := reassignVisitor{name: n}
}
type reassignVisitor struct {
- name *Node
+ name *ir.Node
}
-func (v *reassignVisitor) visit(n *Node) *Node {
+func (v *reassignVisitor) visit(n *ir.Node) *ir.Node {
if n == nil {
return nil
}
switch n.Op {
- case OAS:
+ case ir.OAS:
if n.Left == v.name && n != v.name.Name.Defn {
return n
}
- case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE:
+ case ir.OAS2, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2DOTTYPE:
for _, p := range n.List.Slice() {
if p == v.name && n != v.name.Name.Defn {
return n
return nil
}
-func (v *reassignVisitor) visitList(l Nodes) *Node {
+func (v *reassignVisitor) visitList(l ir.Nodes) *ir.Node {
for _, n := range l.Slice() {
if a := v.visit(n); a != nil {
return a
return nil
}
-func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
- n := asNode(t.Nname)
- if n == nil || n.isBlank() {
- return nblank
+func inlParam(t *types.Field, as *ir.Node, inlvars map[*ir.Node]*ir.Node) *ir.Node {
+ n := ir.AsNode(t.Nname)
+ if n == nil || ir.IsBlank(n) {
+ return ir.BlankNode
}
inlvar := inlvars[n]
if inlvar == nil {
base.Fatalf("missing inlvar for %v", n)
}
- as.Ninit.Append(nod(ODCL, inlvar, nil))
+ as.Ninit.Append(ir.Nod(ir.ODCL, inlvar, nil))
inlvar.Name.Defn = as
return inlvar
}
// parameters.
// The result of mkinlcall MUST be assigned back to n, e.g.
// n.Left = mkinlcall(n.Left, fn, isddd)
-func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
+func mkinlcall(n, fn *ir.Node, maxCost int32, inlMap map[*ir.Node]bool) *ir.Node {
if fn.Func.Inl == nil {
if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
- fmt.Sprintf("%s cannot be inlined", fn.pkgFuncName()))
+ logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", ir.FuncName(Curfn),
+ fmt.Sprintf("%s cannot be inlined", ir.PkgFuncName(fn)))
}
return n
}
// The inlined function body is too big. Typically we use this check to restrict
// inlining into very big functions. See issue 26546 and 17566.
if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
- fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Func.Inl.Cost, fn.pkgFuncName(), maxCost))
+ logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", ir.FuncName(Curfn),
+ fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Func.Inl.Cost, ir.PkgFuncName(fn), maxCost))
}
return n
}
if fn == Curfn || fn.Name.Defn == Curfn {
// Can't recursively inline a function into itself.
if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", Curfn.funcname()))
+ logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(Curfn)))
}
return n
}
if inlMap[fn] {
if base.Flag.LowerM > 1 {
- fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", n.Line(), fn, Curfn.funcname())
+ fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", ir.Line(n), fn, ir.FuncName(Curfn))
}
return n
}
// We have a function node, and it has an inlineable body.
if base.Flag.LowerM > 1 {
- fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
+ fmt.Printf("%v: inlining call to %v %#v { %#v }\n", ir.Line(n), fn.Sym, fn.Type, ir.AsNodes(fn.Func.Inl.Body))
} else if base.Flag.LowerM != 0 {
- fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
+ fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
}
if base.Flag.LowerM > 2 {
- fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
+ fmt.Printf("%v: Before inlining: %+v\n", ir.Line(n), n)
}
- if ssaDump != "" && ssaDump == Curfn.funcname() {
+ if ssaDump != "" && ssaDump == ir.FuncName(Curfn) {
ssaDumpInlined = append(ssaDumpInlined, fn)
}
// may contain side effects (e.g., added by addinit during
// inlconv2expr or inlconv2list). Make sure to preserve these,
// if necessary (#42703).
- if n.Op == OCALLFUNC {
+ if n.Op == ir.OCALLFUNC {
callee := n.Left
- for callee.Op == OCONVNOP {
+ for callee.Op == ir.OCONVNOP {
ninit.AppendNodes(&callee.Ninit)
callee = callee.Left
}
- if callee.Op != ONAME && callee.Op != OCLOSURE && callee.Op != OMETHEXPR {
+ if callee.Op != ir.ONAME && callee.Op != ir.OCLOSURE && callee.Op != ir.OMETHEXPR {
base.Fatalf("unexpected callee expression: %v", callee)
}
}
// Make temp names to use instead of the originals.
- inlvars := make(map[*Node]*Node)
+ inlvars := make(map[*ir.Node]*ir.Node)
// record formals/locals for later post-processing
- var inlfvars []*Node
+ var inlfvars []*ir.Node
// Handle captured variables when inlining closures.
if fn.Name.Defn != nil {
if c := fn.Name.Defn.Func.OClosure; c != nil {
for _, v := range c.Func.ClosureVars.Slice() {
- if v.Op == OXXX {
+ if v.Op == ir.OXXX {
continue
}
// the reassigned check via some sort of copy propagation this would most
// likely need to be changed to a loop to walk up to the correct Param
if o == nil || (o.Name.Curfn != Curfn && o.Name.Curfn.Func.OClosure != Curfn) {
- base.Fatalf("%v: unresolvable capture %v %v\n", n.Line(), fn, v)
+ base.Fatalf("%v: unresolvable capture %v %v\n", ir.Line(n), fn, v)
}
if v.Name.Byval() {
iv := typecheck(inlvar(v), ctxExpr)
- ninit.Append(nod(ODCL, iv, nil))
- ninit.Append(typecheck(nod(OAS, iv, o), ctxStmt))
+ ninit.Append(ir.Nod(ir.ODCL, iv, nil))
+ ninit.Append(typecheck(ir.Nod(ir.OAS, iv, o), ctxStmt))
inlvars[v] = iv
} else {
- addr := newname(lookup("&" + v.Sym.Name))
+ addr := NewName(lookup("&" + v.Sym.Name))
addr.Type = types.NewPtr(v.Type)
ia := typecheck(inlvar(addr), ctxExpr)
- ninit.Append(nod(ODCL, ia, nil))
- ninit.Append(typecheck(nod(OAS, ia, nod(OADDR, o, nil)), ctxStmt))
+ ninit.Append(ir.Nod(ir.ODCL, ia, nil))
+ ninit.Append(typecheck(ir.Nod(ir.OAS, ia, ir.Nod(ir.OADDR, o, nil)), ctxStmt))
inlvars[addr] = ia
// When capturing by reference, all occurrence of the captured var
// must be substituted with dereference of the temporary address
- inlvars[v] = typecheck(nod(ODEREF, ia, nil), ctxExpr)
+ inlvars[v] = typecheck(ir.Nod(ir.ODEREF, ia, nil), ctxExpr)
}
}
}
}
for _, ln := range fn.Func.Inl.Dcl {
- if ln.Op != ONAME {
+ if ln.Op != ir.ONAME {
continue
}
- if ln.Class() == PPARAMOUT { // return values handled below.
+ if ln.Class() == ir.PPARAMOUT { // return values handled below.
continue
}
- if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
+ if isParamStackCopy(ln) { // ignore the on-stack copy of a parameter that moved to the heap
// TODO(mdempsky): Remove once I'm confident
// this never actually happens. We currently
// perform inlining before escape analysis, so
inlf := typecheck(inlvar(ln), ctxExpr)
inlvars[ln] = inlf
if base.Flag.GenDwarfInl > 0 {
- if ln.Class() == PPARAM {
+ if ln.Class() == ir.PPARAM {
inlf.Name.SetInlFormal(true)
} else {
inlf.Name.SetInlLocal(true)
}
nreturns := 0
- inspectList(asNodes(fn.Func.Inl.Body), func(n *Node) bool {
- if n != nil && n.Op == ORETURN {
+ ir.InspectList(ir.AsNodes(fn.Func.Inl.Body), func(n *ir.Node) bool {
+ if n != nil && n.Op == ir.ORETURN {
nreturns++
}
return true
delayretvars := nreturns == 1
// temporaries for return values.
- var retvars []*Node
+ var retvars []*ir.Node
for i, t := range fn.Type.Results().Fields().Slice() {
- var m *Node
- if n := asNode(t.Nname); n != nil && !n.isBlank() && !strings.HasPrefix(n.Sym.Name, "~r") {
+ var m *ir.Node
+ if n := ir.AsNode(t.Nname); n != nil && !ir.IsBlank(n) && !strings.HasPrefix(n.Sym.Name, "~r") {
m = inlvar(n)
m = typecheck(m, ctxExpr)
inlvars[n] = m
}
// Assign arguments to the parameters' temp names.
- as := nod(OAS2, nil, nil)
+ as := ir.Nod(ir.OAS2, nil, nil)
as.SetColas(true)
- if n.Op == OCALLMETH {
+ if n.Op == ir.OCALLMETH {
if n.Left.Left == nil {
base.Fatalf("method call without receiver: %+v", n)
}
// For non-dotted calls to variadic functions, we assign the
// variadic parameter's temp name separately.
- var vas *Node
+ var vas *ir.Node
if recv := fn.Type.Recv(); recv != nil {
as.List.Append(inlParam(recv, as, inlvars))
}
varargs := as.List.Slice()[x:]
- vas = nod(OAS, nil, nil)
+ vas = ir.Nod(ir.OAS, nil, nil)
vas.Left = inlParam(param, vas, inlvars)
if len(varargs) == 0 {
vas.Right = nodnil()
vas.Right.Type = param.Type
} else {
- vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
+ vas.Right = ir.Nod(ir.OCOMPLIT, nil, typenod(param.Type))
vas.Right.List.Set(varargs)
}
}
if !delayretvars {
// Zero the return parameters.
for _, n := range retvars {
- ninit.Append(nod(ODCL, n, nil))
- ras := nod(OAS, n, nil)
+ ninit.Append(ir.Nod(ir.ODCL, n, nil))
+ ras := ir.Nod(ir.OAS, n, nil)
ras = typecheck(ras, ctxStmt)
ninit.Append(ras)
}
// to put a breakpoint. Not sure if that's really necessary or not
// (in which case it could go at the end of the function instead).
// Note issue 28603.
- inlMark := nod(OINLMARK, nil, nil)
+ inlMark := ir.Nod(ir.OINLMARK, nil, nil)
inlMark.Pos = n.Pos.WithIsStmt()
inlMark.Xoffset = int64(newIndex)
ninit.Append(inlMark)
newInlIndex: newIndex,
}
- body := subst.list(asNodes(fn.Func.Inl.Body))
+ body := subst.list(ir.AsNodes(fn.Func.Inl.Body))
- lab := nodSym(OLABEL, nil, retlabel)
+ lab := nodSym(ir.OLABEL, nil, retlabel)
body = append(body, lab)
typecheckslice(body, ctxStmt)
//dumplist("ninit post", ninit);
- call := nod(OINLCALL, nil, nil)
+ call := ir.Nod(ir.OINLCALL, nil, nil)
call.Ninit.Set(ninit.Slice())
call.Nbody.Set(body)
call.Rlist.Set(retvars)
// luckily these are small.
inlnodelist(call.Nbody, maxCost, inlMap)
for _, n := range call.Nbody.Slice() {
- if n.Op == OINLCALL {
+ if n.Op == ir.OINLCALL {
inlconv2stmt(n)
}
}
if base.Flag.LowerM > 2 {
- fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
+ fmt.Printf("%v: After inlining %+v\n\n", ir.Line(call), call)
}
return call
// Every time we expand a function we generate a new set of tmpnames,
// PAUTO's in the calling functions, and link them off of the
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
-func inlvar(var_ *Node) *Node {
+func inlvar(var_ *ir.Node) *ir.Node {
if base.Flag.LowerM > 3 {
fmt.Printf("inlvar %+v\n", var_)
}
- n := newname(var_.Sym)
+ n := NewName(var_.Sym)
n.Type = var_.Type
- n.SetClass(PAUTO)
+ n.SetClass(ir.PAUTO)
n.Name.SetUsed(true)
n.Name.Curfn = Curfn // the calling function, not the called one
n.Name.SetAddrtaken(var_.Name.Addrtaken())
}
// Synthesize a variable to store the inlined function's results in.
-func retvar(t *types.Field, i int) *Node {
- n := newname(lookupN("~R", i))
+func retvar(t *types.Field, i int) *ir.Node {
+ n := NewName(lookupN("~R", i))
n.Type = t.Type
- n.SetClass(PAUTO)
+ n.SetClass(ir.PAUTO)
n.Name.SetUsed(true)
n.Name.Curfn = Curfn // the calling function, not the called one
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
// Synthesize a variable to store the inlined function's arguments
// when they come from a multiple return call.
-func argvar(t *types.Type, i int) *Node {
- n := newname(lookupN("~arg", i))
+func argvar(t *types.Type, i int) *ir.Node {
+ n := NewName(lookupN("~arg", i))
n.Type = t.Elem()
- n.SetClass(PAUTO)
+ n.SetClass(ir.PAUTO)
n.Name.SetUsed(true)
n.Name.Curfn = Curfn // the calling function, not the called one
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
retlabel *types.Sym
// Temporary result variables.
- retvars []*Node
+ retvars []*ir.Node
// Whether result variables should be initialized at the
// "return" statement.
delayretvars bool
- inlvars map[*Node]*Node
+ inlvars map[*ir.Node]*ir.Node
// bases maps from original PosBase to PosBase with an extra
// inlined call frame.
}
// list inlines a list of nodes.
-func (subst *inlsubst) list(ll Nodes) []*Node {
- s := make([]*Node, 0, ll.Len())
+func (subst *inlsubst) list(ll ir.Nodes) []*ir.Node {
+ s := make([]*ir.Node, 0, ll.Len())
for _, n := range ll.Slice() {
s = append(s, subst.node(n))
}
// inlined function, substituting references to input/output
// parameters with ones to the tmpnames, and substituting returns with
// assignments to the output.
-func (subst *inlsubst) node(n *Node) *Node {
+func (subst *inlsubst) node(n *ir.Node) *ir.Node {
if n == nil {
return nil
}
switch n.Op {
- case ONAME:
+ case ir.ONAME:
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
if base.Flag.LowerM > 2 {
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
}
return n
- case OMETHEXPR:
+ case ir.OMETHEXPR:
return n
- case OLITERAL, ONIL, OTYPE:
+ case ir.OLITERAL, ir.ONIL, ir.OTYPE:
// If n is a named constant or type, we can continue
// using it in the inline copy. Otherwise, make a copy
// so we can update the line number.
// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
// dump("Return before substitution", n);
- case ORETURN:
- m := nodSym(OGOTO, nil, subst.retlabel)
+ case ir.ORETURN:
+ m := nodSym(ir.OGOTO, nil, subst.retlabel)
m.Ninit.Set(subst.list(n.Ninit))
if len(subst.retvars) != 0 && n.List.Len() != 0 {
- as := nod(OAS2, nil, nil)
+ as := ir.Nod(ir.OAS2, nil, nil)
// Make a shallow copy of retvars.
// Otherwise OINLCALL.Rlist will be the same list,
if subst.delayretvars {
for _, n := range as.List.Slice() {
- as.Ninit.Append(nod(ODCL, n, nil))
+ as.Ninit.Append(ir.Nod(ir.ODCL, n, nil))
n.Name.Defn = as
}
}
// dump("Return after substitution", m);
return m
- case OGOTO, OLABEL:
- m := n.copy()
+ case ir.OGOTO, ir.OLABEL:
+ m := ir.Copy(n)
m.Pos = subst.updatedPos(m.Pos)
m.Ninit.Set(nil)
p := fmt.Sprintf("%s·%d", n.Sym.Name, inlgen)
return m
}
- m := n.copy()
+ m := ir.Copy(n)
m.Pos = subst.updatedPos(m.Pos)
m.Ninit.Set(nil)
- if n.Op == OCLOSURE {
+ if n.Op == ir.OCLOSURE {
base.Fatalf("cannot inline function containing closure: %+v", n)
}
return base.Ctxt.PosTable.XPos(pos)
}
-func pruneUnusedAutos(ll []*Node, vis *hairyVisitor) []*Node {
- s := make([]*Node, 0, len(ll))
+func pruneUnusedAutos(ll []*ir.Node, vis *hairyVisitor) []*ir.Node {
+ s := make([]*ir.Node, 0, len(ll))
for _, n := range ll {
- if n.Class() == PAUTO {
+ if n.Class() == ir.PAUTO {
if _, found := vis.usedLocals[n]; !found {
continue
}
// devirtualize replaces interface method calls within fn with direct
// concrete-type method calls where applicable.
-func devirtualize(fn *Node) {
+func devirtualize(fn *ir.Node) {
Curfn = fn
- inspectList(fn.Nbody, func(n *Node) bool {
- if n.Op == OCALLINTER {
+ ir.InspectList(fn.Nbody, func(n *ir.Node) bool {
+ if n.Op == ir.OCALLINTER {
devirtualizeCall(n)
}
return true
})
}
-func devirtualizeCall(call *Node) {
+func devirtualizeCall(call *ir.Node) {
recv := staticValue(call.Left.Left)
- if recv.Op != OCONVIFACE {
+ if recv.Op != ir.OCONVIFACE {
return
}
return
}
- x := nodl(call.Left.Pos, ODOTTYPE, call.Left.Left, nil)
+ x := ir.NodAt(call.Left.Pos, ir.ODOTTYPE, call.Left.Left, nil)
x.Type = typ
- x = nodlSym(call.Left.Pos, OXDOT, x, call.Left.Sym)
+ x = nodlSym(call.Left.Pos, ir.OXDOT, x, call.Left.Sym)
x = typecheck(x, ctxExpr|ctxCallee)
switch x.Op {
- case ODOTMETH:
+ case ir.ODOTMETH:
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos, "devirtualizing %v to %v", call.Left, typ)
}
- call.Op = OCALLMETH
+ call.Op = ir.OCALLMETH
call.Left = x
- case ODOTINTER:
+ case ir.ODOTINTER:
// Promoted method from embedded interface-typed field (#42279).
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos, "partially devirtualizing %v to %v", call.Left, typ)
}
- call.Op = OCALLINTER
+ call.Op = ir.OCALLINTER
call.Left = x
default:
// TODO(mdempsky): Turn back into Fatalf after more testing.
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
"cmd/internal/objabi"
"cmd/internal/src"
return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
}
-type PragmaFlag int16
-
-const (
- // Func pragmas.
- Nointerface PragmaFlag = 1 << iota
- Noescape // func parameters don't escape
- Norace // func must not have race detector annotations
- Nosplit // func should not execute on separate stack
- Noinline // func should not be inlined
- NoCheckPtr // func should not be instrumented by checkptr
- CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
- UintptrEscapes // pointers converted to uintptr escape
-
- // Runtime-only func pragmas.
- // See ../../../../runtime/README.md for detailed descriptions.
- Systemstack // func must run on system stack
- Nowritebarrier // emit compiler error instead of write barrier
- Nowritebarrierrec // error on write barrier in this or recursive callees
- Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
-
- // Runtime and cgo type pragmas
- NotInHeap // values of this type must not be heap allocated
-
- // Go command pragmas
- GoBuildPragma
-)
-
const (
- FuncPragmas = Nointerface |
- Noescape |
- Norace |
- Nosplit |
- Noinline |
- NoCheckPtr |
- CgoUnsafeArgs |
- UintptrEscapes |
- Systemstack |
- Nowritebarrier |
- Nowritebarrierrec |
- Yeswritebarrierrec
-
- TypePragmas = NotInHeap
+ FuncPragmas = ir.Nointerface |
+ ir.Noescape |
+ ir.Norace |
+ ir.Nosplit |
+ ir.Noinline |
+ ir.NoCheckPtr |
+ ir.CgoUnsafeArgs |
+ ir.UintptrEscapes |
+ ir.Systemstack |
+ ir.Nowritebarrier |
+ ir.Nowritebarrierrec |
+ ir.Yeswritebarrierrec
+
+ TypePragmas = ir.NotInHeap
)
-func pragmaFlag(verb string) PragmaFlag {
+func pragmaFlag(verb string) ir.PragmaFlag {
switch verb {
case "go:build":
- return GoBuildPragma
+ return ir.GoBuildPragma
case "go:nointerface":
if objabi.Fieldtrack_enabled != 0 {
- return Nointerface
+ return ir.Nointerface
}
case "go:noescape":
- return Noescape
+ return ir.Noescape
case "go:norace":
- return Norace
+ return ir.Norace
case "go:nosplit":
- return Nosplit | NoCheckPtr // implies NoCheckPtr (see #34972)
+ return ir.Nosplit | ir.NoCheckPtr // implies NoCheckPtr (see #34972)
case "go:noinline":
- return Noinline
+ return ir.Noinline
case "go:nocheckptr":
- return NoCheckPtr
+ return ir.NoCheckPtr
case "go:systemstack":
- return Systemstack
+ return ir.Systemstack
case "go:nowritebarrier":
- return Nowritebarrier
+ return ir.Nowritebarrier
case "go:nowritebarrierrec":
- return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
+ return ir.Nowritebarrierrec | ir.Nowritebarrier // implies Nowritebarrier
case "go:yeswritebarrierrec":
- return Yeswritebarrierrec
+ return ir.Yeswritebarrierrec
case "go:cgo_unsafe_args":
- return CgoUnsafeArgs | NoCheckPtr // implies NoCheckPtr (see #34968)
+ return ir.CgoUnsafeArgs | ir.NoCheckPtr // implies NoCheckPtr (see #34968)
case "go:uintptrescapes":
// For the next function declared in the file
// any uintptr arguments may be pointer values
// call. The conversion to uintptr must appear
// in the argument list.
// Used in syscall/dll_windows.go.
- return UintptrEscapes
+ return ir.UintptrEscapes
case "go:notinheap":
- return NotInHeap
+ return ir.NotInHeap
}
return 0
}
"bufio"
"bytes"
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
// See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin
- localpkg = types.NewPkg("", "")
- localpkg.Prefix = "\"\""
+ ir.LocalPkg = types.NewPkg("", "")
+ ir.LocalPkg.Prefix = "\"\""
// We won't know localpkg's height until after import
// processing. In the mean time, set to MaxPkgHeight to ensure
// height comparisons at least work until then.
- localpkg.Height = types.MaxPkgHeight
+ ir.LocalPkg.Height = types.MaxPkgHeight
// pseudo-package, for scoping
- builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
- builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
+ ir.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
+ ir.BuiltinPkg.Prefix = "go.builtin" // not go%2ebuiltin
// pseudo-package, accessed by import "unsafe"
unsafepkg = types.NewPkg("unsafe", "unsafe")
types.Widthptr = Widthptr
types.Dowidth = dowidth
types.Fatalf = base.Fatalf
- types.Sconv = func(s *types.Sym, flag, mode int) string {
- return sconv(s, FmtFlag(flag), fmtMode(mode))
- }
- types.Tconv = func(t *types.Type, flag, mode int) string {
- return tconv(t, FmtFlag(flag), fmtMode(mode))
- }
- types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
- symFormat(sym, s, verb, fmtMode(mode))
- }
- types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
- typeFormat(t, s, verb, fmtMode(mode))
- }
+ ir.InstallTypeFormats()
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
return typenamesym(t).Linksym()
}
- types.FmtLeft = int(FmtLeft)
- types.FmtUnsigned = int(FmtUnsigned)
- types.FErr = int(FErr)
+ types.FmtLeft = int(ir.FmtLeft)
+ types.FmtUnsigned = int(ir.FmtUnsigned)
+ types.FErr = int(ir.FErr)
types.Ctxt = base.Ctxt
initUniverse()
- dclcontext = PEXTERN
+ dclcontext = ir.PEXTERN
autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
timings.Start("fe", "typecheck", "top1")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias()) {
+ if op := n.Op; op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.Left.Name.Param.Alias()) {
xtop[i] = typecheck(n, ctxStmt)
}
}
timings.Start("fe", "typecheck", "top2")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias() {
+ if op := n.Op; op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.Left.Name.Param.Alias() {
xtop[i] = typecheck(n, ctxStmt)
}
}
var fcount int64
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if n.Op == ODCLFUNC {
+ if n.Op == ir.ODCLFUNC {
Curfn = n
decldepth = 1
errorsBefore := base.Errors()
// because variables captured by value do not escape.
timings.Start("fe", "capturevars")
for _, n := range xtop {
- if n.Op == ODCLFUNC && n.Func.OClosure != nil {
+ if n.Op == ir.ODCLFUNC && n.Func.OClosure != nil {
Curfn = n
capturevars(n)
}
if base.Flag.LowerL != 0 {
// Find functions that can be inlined and clone them before walk expands them.
- visitBottomUp(xtop, func(list []*Node, recursive bool) {
+ visitBottomUp(xtop, func(list []*ir.Node, recursive bool) {
numfns := numNonClosures(list)
for _, n := range list {
if !recursive || numfns > 1 {
caninl(n)
} else {
if base.Flag.LowerM > 1 {
- fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
+ fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(n), n.Func.Nname)
}
}
inlcalls(n)
}
for _, n := range xtop {
- if n.Op == ODCLFUNC {
+ if n.Op == ir.ODCLFUNC {
devirtualize(n)
}
}
// before walk reaches a call of a closure.
timings.Start("fe", "xclosures")
for _, n := range xtop {
- if n.Op == ODCLFUNC && n.Func.OClosure != nil {
+ if n.Op == ir.ODCLFUNC && n.Func.OClosure != nil {
Curfn = n
transformclosure(n)
}
fcount = 0
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if n.Op == ODCLFUNC {
+ if n.Op == ir.ODCLFUNC {
funccompile(n)
fcount++
}
// Phase 9: Check external declarations.
timings.Start("be", "externaldcls")
for i, n := range externdcl {
- if n.Op == ONAME {
+ if n.Op == ir.ONAME {
externdcl[i] = typecheck(externdcl[i], ctxExpr)
}
}
}
// numNonClosures returns the number of functions in list which are not closures.
-func numNonClosures(list []*Node) int {
+func numNonClosures(list []*ir.Node) int {
count := 0
for _, n := range list {
if n.Func.OClosure == nil {
}
func mkpackage(pkgname string) {
- if localpkg.Name == "" {
+ if ir.LocalPkg.Name == "" {
if pkgname == "_" {
base.Errorf("invalid package name _")
}
- localpkg.Name = pkgname
+ ir.LocalPkg.Name = pkgname
} else {
- if pkgname != localpkg.Name {
- base.Errorf("package %s; expected %s", pkgname, localpkg.Name)
+ if pkgname != ir.LocalPkg.Name {
+ base.Errorf("package %s; expected %s", pkgname, ir.LocalPkg.Name)
}
}
}
}
var unused []importedPkg
- for _, s := range localpkg.Syms {
- n := asNode(s.Def)
+ for _, s := range ir.LocalPkg.Syms {
+ n := ir.AsNode(s.Def)
if n == nil {
continue
}
- if n.Op == OPACK {
+ if n.Op == ir.OPACK {
// throw away top-level package name left over
// from previous file.
// leave s->block set to cause redeclaration
}
func IsAlias(sym *types.Sym) bool {
- return sym.Def != nil && asNode(sym.Def).Sym != sym
+ return sym.Def != nil && ir.AsNode(sym.Def).Sym != sym
}
// recordFlags records the specified command-line flags to be placed
// together two package main archives. So allow dups.
s.Set(obj.AttrDuplicateOK, true)
base.Ctxt.Data = append(base.Ctxt.Data, s)
- s.P = []byte(localpkg.Name)
+ s.P = []byte(ir.LocalPkg.Name)
}
// currentLang returns the current language version.
func langSupported(major, minor int, pkg *types.Pkg) bool {
if pkg == nil {
// TODO(mdempsky): Set Pkg for local types earlier.
- pkg = localpkg
+ pkg = ir.LocalPkg
}
- if pkg != localpkg {
+ if pkg != ir.LocalPkg {
// Assume imported packages passed type-checking.
return true
}
fmt.Fprintln(&b)
fmt.Fprintln(&b, "package gc")
fmt.Fprintln(&b)
- fmt.Fprintln(&b, `import "cmd/compile/internal/types"`)
+ fmt.Fprintln(&b, `import (`)
+ fmt.Fprintln(&b, ` "cmd/compile/internal/ir"`)
+ fmt.Fprintln(&b, ` "cmd/compile/internal/types"`)
+ fmt.Fprintln(&b, `)`)
mkbuiltin(&b, "runtime")
case "rune":
return "types.Runetype"
}
- return fmt.Sprintf("types.Types[T%s]", strings.ToUpper(t.Name))
+ return fmt.Sprintf("types.Types[types.T%s]", strings.ToUpper(t.Name))
case *ast.SelectorExpr:
if t.X.(*ast.Ident).Name != "unsafe" || t.Sel.Name != "Pointer" {
log.Fatalf("unhandled type: %#v", t)
}
- return "types.Types[TUNSAFEPTR]"
+ return "types.Types[types.TUNSAFEPTR]"
case *ast.ArrayType:
if t.Len == nil {
if len(t.Methods.List) != 0 {
log.Fatal("non-empty interfaces unsupported")
}
- return "types.Types[TINTER]"
+ return "types.Types[types.TINTER]"
case *ast.MapType:
return fmt.Sprintf("types.NewMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value))
case *ast.StarExpr:
}
}
}
- return fmt.Sprintf("[]*Node{%s}", strings.Join(res, ", "))
+ return fmt.Sprintf("[]*ir.Node{%s}", strings.Join(res, ", "))
}
func intconst(e ast.Expr) int64 {
"unicode/utf8"
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
"cmd/compile/internal/types"
"cmd/internal/obj"
testdclstack()
}
- localpkg.Height = myheight
+ ir.LocalPkg.Height = myheight
return lines
}
linknames []linkname
pragcgobuf [][]string
err chan syntax.Error
- scope ScopeID
+ scope ir.ScopeID
importedUnsafe bool
importedEmbed bool
lastCloseScopePos syntax.Pos
}
-func (p *noder) funcBody(fn *Node, block *syntax.BlockStmt) {
+func (p *noder) funcBody(fn *ir.Node, block *syntax.BlockStmt) {
oldScope := p.scope
p.scope = 0
funchdr(fn)
if block != nil {
body := p.stmts(block.List)
if body == nil {
- body = []*Node{nod(OEMPTY, nil, nil)}
+ body = []*ir.Node{ir.Nod(ir.OEMPTY, nil, nil)}
}
fn.Nbody.Set(body)
if trackScopes {
Curfn.Func.Parents = append(Curfn.Func.Parents, p.scope)
p.scopeVars = append(p.scopeVars, len(Curfn.Func.Dcl))
- p.scope = ScopeID(len(Curfn.Func.Parents))
+ p.scope = ir.ScopeID(len(Curfn.Func.Parents))
p.markScope(pos)
}
nmarks := len(Curfn.Func.Marks)
Curfn.Func.Marks[nmarks-1].Scope = p.scope
- prevScope := ScopeID(0)
+ prevScope := ir.ScopeID(0)
if nmarks >= 2 {
prevScope = Curfn.Func.Marks[nmarks-2].Scope
}
if i := len(Curfn.Func.Marks); i > 0 && Curfn.Func.Marks[i-1].Pos == xpos {
Curfn.Func.Marks[i-1].Scope = p.scope
} else {
- Curfn.Func.Marks = append(Curfn.Func.Marks, Mark{xpos, p.scope})
+ Curfn.Func.Marks = append(Curfn.Func.Marks, ir.Mark{Pos: xpos, Scope: p.scope})
}
}
mkpackage(p.file.PkgName.Value)
if pragma, ok := p.file.Pragma.(*Pragma); ok {
- pragma.Flag &^= GoBuildPragma
+ pragma.Flag &^= ir.GoBuildPragma
p.checkUnused(pragma)
}
clearImports()
}
-func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
+func (p *noder) decls(decls []syntax.Decl) (l []*ir.Node) {
var cs constState
for _, decl := range decls {
my = lookup(ipkg.Name)
}
- pack := p.nod(imp, OPACK, nil, nil)
+ pack := p.nod(imp, ir.OPACK, nil, nil)
pack.Sym = my
pack.Name.Pkg = ipkg
if my.Def != nil {
redeclare(pack.Pos, my, "as imported package name")
}
- my.Def = asTypesNode(pack)
+ my.Def = ir.AsTypesNode(pack)
my.Lastlineno = pack.Pos
my.Block = 1 // at top level
}
-func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
+func (p *noder) varDecl(decl *syntax.VarDecl) []*ir.Node {
names := p.declNames(decl.NameList)
typ := p.typeExprOrNil(decl.Type)
- var exprs []*Node
+ var exprs []*ir.Node
if decl.Values != nil {
exprs = p.exprList(decl.Values)
}
// constant declarations are handled correctly (e.g., issue 15550).
type constState struct {
group *syntax.Group
- typ *Node
- values []*Node
+ typ *ir.Node
+ values []*ir.Node
iota int64
}
-func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []*Node {
+func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []*ir.Node {
if decl.Group == nil || decl.Group != cs.group {
*cs = constState{
group: decl.Group,
names := p.declNames(decl.NameList)
typ := p.typeExprOrNil(decl.Type)
- var values []*Node
+ var values []*ir.Node
if decl.Values != nil {
values = p.exprList(decl.Values)
cs.typ, cs.values = typ, values
typ, values = cs.typ, cs.values
}
- nn := make([]*Node, 0, len(names))
+ nn := make([]*ir.Node, 0, len(names))
for i, n := range names {
if i >= len(values) {
base.Errorf("missing value in const declaration")
v = treecopy(v, n.Pos)
}
- n.Op = OLITERAL
+ n.Op = ir.OLITERAL
declare(n, dclcontext)
n.Name.Param.Ntype = typ
n.Name.Defn = v
n.SetIota(cs.iota)
- nn = append(nn, p.nod(decl, ODCLCONST, n, nil))
+ nn = append(nn, p.nod(decl, ir.ODCLCONST, n, nil))
}
if len(values) > len(names) {
return nn
}
-func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
+func (p *noder) typeDecl(decl *syntax.TypeDecl) *ir.Node {
n := p.declName(decl.Name)
- n.Op = OTYPE
+ n.Op = ir.OTYPE
declare(n, dclcontext)
// decl.Type may be nil but in that case we got a syntax error during parsing
p.checkUnused(pragma)
}
- nod := p.nod(decl, ODCLTYPE, n, nil)
- if param.Alias() && !langSupported(1, 9, localpkg) {
+ nod := p.nod(decl, ir.ODCLTYPE, n, nil)
+ if param.Alias() && !langSupported(1, 9, ir.LocalPkg) {
base.ErrorfAt(nod.Pos, "type aliases only supported as of -lang=go1.9")
}
return nod
}
-func (p *noder) declNames(names []*syntax.Name) []*Node {
- nodes := make([]*Node, 0, len(names))
+func (p *noder) declNames(names []*syntax.Name) []*ir.Node {
+ nodes := make([]*ir.Node, 0, len(names))
for _, name := range names {
nodes = append(nodes, p.declName(name))
}
return nodes
}
-func (p *noder) declName(name *syntax.Name) *Node {
+func (p *noder) declName(name *syntax.Name) *ir.Node {
n := dclname(p.name(name))
n.Pos = p.pos(name)
return n
}
-func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
+func (p *noder) funcDecl(fun *syntax.FuncDecl) *ir.Node {
name := p.name(fun.Name)
t := p.signature(fun.Recv, fun.Type)
- f := p.nod(fun, ODCLFUNC, nil, nil)
+ f := p.nod(fun, ir.ODCLFUNC, nil, nil)
if fun.Recv == nil {
if name.Name == "init" {
}
}
- if localpkg.Name == "main" && name.Name == "main" {
+ if ir.LocalPkg.Name == "main" && name.Name == "main" {
if t.List.Len() > 0 || t.Rlist.Len() > 0 {
base.ErrorfAt(f.Pos, "func main must have no arguments and no return values")
}
}
} else {
f.Func.Shortname = name
- name = nblank.Sym // filled in by typecheckfunc
+ name = ir.BlankNode.Sym // filled in by typecheckfunc
}
f.Func.Nname = newfuncnamel(p.pos(fun.Name), name, f.Func)
if pragma, ok := fun.Pragma.(*Pragma); ok {
f.Func.Pragma = pragma.Flag & FuncPragmas
- if pragma.Flag&Systemstack != 0 && pragma.Flag&Nosplit != 0 {
+ if pragma.Flag&ir.Systemstack != 0 && pragma.Flag&ir.Nosplit != 0 {
base.ErrorfAt(f.Pos, "go:nosplit and go:systemstack cannot be combined")
}
pragma.Flag &^= FuncPragmas
}
if fun.Recv == nil {
- declare(f.Func.Nname, PFUNC)
+ declare(f.Func.Nname, ir.PFUNC)
}
p.funcBody(f, fun.Body)
if fun.Body != nil {
- if f.Func.Pragma&Noescape != 0 {
+ if f.Func.Pragma&ir.Noescape != 0 {
base.ErrorfAt(f.Pos, "can only use //go:noescape with external func implementations")
}
} else {
- if base.Flag.Complete || strings.HasPrefix(f.funcname(), "init.") {
+ if base.Flag.Complete || strings.HasPrefix(ir.FuncName(f), "init.") {
// Linknamed functions are allowed to have no body. Hopefully
// the linkname target has a body. See issue 23311.
isLinknamed := false
for _, n := range p.linknames {
- if f.funcname() == n.local {
+ if ir.FuncName(f) == n.local {
isLinknamed = true
break
}
return f
}
-func (p *noder) signature(recv *syntax.Field, typ *syntax.FuncType) *Node {
- n := p.nod(typ, OTFUNC, nil, nil)
+func (p *noder) signature(recv *syntax.Field, typ *syntax.FuncType) *ir.Node {
+ n := p.nod(typ, ir.OTFUNC, nil, nil)
if recv != nil {
n.Left = p.param(recv, false, false)
}
return n
}
-func (p *noder) params(params []*syntax.Field, dddOk bool) []*Node {
- nodes := make([]*Node, 0, len(params))
+func (p *noder) params(params []*syntax.Field, dddOk bool) []*ir.Node {
+ nodes := make([]*ir.Node, 0, len(params))
for i, param := range params {
p.setlineno(param)
nodes = append(nodes, p.param(param, dddOk, i+1 == len(params)))
return nodes
}
-func (p *noder) param(param *syntax.Field, dddOk, final bool) *Node {
+func (p *noder) param(param *syntax.Field, dddOk, final bool) *ir.Node {
var name *types.Sym
if param.Name != nil {
name = p.name(param.Name)
}
typ := p.typeExpr(param.Type)
- n := p.nodSym(param, ODCLFIELD, typ, name)
+ n := p.nodSym(param, ir.ODCLFIELD, typ, name)
// rewrite ...T parameter
- if typ.Op == ODDD {
+ if typ.Op == ir.ODDD {
if !dddOk {
// We mark these as syntax errors to get automatic elimination
// of multiple such errors per line (see ErrorfAt in subr.go).
p.errorAt(param.Name.Pos(), "syntax error: cannot use ... with non-final parameter %s", param.Name.Value)
}
}
- typ.Op = OTARRAY
+ typ.Op = ir.OTARRAY
typ.Right = typ.Left
typ.Left = nil
n.SetIsDDD(true)
return n
}
-func (p *noder) exprList(expr syntax.Expr) []*Node {
+func (p *noder) exprList(expr syntax.Expr) []*ir.Node {
if list, ok := expr.(*syntax.ListExpr); ok {
return p.exprs(list.ElemList)
}
- return []*Node{p.expr(expr)}
+ return []*ir.Node{p.expr(expr)}
}
-func (p *noder) exprs(exprs []syntax.Expr) []*Node {
- nodes := make([]*Node, 0, len(exprs))
+func (p *noder) exprs(exprs []syntax.Expr) []*ir.Node {
+ nodes := make([]*ir.Node, 0, len(exprs))
for _, expr := range exprs {
nodes = append(nodes, p.expr(expr))
}
return nodes
}
-func (p *noder) expr(expr syntax.Expr) *Node {
+func (p *noder) expr(expr syntax.Expr) *ir.Node {
p.setlineno(expr)
switch expr := expr.(type) {
case nil, *syntax.BadExpr:
case *syntax.Name:
return p.mkname(expr)
case *syntax.BasicLit:
- n := nodlit(p.basicLit(expr))
+ n := ir.NewLiteral(p.basicLit(expr))
if expr.Kind == syntax.RuneLit {
n.Type = types.UntypedRune
}
n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error
return n
case *syntax.CompositeLit:
- n := p.nod(expr, OCOMPLIT, nil, nil)
+ n := p.nod(expr, ir.OCOMPLIT, nil, nil)
if expr.Type != nil {
n.Right = p.expr(expr.Type)
}
return n
case *syntax.KeyValueExpr:
// use position of expr.Key rather than of expr (which has position of ':')
- return p.nod(expr.Key, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
+ return p.nod(expr.Key, ir.OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
case *syntax.FuncLit:
return p.funcLit(expr)
case *syntax.ParenExpr:
- return p.nod(expr, OPAREN, p.expr(expr.X), nil)
+ return p.nod(expr, ir.OPAREN, p.expr(expr.X), nil)
case *syntax.SelectorExpr:
// parser.new_dotname
obj := p.expr(expr.X)
- if obj.Op == OPACK {
+ if obj.Op == ir.OPACK {
obj.Name.SetUsed(true)
return importName(obj.Name.Pkg.Lookup(expr.Sel.Value))
}
- n := nodSym(OXDOT, obj, p.name(expr.Sel))
+ n := nodSym(ir.OXDOT, obj, p.name(expr.Sel))
n.Pos = p.pos(expr) // lineno may have been changed by p.expr(expr.X)
return n
case *syntax.IndexExpr:
- return p.nod(expr, OINDEX, p.expr(expr.X), p.expr(expr.Index))
+ return p.nod(expr, ir.OINDEX, p.expr(expr.X), p.expr(expr.Index))
case *syntax.SliceExpr:
- op := OSLICE
+ op := ir.OSLICE
if expr.Full {
- op = OSLICE3
+ op = ir.OSLICE3
}
n := p.nod(expr, op, p.expr(expr.X), nil)
- var index [3]*Node
+ var index [3]*ir.Node
for i, x := range &expr.Index {
if x != nil {
index[i] = p.expr(x)
n.SetSliceBounds(index[0], index[1], index[2])
return n
case *syntax.AssertExpr:
- return p.nod(expr, ODOTTYPE, p.expr(expr.X), p.typeExpr(expr.Type))
+ return p.nod(expr, ir.ODOTTYPE, p.expr(expr.X), p.typeExpr(expr.Type))
case *syntax.Operation:
if expr.Op == syntax.Add && expr.Y != nil {
return p.sum(expr)
}
return p.nod(expr, p.binOp(expr.Op), x, p.expr(expr.Y))
case *syntax.CallExpr:
- n := p.nod(expr, OCALL, p.expr(expr.Fun), nil)
+ n := p.nod(expr, ir.OCALL, p.expr(expr.Fun), nil)
n.List.Set(p.exprs(expr.ArgList))
n.SetIsDDD(expr.HasDots)
return n
case *syntax.ArrayType:
- var len *Node
+ var len *ir.Node
if expr.Len != nil {
len = p.expr(expr.Len)
} else {
- len = p.nod(expr, ODDD, nil, nil)
+ len = p.nod(expr, ir.ODDD, nil, nil)
}
- return p.nod(expr, OTARRAY, len, p.typeExpr(expr.Elem))
+ return p.nod(expr, ir.OTARRAY, len, p.typeExpr(expr.Elem))
case *syntax.SliceType:
- return p.nod(expr, OTARRAY, nil, p.typeExpr(expr.Elem))
+ return p.nod(expr, ir.OTARRAY, nil, p.typeExpr(expr.Elem))
case *syntax.DotsType:
- return p.nod(expr, ODDD, p.typeExpr(expr.Elem), nil)
+ return p.nod(expr, ir.ODDD, p.typeExpr(expr.Elem), nil)
case *syntax.StructType:
return p.structType(expr)
case *syntax.InterfaceType:
case *syntax.FuncType:
return p.signature(nil, expr)
case *syntax.MapType:
- return p.nod(expr, OTMAP, p.typeExpr(expr.Key), p.typeExpr(expr.Value))
+ return p.nod(expr, ir.OTMAP, p.typeExpr(expr.Key), p.typeExpr(expr.Value))
case *syntax.ChanType:
- n := p.nod(expr, OTCHAN, p.typeExpr(expr.Elem), nil)
+ n := p.nod(expr, ir.OTCHAN, p.typeExpr(expr.Elem), nil)
n.SetTChanDir(p.chanDir(expr.Dir))
return n
case *syntax.TypeSwitchGuard:
- n := p.nod(expr, OTYPESW, nil, p.expr(expr.X))
+ n := p.nod(expr, ir.OTYPESW, nil, p.expr(expr.X))
if expr.Lhs != nil {
n.Left = p.declName(expr.Lhs)
- if n.Left.isBlank() {
+ if ir.IsBlank(n.Left) {
base.Errorf("invalid variable name %v in type switch", n.Left)
}
}
// sum efficiently handles very large summation expressions (such as
// in issue #16394). In particular, it avoids left recursion and
// collapses string literals.
-func (p *noder) sum(x syntax.Expr) *Node {
+func (p *noder) sum(x syntax.Expr) *ir.Node {
// While we need to handle long sums with asymptotic
// efficiency, the vast majority of sums are very small: ~95%
// have only 2 or 3 operands, and ~99% of string literals are
// handle correctly. For now, we avoid these problems by
// treating named string constants the same as non-constant
// operands.
- var nstr *Node
+ var nstr *ir.Node
chunks := make([]string, 0, 1)
n := p.expr(x)
- if Isconst(n, constant.String) && n.Sym == nil {
+ if ir.IsConst(n, constant.String) && n.Sym == nil {
nstr = n
chunks = append(chunks, nstr.StringVal())
}
add := adds[i]
r := p.expr(add.Y)
- if Isconst(r, constant.String) && r.Sym == nil {
+ if ir.IsConst(r, constant.String) && r.Sym == nil {
if nstr != nil {
// Collapse r into nstr instead of adding to n.
chunks = append(chunks, r.StringVal())
nstr = nil
chunks = chunks[:0]
}
- n = p.nod(add, OADD, n, r)
+ n = p.nod(add, ir.OADD, n, r)
}
if len(chunks) > 1 {
nstr.SetVal(constant.MakeString(strings.Join(chunks, "")))
return n
}
-func (p *noder) typeExpr(typ syntax.Expr) *Node {
+func (p *noder) typeExpr(typ syntax.Expr) *ir.Node {
// TODO(mdempsky): Be stricter? typecheck should handle errors anyway.
return p.expr(typ)
}
-func (p *noder) typeExprOrNil(typ syntax.Expr) *Node {
+func (p *noder) typeExprOrNil(typ syntax.Expr) *ir.Node {
if typ != nil {
return p.expr(typ)
}
panic("unhandled ChanDir")
}
-func (p *noder) structType(expr *syntax.StructType) *Node {
- l := make([]*Node, 0, len(expr.FieldList))
+func (p *noder) structType(expr *syntax.StructType) *ir.Node {
+ l := make([]*ir.Node, 0, len(expr.FieldList))
for i, field := range expr.FieldList {
p.setlineno(field)
- var n *Node
+ var n *ir.Node
if field.Name == nil {
n = p.embedded(field.Type)
} else {
- n = p.nodSym(field, ODCLFIELD, p.typeExpr(field.Type), p.name(field.Name))
+ n = p.nodSym(field, ir.ODCLFIELD, p.typeExpr(field.Type), p.name(field.Name))
}
if i < len(expr.TagList) && expr.TagList[i] != nil {
n.SetVal(p.basicLit(expr.TagList[i]))
}
p.setlineno(expr)
- n := p.nod(expr, OTSTRUCT, nil, nil)
+ n := p.nod(expr, ir.OTSTRUCT, nil, nil)
n.List.Set(l)
return n
}
-func (p *noder) interfaceType(expr *syntax.InterfaceType) *Node {
- l := make([]*Node, 0, len(expr.MethodList))
+func (p *noder) interfaceType(expr *syntax.InterfaceType) *ir.Node {
+ l := make([]*ir.Node, 0, len(expr.MethodList))
for _, method := range expr.MethodList {
p.setlineno(method)
- var n *Node
+ var n *ir.Node
if method.Name == nil {
- n = p.nodSym(method, ODCLFIELD, importName(p.packname(method.Type)), nil)
+ n = p.nodSym(method, ir.ODCLFIELD, importName(p.packname(method.Type)), nil)
} else {
mname := p.name(method.Name)
sig := p.typeExpr(method.Type)
sig.Left = fakeRecv()
- n = p.nodSym(method, ODCLFIELD, sig, mname)
+ n = p.nodSym(method, ir.ODCLFIELD, sig, mname)
ifacedcl(n)
}
l = append(l, n)
}
- n := p.nod(expr, OTINTER, nil, nil)
+ n := p.nod(expr, ir.OTINTER, nil, nil)
n.List.Set(l)
return n
}
return name
case *syntax.SelectorExpr:
name := p.name(expr.X.(*syntax.Name))
- def := asNode(name.Def)
+ def := ir.AsNode(name.Def)
if def == nil {
base.Errorf("undefined: %v", name)
return name
}
var pkg *types.Pkg
- if def.Op != OPACK {
+ if def.Op != ir.OPACK {
base.Errorf("%v is not a package", name)
- pkg = localpkg
+ pkg = ir.LocalPkg
} else {
def.Name.SetUsed(true)
pkg = def.Name.Pkg
panic(fmt.Sprintf("unexpected packname: %#v", expr))
}
-func (p *noder) embedded(typ syntax.Expr) *Node {
+func (p *noder) embedded(typ syntax.Expr) *ir.Node {
op, isStar := typ.(*syntax.Operation)
if isStar {
if op.Op != syntax.Mul || op.Y != nil {
}
sym := p.packname(typ)
- n := p.nodSym(typ, ODCLFIELD, importName(sym), lookup(sym.Name))
+ n := p.nodSym(typ, ir.ODCLFIELD, importName(sym), lookup(sym.Name))
n.SetEmbedded(true)
if isStar {
- n.Left = p.nod(op, ODEREF, n.Left, nil)
+ n.Left = p.nod(op, ir.ODEREF, n.Left, nil)
}
return n
}
-func (p *noder) stmts(stmts []syntax.Stmt) []*Node {
+func (p *noder) stmts(stmts []syntax.Stmt) []*ir.Node {
return p.stmtsFall(stmts, false)
}
-func (p *noder) stmtsFall(stmts []syntax.Stmt, fallOK bool) []*Node {
- var nodes []*Node
+func (p *noder) stmtsFall(stmts []syntax.Stmt, fallOK bool) []*ir.Node {
+ var nodes []*ir.Node
for i, stmt := range stmts {
s := p.stmtFall(stmt, fallOK && i+1 == len(stmts))
if s == nil {
- } else if s.Op == OBLOCK && s.Ninit.Len() == 0 {
+ } else if s.Op == ir.OBLOCK && s.Ninit.Len() == 0 {
nodes = append(nodes, s.List.Slice()...)
} else {
nodes = append(nodes, s)
return nodes
}
-func (p *noder) stmt(stmt syntax.Stmt) *Node {
+func (p *noder) stmt(stmt syntax.Stmt) *ir.Node {
return p.stmtFall(stmt, false)
}
-func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
+func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *ir.Node {
p.setlineno(stmt)
switch stmt := stmt.(type) {
case *syntax.EmptyStmt:
l := p.blockStmt(stmt)
if len(l) == 0 {
// TODO(mdempsky): Line number?
- return nod(OEMPTY, nil, nil)
+ return ir.Nod(ir.OEMPTY, nil, nil)
}
return liststmt(l)
case *syntax.ExprStmt:
return p.wrapname(stmt, p.expr(stmt.X))
case *syntax.SendStmt:
- return p.nod(stmt, OSEND, p.expr(stmt.Chan), p.expr(stmt.Value))
+ return p.nod(stmt, ir.OSEND, p.expr(stmt.Chan), p.expr(stmt.Value))
case *syntax.DeclStmt:
return liststmt(p.decls(stmt.DeclList))
case *syntax.AssignStmt:
if stmt.Op != 0 && stmt.Op != syntax.Def {
- n := p.nod(stmt, OASOP, p.expr(stmt.Lhs), p.expr(stmt.Rhs))
+ n := p.nod(stmt, ir.OASOP, p.expr(stmt.Lhs), p.expr(stmt.Rhs))
n.SetImplicit(stmt.Rhs == syntax.ImplicitOne)
n.SetSubOp(p.binOp(stmt.Op))
return n
}
- n := p.nod(stmt, OAS, nil, nil) // assume common case
+ n := p.nod(stmt, ir.OAS, nil, nil) // assume common case
rhs := p.exprList(stmt.Rhs)
lhs := p.assignList(stmt.Lhs, n, stmt.Op == syntax.Def)
n.Left = lhs[0]
n.Right = rhs[0]
} else {
- n.Op = OAS2
+ n.Op = ir.OAS2
n.List.Set(lhs)
n.Rlist.Set(rhs)
}
return n
case *syntax.BranchStmt:
- var op Op
+ var op ir.Op
switch stmt.Tok {
case syntax.Break:
- op = OBREAK
+ op = ir.OBREAK
case syntax.Continue:
- op = OCONTINUE
+ op = ir.OCONTINUE
case syntax.Fallthrough:
if !fallOK {
base.Errorf("fallthrough statement out of place")
}
- op = OFALL
+ op = ir.OFALL
case syntax.Goto:
- op = OGOTO
+ op = ir.OGOTO
default:
panic("unhandled BranchStmt")
}
}
return n
case *syntax.CallStmt:
- var op Op
+ var op ir.Op
switch stmt.Tok {
case syntax.Defer:
- op = ODEFER
+ op = ir.ODEFER
case syntax.Go:
- op = OGO
+ op = ir.OGO
default:
panic("unhandled CallStmt")
}
return p.nod(stmt, op, p.expr(stmt.Call), nil)
case *syntax.ReturnStmt:
- var results []*Node
+ var results []*ir.Node
if stmt.Results != nil {
results = p.exprList(stmt.Results)
}
- n := p.nod(stmt, ORETURN, nil, nil)
+ n := p.nod(stmt, ir.ORETURN, nil, nil)
n.List.Set(results)
if n.List.Len() == 0 && Curfn != nil {
for _, ln := range Curfn.Func.Dcl {
- if ln.Class() == PPARAM {
+ if ln.Class() == ir.PPARAM {
continue
}
- if ln.Class() != PPARAMOUT {
+ if ln.Class() != ir.PPARAMOUT {
break
}
- if asNode(ln.Sym.Def) != ln {
+ if ir.AsNode(ln.Sym.Def) != ln {
base.Errorf("%s is shadowed during return", ln.Sym.Name)
}
}
panic("unhandled Stmt")
}
-func (p *noder) assignList(expr syntax.Expr, defn *Node, colas bool) []*Node {
+func (p *noder) assignList(expr syntax.Expr, defn *ir.Node, colas bool) []*ir.Node {
if !colas {
return p.exprList(expr)
}
exprs = []syntax.Expr{expr}
}
- res := make([]*Node, len(exprs))
+ res := make([]*ir.Node, len(exprs))
seen := make(map[*types.Sym]bool, len(exprs))
newOrErr := false
for i, expr := range exprs {
p.setlineno(expr)
- res[i] = nblank
+ res[i] = ir.BlankNode
name, ok := expr.(*syntax.Name)
if !ok {
}
newOrErr = true
- n := newname(sym)
+ n := NewName(sym)
declare(n, dclcontext)
n.Name.Defn = defn
- defn.Ninit.Append(nod(ODCL, n, nil))
+ defn.Ninit.Append(ir.Nod(ir.ODCL, n, nil))
res[i] = n
}
return res
}
-func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
+func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*ir.Node {
p.openScope(stmt.Pos())
nodes := p.stmts(stmt.List)
p.closeScope(stmt.Rbrace)
return nodes
}
-func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
+func (p *noder) ifStmt(stmt *syntax.IfStmt) *ir.Node {
p.openScope(stmt.Pos())
- n := p.nod(stmt, OIF, nil, nil)
+ n := p.nod(stmt, ir.OIF, nil, nil)
if stmt.Init != nil {
n.Ninit.Set1(p.stmt(stmt.Init))
}
n.Nbody.Set(p.blockStmt(stmt.Then))
if stmt.Else != nil {
e := p.stmt(stmt.Else)
- if e.Op == OBLOCK && e.Ninit.Len() == 0 {
+ if e.Op == ir.OBLOCK && e.Ninit.Len() == 0 {
n.Rlist.Set(e.List.Slice())
} else {
n.Rlist.Set1(e)
return n
}
-func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
+func (p *noder) forStmt(stmt *syntax.ForStmt) *ir.Node {
p.openScope(stmt.Pos())
- var n *Node
+ var n *ir.Node
if r, ok := stmt.Init.(*syntax.RangeClause); ok {
if stmt.Cond != nil || stmt.Post != nil {
panic("unexpected RangeClause")
}
- n = p.nod(r, ORANGE, nil, p.expr(r.X))
+ n = p.nod(r, ir.ORANGE, nil, p.expr(r.X))
if r.Lhs != nil {
n.List.Set(p.assignList(r.Lhs, n, r.Def))
}
} else {
- n = p.nod(stmt, OFOR, nil, nil)
+ n = p.nod(stmt, ir.OFOR, nil, nil)
if stmt.Init != nil {
n.Ninit.Set1(p.stmt(stmt.Init))
}
return n
}
-func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
+func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *ir.Node {
p.openScope(stmt.Pos())
- n := p.nod(stmt, OSWITCH, nil, nil)
+ n := p.nod(stmt, ir.OSWITCH, nil, nil)
if stmt.Init != nil {
n.Ninit.Set1(p.stmt(stmt.Init))
}
}
tswitch := n.Left
- if tswitch != nil && tswitch.Op != OTYPESW {
+ if tswitch != nil && tswitch.Op != ir.OTYPESW {
tswitch = nil
}
n.List.Set(p.caseClauses(stmt.Body, tswitch, stmt.Rbrace))
return n
}
-func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node, rbrace syntax.Pos) []*Node {
- nodes := make([]*Node, 0, len(clauses))
+func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.Node, rbrace syntax.Pos) []*ir.Node {
+ nodes := make([]*ir.Node, 0, len(clauses))
for i, clause := range clauses {
p.setlineno(clause)
if i > 0 {
}
p.openScope(clause.Pos())
- n := p.nod(clause, OCASE, nil, nil)
+ n := p.nod(clause, ir.OCASE, nil, nil)
if clause.Cases != nil {
n.List.Set(p.exprList(clause.Cases))
}
if tswitch != nil && tswitch.Left != nil {
- nn := newname(tswitch.Left.Sym)
+ nn := NewName(tswitch.Left.Sym)
declare(nn, dclcontext)
n.Rlist.Set1(nn)
// keep track of the instances for reporting unused
}
n.Nbody.Set(p.stmtsFall(body, true))
- if l := n.Nbody.Len(); l > 0 && n.Nbody.Index(l-1).Op == OFALL {
+ if l := n.Nbody.Len(); l > 0 && n.Nbody.Index(l-1).Op == ir.OFALL {
if tswitch != nil {
base.Errorf("cannot fallthrough in type switch")
}
return nodes
}
-func (p *noder) selectStmt(stmt *syntax.SelectStmt) *Node {
- n := p.nod(stmt, OSELECT, nil, nil)
+func (p *noder) selectStmt(stmt *syntax.SelectStmt) *ir.Node {
+ n := p.nod(stmt, ir.OSELECT, nil, nil)
n.List.Set(p.commClauses(stmt.Body, stmt.Rbrace))
return n
}
-func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []*Node {
- nodes := make([]*Node, 0, len(clauses))
+func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []*ir.Node {
+ nodes := make([]*ir.Node, 0, len(clauses))
for i, clause := range clauses {
p.setlineno(clause)
if i > 0 {
}
p.openScope(clause.Pos())
- n := p.nod(clause, OCASE, nil, nil)
+ n := p.nod(clause, ir.OCASE, nil, nil)
if clause.Comm != nil {
n.List.Set1(p.stmt(clause.Comm))
}
return nodes
}
-func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) *Node {
- lhs := p.nodSym(label, OLABEL, nil, p.name(label.Label))
+func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) *ir.Node {
+ lhs := p.nodSym(label, ir.OLABEL, nil, p.name(label.Label))
- var ls *Node
+ var ls *ir.Node
if label.Stmt != nil { // TODO(mdempsky): Should always be present.
ls = p.stmtFall(label.Stmt, fallOK)
}
lhs.Name.Defn = ls
- l := []*Node{lhs}
+ l := []*ir.Node{lhs}
if ls != nil {
- if ls.Op == OBLOCK && ls.Ninit.Len() == 0 {
+ if ls.Op == ir.OBLOCK && ls.Ninit.Len() == 0 {
l = append(l, ls.List.Slice()...)
} else {
l = append(l, ls)
return liststmt(l)
}
-var unOps = [...]Op{
- syntax.Recv: ORECV,
- syntax.Mul: ODEREF,
- syntax.And: OADDR,
+var unOps = [...]ir.Op{
+ syntax.Recv: ir.ORECV,
+ syntax.Mul: ir.ODEREF,
+ syntax.And: ir.OADDR,
- syntax.Not: ONOT,
- syntax.Xor: OBITNOT,
- syntax.Add: OPLUS,
- syntax.Sub: ONEG,
+ syntax.Not: ir.ONOT,
+ syntax.Xor: ir.OBITNOT,
+ syntax.Add: ir.OPLUS,
+ syntax.Sub: ir.ONEG,
}
-func (p *noder) unOp(op syntax.Operator) Op {
+func (p *noder) unOp(op syntax.Operator) ir.Op {
if uint64(op) >= uint64(len(unOps)) || unOps[op] == 0 {
panic("invalid Operator")
}
return unOps[op]
}
-var binOps = [...]Op{
- syntax.OrOr: OOROR,
- syntax.AndAnd: OANDAND,
+var binOps = [...]ir.Op{
+ syntax.OrOr: ir.OOROR,
+ syntax.AndAnd: ir.OANDAND,
- syntax.Eql: OEQ,
- syntax.Neq: ONE,
- syntax.Lss: OLT,
- syntax.Leq: OLE,
- syntax.Gtr: OGT,
- syntax.Geq: OGE,
+ syntax.Eql: ir.OEQ,
+ syntax.Neq: ir.ONE,
+ syntax.Lss: ir.OLT,
+ syntax.Leq: ir.OLE,
+ syntax.Gtr: ir.OGT,
+ syntax.Geq: ir.OGE,
- syntax.Add: OADD,
- syntax.Sub: OSUB,
- syntax.Or: OOR,
- syntax.Xor: OXOR,
+ syntax.Add: ir.OADD,
+ syntax.Sub: ir.OSUB,
+ syntax.Or: ir.OOR,
+ syntax.Xor: ir.OXOR,
- syntax.Mul: OMUL,
- syntax.Div: ODIV,
- syntax.Rem: OMOD,
- syntax.And: OAND,
- syntax.AndNot: OANDNOT,
- syntax.Shl: OLSH,
- syntax.Shr: ORSH,
+ syntax.Mul: ir.OMUL,
+ syntax.Div: ir.ODIV,
+ syntax.Rem: ir.OMOD,
+ syntax.And: ir.OAND,
+ syntax.AndNot: ir.OANDNOT,
+ syntax.Shl: ir.OLSH,
+ syntax.Shr: ir.ORSH,
}
-func (p *noder) binOp(op syntax.Operator) Op {
+func (p *noder) binOp(op syntax.Operator) ir.Op {
if uint64(op) >= uint64(len(binOps)) || binOps[op] == 0 {
panic("invalid Operator")
}
// literal is not compatible with the current language version.
func checkLangCompat(lit *syntax.BasicLit) {
s := lit.Value
- if len(s) <= 2 || langSupported(1, 13, localpkg) {
+ if len(s) <= 2 || langSupported(1, 13, ir.LocalPkg) {
return
}
// len(s) > 2
return lookup(name.Value)
}
-func (p *noder) mkname(name *syntax.Name) *Node {
+func (p *noder) mkname(name *syntax.Name) *ir.Node {
// TODO(mdempsky): Set line number?
return mkname(p.name(name))
}
-func (p *noder) wrapname(n syntax.Node, x *Node) *Node {
+func (p *noder) wrapname(n syntax.Node, x *ir.Node) *ir.Node {
// These nodes do not carry line numbers.
// Introduce a wrapper node to give them the correct line.
switch x.Op {
- case OTYPE, OLITERAL:
+ case ir.OTYPE, ir.OLITERAL:
if x.Sym == nil {
break
}
fallthrough
- case ONAME, ONONAME, OPACK:
- x = p.nod(n, OPAREN, x, nil)
+ case ir.ONAME, ir.ONONAME, ir.OPACK:
+ x = p.nod(n, ir.OPAREN, x, nil)
x.SetImplicit(true)
}
return x
}
-func (p *noder) nod(orig syntax.Node, op Op, left, right *Node) *Node {
- return nodl(p.pos(orig), op, left, right)
+func (p *noder) nod(orig syntax.Node, op ir.Op, left, right *ir.Node) *ir.Node {
+ return ir.NodAt(p.pos(orig), op, left, right)
}
-func (p *noder) nodSym(orig syntax.Node, op Op, left *Node, sym *types.Sym) *Node {
+func (p *noder) nodSym(orig syntax.Node, op ir.Op, left *ir.Node, sym *types.Sym) *ir.Node {
n := nodSym(op, left, sym)
n.Pos = p.pos(orig)
return n
// *Pragma is the value stored in a syntax.Pragma during parsing.
type Pragma struct {
- Flag PragmaFlag // collected bits
- Pos []PragmaPos // position of each individual flag
+ Flag ir.PragmaFlag // collected bits
+ Pos []PragmaPos // position of each individual flag
Embeds []PragmaEmbed
}
type PragmaPos struct {
- Flag PragmaFlag
+ Flag ir.PragmaFlag
Pos syntax.Pos
}
verb = verb[:i]
}
flag := pragmaFlag(verb)
- const runtimePragmas = Systemstack | Nowritebarrier | Nowritebarrierrec | Yeswritebarrierrec
+ const runtimePragmas = ir.Systemstack | ir.Nowritebarrier | ir.Nowritebarrierrec | ir.Yeswritebarrierrec
if !base.Flag.CompilingRuntime && flag&runtimePragmas != 0 {
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in runtime", verb)})
}
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
}
-func mkname(sym *types.Sym) *Node {
+func mkname(sym *types.Sym) *ir.Node {
n := oldname(sym)
if n.Name != nil && n.Name.Pack != nil {
n.Name.Pack.Name.SetUsed(true)
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/bio"
"cmd/internal/obj"
if base.Flag.BuildID != "" {
fmt.Fprintf(bout, "build id %q\n", base.Flag.BuildID)
}
- if localpkg.Name == "main" {
+ if ir.LocalPkg.Name == "main" {
fmt.Fprintf(bout, "main\n")
}
fmt.Fprintf(bout, "\n") // header ends with blank line
for {
for i := xtops; i < len(xtop); i++ {
n := xtop[i]
- if n.Op == ODCLFUNC {
+ if n.Op == ir.ODCLFUNC {
funccompile(n)
}
}
}
func addptabs() {
- if !base.Ctxt.Flag_dynlink || localpkg.Name != "main" {
+ if !base.Ctxt.Flag_dynlink || ir.LocalPkg.Name != "main" {
return
}
for _, exportn := range exportlist {
s := exportn.Sym
- n := asNode(s.Def)
+ n := ir.AsNode(s.Def)
if n == nil {
continue
}
- if n.Op != ONAME {
+ if n.Op != ir.ONAME {
continue
}
if !types.IsExported(s.Name) {
if s.Pkg.Name != "main" {
continue
}
- if n.Type.Etype == TFUNC && n.Class() == PFUNC {
+ if n.Type.Etype == types.TFUNC && n.Class() == ir.PFUNC {
// function
- ptabs = append(ptabs, ptabEntry{s: s, t: asNode(s.Def).Type})
+ ptabs = append(ptabs, ptabEntry{s: s, t: ir.AsNode(s.Def).Type})
} else {
// variable
- ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(asNode(s.Def).Type)})
+ ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(ir.AsNode(s.Def).Type)})
}
}
}
-func dumpGlobal(n *Node) {
+func dumpGlobal(n *ir.Node) {
if n.Type == nil {
base.Fatalf("external %v nil type\n", n)
}
- if n.Class() == PFUNC {
+ if n.Class() == ir.PFUNC {
return
}
- if n.Sym.Pkg != localpkg {
+ if n.Sym.Pkg != ir.LocalPkg {
return
}
dowidth(n.Type)
ggloblnod(n)
}
-func dumpGlobalConst(n *Node) {
+func dumpGlobalConst(n *ir.Node) {
// only export typed constants
t := n.Type
if t == nil {
return
}
- if n.Sym.Pkg != localpkg {
+ if n.Sym.Pkg != ir.LocalPkg {
return
}
// only export integer constants for now
v := n.Val()
if t.IsUntyped() {
// Export untyped integers as int (if they fit).
- t = types.Types[TINT]
+ t = types.Types[types.TINT]
if doesoverflow(v, t) {
return
}
}
- base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym.Name, typesymname(t), int64Val(t, v))
+ base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym.Name, typesymname(t), ir.Int64Val(t, v))
}
func dumpglobls() {
// add globals
for _, n := range externdcl {
switch n.Op {
- case ONAME:
+ case ir.ONAME:
dumpGlobal(n)
- case OLITERAL:
+ case ir.OLITERAL:
dumpGlobalConst(n)
}
}
var slicedataGen int
-func slicedata(pos src.XPos, s string) *Node {
+func slicedata(pos src.XPos, s string) *ir.Node {
slicedataGen++
symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
- sym := localpkg.Lookup(symname)
- symnode := newname(sym)
- sym.Def = asTypesNode(symnode)
+ sym := ir.LocalPkg.Lookup(symname)
+ symnode := NewName(sym)
+ sym.Def = ir.AsTypesNode(symnode)
lsym := sym.Linksym()
off := dstringdata(lsym, 0, s, pos, "slice")
return symnode
}
-func slicebytes(nam *Node, s string) {
- if nam.Op != ONAME {
+func slicebytes(nam *ir.Node, s string) {
+ if nam.Op != ir.ONAME {
base.Fatalf("slicebytes %v", nam)
}
slicesym(nam, slicedata(nam.Pos, s), int64(len(s)))
// slicesym writes a static slice symbol {&arr, lencap, lencap} to n.
// arr must be an ONAME. slicesym does not modify n.
-func slicesym(n, arr *Node, lencap int64) {
+func slicesym(n, arr *ir.Node, lencap int64) {
s := n.Sym.Linksym()
off := n.Xoffset
- if arr.Op != ONAME {
+ if arr.Op != ir.ONAME {
base.Fatalf("slicesym non-name arr %v", arr)
}
s.WriteAddr(base.Ctxt, off, Widthptr, arr.Sym.Linksym(), arr.Xoffset)
// addrsym writes the static address of a to n. a must be an ONAME.
// Neither n nor a is modified.
-func addrsym(n, a *Node) {
- if n.Op != ONAME {
+func addrsym(n, a *ir.Node) {
+ if n.Op != ir.ONAME {
base.Fatalf("addrsym n op %v", n.Op)
}
if n.Sym == nil {
base.Fatalf("addrsym nil n sym")
}
- if a.Op != ONAME {
+ if a.Op != ir.ONAME {
base.Fatalf("addrsym a op %v", a.Op)
}
s := n.Sym.Linksym()
// pfuncsym writes the static address of f to n. f must be a global function.
// Neither n nor f is modified.
-func pfuncsym(n, f *Node) {
- if n.Op != ONAME {
+func pfuncsym(n, f *ir.Node) {
+ if n.Op != ir.ONAME {
base.Fatalf("pfuncsym n op %v", n.Op)
}
if n.Sym == nil {
base.Fatalf("pfuncsym nil n sym")
}
- if f.Class() != PFUNC {
+ if f.Class() != ir.PFUNC {
base.Fatalf("pfuncsym class not PFUNC %d", f.Class())
}
s := n.Sym.Linksym()
// litsym writes the static literal c to n.
// Neither n nor c is modified.
-func litsym(n, c *Node, wid int) {
- if n.Op != ONAME {
+func litsym(n, c *ir.Node, wid int) {
+ if n.Op != ir.ONAME {
base.Fatalf("litsym n op %v", n.Op)
}
if n.Sym == nil {
if !types.Identical(n.Type, c.Type) {
base.Fatalf("litsym: type mismatch: %v has type %v, but %v has type %v", n, n.Type, c, c.Type)
}
- if c.Op == ONIL {
+ if c.Op == ir.ONIL {
return
}
- if c.Op != OLITERAL {
+ if c.Op != ir.OLITERAL {
base.Fatalf("litsym c op %v", c.Op)
}
s := n.Sym.Linksym()
s.WriteInt(base.Ctxt, n.Xoffset, wid, i)
case constant.Int:
- s.WriteInt(base.Ctxt, n.Xoffset, wid, int64Val(n.Type, u))
+ s.WriteInt(base.Ctxt, n.Xoffset, wid, ir.Int64Val(n.Type, u))
case constant.Float:
f, _ := constant.Float64Val(u)
switch n.Type.Etype {
- case TFLOAT32:
+ case types.TFLOAT32:
s.WriteFloat32(base.Ctxt, n.Xoffset, float32(f))
- case TFLOAT64:
+ case types.TFLOAT64:
s.WriteFloat64(base.Ctxt, n.Xoffset, f)
}
re, _ := constant.Float64Val(constant.Real(u))
im, _ := constant.Float64Val(constant.Imag(u))
switch n.Type.Etype {
- case TCOMPLEX64:
+ case types.TCOMPLEX64:
s.WriteFloat32(base.Ctxt, n.Xoffset, float32(re))
s.WriteFloat32(base.Ctxt, n.Xoffset+4, float32(im))
- case TCOMPLEX128:
+ case types.TCOMPLEX128:
s.WriteFloat64(base.Ctxt, n.Xoffset, re)
s.WriteFloat64(base.Ctxt, n.Xoffset+8, im)
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
// Order holds state during the ordering process.
type Order struct {
- out []*Node // list of generated statements
- temp []*Node // stack of temporary variables
- free map[string][]*Node // free list of unused temporaries, by type.LongString().
+ out []*ir.Node // list of generated statements
+ temp []*ir.Node // stack of temporary variables
+ free map[string][]*ir.Node // free list of unused temporaries, by type.LongString().
}
// Order rewrites fn.Nbody to apply the ordering constraints
// described in the comment at the top of the file.
-func order(fn *Node) {
+func order(fn *ir.Node) {
if base.Flag.W > 1 {
s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
- dumplist(s, fn.Nbody)
+ ir.DumpList(s, fn.Nbody)
}
- orderBlock(&fn.Nbody, map[string][]*Node{})
+ orderBlock(&fn.Nbody, map[string][]*ir.Node{})
}
// newTemp allocates a new temporary with the given type,
// pushes it onto the temp stack, and returns it.
// If clear is true, newTemp emits code to zero the temporary.
-func (o *Order) newTemp(t *types.Type, clear bool) *Node {
- var v *Node
+func (o *Order) newTemp(t *types.Type, clear bool) *ir.Node {
+ var v *ir.Node
// Note: LongString is close to the type equality we want,
// but not exactly. We still need to double-check with types.Identical.
key := t.LongString()
v = temp(t)
}
if clear {
- a := nod(OAS, v, nil)
+ a := ir.Nod(ir.OAS, v, nil)
a = typecheck(a, ctxStmt)
o.out = append(o.out, a)
}
// (The other candidate would be map access, but map access
// returns a pointer to the result data instead of taking a pointer
// to be filled in.)
-func (o *Order) copyExpr(n *Node, t *types.Type, clear bool) *Node {
+func (o *Order) copyExpr(n *ir.Node, t *types.Type, clear bool) *ir.Node {
v := o.newTemp(t, clear)
- a := nod(OAS, v, n)
+ a := ir.Nod(ir.OAS, v, n)
a = typecheck(a, ctxStmt)
o.out = append(o.out, a)
return v
// The definition of cheap is that n is a variable or constant.
// If not, cheapExpr allocates a new tmp, emits tmp = n,
// and then returns tmp.
-func (o *Order) cheapExpr(n *Node) *Node {
+func (o *Order) cheapExpr(n *ir.Node) *ir.Node {
if n == nil {
return nil
}
switch n.Op {
- case ONAME, OLITERAL, ONIL:
+ case ir.ONAME, ir.OLITERAL, ir.ONIL:
return n
- case OLEN, OCAP:
+ case ir.OLEN, ir.OCAP:
l := o.cheapExpr(n.Left)
if l == n.Left {
return n
}
- a := n.sepcopy()
+ a := ir.SepCopy(n)
a.Left = l
return typecheck(a, ctxExpr)
}
// as assigning to the original n.
//
// The intended use is to apply to x when rewriting x += y into x = x + y.
-func (o *Order) safeExpr(n *Node) *Node {
+func (o *Order) safeExpr(n *ir.Node) *ir.Node {
switch n.Op {
- case ONAME, OLITERAL, ONIL:
+ case ir.ONAME, ir.OLITERAL, ir.ONIL:
return n
- case ODOT, OLEN, OCAP:
+ case ir.ODOT, ir.OLEN, ir.OCAP:
l := o.safeExpr(n.Left)
if l == n.Left {
return n
}
- a := n.sepcopy()
+ a := ir.SepCopy(n)
a.Left = l
return typecheck(a, ctxExpr)
- case ODOTPTR, ODEREF:
+ case ir.ODOTPTR, ir.ODEREF:
l := o.cheapExpr(n.Left)
if l == n.Left {
return n
}
- a := n.sepcopy()
+ a := ir.SepCopy(n)
a.Left = l
return typecheck(a, ctxExpr)
- case OINDEX, OINDEXMAP:
- var l *Node
+ case ir.OINDEX, ir.OINDEXMAP:
+ var l *ir.Node
if n.Left.Type.IsArray() {
l = o.safeExpr(n.Left)
} else {
if l == n.Left && r == n.Right {
return n
}
- a := n.sepcopy()
+ a := ir.SepCopy(n)
a.Left = l
a.Right = r
return typecheck(a, ctxExpr)
// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
// because we emit explicit VARKILL instructions marking the end of those
// temporaries' lifetimes.
-func isaddrokay(n *Node) bool {
- return islvalue(n) && (n.Op != ONAME || n.Class() == PEXTERN || n.IsAutoTmp())
+func isaddrokay(n *ir.Node) bool {
+ return islvalue(n) && (n.Op != ir.ONAME || n.Class() == ir.PEXTERN || n.IsAutoTmp())
}
// addrTemp ensures that n is okay to pass by address to runtime routines.
// tmp = n, and then returns tmp.
// The result of addrTemp MUST be assigned back to n, e.g.
// n.Left = o.addrTemp(n.Left)
-func (o *Order) addrTemp(n *Node) *Node {
- if n.Op == OLITERAL || n.Op == ONIL {
+func (o *Order) addrTemp(n *ir.Node) *ir.Node {
+ if n.Op == ir.OLITERAL || n.Op == ir.ONIL {
// TODO: expand this to all static composite literal nodes?
n = defaultlit(n, nil)
dowidth(n.Type)
// mapKeyTemp prepares n to be a key in a map runtime call and returns n.
// It should only be used for map runtime calls which have *_fast* versions.
-func (o *Order) mapKeyTemp(t *types.Type, n *Node) *Node {
+func (o *Order) mapKeyTemp(t *types.Type, n *ir.Node) *ir.Node {
// Most map calls need to take the address of the key.
// Exception: map*_fast* calls. See golang.org/issue/19015.
if mapfast(t) == mapslow {
// It would be nice to handle these generally, but because
// []byte keys are not allowed in maps, the use of string(k)
// comes up in important cases in practice. See issue 3512.
-func mapKeyReplaceStrConv(n *Node) bool {
+func mapKeyReplaceStrConv(n *ir.Node) bool {
var replaced bool
switch n.Op {
- case OBYTES2STR:
- n.Op = OBYTES2STRTMP
+ case ir.OBYTES2STR:
+ n.Op = ir.OBYTES2STRTMP
replaced = true
- case OSTRUCTLIT:
+ case ir.OSTRUCTLIT:
for _, elem := range n.List.Slice() {
if mapKeyReplaceStrConv(elem.Left) {
replaced = true
}
}
- case OARRAYLIT:
+ case ir.OARRAYLIT:
for _, elem := range n.List.Slice() {
- if elem.Op == OKEY {
+ if elem.Op == ir.OKEY {
elem = elem.Right
}
if mapKeyReplaceStrConv(elem) {
// cleanTempNoPop emits VARKILL instructions to *out
// for each temporary above the mark on the temporary stack.
// It does not pop the temporaries from the stack.
-func (o *Order) cleanTempNoPop(mark ordermarker) []*Node {
- var out []*Node
+func (o *Order) cleanTempNoPop(mark ordermarker) []*ir.Node {
+ var out []*ir.Node
for i := len(o.temp) - 1; i >= int(mark); i-- {
n := o.temp[i]
- kill := nod(OVARKILL, n, nil)
+ kill := ir.Nod(ir.OVARKILL, n, nil)
kill = typecheck(kill, ctxStmt)
out = append(out, kill)
}
}
// stmtList orders each of the statements in the list.
-func (o *Order) stmtList(l Nodes) {
+func (o *Order) stmtList(l ir.Nodes) {
s := l.Slice()
for i := range s {
orderMakeSliceCopy(s[i:])
// m = OMAKESLICE([]T, x); OCOPY(m, s)
// and rewrites it to:
// m = OMAKESLICECOPY([]T, x, s); nil
-func orderMakeSliceCopy(s []*Node) {
+func orderMakeSliceCopy(s []*ir.Node) {
if base.Flag.N != 0 || instrumenting {
return
}
asn := s[0]
copyn := s[1]
- if asn == nil || asn.Op != OAS {
+ if asn == nil || asn.Op != ir.OAS {
return
}
- if asn.Left.Op != ONAME {
+ if asn.Left.Op != ir.ONAME {
return
}
- if asn.Left.isBlank() {
+ if ir.IsBlank(asn.Left) {
return
}
maken := asn.Right
- if maken == nil || maken.Op != OMAKESLICE {
+ if maken == nil || maken.Op != ir.OMAKESLICE {
return
}
if maken.Esc == EscNone {
if maken.Left == nil || maken.Right != nil {
return
}
- if copyn.Op != OCOPY {
+ if copyn.Op != ir.OCOPY {
return
}
- if copyn.Left.Op != ONAME {
+ if copyn.Left.Op != ir.ONAME {
return
}
if asn.Left.Sym != copyn.Left.Sym {
return
}
- if copyn.Right.Op != ONAME {
+ if copyn.Right.Op != ir.ONAME {
return
}
return
}
- maken.Op = OMAKESLICECOPY
+ maken.Op = ir.OMAKESLICECOPY
maken.Right = copyn.Right
// Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
- maken.SetBounded(maken.Left.Op == OLEN && samesafeexpr(maken.Left.Left, copyn.Right))
+ maken.SetBounded(maken.Left.Op == ir.OLEN && samesafeexpr(maken.Left.Left, copyn.Right))
maken = typecheck(maken, ctxExpr)
// Create a new uint8 counter to be allocated in section
// __libfuzzer_extra_counters.
- counter := staticname(types.Types[TUINT8])
+ counter := staticname(types.Types[types.TUINT8])
counter.Name.SetLibfuzzerExtraCounter(true)
// counter += 1
- incr := nod(OASOP, counter, nodintconst(1))
- incr.SetSubOp(OADD)
+ incr := ir.Nod(ir.OASOP, counter, nodintconst(1))
+ incr.SetSubOp(ir.OADD)
incr = typecheck(incr, ctxStmt)
o.out = append(o.out, incr)
// orderBlock orders the block of statements in n into a new slice,
// and then replaces the old slice in n with the new slice.
// free is a map that can be used to obtain temporary variables by type.
-func orderBlock(n *Nodes, free map[string][]*Node) {
+func orderBlock(n *ir.Nodes, free map[string][]*ir.Node) {
var order Order
order.free = free
mark := order.markTemp()
// leaves them as the init list of the final *np.
// The result of exprInPlace MUST be assigned back to n, e.g.
// n.Left = o.exprInPlace(n.Left)
-func (o *Order) exprInPlace(n *Node) *Node {
+func (o *Order) exprInPlace(n *ir.Node) *ir.Node {
var order Order
order.free = o.free
n = order.expr(n, nil)
// The result of orderStmtInPlace MUST be assigned back to n, e.g.
// n.Left = orderStmtInPlace(n.Left)
// free is a map that can be used to obtain temporary variables by type.
-func orderStmtInPlace(n *Node, free map[string][]*Node) *Node {
+func orderStmtInPlace(n *ir.Node, free map[string][]*ir.Node) *ir.Node {
var order Order
order.free = free
mark := order.markTemp()
}
// init moves n's init list to o.out.
-func (o *Order) init(n *Node) {
- if n.mayBeShared() {
+func (o *Order) init(n *ir.Node) {
+ if ir.MayBeShared(n) {
// For concurrency safety, don't mutate potentially shared nodes.
// First, ensure that no work is required here.
if n.Ninit.Len() > 0 {
// call orders the call expression n.
// n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
-func (o *Order) call(n *Node) {
+func (o *Order) call(n *ir.Node) {
if n.Ninit.Len() > 0 {
// Caller should have already called o.init(n).
base.Fatalf("%v with unexpected ninit", n.Op)
}
// Builtin functions.
- if n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER {
+ if n.Op != ir.OCALLFUNC && n.Op != ir.OCALLMETH && n.Op != ir.OCALLINTER {
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
o.exprList(n.List)
n.Left = o.expr(n.Left, nil)
o.exprList(n.List)
- if n.Op == OCALLINTER {
+ if n.Op == ir.OCALLINTER {
return
}
- keepAlive := func(arg *Node) {
+ keepAlive := func(arg *ir.Node) {
// If the argument is really a pointer being converted to uintptr,
// arrange for the pointer to be kept alive until the call returns,
// by copying it into a temp and marking that temp
// still alive when we pop the temp stack.
- if arg.Op == OCONVNOP && arg.Left.Type.IsUnsafePtr() {
+ if arg.Op == ir.OCONVNOP && arg.Left.Type.IsUnsafePtr() {
x := o.copyExpr(arg.Left, arg.Left.Type, false)
arg.Left = x
x.Name.SetAddrtaken(true) // ensure SSA keeps the x variable
- n.Nbody.Append(typecheck(nod(OVARLIVE, x, nil), ctxStmt))
+ n.Nbody.Append(typecheck(ir.Nod(ir.OVARLIVE, x, nil), ctxStmt))
}
}
// Check for "unsafe-uintptr" tag provided by escape analysis.
for i, param := range n.Left.Type.Params().FieldSlice() {
if param.Note == unsafeUintptrTag || param.Note == uintptrEscapesTag {
- if arg := n.List.Index(i); arg.Op == OSLICELIT {
+ if arg := n.List.Index(i); arg.Op == ir.OSLICELIT {
for _, elt := range arg.List.Slice() {
keepAlive(elt)
}
// cases they are also typically registerizable, so not much harm done.
// And this only applies to the multiple-assignment form.
// We could do a more precise analysis if needed, like in walk.go.
-func (o *Order) mapAssign(n *Node) {
+func (o *Order) mapAssign(n *ir.Node) {
switch n.Op {
default:
base.Fatalf("order.mapAssign %v", n.Op)
- case OAS, OASOP:
- if n.Left.Op == OINDEXMAP {
+ case ir.OAS, ir.OASOP:
+ if n.Left.Op == ir.OINDEXMAP {
// Make sure we evaluate the RHS before starting the map insert.
// We need to make sure the RHS won't panic. See issue 22881.
- if n.Right.Op == OAPPEND {
+ if n.Right.Op == ir.OAPPEND {
s := n.Right.List.Slice()[1:]
for i, n := range s {
s[i] = o.cheapExpr(n)
}
o.out = append(o.out, n)
- case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
- var post []*Node
+ case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC:
+ var post []*ir.Node
for i, m := range n.List.Slice() {
switch {
- case m.Op == OINDEXMAP:
+ case m.Op == ir.OINDEXMAP:
if !m.Left.IsAutoTmp() {
m.Left = o.copyExpr(m.Left, m.Left.Type, false)
}
m.Right = o.copyExpr(m.Right, m.Right.Type, false)
}
fallthrough
- case instrumenting && n.Op == OAS2FUNC && !m.isBlank():
+ case instrumenting && n.Op == ir.OAS2FUNC && !ir.IsBlank(m):
t := o.newTemp(m.Type, false)
n.List.SetIndex(i, t)
- a := nod(OAS, m, t)
+ a := ir.Nod(ir.OAS, m, t)
a = typecheck(a, ctxStmt)
post = append(post, a)
}
// stmt orders the statement n, appending to o.out.
// Temporaries created during the statement are cleaned
// up using VARKILL instructions as possible.
-func (o *Order) stmt(n *Node) {
+func (o *Order) stmt(n *ir.Node) {
if n == nil {
return
}
default:
base.Fatalf("order.stmt %v", n.Op)
- case OVARKILL, OVARLIVE, OINLMARK:
+ case ir.OVARKILL, ir.OVARLIVE, ir.OINLMARK:
o.out = append(o.out, n)
- case OAS:
+ case ir.OAS:
t := o.markTemp()
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, n.Left)
o.mapAssign(n)
o.cleanTemp(t)
- case OASOP:
+ case ir.OASOP:
t := o.markTemp()
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
- if instrumenting || n.Left.Op == OINDEXMAP && (n.SubOp() == ODIV || n.SubOp() == OMOD) {
+ if instrumenting || n.Left.Op == ir.OINDEXMAP && (n.SubOp() == ir.ODIV || n.SubOp() == ir.OMOD) {
// Rewrite m[k] op= r into m[k] = m[k] op r so
// that we can ensure that if op panics
// because r is zero, the panic happens before
n.Left = o.safeExpr(n.Left)
l := treecopy(n.Left, src.NoXPos)
- if l.Op == OINDEXMAP {
+ if l.Op == ir.OINDEXMAP {
l.SetIndexMapLValue(false)
}
l = o.copyExpr(l, n.Left.Type, false)
- n.Right = nod(n.SubOp(), l, n.Right)
+ n.Right = ir.Nod(n.SubOp(), l, n.Right)
n.Right = typecheck(n.Right, ctxExpr)
n.Right = o.expr(n.Right, nil)
- n.Op = OAS
+ n.Op = ir.OAS
n.ResetAux()
}
o.mapAssign(n)
o.cleanTemp(t)
- case OAS2:
+ case ir.OAS2:
t := o.markTemp()
o.exprList(n.List)
o.exprList(n.Rlist)
o.cleanTemp(t)
// Special: avoid copy of func call n.Right
- case OAS2FUNC:
+ case ir.OAS2FUNC:
t := o.markTemp()
o.exprList(n.List)
o.init(n.Right)
//
// OAS2MAPR: make sure key is addressable if needed,
// and make sure OINDEXMAP is not copied out.
- case OAS2DOTTYPE, OAS2RECV, OAS2MAPR:
+ case ir.OAS2DOTTYPE, ir.OAS2RECV, ir.OAS2MAPR:
t := o.markTemp()
o.exprList(n.List)
switch r := n.Right; r.Op {
- case ODOTTYPE2, ORECV:
+ case ir.ODOTTYPE2, ir.ORECV:
r.Left = o.expr(r.Left, nil)
- case OINDEXMAP:
+ case ir.OINDEXMAP:
r.Left = o.expr(r.Left, nil)
r.Right = o.expr(r.Right, nil)
// See similar conversion for OINDEXMAP below.
o.cleanTemp(t)
// Special: does not save n onto out.
- case OBLOCK, OEMPTY:
+ case ir.OBLOCK, ir.OEMPTY:
o.stmtList(n.List)
// Special: n->left is not an expression; save as is.
- case OBREAK,
- OCONTINUE,
- ODCL,
- ODCLCONST,
- ODCLTYPE,
- OFALL,
- OGOTO,
- OLABEL,
- ORETJMP:
+ case ir.OBREAK,
+ ir.OCONTINUE,
+ ir.ODCL,
+ ir.ODCLCONST,
+ ir.ODCLTYPE,
+ ir.OFALL,
+ ir.OGOTO,
+ ir.OLABEL,
+ ir.ORETJMP:
o.out = append(o.out, n)
// Special: handle call arguments.
- case OCALLFUNC, OCALLINTER, OCALLMETH:
+ case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
t := o.markTemp()
o.call(n)
o.out = append(o.out, n)
o.cleanTemp(t)
- case OCLOSE,
- OCOPY,
- OPRINT,
- OPRINTN,
- ORECOVER,
- ORECV:
+ case ir.OCLOSE,
+ ir.OCOPY,
+ ir.OPRINT,
+ ir.OPRINTN,
+ ir.ORECOVER,
+ ir.ORECV:
t := o.markTemp()
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
o.cleanTemp(t)
// Special: order arguments to inner call but not call itself.
- case ODEFER, OGO:
+ case ir.ODEFER, ir.OGO:
t := o.markTemp()
o.init(n.Left)
o.call(n.Left)
o.out = append(o.out, n)
o.cleanTemp(t)
- case ODELETE:
+ case ir.ODELETE:
t := o.markTemp()
n.List.SetFirst(o.expr(n.List.First(), nil))
n.List.SetSecond(o.expr(n.List.Second(), nil))
// Clean temporaries from condition evaluation at
// beginning of loop body and after for statement.
- case OFOR:
+ case ir.OFOR:
t := o.markTemp()
n.Left = o.exprInPlace(n.Left)
n.Nbody.Prepend(o.cleanTempNoPop(t)...)
// Clean temporaries from condition at
// beginning of both branches.
- case OIF:
+ case ir.OIF:
t := o.markTemp()
n.Left = o.exprInPlace(n.Left)
n.Nbody.Prepend(o.cleanTempNoPop(t)...)
// Special: argument will be converted to interface using convT2E
// so make sure it is an addressable temporary.
- case OPANIC:
+ case ir.OPANIC:
t := o.markTemp()
n.Left = o.expr(n.Left, nil)
if !n.Left.Type.IsInterface() {
o.out = append(o.out, n)
o.cleanTemp(t)
- case ORANGE:
+ case ir.ORANGE:
// n.Right is the expression being ranged over.
// order it, and then make a copy if we need one.
// We almost always do, to ensure that we don't
// Mark []byte(str) range expression to reuse string backing storage.
// It is safe because the storage cannot be mutated.
- if n.Right.Op == OSTR2BYTES {
- n.Right.Op = OSTR2BYTESTMP
+ if n.Right.Op == ir.OSTR2BYTES {
+ n.Right.Op = ir.OSTR2BYTESTMP
}
t := o.markTemp()
default:
base.Fatalf("order.stmt range %v", n.Type)
- case TARRAY, TSLICE:
- if n.List.Len() < 2 || n.List.Second().isBlank() {
+ case types.TARRAY, types.TSLICE:
+ if n.List.Len() < 2 || ir.IsBlank(n.List.Second()) {
// for i := range x will only use x once, to compute len(x).
// No need to copy it.
break
}
fallthrough
- case TCHAN, TSTRING:
+ case types.TCHAN, types.TSTRING:
// chan, string, slice, array ranges use value multiple times.
// make copy.
r := n.Right
- if r.Type.IsString() && r.Type != types.Types[TSTRING] {
- r = nod(OCONV, r, nil)
- r.Type = types.Types[TSTRING]
+ if r.Type.IsString() && r.Type != types.Types[types.TSTRING] {
+ r = ir.Nod(ir.OCONV, r, nil)
+ r.Type = types.Types[types.TSTRING]
r = typecheck(r, ctxExpr)
}
n.Right = o.copyExpr(r, r.Type, false)
- case TMAP:
+ case types.TMAP:
if isMapClear(n) {
// Preserve the body of the map clear pattern so it can
// be detected during walk. The loop body will not be used
o.out = append(o.out, n)
o.cleanTemp(t)
- case ORETURN:
+ case ir.ORETURN:
o.exprList(n.List)
o.out = append(o.out, n)
// reordered after the channel evaluation for a different
// case (if p were nil, then the timing of the fault would
// give this away).
- case OSELECT:
+ case ir.OSELECT:
t := o.markTemp()
for _, n2 := range n.List.Slice() {
- if n2.Op != OCASE {
+ if n2.Op != ir.OCASE {
base.Fatalf("order select case %v", n2.Op)
}
r := n2.Left
}
switch r.Op {
default:
- Dump("select case", r)
+ ir.Dump("select case", r)
base.Fatalf("unknown op in select %v", r.Op)
// If this is case x := <-ch or case x, y := <-ch, the case has
// the ODCL nodes to declare x and y. We want to delay that
// declaration (and possible allocation) until inside the case body.
// Delete the ODCL nodes here and recreate them inside the body below.
- case OSELRECV, OSELRECV2:
+ case ir.OSELRECV, ir.OSELRECV2:
if r.Colas() {
i := 0
- if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left {
+ if r.Ninit.Len() != 0 && r.Ninit.First().Op == ir.ODCL && r.Ninit.First().Left == r.Left {
i++
}
- if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() {
+ if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ir.ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() {
i++
}
if i >= r.Ninit.Len() {
}
if r.Ninit.Len() != 0 {
- dumplist("ninit", r.Ninit)
+ ir.DumpList("ninit", r.Ninit)
base.Fatalf("ninit on select recv")
}
// c is always evaluated; x and ok are only evaluated when assigned.
r.Right.Left = o.expr(r.Right.Left, nil)
- if r.Right.Left.Op != ONAME {
+ if r.Right.Left.Op != ir.ONAME {
r.Right.Left = o.copyExpr(r.Right.Left, r.Right.Left.Type, false)
}
// temporary per distinct type, sharing the temp among all receives
// with that temp. Similarly one ok bool could be shared among all
// the x,ok receives. Not worth doing until there's a clear need.
- if r.Left != nil && r.Left.isBlank() {
+ if r.Left != nil && ir.IsBlank(r.Left) {
r.Left = nil
}
if r.Left != nil {
tmp1 := r.Left
if r.Colas() {
- tmp2 := nod(ODCL, tmp1, nil)
+ tmp2 := ir.Nod(ir.ODCL, tmp1, nil)
tmp2 = typecheck(tmp2, ctxStmt)
n2.Ninit.Append(tmp2)
}
r.Left = o.newTemp(r.Right.Left.Type.Elem(), r.Right.Left.Type.Elem().HasPointers())
- tmp2 := nod(OAS, tmp1, r.Left)
+ tmp2 := ir.Nod(ir.OAS, tmp1, r.Left)
tmp2 = typecheck(tmp2, ctxStmt)
n2.Ninit.Append(tmp2)
}
- if r.List.Len() != 0 && r.List.First().isBlank() {
+ if r.List.Len() != 0 && ir.IsBlank(r.List.First()) {
r.List.Set(nil)
}
if r.List.Len() != 0 {
tmp1 := r.List.First()
if r.Colas() {
- tmp2 := nod(ODCL, tmp1, nil)
+ tmp2 := ir.Nod(ir.ODCL, tmp1, nil)
tmp2 = typecheck(tmp2, ctxStmt)
n2.Ninit.Append(tmp2)
}
- r.List.Set1(o.newTemp(types.Types[TBOOL], false))
+ r.List.Set1(o.newTemp(types.Types[types.TBOOL], false))
tmp2 := okas(tmp1, r.List.First())
tmp2 = typecheck(tmp2, ctxStmt)
n2.Ninit.Append(tmp2)
}
orderBlock(&n2.Ninit, o.free)
- case OSEND:
+ case ir.OSEND:
if r.Ninit.Len() != 0 {
- dumplist("ninit", r.Ninit)
+ ir.DumpList("ninit", r.Ninit)
base.Fatalf("ninit on select send")
}
o.popTemp(t)
// Special: value being sent is passed as a pointer; make it addressable.
- case OSEND:
+ case ir.OSEND:
t := o.markTemp()
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
// the if-else chain instead.)
// For now just clean all the temporaries at the end.
// In practice that's fine.
- case OSWITCH:
+ case ir.OSWITCH:
if base.Debug.Libfuzzer != 0 && !hasDefaultCase(n) {
// Add empty "default:" case for instrumentation.
- n.List.Append(nod(OCASE, nil, nil))
+ n.List.Append(ir.Nod(ir.OCASE, nil, nil))
}
t := o.markTemp()
n.Left = o.expr(n.Left, nil)
for _, ncas := range n.List.Slice() {
- if ncas.Op != OCASE {
+ if ncas.Op != ir.OCASE {
base.Fatalf("order switch case %v", ncas.Op)
}
o.exprListInPlace(ncas.List)
base.Pos = lno
}
-func hasDefaultCase(n *Node) bool {
+func hasDefaultCase(n *ir.Node) bool {
for _, ncas := range n.List.Slice() {
- if ncas.Op != OCASE {
+ if ncas.Op != ir.OCASE {
base.Fatalf("expected case, found %v", ncas.Op)
}
if ncas.List.Len() == 0 {
}
// exprList orders the expression list l into o.
-func (o *Order) exprList(l Nodes) {
+func (o *Order) exprList(l ir.Nodes) {
s := l.Slice()
for i := range s {
s[i] = o.expr(s[i], nil)
// exprListInPlace orders the expression list l but saves
// the side effects on the individual expression ninit lists.
-func (o *Order) exprListInPlace(l Nodes) {
+func (o *Order) exprListInPlace(l ir.Nodes) {
s := l.Slice()
for i := range s {
s[i] = o.exprInPlace(s[i])
}
// prealloc[x] records the allocation to use for x.
-var prealloc = map[*Node]*Node{}
+var prealloc = map[*ir.Node]*ir.Node{}
// expr orders a single expression, appending side
// effects to o.out as needed.
// to avoid copying the result of the expression to a temporary.)
// The result of expr MUST be assigned back to n, e.g.
// n.Left = o.expr(n.Left, lhs)
-func (o *Order) expr(n, lhs *Node) *Node {
+func (o *Order) expr(n, lhs *ir.Node) *ir.Node {
if n == nil {
return n
}
// Addition of strings turns into a function call.
// Allocate a temporary to hold the strings.
// Fewer than 5 strings use direct runtime helpers.
- case OADDSTR:
+ case ir.OADDSTR:
o.exprList(n.List)
if n.List.Len() > 5 {
- t := types.NewArray(types.Types[TSTRING], int64(n.List.Len()))
+ t := types.NewArray(types.Types[types.TSTRING], int64(n.List.Len()))
prealloc[n] = o.newTemp(t, false)
}
haslit := false
for _, n1 := range n.List.Slice() {
- hasbyte = hasbyte || n1.Op == OBYTES2STR
- haslit = haslit || n1.Op == OLITERAL && len(n1.StringVal()) != 0
+ hasbyte = hasbyte || n1.Op == ir.OBYTES2STR
+ haslit = haslit || n1.Op == ir.OLITERAL && len(n1.StringVal()) != 0
}
if haslit && hasbyte {
for _, n2 := range n.List.Slice() {
- if n2.Op == OBYTES2STR {
- n2.Op = OBYTES2STRTMP
+ if n2.Op == ir.OBYTES2STR {
+ n2.Op = ir.OBYTES2STRTMP
}
}
}
- case OINDEXMAP:
+ case ir.OINDEXMAP:
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
needCopy := false
// concrete type (not interface) argument might need an addressable
// temporary to pass to the runtime conversion routine.
- case OCONVIFACE:
+ case ir.OCONVIFACE:
n.Left = o.expr(n.Left, nil)
if n.Left.Type.IsInterface() {
break
n.Left = o.addrTemp(n.Left)
}
- case OCONVNOP:
- if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) {
+ case ir.OCONVNOP:
+ if n.Type.IsKind(types.TUNSAFEPTR) && n.Left.Type.IsKind(types.TUINTPTR) && (n.Left.Op == ir.OCALLFUNC || n.Left.Op == ir.OCALLINTER || n.Left.Op == ir.OCALLMETH) {
// When reordering unsafe.Pointer(f()) into a separate
// statement, the conversion and function call must stay
// together. See golang.org/issue/15329.
o.init(n.Left)
o.call(n.Left)
- if lhs == nil || lhs.Op != ONAME || instrumenting {
+ if lhs == nil || lhs.Op != ir.ONAME || instrumenting {
n = o.copyExpr(n, n.Type, false)
}
} else {
n.Left = o.expr(n.Left, nil)
}
- case OANDAND, OOROR:
+ case ir.OANDAND, ir.OOROR:
// ... = LHS && RHS
//
// var r bool
// Evaluate left-hand side.
lhs := o.expr(n.Left, nil)
- o.out = append(o.out, typecheck(nod(OAS, r, lhs), ctxStmt))
+ o.out = append(o.out, typecheck(ir.Nod(ir.OAS, r, lhs), ctxStmt))
// Evaluate right-hand side, save generated code.
saveout := o.out
t := o.markTemp()
o.edge()
rhs := o.expr(n.Right, nil)
- o.out = append(o.out, typecheck(nod(OAS, r, rhs), ctxStmt))
+ o.out = append(o.out, typecheck(ir.Nod(ir.OAS, r, rhs), ctxStmt))
o.cleanTemp(t)
gen := o.out
o.out = saveout
// If left-hand side doesn't cause a short-circuit, issue right-hand side.
- nif := nod(OIF, r, nil)
- if n.Op == OANDAND {
+ nif := ir.Nod(ir.OIF, r, nil)
+ if n.Op == ir.OANDAND {
nif.Nbody.Set(gen)
} else {
nif.Rlist.Set(gen)
o.out = append(o.out, nif)
n = r
- case OCALLFUNC,
- OCALLINTER,
- OCALLMETH,
- OCAP,
- OCOMPLEX,
- OCOPY,
- OIMAG,
- OLEN,
- OMAKECHAN,
- OMAKEMAP,
- OMAKESLICE,
- OMAKESLICECOPY,
- ONEW,
- OREAL,
- ORECOVER,
- OSTR2BYTES,
- OSTR2BYTESTMP,
- OSTR2RUNES:
+ case ir.OCALLFUNC,
+ ir.OCALLINTER,
+ ir.OCALLMETH,
+ ir.OCAP,
+ ir.OCOMPLEX,
+ ir.OCOPY,
+ ir.OIMAG,
+ ir.OLEN,
+ ir.OMAKECHAN,
+ ir.OMAKEMAP,
+ ir.OMAKESLICE,
+ ir.OMAKESLICECOPY,
+ ir.ONEW,
+ ir.OREAL,
+ ir.ORECOVER,
+ ir.OSTR2BYTES,
+ ir.OSTR2BYTESTMP,
+ ir.OSTR2RUNES:
if isRuneCount(n) {
// len([]rune(s)) is rewritten to runtime.countrunes(s) later.
o.call(n)
}
- if lhs == nil || lhs.Op != ONAME || instrumenting {
+ if lhs == nil || lhs.Op != ir.ONAME || instrumenting {
n = o.copyExpr(n, n.Type, false)
}
- case OAPPEND:
+ case ir.OAPPEND:
// Check for append(x, make([]T, y)...) .
if isAppendOfMake(n) {
n.List.SetFirst(o.expr(n.List.First(), nil)) // order x
o.exprList(n.List)
}
- if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
+ if lhs == nil || lhs.Op != ir.ONAME && !samesafeexpr(lhs, n.List.First()) {
n = o.copyExpr(n, n.Type, false)
}
- case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+ case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
n.Left = o.expr(n.Left, nil)
low, high, max := n.SliceBounds()
low = o.expr(low, nil)
max = o.expr(max, nil)
max = o.cheapExpr(max)
n.SetSliceBounds(low, high, max)
- if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
+ if lhs == nil || lhs.Op != ir.ONAME && !samesafeexpr(lhs, n.Left) {
n = o.copyExpr(n, n.Type, false)
}
- case OCLOSURE:
+ case ir.OCLOSURE:
if n.Transient() && n.Func.ClosureVars.Len() > 0 {
prealloc[n] = o.newTemp(closureType(n), false)
}
- case OSLICELIT, OCALLPART:
+ case ir.OSLICELIT, ir.OCALLPART:
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
o.exprList(n.List)
if n.Transient() {
var t *types.Type
switch n.Op {
- case OSLICELIT:
+ case ir.OSLICELIT:
t = types.NewArray(n.Type.Elem(), n.Right.Int64Val())
- case OCALLPART:
+ case ir.OCALLPART:
t = partialCallType(n)
}
prealloc[n] = o.newTemp(t, false)
}
- case ODOTTYPE, ODOTTYPE2:
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
n.Left = o.expr(n.Left, nil)
if !isdirectiface(n.Type) || instrumenting {
n = o.copyExpr(n, n.Type, true)
}
- case ORECV:
+ case ir.ORECV:
n.Left = o.expr(n.Left, nil)
n = o.copyExpr(n, n.Type, true)
- case OEQ, ONE, OLT, OLE, OGT, OGE:
+ case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
// Mark string(byteSlice) arguments to reuse byteSlice backing
// buffer during conversion. String comparison does not
// memorize the strings for later use, so it is safe.
- if n.Left.Op == OBYTES2STR {
- n.Left.Op = OBYTES2STRTMP
+ if n.Left.Op == ir.OBYTES2STR {
+ n.Left.Op = ir.OBYTES2STRTMP
}
- if n.Right.Op == OBYTES2STR {
- n.Right.Op = OBYTES2STRTMP
+ if n.Right.Op == ir.OBYTES2STR {
+ n.Right.Op = ir.OBYTES2STRTMP
}
case t.IsStruct() || t.IsArray():
n.Left = o.addrTemp(n.Left)
n.Right = o.addrTemp(n.Right)
}
- case OMAPLIT:
+ case ir.OMAPLIT:
// Order map by converting:
// map[int]int{
// a(): b(),
// See issue 26552.
entries := n.List.Slice()
statics := entries[:0]
- var dynamics []*Node
+ var dynamics []*ir.Node
for _, r := range entries {
- if r.Op != OKEY {
+ if r.Op != ir.OKEY {
base.Fatalf("OMAPLIT entry not OKEY: %v\n", r)
}
// Emit the creation of the map (with all its static entries).
m := o.newTemp(n.Type, false)
- as := nod(OAS, m, n)
+ as := ir.Nod(ir.OAS, m, n)
typecheck(as, ctxStmt)
o.stmt(as)
n = m
// Emit eval+insert of dynamic entries, one at a time.
for _, r := range dynamics {
- as := nod(OAS, nod(OINDEX, n, r.Left), r.Right)
+ as := ir.Nod(ir.OAS, ir.Nod(ir.OINDEX, n, r.Left), r.Right)
typecheck(as, ctxStmt) // Note: this converts the OINDEX to an OINDEXMAP
o.stmt(as)
}
// okas creates and returns an assignment of val to ok,
// including an explicit conversion if necessary.
-func okas(ok, val *Node) *Node {
- if !ok.isBlank() {
+func okas(ok, val *ir.Node) *ir.Node {
+ if !ir.IsBlank(ok) {
val = conv(val, ok.Type)
}
- return nod(OAS, ok, val)
+ return ir.Nod(ir.OAS, ok, val)
}
// as2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
// tmp1, tmp2, tmp3 = ...
// a, b, a = tmp1, tmp2, tmp3
// This is necessary to ensure left to right assignment order.
-func (o *Order) as2(n *Node) {
- tmplist := []*Node{}
- left := []*Node{}
+func (o *Order) as2(n *ir.Node) {
+ tmplist := []*ir.Node{}
+ left := []*ir.Node{}
for ni, l := range n.List.Slice() {
- if !l.isBlank() {
+ if !ir.IsBlank(l) {
tmp := o.newTemp(l.Type, l.Type.HasPointers())
n.List.SetIndex(ni, tmp)
tmplist = append(tmplist, tmp)
o.out = append(o.out, n)
- as := nod(OAS2, nil, nil)
+ as := ir.Nod(ir.OAS2, nil, nil)
as.List.Set(left)
as.Rlist.Set(tmplist)
as = typecheck(as, ctxStmt)
// okAs2 orders OAS2XXX with ok.
// Just like as2, this also adds temporaries to ensure left-to-right assignment.
-func (o *Order) okAs2(n *Node) {
- var tmp1, tmp2 *Node
- if !n.List.First().isBlank() {
+func (o *Order) okAs2(n *ir.Node) {
+ var tmp1, tmp2 *ir.Node
+ if !ir.IsBlank(n.List.First()) {
typ := n.Right.Type
tmp1 = o.newTemp(typ, typ.HasPointers())
}
- if !n.List.Second().isBlank() {
- tmp2 = o.newTemp(types.Types[TBOOL], false)
+ if !ir.IsBlank(n.List.Second()) {
+ tmp2 = o.newTemp(types.Types[types.TBOOL], false)
}
o.out = append(o.out, n)
if tmp1 != nil {
- r := nod(OAS, n.List.First(), tmp1)
+ r := ir.Nod(ir.OAS, n.List.First(), tmp1)
r = typecheck(r, ctxStmt)
o.mapAssign(r)
n.List.SetFirst(tmp1)
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/dwarf"
// "Portable" code generation.
var (
- compilequeue []*Node // functions waiting to be compiled
+ compilequeue []*ir.Node // functions waiting to be compiled
)
-func emitptrargsmap(fn *Node) {
- if fn.funcname() == "_" || fn.Func.Nname.Sym.Linkname != "" {
+func emitptrargsmap(fn *ir.Node) {
+ if ir.FuncName(fn) == "_" || fn.Func.Nname.Sym.Linkname != "" {
return
}
- lsym := base.Ctxt.Lookup(fn.Func.lsym.Name + ".args_stackmap")
+ lsym := base.Ctxt.Lookup(fn.Func.LSym.Name + ".args_stackmap")
nptr := int(fn.Type.ArgWidth() / int64(Widthptr))
bv := bvalloc(int32(nptr) * 2)
off := duint32(lsym, 0, uint32(nbitmap))
off = duint32(lsym, off, uint32(bv.n))
- if fn.IsMethod() {
+ if ir.IsMethod(fn) {
onebitwalktype1(fn.Type.Recvs(), 0, bv)
}
if fn.Type.NumParams() > 0 {
// really means, in memory, things with pointers needing zeroing at
// the top of the stack and increasing in size.
// Non-autos sort on offset.
-func cmpstackvarlt(a, b *Node) bool {
- if (a.Class() == PAUTO) != (b.Class() == PAUTO) {
- return b.Class() == PAUTO
+func cmpstackvarlt(a, b *ir.Node) bool {
+ if (a.Class() == ir.PAUTO) != (b.Class() == ir.PAUTO) {
+ return b.Class() == ir.PAUTO
}
- if a.Class() != PAUTO {
+ if a.Class() != ir.PAUTO {
return a.Xoffset < b.Xoffset
}
}
// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
-type byStackVar []*Node
+type byStackVar []*ir.Node
func (s byStackVar) Len() int { return len(s) }
func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
// Mark the PAUTO's unused.
for _, ln := range fn.Dcl {
- if ln.Class() == PAUTO {
+ if ln.Class() == ir.PAUTO {
ln.Name.SetUsed(false)
}
}
for _, l := range f.RegAlloc {
if ls, ok := l.(ssa.LocalSlot); ok {
- ls.N.(*Node).Name.SetUsed(true)
+ ls.N.(*ir.Node).Name.SetUsed(true)
}
}
scratchUsed := false
for _, b := range f.Blocks {
for _, v := range b.Values {
- if n, ok := v.Aux.(*Node); ok {
+ if n, ok := v.Aux.(*ir.Node); ok {
switch n.Class() {
- case PPARAM, PPARAMOUT:
+ case ir.PPARAM, ir.PPARAMOUT:
// Don't modify nodfp; it is a global.
if n != nodfp {
n.Name.SetUsed(true)
}
- case PAUTO:
+ case ir.PAUTO:
n.Name.SetUsed(true)
}
}
}
if f.Config.NeedsFpScratch && scratchUsed {
- s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[TUINT64])
+ s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[types.TUINT64])
}
sort.Sort(byStackVar(fn.Dcl))
// Reassign stack offsets of the locals that are used.
lastHasPtr := false
for i, n := range fn.Dcl {
- if n.Op != ONAME || n.Class() != PAUTO {
+ if n.Op != ir.ONAME || n.Class() != ir.PAUTO {
continue
}
if !n.Name.Used() {
s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
}
-func funccompile(fn *Node) {
+func funccompile(fn *ir.Node) {
if Curfn != nil {
base.Fatalf("funccompile %v inside %v", fn.Func.Nname.Sym, Curfn.Func.Nname.Sym)
}
if fn.Nbody.Len() == 0 {
// Initialize ABI wrappers if necessary.
- fn.Func.initLSym(false)
+ initLSym(fn.Func, false)
emitptrargsmap(fn)
return
}
- dclcontext = PAUTO
+ dclcontext = ir.PAUTO
Curfn = fn
compile(fn)
Curfn = nil
- dclcontext = PEXTERN
+ dclcontext = ir.PEXTERN
}
-func compile(fn *Node) {
+func compile(fn *ir.Node) {
errorsBefore := base.Errors()
order(fn)
if base.Errors() > errorsBefore {
// Set up the function's LSym early to avoid data races with the assemblers.
// Do this before walk, as walk needs the LSym to set attributes/relocations
// (e.g. in markTypeUsedInInterface).
- fn.Func.initLSym(true)
+ initLSym(fn.Func, true)
walk(fn)
if base.Errors() > errorsBefore {
// From this point, there should be no uses of Curfn. Enforce that.
Curfn = nil
- if fn.funcname() == "_" {
+ if ir.FuncName(fn) == "_" {
// We don't need to generate code for this function, just report errors in its body.
// At this point we've generated any errors needed.
// (Beyond here we generate only non-spec errors, like "stack frame too large".)
// phase of the compiler.
for _, n := range fn.Func.Dcl {
switch n.Class() {
- case PPARAM, PPARAMOUT, PAUTO:
+ case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
if livenessShouldTrack(n) && n.Name.Addrtaken() {
dtypesym(n.Type)
// Also make sure we allocate a linker symbol
// for the stack object data, for the same reason.
- if fn.Func.lsym.Func().StackObjects == nil {
- fn.Func.lsym.Func().StackObjects = base.Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
+ if fn.Func.LSym.Func().StackObjects == nil {
+ fn.Func.LSym.Func().StackObjects = base.Ctxt.Lookup(fn.Func.LSym.Name + ".stkobj")
}
}
}
// If functions are not compiled immediately,
// they are enqueued in compilequeue,
// which is drained by compileFunctions.
-func compilenow(fn *Node) bool {
+func compilenow(fn *ir.Node) bool {
// Issue 38068: if this function is a method AND an inline
// candidate AND was not inlined (yet), put it onto the compile
// queue instead of compiling it immediately. This is in case we
// wind up inlining it into a method wrapper that is generated by
// compiling a function later on in the xtop list.
- if fn.IsMethod() && isInlinableButNotInlined(fn) {
+ if ir.IsMethod(fn) && isInlinableButNotInlined(fn) {
return false
}
return base.Flag.LowerC == 1 && base.Debug.CompileLater == 0
// isInlinableButNotInlined returns true if 'fn' was marked as an
// inline candidate but then never inlined (presumably because we
// found no call sites).
-func isInlinableButNotInlined(fn *Node) bool {
+func isInlinableButNotInlined(fn *ir.Node) bool {
if fn.Func.Nname.Func.Inl == nil {
return false
}
// uses it to generate a plist,
// and flushes that plist to machine code.
// worker indicates which of the backend workers is doing the processing.
-func compileSSA(fn *Node, worker int) {
+func compileSSA(fn *ir.Node, worker int) {
f := buildssa(fn, worker)
// Note: check arg size to fix issue 25507.
if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize {
sizeCalculationDisabled = true // not safe to calculate sizes concurrently
if race.Enabled {
// Randomize compilation order to try to shake out races.
- tmp := make([]*Node, len(compilequeue))
+ tmp := make([]*ir.Node, len(compilequeue))
perm := rand.Perm(len(compilequeue))
for i, v := range perm {
tmp[v] = compilequeue[i]
}
var wg sync.WaitGroup
base.Ctxt.InParallel = true
- c := make(chan *Node, base.Flag.LowerC)
+ c := make(chan *ir.Node, base.Flag.LowerC)
for i := 0; i < base.Flag.LowerC; i++ {
wg.Add(1)
go func(worker int) {
}
func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
- fn := curfn.(*Node)
+ fn := curfn.(*ir.Node)
if fn.Func.Nname != nil {
if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
base.Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
//
// These two adjustments keep toolstash -cmp working for now.
// Deciding the right answer is, as they say, future work.
- isODCLFUNC := fn.Op == ODCLFUNC
+ isODCLFUNC := fn.Op == ir.ODCLFUNC
- var apdecls []*Node
+ var apdecls []*ir.Node
// Populate decls for fn.
if isODCLFUNC {
for _, n := range fn.Func.Dcl {
- if n.Op != ONAME { // might be OTYPE or OLITERAL
+ if n.Op != ir.ONAME { // might be OTYPE or OLITERAL
continue
}
switch n.Class() {
- case PAUTO:
+ case ir.PAUTO:
if !n.Name.Used() {
// Text == nil -> generating abstract function
if fnsym.Func().Text != nil {
}
continue
}
- case PPARAM, PPARAMOUT:
+ case ir.PPARAM, ir.PPARAMOUT:
default:
continue
}
}
fnsym.Func().Autot = nil
- var varScopes []ScopeID
+ var varScopes []ir.ScopeID
for _, decl := range decls {
pos := declPos(decl)
varScopes = append(varScopes, findScope(fn.Func.Marks, pos))
return scopes, inlcalls
}
-func declPos(decl *Node) src.XPos {
+func declPos(decl *ir.Node) src.XPos {
if decl.Name.Defn != nil && (decl.Name.Captured() || decl.Name.Byval()) {
// It's not clear which position is correct for captured variables here:
// * decl.Pos is the wrong position for captured variables, in the inner
// createSimpleVars creates a DWARF entry for every variable declared in the
// function, claiming that they are permanently on the stack.
-func createSimpleVars(fnsym *obj.LSym, apDecls []*Node) ([]*Node, []*dwarf.Var, map[*Node]bool) {
+func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Node) ([]*ir.Node, []*dwarf.Var, map[*ir.Node]bool) {
var vars []*dwarf.Var
- var decls []*Node
- selected := make(map[*Node]bool)
+ var decls []*ir.Node
+ selected := make(map[*ir.Node]bool)
for _, n := range apDecls {
if n.IsAutoTmp() {
continue
return decls, vars, selected
}
-func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
+func createSimpleVar(fnsym *obj.LSym, n *ir.Node) *dwarf.Var {
var abbrev int
offs := n.Xoffset
switch n.Class() {
- case PAUTO:
+ case ir.PAUTO:
abbrev = dwarf.DW_ABRV_AUTO
if base.Ctxt.FixedFrameSize() == 0 {
offs -= int64(Widthptr)
offs -= int64(Widthptr)
}
- case PPARAM, PPARAMOUT:
+ case ir.PPARAM, ir.PPARAMOUT:
abbrev = dwarf.DW_ABRV_PARAM
offs += base.Ctxt.FixedFrameSize()
default:
declpos := base.Ctxt.InnermostPos(declPos(n))
return &dwarf.Var{
Name: n.Sym.Name,
- IsReturnValue: n.Class() == PPARAMOUT,
+ IsReturnValue: n.Class() == ir.PPARAMOUT,
IsInlFormal: n.Name.InlFormal(),
Abbrev: abbrev,
StackOffset: int32(offs),
// createComplexVars creates recomposed DWARF vars with location lists,
// suitable for describing optimized code.
-func createComplexVars(fnsym *obj.LSym, fn *Func) ([]*Node, []*dwarf.Var, map[*Node]bool) {
+func createComplexVars(fnsym *obj.LSym, fn *ir.Func) ([]*ir.Node, []*dwarf.Var, map[*ir.Node]bool) {
debugInfo := fn.DebugInfo
// Produce a DWARF variable entry for each user variable.
- var decls []*Node
+ var decls []*ir.Node
var vars []*dwarf.Var
- ssaVars := make(map[*Node]bool)
+ ssaVars := make(map[*ir.Node]bool)
for varID, dvar := range debugInfo.Vars {
- n := dvar.(*Node)
+ n := dvar.(*ir.Node)
ssaVars[n] = true
for _, slot := range debugInfo.VarSlots[varID] {
- ssaVars[debugInfo.Slots[slot].N.(*Node)] = true
+ ssaVars[debugInfo.Slots[slot].N.(*ir.Node)] = true
}
if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID)); dvar != nil {
// createDwarfVars process fn, returning a list of DWARF variables and the
// Nodes they represent.
-func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *Func, apDecls []*Node) ([]*Node, []*dwarf.Var) {
+func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir.Node) ([]*ir.Node, []*dwarf.Var) {
// Collect a raw list of DWARF vars.
var vars []*dwarf.Var
- var decls []*Node
- var selected map[*Node]bool
+ var decls []*ir.Node
+ var selected map[*ir.Node]bool
if base.Ctxt.Flag_locationlists && base.Ctxt.Flag_optimize && fn.DebugInfo != nil && complexOK {
decls, vars, selected = createComplexVars(fnsym, fn)
} else {
if c == '.' || n.Type.IsUntyped() {
continue
}
- if n.Class() == PPARAM && !canSSAType(n.Type) {
+ if n.Class() == ir.PPARAM && !canSSAType(n.Type) {
// SSA-able args get location lists, and may move in and
// out of registers, so those are handled elsewhere.
// Autos and named output params seem to get handled
typename := dwarf.InfoPrefix + typesymname(n.Type)
decls = append(decls, n)
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
- isReturnValue := (n.Class() == PPARAMOUT)
- if n.Class() == PPARAM || n.Class() == PPARAMOUT {
+ isReturnValue := (n.Class() == ir.PPARAMOUT)
+ if n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
- } else if n.Class() == PAUTOHEAP {
+ } else if n.Class() == ir.PAUTOHEAP {
// If dcl in question has been promoted to heap, do a bit
// of extra work to recover original class (auto or param);
// see issue 30908. This insures that we get the proper
// and not stack).
// TODO(thanm): generate a better location expression
stackcopy := n.Name.Param.Stackcopy
- if stackcopy != nil && (stackcopy.Class() == PPARAM || stackcopy.Class() == PPARAMOUT) {
+ if stackcopy != nil && (stackcopy.Class() == ir.PPARAM || stackcopy.Class() == ir.PPARAMOUT) {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
- isReturnValue = (stackcopy.Class() == PPARAMOUT)
+ isReturnValue = (stackcopy.Class() == ir.PPARAMOUT)
}
}
inlIndex := 0
// function that is not local to the package being compiled, then the
// names of the variables may have been "versioned" to avoid conflicts
// with local vars; disregard this versioning when sorting.
-func preInliningDcls(fnsym *obj.LSym) []*Node {
- fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node)
- var rdcl []*Node
+func preInliningDcls(fnsym *obj.LSym) []*ir.Node {
+ fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*ir.Node)
+ var rdcl []*ir.Node
for _, n := range fn.Func.Inl.Dcl {
c := n.Sym.Name[0]
// Avoid reporting "_" parameters, since if there are more than
// stack pointer, suitable for use in a DWARF location entry. This has nothing
// to do with its offset in the user variable.
func stackOffset(slot ssa.LocalSlot) int32 {
- n := slot.N.(*Node)
+ n := slot.N.(*ir.Node)
var off int64
switch n.Class() {
- case PAUTO:
+ case ir.PAUTO:
if base.Ctxt.FixedFrameSize() == 0 {
off -= int64(Widthptr)
}
// There is a word space for FP on ARM64 even if the frame pointer is disabled
off -= int64(Widthptr)
}
- case PPARAM, PPARAMOUT:
+ case ir.PPARAM, ir.PPARAMOUT:
off += base.Ctxt.FixedFrameSize()
}
return int32(off + n.Xoffset + slot.Off)
}
// createComplexVar builds a single DWARF variable entry and location list.
-func createComplexVar(fnsym *obj.LSym, fn *Func, varID ssa.VarID) *dwarf.Var {
+func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var {
debug := fn.DebugInfo
- n := debug.Vars[varID].(*Node)
+ n := debug.Vars[varID].(*ir.Node)
var abbrev int
switch n.Class() {
- case PAUTO:
+ case ir.PAUTO:
abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
- case PPARAM, PPARAMOUT:
+ case ir.PPARAM, ir.PPARAMOUT:
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
default:
return nil
declpos := base.Ctxt.InnermostPos(n.Pos)
dvar := &dwarf.Var{
Name: n.Sym.Name,
- IsReturnValue: n.Class() == PPARAMOUT,
+ IsReturnValue: n.Class() == ir.PPARAMOUT,
IsInlFormal: n.Name.InlFormal(),
Abbrev: abbrev,
Type: base.Ctxt.Lookup(typename),
package gc
import (
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"reflect"
"sort"
)
func typeWithoutPointers() *types.Type {
- t := types.New(TSTRUCT)
- f := &types.Field{Type: types.New(TINT)}
+ t := types.New(types.TSTRUCT)
+ f := &types.Field{Type: types.New(types.TINT)}
t.SetFields([]*types.Field{f})
return t
}
func typeWithPointers() *types.Type {
- t := types.New(TSTRUCT)
- f := &types.Field{Type: types.NewPtr(types.New(TINT))}
+ t := types.New(types.TSTRUCT)
+ f := &types.Field{Type: types.NewPtr(types.New(types.TINT))}
t.SetFields([]*types.Field{f})
return t
}
-func markUsed(n *Node) *Node {
+func markUsed(n *ir.Node) *ir.Node {
n.Name.SetUsed(true)
return n
}
-func markNeedZero(n *Node) *Node {
+func markNeedZero(n *ir.Node) *ir.Node {
n.Name.SetNeedzero(true)
return n
}
// Test all code paths for cmpstackvarlt.
func TestCmpstackvar(t *testing.T) {
- nod := func(xoffset int64, t *types.Type, s *types.Sym, cl Class) *Node {
+ nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Node {
if s == nil {
s = &types.Sym{Name: "."}
}
- n := newname(s)
+ n := NewName(s)
n.Type = t
n.Xoffset = xoffset
n.SetClass(cl)
return n
}
testdata := []struct {
- a, b *Node
+ a, b *ir.Node
lt bool
}{
{
- nod(0, nil, nil, PAUTO),
- nod(0, nil, nil, PFUNC),
+ nod(0, nil, nil, ir.PAUTO),
+ nod(0, nil, nil, ir.PFUNC),
false,
},
{
- nod(0, nil, nil, PFUNC),
- nod(0, nil, nil, PAUTO),
+ nod(0, nil, nil, ir.PFUNC),
+ nod(0, nil, nil, ir.PAUTO),
true,
},
{
- nod(0, nil, nil, PFUNC),
- nod(10, nil, nil, PFUNC),
+ nod(0, nil, nil, ir.PFUNC),
+ nod(10, nil, nil, ir.PFUNC),
true,
},
{
- nod(20, nil, nil, PFUNC),
- nod(10, nil, nil, PFUNC),
+ nod(20, nil, nil, ir.PFUNC),
+ nod(10, nil, nil, ir.PFUNC),
false,
},
{
- nod(10, nil, nil, PFUNC),
- nod(10, nil, nil, PFUNC),
+ nod(10, nil, nil, ir.PFUNC),
+ nod(10, nil, nil, ir.PFUNC),
false,
},
{
- nod(10, nil, nil, PPARAM),
- nod(20, nil, nil, PPARAMOUT),
+ nod(10, nil, nil, ir.PPARAM),
+ nod(20, nil, nil, ir.PPARAMOUT),
true,
},
{
- nod(10, nil, nil, PPARAMOUT),
- nod(20, nil, nil, PPARAM),
+ nod(10, nil, nil, ir.PPARAMOUT),
+ nod(20, nil, nil, ir.PPARAM),
true,
},
{
- markUsed(nod(0, nil, nil, PAUTO)),
- nod(0, nil, nil, PAUTO),
+ markUsed(nod(0, nil, nil, ir.PAUTO)),
+ nod(0, nil, nil, ir.PAUTO),
true,
},
{
- nod(0, nil, nil, PAUTO),
- markUsed(nod(0, nil, nil, PAUTO)),
+ nod(0, nil, nil, ir.PAUTO),
+ markUsed(nod(0, nil, nil, ir.PAUTO)),
false,
},
{
- nod(0, typeWithoutPointers(), nil, PAUTO),
- nod(0, typeWithPointers(), nil, PAUTO),
+ nod(0, typeWithoutPointers(), nil, ir.PAUTO),
+ nod(0, typeWithPointers(), nil, ir.PAUTO),
false,
},
{
- nod(0, typeWithPointers(), nil, PAUTO),
- nod(0, typeWithoutPointers(), nil, PAUTO),
+ nod(0, typeWithPointers(), nil, ir.PAUTO),
+ nod(0, typeWithoutPointers(), nil, ir.PAUTO),
true,
},
{
- markNeedZero(nod(0, &types.Type{}, nil, PAUTO)),
- nod(0, &types.Type{}, nil, PAUTO),
+ markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
+ nod(0, &types.Type{}, nil, ir.PAUTO),
true,
},
{
- nod(0, &types.Type{}, nil, PAUTO),
- markNeedZero(nod(0, &types.Type{}, nil, PAUTO)),
+ nod(0, &types.Type{}, nil, ir.PAUTO),
+ markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
false,
},
{
- nod(0, &types.Type{Width: 1}, nil, PAUTO),
- nod(0, &types.Type{Width: 2}, nil, PAUTO),
+ nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
+ nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
false,
},
{
- nod(0, &types.Type{Width: 2}, nil, PAUTO),
- nod(0, &types.Type{Width: 1}, nil, PAUTO),
+ nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
+ nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
true,
},
{
- nod(0, &types.Type{}, &types.Sym{Name: "abc"}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
true,
},
{
- nod(0, &types.Type{}, &types.Sym{Name: "abc"}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{Name: "abc"}, PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
false,
},
{
- nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{Name: "abc"}, PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
false,
},
}
}
func TestStackvarSort(t *testing.T) {
- nod := func(xoffset int64, t *types.Type, s *types.Sym, cl Class) *Node {
- n := newname(s)
+ nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Node {
+ n := NewName(s)
n.Type = t
n.Xoffset = xoffset
n.SetClass(cl)
return n
}
- inp := []*Node{
- nod(0, &types.Type{}, &types.Sym{}, PFUNC),
- nod(0, &types.Type{}, &types.Sym{}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{}, PFUNC),
- nod(10, &types.Type{}, &types.Sym{}, PFUNC),
- nod(20, &types.Type{}, &types.Sym{}, PFUNC),
- markUsed(nod(0, &types.Type{}, &types.Sym{}, PAUTO)),
- nod(0, typeWithoutPointers(), &types.Sym{}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{}, PAUTO),
- markNeedZero(nod(0, &types.Type{}, &types.Sym{}, PAUTO)),
- nod(0, &types.Type{Width: 1}, &types.Sym{}, PAUTO),
- nod(0, &types.Type{Width: 2}, &types.Sym{}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{Name: "abc"}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, PAUTO),
+ inp := []*ir.Node{
+ nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
+ nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
+ nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
+ nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
+ markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
+ nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
+ markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
+ nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
+ nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
}
- want := []*Node{
- nod(0, &types.Type{}, &types.Sym{}, PFUNC),
- nod(0, &types.Type{}, &types.Sym{}, PFUNC),
- nod(10, &types.Type{}, &types.Sym{}, PFUNC),
- nod(20, &types.Type{}, &types.Sym{}, PFUNC),
- markUsed(nod(0, &types.Type{}, &types.Sym{}, PAUTO)),
- markNeedZero(nod(0, &types.Type{}, &types.Sym{}, PAUTO)),
- nod(0, &types.Type{Width: 2}, &types.Sym{}, PAUTO),
- nod(0, &types.Type{Width: 1}, &types.Sym{}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{Name: "abc"}, PAUTO),
- nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, PAUTO),
- nod(0, typeWithoutPointers(), &types.Sym{}, PAUTO),
+ want := []*ir.Node{
+ nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
+ nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
+ nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
+ nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
+ markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
+ markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
+ nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
+ nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
+ nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
+ nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
}
sort.Sort(byStackVar(inp))
if !reflect.DeepEqual(want, inp) {
package gc
import (
+ "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/src"
}
type phiState struct {
- s *state // SSA state
- f *ssa.Func // function to work on
- defvars []map[*Node]*ssa.Value // defined variables at end of each block
+ s *state // SSA state
+ f *ssa.Func // function to work on
+ defvars []map[*ir.Node]*ssa.Value // defined variables at end of each block
- varnum map[*Node]int32 // variable numbering
+ varnum map[*ir.Node]int32 // variable numbering
// properties of the dominator tree
idom []*ssa.Block // dominator parents
// Find all the variables for which we need to match up reads & writes.
// This step prunes any basic-block-only variables from consideration.
// Generate a numbering for these variables.
- s.varnum = map[*Node]int32{}
- var vars []*Node
+ s.varnum = map[*ir.Node]int32{}
+ var vars []*ir.Node
var vartypes []*types.Type
for _, b := range s.f.Blocks {
for _, v := range b.Values {
if v.Op != ssa.OpFwdRef {
continue
}
- var_ := v.Aux.(*Node)
+ var_ := v.Aux.(*ir.Node)
// Optimization: look back 1 block for the definition.
if len(b.Preds) == 1 {
}
}
-func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ *types.Type) {
+func (s *phiState) insertVarPhis(n int, var_ *ir.Node, defs []*ssa.Block, typ *types.Type) {
priq := &s.priq
q := s.q
queued := s.queued
if v.Op != ssa.OpFwdRef {
continue
}
- n := s.varnum[v.Aux.(*Node)]
+ n := s.varnum[v.Aux.(*ir.Node)]
v.Op = ssa.OpCopy
v.Aux = nil
v.AddArg(values[n])
// Variant to use for small functions.
type simplePhiState struct {
- s *state // SSA state
- f *ssa.Func // function to work on
- fwdrefs []*ssa.Value // list of FwdRefs to be processed
- defvars []map[*Node]*ssa.Value // defined variables at end of each block
- reachable []bool // which blocks are reachable
+ s *state // SSA state
+ f *ssa.Func // function to work on
+ fwdrefs []*ssa.Value // list of FwdRefs to be processed
+ defvars []map[*ir.Node]*ssa.Value // defined variables at end of each block
+ reachable []bool // which blocks are reachable
}
func (s *simplePhiState) insertPhis() {
continue
}
s.fwdrefs = append(s.fwdrefs, v)
- var_ := v.Aux.(*Node)
+ var_ := v.Aux.(*ir.Node)
if _, ok := s.defvars[b.ID][var_]; !ok {
s.defvars[b.ID][var_] = v // treat FwdDefs as definitions.
}
v := s.fwdrefs[len(s.fwdrefs)-1]
s.fwdrefs = s.fwdrefs[:len(s.fwdrefs)-1]
b := v.Block
- var_ := v.Aux.(*Node)
+ var_ := v.Aux.(*ir.Node)
if b == s.f.Entry {
// No variable should be live at entry.
s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v)
}
// lookupVarOutgoing finds the variable's value at the end of block b.
-func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ *Node, line src.XPos) *ssa.Value {
+func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ *ir.Node, line src.XPos) *ssa.Value {
for {
if v := s.defvars[b.ID][var_]; v != nil {
return v
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/obj"
// A collection of global state used by liveness analysis.
type Liveness struct {
- fn *Node
+ fn *ir.Node
f *ssa.Func
- vars []*Node
- idx map[*Node]int32
+ vars []*ir.Node
+ idx map[*ir.Node]int32
stkptrsize int64
be []BlockEffects
// nor do we care about non-local variables,
// nor do we care about empty structs (handled by the pointer check),
// nor do we care about the fake PAUTOHEAP variables.
-func livenessShouldTrack(n *Node) bool {
- return n.Op == ONAME && (n.Class() == PAUTO || n.Class() == PPARAM || n.Class() == PPARAMOUT) && n.Type.HasPointers()
+func livenessShouldTrack(n *ir.Node) bool {
+ return n.Op == ir.ONAME && (n.Class() == ir.PAUTO || n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT) && n.Type.HasPointers()
}
// getvariables returns the list of on-stack variables that we need to track
// and a map for looking up indices by *Node.
-func getvariables(fn *Node) ([]*Node, map[*Node]int32) {
- var vars []*Node
+func getvariables(fn *ir.Node) ([]*ir.Node, map[*ir.Node]int32) {
+ var vars []*ir.Node
for _, n := range fn.Func.Dcl {
if livenessShouldTrack(n) {
vars = append(vars, n)
}
}
- idx := make(map[*Node]int32, len(vars))
+ idx := make(map[*ir.Node]int32, len(vars))
for i, n := range vars {
idx[n] = int32(i)
}
for i, node := range lv.vars {
switch node.Class() {
- case PPARAM:
+ case ir.PPARAM:
// A return instruction with a p.to is a tail return, which brings
// the stack pointer back up (if it ever went down) and then jumps
// to a new function entirely. That form of instruction must read
// function runs.
lv.cache.tailuevar = append(lv.cache.tailuevar, int32(i))
- case PPARAMOUT:
+ case ir.PPARAMOUT:
// All results are live at every return point.
// Note that this point is after escaping return values
// are copied back to the stack using their PAUTOHEAP references.
// If v does not affect any tracked variables, it returns -1, 0.
func (lv *Liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
n, e := affectedNode(v)
- if e == 0 || n == nil || n.Op != ONAME { // cheapest checks first
+ if e == 0 || n == nil || n.Op != ir.ONAME { // cheapest checks first
return -1, 0
}
}
// affectedNode returns the *Node affected by v
-func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
+func affectedNode(v *ssa.Value) (*ir.Node, ssa.SymEffect) {
// Special cases.
switch v.Op {
case ssa.OpLoadReg:
return n, ssa.SymWrite
case ssa.OpVarLive:
- return v.Aux.(*Node), ssa.SymRead
+ return v.Aux.(*ir.Node), ssa.SymRead
case ssa.OpVarDef, ssa.OpVarKill:
- return v.Aux.(*Node), ssa.SymWrite
+ return v.Aux.(*ir.Node), ssa.SymWrite
case ssa.OpKeepAlive:
n, _ := AutoVar(v.Args[0])
return n, ssa.SymRead
case nil, *obj.LSym:
// ok, but no node
return nil, e
- case *Node:
+ case *ir.Node:
return a, e
default:
base.Fatalf("weird aux: %s", v.LongString())
// Constructs a new liveness structure used to hold the global state of the
// liveness computation. The cfg argument is a slice of *BasicBlocks and the
// vars argument is a slice of *Nodes.
-func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkptrsize int64) *Liveness {
+func newliveness(fn *ir.Node, f *ssa.Func, vars []*ir.Node, idx map[*ir.Node]int32, stkptrsize int64) *Liveness {
lv := &Liveness{
fn: fn,
f: f,
}
switch t.Etype {
- case TPTR, TUNSAFEPTR, TFUNC, TCHAN, TMAP:
+ case types.TPTR, types.TUNSAFEPTR, types.TFUNC, types.TCHAN, types.TMAP:
if off&int64(Widthptr-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
bv.Set(int32(off / int64(Widthptr))) // pointer
- case TSTRING:
+ case types.TSTRING:
// struct { byte *str; intgo len; }
if off&int64(Widthptr-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
bv.Set(int32(off / int64(Widthptr))) //pointer in first slot
- case TINTER:
+ case types.TINTER:
// struct { Itab *tab; void *data; }
// or, when isnilinter(t)==true:
// struct { Type *type; void *data; }
// well as scan itabs to update their itab._type fields).
bv.Set(int32(off/int64(Widthptr) + 1)) // pointer in second slot
- case TSLICE:
+ case types.TSLICE:
// struct { byte *array; uintgo len; uintgo cap; }
if off&int64(Widthptr-1) != 0 {
base.Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
}
bv.Set(int32(off / int64(Widthptr))) // pointer in first slot (BitsPointer)
- case TARRAY:
+ case types.TARRAY:
elt := t.Elem()
if elt.Width == 0 {
// Short-circuit for #20739.
off += elt.Width
}
- case TSTRUCT:
+ case types.TSTRUCT:
for _, f := range t.Fields().Slice() {
onebitwalktype1(f.Type, off+f.Offset, bv)
}
// Generates live pointer value maps for arguments and local variables. The
// this argument and the in arguments are always assumed live. The vars
// argument is a slice of *Nodes.
-func (lv *Liveness) pointerMap(liveout bvec, vars []*Node, args, locals bvec) {
+func (lv *Liveness) pointerMap(liveout bvec, vars []*ir.Node, args, locals bvec) {
for i := int32(0); ; i++ {
i = liveout.Next(i)
if i < 0 {
}
node := vars[i]
switch node.Class() {
- case PAUTO:
+ case ir.PAUTO:
onebitwalktype1(node.Type, node.Xoffset+lv.stkptrsize, locals)
- case PPARAM, PPARAMOUT:
+ case ir.PPARAM, ir.PPARAMOUT:
onebitwalktype1(node.Type, node.Xoffset, args)
}
}
// don't need to keep the stack copy live?
if lv.fn.Func.HasDefer() {
for i, n := range lv.vars {
- if n.Class() == PPARAMOUT {
+ if n.Class() == ir.PPARAMOUT {
if n.Name.IsOutputParamHeapAddr() {
// Just to be paranoid. Heap addresses are PAUTOs.
base.Fatalf("variable %v both output param and heap output param", n)
if !liveout.Get(int32(i)) {
continue
}
- if n.Class() == PPARAM {
+ if n.Class() == ir.PPARAM {
continue // ok
}
base.Fatalf("bad live variable at entry of %v: %L", lv.fn.Func.Nname, n)
// the only things that can possibly be live are the
// input parameters.
for j, n := range lv.vars {
- if n.Class() != PPARAM && lv.stackMaps[0].Get(int32(j)) {
+ if n.Class() != ir.PPARAM && lv.stackMaps[0].Get(int32(j)) {
lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Func.Nname, n)
}
}
}
func (lv *Liveness) showlive(v *ssa.Value, live bvec) {
- if base.Flag.Live == 0 || lv.fn.funcname() == "init" || strings.HasPrefix(lv.fn.funcname(), ".") {
+ if base.Flag.Live == 0 || ir.FuncName(lv.fn) == "init" || strings.HasPrefix(ir.FuncName(lv.fn), ".") {
return
}
if !(v == nil || v.Op.IsCall()) {
s := "live at "
if v == nil {
- s += fmt.Sprintf("entry to %s:", lv.fn.funcname())
+ s += fmt.Sprintf("entry to %s:", ir.FuncName(lv.fn))
} else if sym, ok := v.Aux.(*ssa.AuxCall); ok && sym.Fn != nil {
fn := sym.Fn.Name
if pos := strings.Index(fn, "."); pos >= 0 {
// This format synthesizes the information used during the multiple passes
// into a single presentation.
func (lv *Liveness) printDebug() {
- fmt.Printf("liveness: %s\n", lv.fn.funcname())
+ fmt.Printf("liveness: %s\n", ir.FuncName(lv.fn))
for i, b := range lv.f.Blocks {
if i > 0 {
// Size args bitmaps to be just large enough to hold the largest pointer.
// First, find the largest Xoffset node we care about.
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
- var maxArgNode *Node
+ var maxArgNode *ir.Node
for _, n := range lv.vars {
switch n.Class() {
- case PPARAM, PPARAMOUT:
+ case ir.PPARAM, ir.PPARAMOUT:
if maxArgNode == nil || n.Xoffset > maxArgNode.Xoffset {
maxArgNode = n
}
}
// Emit the live pointer map data structures
- ls := e.curfn.Func.lsym
+ ls := e.curfn.Func.LSym
fninfo := ls.Func()
fninfo.GCArgs, fninfo.GCLocals = lv.emit()
func isfat(t *types.Type) bool {
if t != nil {
switch t.Etype {
- case TSLICE, TSTRING,
- TINTER: // maybe remove later
+ case types.TSLICE, types.TSTRING,
+ types.TINTER: // maybe remove later
return true
- case TARRAY:
+ case types.TARRAY:
// Array of 1 element, check if element is fat
if t.NumElem() == 1 {
return isfat(t.Elem())
}
return true
- case TSTRUCT:
+ case types.TSTRUCT:
// Struct with 1 field, check if field is fat
if t.NumFields() == 1 {
return isfat(t.Field(0).Type)
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"cmd/internal/sys"
return false
}
-func instrument(fn *Node) {
- if fn.Func.Pragma&Norace != 0 {
+func instrument(fn *ir.Node) {
+ if fn.Func.Pragma&ir.Norace != 0 {
return
}
// This only works for amd64. This will not
// work on arm or others that might support
// race in the future.
- nodpc := nodfp.copy()
- nodpc.Type = types.Types[TUINTPTR]
+ nodpc := ir.Copy(nodfp)
+ nodpc.Type = types.Types[types.TUINTPTR]
nodpc.Xoffset = int64(-Widthptr)
fn.Func.Dcl = append(fn.Func.Dcl, nodpc)
fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc))
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/sys"
"unicode/utf8"
)
// range
-func typecheckrange(n *Node) {
+func typecheckrange(n *ir.Node) {
// Typechecking order is important here:
// 0. first typecheck range expression (slice/map/chan),
// it is evaluated only once and so logically it is not part of the loop.
decldepth--
}
-func typecheckrangeExpr(n *Node) {
+func typecheckrangeExpr(n *ir.Node) {
n.Right = typecheck(n.Right, ctxExpr)
t := n.Right.Type
base.ErrorfAt(n.Pos, "cannot range over %L", n.Right)
return
- case TARRAY, TSLICE:
- t1 = types.Types[TINT]
+ case types.TARRAY, types.TSLICE:
+ t1 = types.Types[types.TINT]
t2 = t.Elem()
- case TMAP:
+ case types.TMAP:
t1 = t.Key()
t2 = t.Elem()
- case TCHAN:
+ case types.TCHAN:
if !t.ChanDir().CanRecv() {
base.ErrorfAt(n.Pos, "invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
return
toomany = true
}
- case TSTRING:
- t1 = types.Types[TINT]
+ case types.TSTRING:
+ t1 = types.Types[types.TINT]
t2 = types.Runetype
}
base.ErrorfAt(n.Pos, "too many variables in range")
}
- var v1, v2 *Node
+ var v1, v2 *ir.Node
if n.List.Len() != 0 {
v1 = n.List.First()
}
// "if the second iteration variable is the blank identifier, the range
// clause is equivalent to the same clause with only the first variable
// present."
- if v2.isBlank() {
+ if ir.IsBlank(v2) {
if v1 != nil {
n.List.Set1(v1)
}
if v1.Name != nil && v1.Name.Defn == n {
v1.Type = t1
} else if v1.Type != nil {
- if op, why := assignop(t1, v1.Type); op == OXXX {
+ if op, why := assignop(t1, v1.Type); op == ir.OXXX {
base.ErrorfAt(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
}
}
if v2.Name != nil && v2.Name.Defn == n {
v2.Type = t2
} else if v2.Type != nil {
- if op, why := assignop(t2, v2.Type); op == OXXX {
+ if op, why := assignop(t2, v2.Type); op == ir.OXXX {
base.ErrorfAt(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
}
}
// simpler forms. The result must be assigned back to n.
// Node n may also be modified in place, and may also be
// the returned node.
-func walkrange(n *Node) *Node {
+func walkrange(n *ir.Node) *ir.Node {
if isMapClear(n) {
m := n.Right
lno := setlineno(m)
lno := setlineno(a)
n.Right = nil
- var v1, v2 *Node
+ var v1, v2 *ir.Node
l := n.List.Len()
if l > 0 {
v1 = n.List.First()
v2 = n.List.Second()
}
- if v2.isBlank() {
+ if ir.IsBlank(v2) {
v2 = nil
}
- if v1.isBlank() && v2 == nil {
+ if ir.IsBlank(v1) && v2 == nil {
v1 = nil
}
// to avoid erroneous processing by racewalk.
n.List.Set(nil)
- var ifGuard *Node
+ var ifGuard *ir.Node
- translatedLoopOp := OFOR
+ translatedLoopOp := ir.OFOR
- var body []*Node
- var init []*Node
+ var body []*ir.Node
+ var init []*ir.Node
switch t.Etype {
default:
base.Fatalf("walkrange")
- case TARRAY, TSLICE:
+ case types.TARRAY, types.TSLICE:
if arrayClear(n, v1, v2, a) {
base.Pos = lno
return n
// order.stmt arranged for a copy of the array/slice variable if needed.
ha := a
- hv1 := temp(types.Types[TINT])
- hn := temp(types.Types[TINT])
+ hv1 := temp(types.Types[types.TINT])
+ hn := temp(types.Types[types.TINT])
- init = append(init, nod(OAS, hv1, nil))
- init = append(init, nod(OAS, hn, nod(OLEN, ha, nil)))
+ init = append(init, ir.Nod(ir.OAS, hv1, nil))
+ init = append(init, ir.Nod(ir.OAS, hn, ir.Nod(ir.OLEN, ha, nil)))
- n.Left = nod(OLT, hv1, hn)
- n.Right = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)))
+ n.Left = ir.Nod(ir.OLT, hv1, hn)
+ n.Right = ir.Nod(ir.OAS, hv1, ir.Nod(ir.OADD, hv1, nodintconst(1)))
// for range ha { body }
if v1 == nil {
// for v1 := range ha { body }
if v2 == nil {
- body = []*Node{nod(OAS, v1, hv1)}
+ body = []*ir.Node{ir.Nod(ir.OAS, v1, hv1)}
break
}
// for v1, v2 := range ha { body }
if cheapComputableIndex(n.Type.Elem().Width) {
// v1, v2 = hv1, ha[hv1]
- tmp := nod(OINDEX, ha, hv1)
+ tmp := ir.Nod(ir.OINDEX, ha, hv1)
tmp.SetBounded(true)
// Use OAS2 to correctly handle assignments
// of the form "v1, a[v1] := range".
- a := nod(OAS2, nil, nil)
+ a := ir.Nod(ir.OAS2, nil, nil)
a.List.Set2(v1, v2)
a.Rlist.Set2(hv1, tmp)
- body = []*Node{a}
+ body = []*ir.Node{a}
break
}
// TODO(austin): OFORUNTIL inhibits bounds-check
// elimination on the index variable (see #20711).
// Enhance the prove pass to understand this.
- ifGuard = nod(OIF, nil, nil)
- ifGuard.Left = nod(OLT, hv1, hn)
- translatedLoopOp = OFORUNTIL
+ ifGuard = ir.Nod(ir.OIF, nil, nil)
+ ifGuard.Left = ir.Nod(ir.OLT, hv1, hn)
+ translatedLoopOp = ir.OFORUNTIL
hp := temp(types.NewPtr(n.Type.Elem()))
- tmp := nod(OINDEX, ha, nodintconst(0))
+ tmp := ir.Nod(ir.OINDEX, ha, nodintconst(0))
tmp.SetBounded(true)
- init = append(init, nod(OAS, hp, nod(OADDR, tmp, nil)))
+ init = append(init, ir.Nod(ir.OAS, hp, ir.Nod(ir.OADDR, tmp, nil)))
// Use OAS2 to correctly handle assignments
// of the form "v1, a[v1] := range".
- a := nod(OAS2, nil, nil)
+ a := ir.Nod(ir.OAS2, nil, nil)
a.List.Set2(v1, v2)
- a.Rlist.Set2(hv1, nod(ODEREF, hp, nil))
+ a.Rlist.Set2(hv1, ir.Nod(ir.ODEREF, hp, nil))
body = append(body, a)
// Advance pointer as part of the late increment.
// This runs *after* the condition check, so we know
// advancing the pointer is safe and won't go past the
// end of the allocation.
- a = nod(OAS, hp, addptr(hp, t.Elem().Width))
+ a = ir.Nod(ir.OAS, hp, addptr(hp, t.Elem().Width))
a = typecheck(a, ctxStmt)
n.List.Set1(a)
- case TMAP:
+ case types.TMAP:
// order.stmt allocated the iterator for us.
// we only use a once, so no copy needed.
ha := a
fn := syslook("mapiterinit")
fn = substArgTypes(fn, t.Key(), t.Elem(), th)
- init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nod(OADDR, hit, nil)))
- n.Left = nod(ONE, nodSym(ODOT, hit, keysym), nodnil())
+ init = append(init, mkcall1(fn, nil, nil, typename(t), ha, ir.Nod(ir.OADDR, hit, nil)))
+ n.Left = ir.Nod(ir.ONE, nodSym(ir.ODOT, hit, keysym), nodnil())
fn = syslook("mapiternext")
fn = substArgTypes(fn, th)
- n.Right = mkcall1(fn, nil, nil, nod(OADDR, hit, nil))
+ n.Right = mkcall1(fn, nil, nil, ir.Nod(ir.OADDR, hit, nil))
- key := nodSym(ODOT, hit, keysym)
- key = nod(ODEREF, key, nil)
+ key := nodSym(ir.ODOT, hit, keysym)
+ key = ir.Nod(ir.ODEREF, key, nil)
if v1 == nil {
body = nil
} else if v2 == nil {
- body = []*Node{nod(OAS, v1, key)}
+ body = []*ir.Node{ir.Nod(ir.OAS, v1, key)}
} else {
- elem := nodSym(ODOT, hit, elemsym)
- elem = nod(ODEREF, elem, nil)
- a := nod(OAS2, nil, nil)
+ elem := nodSym(ir.ODOT, hit, elemsym)
+ elem = ir.Nod(ir.ODEREF, elem, nil)
+ a := ir.Nod(ir.OAS2, nil, nil)
a.List.Set2(v1, v2)
a.Rlist.Set2(key, elem)
- body = []*Node{a}
+ body = []*ir.Node{a}
}
- case TCHAN:
+ case types.TCHAN:
// order.stmt arranged for a copy of the channel variable.
ha := a
hv1 := temp(t.Elem())
hv1.SetTypecheck(1)
if t.Elem().HasPointers() {
- init = append(init, nod(OAS, hv1, nil))
+ init = append(init, ir.Nod(ir.OAS, hv1, nil))
}
- hb := temp(types.Types[TBOOL])
+ hb := temp(types.Types[types.TBOOL])
- n.Left = nod(ONE, hb, nodbool(false))
- a := nod(OAS2RECV, nil, nil)
+ n.Left = ir.Nod(ir.ONE, hb, nodbool(false))
+ a := ir.Nod(ir.OAS2RECV, nil, nil)
a.SetTypecheck(1)
a.List.Set2(hv1, hb)
- a.Right = nod(ORECV, ha, nil)
+ a.Right = ir.Nod(ir.ORECV, ha, nil)
n.Left.Ninit.Set1(a)
if v1 == nil {
body = nil
} else {
- body = []*Node{nod(OAS, v1, hv1)}
+ body = []*ir.Node{ir.Nod(ir.OAS, v1, hv1)}
}
// Zero hv1. This prevents hv1 from being the sole, inaccessible
// reference to an otherwise GC-able value during the next channel receive.
// See issue 15281.
- body = append(body, nod(OAS, hv1, nil))
+ body = append(body, ir.Nod(ir.OAS, hv1, nil))
- case TSTRING:
+ case types.TSTRING:
// Transform string range statements like "for v1, v2 = range a" into
//
// ha := a
// order.stmt arranged for a copy of the string variable.
ha := a
- hv1 := temp(types.Types[TINT])
- hv1t := temp(types.Types[TINT])
+ hv1 := temp(types.Types[types.TINT])
+ hv1t := temp(types.Types[types.TINT])
hv2 := temp(types.Runetype)
// hv1 := 0
- init = append(init, nod(OAS, hv1, nil))
+ init = append(init, ir.Nod(ir.OAS, hv1, nil))
// hv1 < len(ha)
- n.Left = nod(OLT, hv1, nod(OLEN, ha, nil))
+ n.Left = ir.Nod(ir.OLT, hv1, ir.Nod(ir.OLEN, ha, nil))
if v1 != nil {
// hv1t = hv1
- body = append(body, nod(OAS, hv1t, hv1))
+ body = append(body, ir.Nod(ir.OAS, hv1t, hv1))
}
// hv2 := rune(ha[hv1])
- nind := nod(OINDEX, ha, hv1)
+ nind := ir.Nod(ir.OINDEX, ha, hv1)
nind.SetBounded(true)
- body = append(body, nod(OAS, hv2, conv(nind, types.Runetype)))
+ body = append(body, ir.Nod(ir.OAS, hv2, conv(nind, types.Runetype)))
// if hv2 < utf8.RuneSelf
- nif := nod(OIF, nil, nil)
- nif.Left = nod(OLT, hv2, nodintconst(utf8.RuneSelf))
+ nif := ir.Nod(ir.OIF, nil, nil)
+ nif.Left = ir.Nod(ir.OLT, hv2, nodintconst(utf8.RuneSelf))
// hv1++
- nif.Nbody.Set1(nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))))
+ nif.Nbody.Set1(ir.Nod(ir.OAS, hv1, ir.Nod(ir.OADD, hv1, nodintconst(1))))
// } else {
- eif := nod(OAS2, nil, nil)
+ eif := ir.Nod(ir.OAS2, nil, nil)
nif.Rlist.Set1(eif)
// hv2, hv1 = decoderune(ha, hv1)
if v1 != nil {
if v2 != nil {
// v1, v2 = hv1t, hv2
- a := nod(OAS2, nil, nil)
+ a := ir.Nod(ir.OAS2, nil, nil)
a.List.Set2(v1, v2)
a.Rlist.Set2(hv1t, hv2)
body = append(body, a)
} else {
// v1 = hv1t
- body = append(body, nod(OAS, v1, hv1t))
+ body = append(body, ir.Nod(ir.OAS, v1, hv1t))
}
}
}
// }
//
// where == for keys of map m is reflexive.
-func isMapClear(n *Node) bool {
+func isMapClear(n *ir.Node) bool {
if base.Flag.N != 0 || instrumenting {
return false
}
- if n.Op != ORANGE || n.Type.Etype != TMAP || n.List.Len() != 1 {
+ if n.Op != ir.ORANGE || n.Type.Etype != types.TMAP || n.List.Len() != 1 {
return false
}
k := n.List.First()
- if k == nil || k.isBlank() {
+ if k == nil || ir.IsBlank(k) {
return false
}
}
stmt := n.Nbody.First() // only stmt in body
- if stmt == nil || stmt.Op != ODELETE {
+ if stmt == nil || stmt.Op != ir.ODELETE {
return false
}
}
// mapClear constructs a call to runtime.mapclear for the map m.
-func mapClear(m *Node) *Node {
+func mapClear(m *ir.Node) *ir.Node {
t := m.Type
// instantiate mapclear(typ *type, hmap map[any]any)
// in which the evaluation of a is side-effect-free.
//
// Parameters are as in walkrange: "for v1, v2 = range a".
-func arrayClear(n, v1, v2, a *Node) bool {
+func arrayClear(n, v1, v2, a *ir.Node) bool {
if base.Flag.N != 0 || instrumenting {
return false
}
}
stmt := n.Nbody.First() // only stmt in body
- if stmt.Op != OAS || stmt.Left.Op != OINDEX {
+ if stmt.Op != ir.OAS || stmt.Left.Op != ir.OINDEX {
return false
}
// memclr{NoHeap,Has}Pointers(hp, hn)
// i = len(a) - 1
// }
- n.Op = OIF
+ n.Op = ir.OIF
n.Nbody.Set(nil)
- n.Left = nod(ONE, nod(OLEN, a, nil), nodintconst(0))
+ n.Left = ir.Nod(ir.ONE, ir.Nod(ir.OLEN, a, nil), nodintconst(0))
// hp = &a[0]
- hp := temp(types.Types[TUNSAFEPTR])
+ hp := temp(types.Types[types.TUNSAFEPTR])
- tmp := nod(OINDEX, a, nodintconst(0))
+ tmp := ir.Nod(ir.OINDEX, a, nodintconst(0))
tmp.SetBounded(true)
- tmp = nod(OADDR, tmp, nil)
- tmp = convnop(tmp, types.Types[TUNSAFEPTR])
- n.Nbody.Append(nod(OAS, hp, tmp))
+ tmp = ir.Nod(ir.OADDR, tmp, nil)
+ tmp = convnop(tmp, types.Types[types.TUNSAFEPTR])
+ n.Nbody.Append(ir.Nod(ir.OAS, hp, tmp))
// hn = len(a) * sizeof(elem(a))
- hn := temp(types.Types[TUINTPTR])
+ hn := temp(types.Types[types.TUINTPTR])
- tmp = nod(OLEN, a, nil)
- tmp = nod(OMUL, tmp, nodintconst(elemsize))
- tmp = conv(tmp, types.Types[TUINTPTR])
- n.Nbody.Append(nod(OAS, hn, tmp))
+ tmp = ir.Nod(ir.OLEN, a, nil)
+ tmp = ir.Nod(ir.OMUL, tmp, nodintconst(elemsize))
+ tmp = conv(tmp, types.Types[types.TUINTPTR])
+ n.Nbody.Append(ir.Nod(ir.OAS, hn, tmp))
- var fn *Node
+ var fn *ir.Node
if a.Type.Elem().HasPointers() {
// memclrHasPointers(hp, hn)
- Curfn.Func.setWBPos(stmt.Pos)
+ Curfn.Func.SetWBPos(stmt.Pos)
fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
} else {
// memclrNoHeapPointers(hp, hn)
n.Nbody.Append(fn)
// i = len(a) - 1
- v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, nil), nodintconst(1)))
+ v1 = ir.Nod(ir.OAS, v1, ir.Nod(ir.OSUB, ir.Nod(ir.OLEN, a, nil), nodintconst(1)))
n.Nbody.Append(v1)
}
// addptr returns (*T)(uintptr(p) + n).
-func addptr(p *Node, n int64) *Node {
+func addptr(p *ir.Node, n int64) *ir.Node {
t := p.Type
- p = nod(OCONVNOP, p, nil)
- p.Type = types.Types[TUINTPTR]
+ p = ir.Nod(ir.OCONVNOP, p, nil)
+ p.Type = types.Types[types.TUINTPTR]
- p = nod(OADD, p, nodintconst(n))
+ p = ir.Nod(ir.OADD, p, nodintconst(n))
- p = nod(OCONVNOP, p, nil)
+ p = ir.Nod(ir.OCONVNOP, p, nil)
p.Type = t
return p
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/gcprog"
"cmd/internal/obj"
return t.MapType().Bucket
}
- bucket := types.New(TSTRUCT)
+ bucket := types.New(types.TSTRUCT)
keytype := t.Key()
elemtype := t.Elem()
dowidth(keytype)
field := make([]*types.Field, 0, 5)
// The first field is: uint8 topbits[BUCKETSIZE].
- arr := types.NewArray(types.Types[TUINT8], BUCKETSIZE)
+ arr := types.NewArray(types.Types[types.TUINT8], BUCKETSIZE)
field = append(field, makefield("topbits", arr))
arr = types.NewArray(keytype, BUCKETSIZE)
// See comment on hmap.overflow in runtime/map.go.
otyp := types.NewPtr(bucket)
if !elemtype.HasPointers() && !keytype.HasPointers() {
- otyp = types.Types[TUINTPTR]
+ otyp = types.Types[types.TUINTPTR]
}
overflow := makefield("overflow", otyp)
field = append(field, overflow)
// }
// must match runtime/map.go:hmap.
fields := []*types.Field{
- makefield("count", types.Types[TINT]),
- makefield("flags", types.Types[TUINT8]),
- makefield("B", types.Types[TUINT8]),
- makefield("noverflow", types.Types[TUINT16]),
- makefield("hash0", types.Types[TUINT32]), // Used in walk.go for OMAKEMAP.
- makefield("buckets", types.NewPtr(bmap)), // Used in walk.go for OMAKEMAP.
+ makefield("count", types.Types[types.TINT]),
+ makefield("flags", types.Types[types.TUINT8]),
+ makefield("B", types.Types[types.TUINT8]),
+ makefield("noverflow", types.Types[types.TUINT16]),
+ makefield("hash0", types.Types[types.TUINT32]), // Used in walk.go for OMAKEMAP.
+ makefield("buckets", types.NewPtr(bmap)), // Used in walk.go for OMAKEMAP.
makefield("oldbuckets", types.NewPtr(bmap)),
- makefield("nevacuate", types.Types[TUINTPTR]),
- makefield("extra", types.Types[TUNSAFEPTR]),
+ makefield("nevacuate", types.Types[types.TUINTPTR]),
+ makefield("extra", types.Types[types.TUNSAFEPTR]),
}
- hmap := types.New(TSTRUCT)
+ hmap := types.New(types.TSTRUCT)
hmap.SetNoalg(true)
hmap.SetFields(fields)
dowidth(hmap)
fields := []*types.Field{
makefield("key", types.NewPtr(t.Key())), // Used in range.go for TMAP.
makefield("elem", types.NewPtr(t.Elem())), // Used in range.go for TMAP.
- makefield("t", types.Types[TUNSAFEPTR]),
+ makefield("t", types.Types[types.TUNSAFEPTR]),
makefield("h", types.NewPtr(hmap)),
makefield("buckets", types.NewPtr(bmap)),
makefield("bptr", types.NewPtr(bmap)),
- makefield("overflow", types.Types[TUNSAFEPTR]),
- makefield("oldoverflow", types.Types[TUNSAFEPTR]),
- makefield("startBucket", types.Types[TUINTPTR]),
- makefield("offset", types.Types[TUINT8]),
- makefield("wrapped", types.Types[TBOOL]),
- makefield("B", types.Types[TUINT8]),
- makefield("i", types.Types[TUINT8]),
- makefield("bucket", types.Types[TUINTPTR]),
- makefield("checkBucket", types.Types[TUINTPTR]),
+ makefield("overflow", types.Types[types.TUNSAFEPTR]),
+ makefield("oldoverflow", types.Types[types.TUNSAFEPTR]),
+ makefield("startBucket", types.Types[types.TUINTPTR]),
+ makefield("offset", types.Types[types.TUINT8]),
+ makefield("wrapped", types.Types[types.TBOOL]),
+ makefield("B", types.Types[types.TUINT8]),
+ makefield("i", types.Types[types.TUINT8]),
+ makefield("bucket", types.Types[types.TUINTPTR]),
+ makefield("checkBucket", types.Types[types.TUINTPTR]),
}
// build iterator struct holding the above fields
- hiter := types.New(TSTRUCT)
+ hiter := types.New(types.TSTRUCT)
hiter.SetNoalg(true)
hiter.SetFields(fields)
dowidth(hiter)
// Unlike the global makefield function, this one needs to set Pkg
// because these types might be compared (in SSA CSE sorting).
// TODO: unify this makefield and the global one above.
- sym := &types.Sym{Name: name, Pkg: localpkg}
+ sym := &types.Sym{Name: name, Pkg: ir.LocalPkg}
return types.NewField(src.NoXPos, sym, typ)
}
- argtype := types.NewArray(types.Types[TUINT8], stksize)
+ argtype := types.NewArray(types.Types[types.TUINT8], stksize)
argtype.Width = stksize
argtype.Align = 1
// These fields must match the ones in runtime/runtime2.go:_defer and
// cmd/compile/internal/gc/ssa.go:(*state).call.
fields := []*types.Field{
- makefield("siz", types.Types[TUINT32]),
- makefield("started", types.Types[TBOOL]),
- makefield("heap", types.Types[TBOOL]),
- makefield("openDefer", types.Types[TBOOL]),
- makefield("sp", types.Types[TUINTPTR]),
- makefield("pc", types.Types[TUINTPTR]),
+ makefield("siz", types.Types[types.TUINT32]),
+ makefield("started", types.Types[types.TBOOL]),
+ makefield("heap", types.Types[types.TBOOL]),
+ makefield("openDefer", types.Types[types.TBOOL]),
+ makefield("sp", types.Types[types.TUINTPTR]),
+ makefield("pc", types.Types[types.TUINTPTR]),
// Note: the types here don't really matter. Defer structures
// are always scanned explicitly during stack copying and GC,
// so we make them uintptr type even though they are real pointers.
- makefield("fn", types.Types[TUINTPTR]),
- makefield("_panic", types.Types[TUINTPTR]),
- makefield("link", types.Types[TUINTPTR]),
- makefield("framepc", types.Types[TUINTPTR]),
- makefield("varp", types.Types[TUINTPTR]),
- makefield("fd", types.Types[TUINTPTR]),
+ makefield("fn", types.Types[types.TUINTPTR]),
+ makefield("_panic", types.Types[types.TUINTPTR]),
+ makefield("link", types.Types[types.TUINTPTR]),
+ makefield("framepc", types.Types[types.TUINTPTR]),
+ makefield("varp", types.Types[types.TUINTPTR]),
+ makefield("fd", types.Types[types.TUINTPTR]),
makefield("args", argtype),
}
// build struct holding the above fields
- s := types.New(TSTRUCT)
+ s := types.New(types.TSTRUCT)
s.SetNoalg(true)
s.SetFields(fields)
s.Width = widstruct(s, s, 0, 1)
if receiver != nil {
inLen++
}
- in := make([]*Node, 0, inLen)
+ in := make([]*ir.Node, 0, inLen)
if receiver != nil {
d := anonfield(receiver)
}
outLen := f.Results().Fields().Len()
- out := make([]*Node, 0, outLen)
+ out := make([]*ir.Node, 0, outLen)
for _, t := range f.Results().Fields().Slice() {
d := anonfield(t.Type)
out = append(out, d)
func imethods(t *types.Type) []*Sig {
var methods []*Sig
for _, f := range t.Fields().Slice() {
- if f.Type.Etype != TFUNC || f.Sym == nil {
+ if f.Type.Etype != types.TFUNC || f.Sym == nil {
continue
}
if f.Sym.IsBlank() {
}
str := p.Path
- if p == localpkg {
+ if p == ir.LocalPkg {
// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
str = base.Ctxt.Pkgpath
}
return duintptr(s, ot, 0)
}
- if pkg == localpkg && base.Ctxt.Pkgpath == "" {
+ if pkg == ir.LocalPkg && base.Ctxt.Pkgpath == "" {
// If we don't know the full import path of the package being compiled
// (i.e. -p was not passed on the compiler command line), emit a reference to
// type..importpath.""., which the linker will rewrite using the correct import path.
if pkg == nil {
return duint32(s, ot, 0)
}
- if pkg == localpkg && base.Ctxt.Pkgpath == "" {
+ if pkg == ir.LocalPkg && base.Ctxt.Pkgpath == "" {
// If we don't know the full import path of the package being compiled
// (i.e. -p was not passed on the compiler command line), emit a reference to
// type..importpath.""., which the linker will rewrite using the correct import path.
tsym := t.Sym
if tsym == nil {
switch t.Etype {
- case TARRAY, TSLICE, TPTR, TCHAN:
+ case types.TARRAY, types.TSLICE, types.TPTR, types.TCHAN:
if t.Elem() != nil {
tsym = t.Elem().Sym
}
}
var kinds = []int{
- TINT: objabi.KindInt,
- TUINT: objabi.KindUint,
- TINT8: objabi.KindInt8,
- TUINT8: objabi.KindUint8,
- TINT16: objabi.KindInt16,
- TUINT16: objabi.KindUint16,
- TINT32: objabi.KindInt32,
- TUINT32: objabi.KindUint32,
- TINT64: objabi.KindInt64,
- TUINT64: objabi.KindUint64,
- TUINTPTR: objabi.KindUintptr,
- TFLOAT32: objabi.KindFloat32,
- TFLOAT64: objabi.KindFloat64,
- TBOOL: objabi.KindBool,
- TSTRING: objabi.KindString,
- TPTR: objabi.KindPtr,
- TSTRUCT: objabi.KindStruct,
- TINTER: objabi.KindInterface,
- TCHAN: objabi.KindChan,
- TMAP: objabi.KindMap,
- TARRAY: objabi.KindArray,
- TSLICE: objabi.KindSlice,
- TFUNC: objabi.KindFunc,
- TCOMPLEX64: objabi.KindComplex64,
- TCOMPLEX128: objabi.KindComplex128,
- TUNSAFEPTR: objabi.KindUnsafePointer,
+ types.TINT: objabi.KindInt,
+ types.TUINT: objabi.KindUint,
+ types.TINT8: objabi.KindInt8,
+ types.TUINT8: objabi.KindUint8,
+ types.TINT16: objabi.KindInt16,
+ types.TUINT16: objabi.KindUint16,
+ types.TINT32: objabi.KindInt32,
+ types.TUINT32: objabi.KindUint32,
+ types.TINT64: objabi.KindInt64,
+ types.TUINT64: objabi.KindUint64,
+ types.TUINTPTR: objabi.KindUintptr,
+ types.TFLOAT32: objabi.KindFloat32,
+ types.TFLOAT64: objabi.KindFloat64,
+ types.TBOOL: objabi.KindBool,
+ types.TSTRING: objabi.KindString,
+ types.TPTR: objabi.KindPtr,
+ types.TSTRUCT: objabi.KindStruct,
+ types.TINTER: objabi.KindInterface,
+ types.TCHAN: objabi.KindChan,
+ types.TMAP: objabi.KindMap,
+ types.TARRAY: objabi.KindArray,
+ types.TSLICE: objabi.KindSlice,
+ types.TFUNC: objabi.KindFunc,
+ types.TCOMPLEX64: objabi.KindComplex64,
+ types.TCOMPLEX128: objabi.KindComplex128,
+ types.TUNSAFEPTR: objabi.KindUnsafePointer,
}
// typeptrdata returns the length in bytes of the prefix of t
}
switch t.Etype {
- case TPTR,
- TUNSAFEPTR,
- TFUNC,
- TCHAN,
- TMAP:
+ case types.TPTR,
+ types.TUNSAFEPTR,
+ types.TFUNC,
+ types.TCHAN,
+ types.TMAP:
return int64(Widthptr)
- case TSTRING:
+ case types.TSTRING:
// struct { byte *str; intgo len; }
return int64(Widthptr)
- case TINTER:
+ case types.TINTER:
// struct { Itab *tab; void *data; } or
// struct { Type *type; void *data; }
// Note: see comment in plive.go:onebitwalktype1.
return 2 * int64(Widthptr)
- case TSLICE:
+ case types.TSLICE:
// struct { byte *array; uintgo len; uintgo cap; }
return int64(Widthptr)
- case TARRAY:
+ case types.TARRAY:
// haspointers already eliminated t.NumElem() == 0.
return (t.NumElem()-1)*t.Elem().Width + typeptrdata(t.Elem())
- case TSTRUCT:
+ case types.TSTRUCT:
// Find the last field that has pointers.
var lastPtrField *types.Field
for _, t1 := range t.Fields().Slice() {
return s
}
-func typename(t *types.Type) *Node {
+func typename(t *types.Type) *ir.Node {
s := typenamesym(t)
if s.Def == nil {
- n := newnamel(src.NoXPos, s)
- n.Type = types.Types[TUINT8]
- n.SetClass(PEXTERN)
+ n := ir.NewNameAt(src.NoXPos, s)
+ n.Type = types.Types[types.TUINT8]
+ n.SetClass(ir.PEXTERN)
n.SetTypecheck(1)
- s.Def = asTypesNode(n)
+ s.Def = ir.AsTypesNode(n)
}
- n := nod(OADDR, asNode(s.Def), nil)
- n.Type = types.NewPtr(asNode(s.Def).Type)
+ n := ir.Nod(ir.OADDR, ir.AsNode(s.Def), nil)
+ n.Type = types.NewPtr(ir.AsNode(s.Def).Type)
n.SetTypecheck(1)
return n
}
-func itabname(t, itype *types.Type) *Node {
+func itabname(t, itype *types.Type) *ir.Node {
if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
base.Fatalf("itabname(%v, %v)", t, itype)
}
s := itabpkg.Lookup(t.ShortString() + "," + itype.ShortString())
if s.Def == nil {
- n := newname(s)
- n.Type = types.Types[TUINT8]
- n.SetClass(PEXTERN)
+ n := NewName(s)
+ n.Type = types.Types[types.TUINT8]
+ n.SetClass(ir.PEXTERN)
n.SetTypecheck(1)
- s.Def = asTypesNode(n)
+ s.Def = ir.AsTypesNode(n)
itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
}
- n := nod(OADDR, asNode(s.Def), nil)
- n.Type = types.NewPtr(asNode(s.Def).Type)
+ n := ir.Nod(ir.OADDR, ir.AsNode(s.Def), nil)
+ n.Type = types.NewPtr(ir.AsNode(s.Def).Type)
n.SetTypecheck(1)
return n
}
// That is, if x==x for all x of type t.
func isreflexive(t *types.Type) bool {
switch t.Etype {
- case TBOOL,
- TINT,
- TUINT,
- TINT8,
- TUINT8,
- TINT16,
- TUINT16,
- TINT32,
- TUINT32,
- TINT64,
- TUINT64,
- TUINTPTR,
- TPTR,
- TUNSAFEPTR,
- TSTRING,
- TCHAN:
+ case types.TBOOL,
+ types.TINT,
+ types.TUINT,
+ types.TINT8,
+ types.TUINT8,
+ types.TINT16,
+ types.TUINT16,
+ types.TINT32,
+ types.TUINT32,
+ types.TINT64,
+ types.TUINT64,
+ types.TUINTPTR,
+ types.TPTR,
+ types.TUNSAFEPTR,
+ types.TSTRING,
+ types.TCHAN:
return true
- case TFLOAT32,
- TFLOAT64,
- TCOMPLEX64,
- TCOMPLEX128,
- TINTER:
+ case types.TFLOAT32,
+ types.TFLOAT64,
+ types.TCOMPLEX64,
+ types.TCOMPLEX128,
+ types.TINTER:
return false
- case TARRAY:
+ case types.TARRAY:
return isreflexive(t.Elem())
- case TSTRUCT:
+ case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() {
if !isreflexive(t1.Type) {
return false
// need the key to be updated.
func needkeyupdate(t *types.Type) bool {
switch t.Etype {
- case TBOOL, TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32,
- TINT64, TUINT64, TUINTPTR, TPTR, TUNSAFEPTR, TCHAN:
+ case types.TBOOL, types.TINT, types.TUINT, types.TINT8, types.TUINT8, types.TINT16, types.TUINT16, types.TINT32, types.TUINT32,
+ types.TINT64, types.TUINT64, types.TUINTPTR, types.TPTR, types.TUNSAFEPTR, types.TCHAN:
return false
- case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, // floats and complex can be +0/-0
- TINTER,
- TSTRING: // strings might have smaller backing stores
+ case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, // floats and complex can be +0/-0
+ types.TINTER,
+ types.TSTRING: // strings might have smaller backing stores
return true
- case TARRAY:
+ case types.TARRAY:
return needkeyupdate(t.Elem())
- case TSTRUCT:
+ case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() {
if needkeyupdate(t1.Type) {
return true
// hashMightPanic reports whether the hash of a map key of type t might panic.
func hashMightPanic(t *types.Type) bool {
switch t.Etype {
- case TINTER:
+ case types.TINTER:
return true
- case TARRAY:
+ case types.TARRAY:
return hashMightPanic(t.Elem())
- case TSTRUCT:
+ case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() {
if hashMightPanic(t1.Type) {
return true
if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Etype] && tbase != types.Bytetype && tbase != types.Runetype && tbase != types.Errortype) { // int, float, etc
// named types from other files are defined only by those files
- if tbase.Sym != nil && tbase.Sym.Pkg != localpkg {
+ if tbase.Sym != nil && tbase.Sym.Pkg != ir.LocalPkg {
if i, ok := typeSymIdx[tbase]; ok {
lsym.Pkg = tbase.Sym.Pkg.Prefix
if t != tbase {
return lsym
}
// TODO(mdempsky): Investigate whether this can happen.
- if tbase.Etype == TFORW {
+ if tbase.Etype == types.TFORW {
return lsym
}
}
ot = dcommontype(lsym, t)
ot = dextratype(lsym, ot, t, 0)
- case TARRAY:
+ case types.TARRAY:
// ../../../../runtime/type.go:/arrayType
s1 := dtypesym(t.Elem())
t2 := types.NewSlice(t.Elem())
ot = duintptr(lsym, ot, uint64(t.NumElem()))
ot = dextratype(lsym, ot, t, 0)
- case TSLICE:
+ case types.TSLICE:
// ../../../../runtime/type.go:/sliceType
s1 := dtypesym(t.Elem())
ot = dcommontype(lsym, t)
ot = dsymptr(lsym, ot, s1, 0)
ot = dextratype(lsym, ot, t, 0)
- case TCHAN:
+ case types.TCHAN:
// ../../../../runtime/type.go:/chanType
s1 := dtypesym(t.Elem())
ot = dcommontype(lsym, t)
ot = duintptr(lsym, ot, uint64(t.ChanDir()))
ot = dextratype(lsym, ot, t, 0)
- case TFUNC:
+ case types.TFUNC:
for _, t1 := range t.Recvs().Fields().Slice() {
dtypesym(t1.Type)
}
ot = dsymptr(lsym, ot, dtypesym(t1.Type), 0)
}
- case TINTER:
+ case types.TINTER:
m := imethods(t)
n := len(m)
for _, a := range m {
}
// ../../../../runtime/type.go:/mapType
- case TMAP:
+ case types.TMAP:
s1 := dtypesym(t.Key())
s2 := dtypesym(t.Elem())
s3 := dtypesym(bmap(t))
ot = duint32(lsym, ot, flags)
ot = dextratype(lsym, ot, t, 0)
- case TPTR:
- if t.Elem().Etype == TANY {
+ case types.TPTR:
+ if t.Elem().Etype == types.TANY {
// ../../../../runtime/type.go:/UnsafePointerType
ot = dcommontype(lsym, t)
ot = dextratype(lsym, ot, t, 0)
// ../../../../runtime/type.go:/structType
// for security, only the exported fields.
- case TSTRUCT:
+ case types.TSTRUCT:
fields := t.Fields().Slice()
for _, t1 := range fields {
dtypesym(t1.Type)
// functions must return the existing type structure rather
// than creating a new one.
switch t.Etype {
- case TPTR, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT:
+ case types.TPTR, types.TARRAY, types.TCHAN, types.TFUNC, types.TMAP, types.TSLICE, types.TSTRUCT:
keep = true
}
}
}
}
-func addsignats(dcls []*Node) {
+func addsignats(dcls []*ir.Node) {
// copy types from dcl list to signatset
for _, n := range dcls {
- if n.Op == OTYPE {
+ if n.Op == ir.OTYPE {
addsignat(n.Type)
}
}
}
// process ptabs
- if localpkg.Name == "main" && len(ptabs) > 0 {
+ if ir.LocalPkg.Name == "main" && len(ptabs) > 0 {
ot := 0
s := base.Ctxt.Lookup("go.plugin.tabs")
for _, p := range ptabs {
// another possible choice would be package main,
// but using runtime means fewer copies in object files.
if base.Ctxt.Pkgpath == "runtime" {
- for i := types.EType(1); i <= TBOOL; i++ {
+ for i := types.EType(1); i <= types.TBOOL; i++ {
dtypesym(types.NewPtr(types.Types[i]))
}
- dtypesym(types.NewPtr(types.Types[TSTRING]))
- dtypesym(types.NewPtr(types.Types[TUNSAFEPTR]))
+ dtypesym(types.NewPtr(types.Types[types.TSTRING]))
+ dtypesym(types.NewPtr(types.Types[types.TUNSAFEPTR]))
// emit type structs for error and func(error) string.
// The latter is the type of an auto-generated wrapper.
dtypesym(types.NewPtr(types.Errortype))
- dtypesym(functype(nil, []*Node{anonfield(types.Errortype)}, []*Node{anonfield(types.Types[TSTRING])}))
+ dtypesym(functype(nil, []*ir.Node{anonfield(types.Errortype)}, []*ir.Node{anonfield(types.Types[types.TSTRING])}))
// add paths for runtime and main, which 6l imports implicitly.
dimportpath(Runtimepkg)
// For non-trivial arrays, the program describes the full t.Width size.
func dgcprog(t *types.Type) (*obj.LSym, int64) {
dowidth(t)
- if t.Width == BADWIDTH {
+ if t.Width == types.BADWIDTH {
base.Fatalf("dgcprog: %v badwidth", t)
}
lsym := typesymprefix(".gcprog", t).Linksym()
default:
base.Fatalf("GCProg.emit: unexpected type %v", t)
- case TSTRING:
+ case types.TSTRING:
p.w.Ptr(offset / int64(Widthptr))
- case TINTER:
+ case types.TINTER:
// Note: the first word isn't a pointer. See comment in plive.go:onebitwalktype1.
p.w.Ptr(offset/int64(Widthptr) + 1)
- case TSLICE:
+ case types.TSLICE:
p.w.Ptr(offset / int64(Widthptr))
- case TARRAY:
+ case types.TARRAY:
if t.NumElem() == 0 {
// should have been handled by haspointers check above
base.Fatalf("GCProg.emit: empty array")
p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr))
p.w.Repeat(elem.Width/int64(Widthptr), count-1)
- case TSTRUCT:
+ case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() {
p.emit(t1.Type, offset+t1.Offset)
}
// zeroaddr returns the address of a symbol with at least
// size bytes of zeros.
-func zeroaddr(size int64) *Node {
+func zeroaddr(size int64) *ir.Node {
if size >= 1<<31 {
base.Fatalf("map elem too big %d", size)
}
}
s := mappkg.Lookup("zero")
if s.Def == nil {
- x := newname(s)
- x.Type = types.Types[TUINT8]
- x.SetClass(PEXTERN)
+ x := NewName(s)
+ x.Type = types.Types[types.TUINT8]
+ x.SetClass(ir.PEXTERN)
x.SetTypecheck(1)
- s.Def = asTypesNode(x)
+ s.Def = ir.AsTypesNode(x)
}
- z := nod(OADDR, asNode(s.Def), nil)
- z.Type = types.NewPtr(types.Types[TUINT8])
+ z := ir.Nod(ir.OADDR, ir.AsNode(s.Def), nil)
+ z.Type = types.NewPtr(types.Types[types.TUINT8])
z.SetTypecheck(1)
return z
}
package gc
+import "cmd/compile/internal/ir"
+
// Strongly connected components.
//
// Run analysis on minimal sets of mutually recursive functions
// when analyzing a set of mutually recursive functions.
type bottomUpVisitor struct {
- analyze func([]*Node, bool)
+ analyze func([]*ir.Node, bool)
visitgen uint32
- nodeID map[*Node]uint32
- stack []*Node
+ nodeID map[*ir.Node]uint32
+ stack []*ir.Node
}
// visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list.
// If recursive is false, the list consists of only a single function and its closures.
// If recursive is true, the list may still contain only a single function,
// if that function is itself recursive.
-func visitBottomUp(list []*Node, analyze func(list []*Node, recursive bool)) {
+func visitBottomUp(list []*ir.Node, analyze func(list []*ir.Node, recursive bool)) {
var v bottomUpVisitor
v.analyze = analyze
- v.nodeID = make(map[*Node]uint32)
+ v.nodeID = make(map[*ir.Node]uint32)
for _, n := range list {
- if n.Op == ODCLFUNC && !n.Func.IsHiddenClosure() {
+ if n.Op == ir.ODCLFUNC && !n.Func.IsHiddenClosure() {
v.visit(n)
}
}
}
-func (v *bottomUpVisitor) visit(n *Node) uint32 {
+func (v *bottomUpVisitor) visit(n *ir.Node) uint32 {
if id := v.nodeID[n]; id > 0 {
// already visited
return id
min := v.visitgen
v.stack = append(v.stack, n)
- inspectList(n.Nbody, func(n *Node) bool {
+ ir.InspectList(n.Nbody, func(n *ir.Node) bool {
switch n.Op {
- case ONAME:
- if n.Class() == PFUNC {
+ case ir.ONAME:
+ if n.Class() == ir.PFUNC {
if n != nil && n.Name.Defn != nil {
if m := v.visit(n.Name.Defn); m < min {
min = m
}
}
}
- case OMETHEXPR:
- fn := n.MethodName()
+ case ir.OMETHEXPR:
+ fn := methodExprName(n)
if fn != nil && fn.Name.Defn != nil {
if m := v.visit(fn.Name.Defn); m < min {
min = m
}
}
- case ODOTMETH:
- fn := n.MethodName()
- if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
+ case ir.ODOTMETH:
+ fn := methodExprName(n)
+ if fn != nil && fn.Op == ir.ONAME && fn.Class() == ir.PFUNC && fn.Name.Defn != nil {
if m := v.visit(fn.Name.Defn); m < min {
min = m
}
}
- case OCALLPART:
- fn := asNode(callpartMethod(n).Nname)
- if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
+ case ir.OCALLPART:
+ fn := ir.AsNode(callpartMethod(n).Nname)
+ if fn != nil && fn.Op == ir.ONAME && fn.Class() == ir.PFUNC && fn.Name.Defn != nil {
if m := v.visit(fn.Name.Defn); m < min {
min = m
}
}
- case OCLOSURE:
+ case ir.OCLOSURE:
if m := v.visit(n.Func.Decl); m < min {
min = m
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/internal/dwarf"
"cmd/internal/obj"
"cmd/internal/src"
return base.Ctxt.PosTable.Pos(p).Before(base.Ctxt.PosTable.Pos(q))
}
-func findScope(marks []Mark, pos src.XPos) ScopeID {
+func findScope(marks []ir.Mark, pos src.XPos) ir.ScopeID {
i := sort.Search(len(marks), func(i int) bool {
return xposBefore(pos, marks[i].Pos)
})
return marks[i-1].Scope
}
-func assembleScopes(fnsym *obj.LSym, fn *Node, dwarfVars []*dwarf.Var, varScopes []ScopeID) []dwarf.Scope {
+func assembleScopes(fnsym *obj.LSym, fn *ir.Node, dwarfVars []*dwarf.Var, varScopes []ir.ScopeID) []dwarf.Scope {
// Initialize the DWARF scope tree based on lexical scopes.
dwarfScopes := make([]dwarf.Scope, 1+len(fn.Func.Parents))
for i, parent := range fn.Func.Parents {
}
// scopeVariables assigns DWARF variable records to their scopes.
-func scopeVariables(dwarfVars []*dwarf.Var, varScopes []ScopeID, dwarfScopes []dwarf.Scope) {
+func scopeVariables(dwarfVars []*dwarf.Var, varScopes []ir.ScopeID, dwarfScopes []dwarf.Scope) {
sort.Stable(varsByScopeAndOffset{dwarfVars, varScopes})
i0 := 0
}
// scopePCs assigns PC ranges to their scopes.
-func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) {
+func scopePCs(fnsym *obj.LSym, marks []ir.Mark, dwarfScopes []dwarf.Scope) {
// If there aren't any child scopes (in particular, when scope
// tracking is disabled), we can skip a whole lot of work.
if len(marks) == 0 {
type varsByScopeAndOffset struct {
vars []*dwarf.Var
- scopes []ScopeID
+ scopes []ir.ScopeID
}
func (v varsByScopeAndOffset) Len() int {
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
)
// select
-func typecheckselect(sel *Node) {
- var def *Node
+func typecheckselect(sel *ir.Node) {
+ var def *ir.Node
lno := setlineno(sel)
typecheckslice(sel.Ninit.Slice(), ctxStmt)
for _, ncase := range sel.List.Slice() {
- if ncase.Op != OCASE {
+ if ncase.Op != ir.OCASE {
setlineno(ncase)
base.Fatalf("typecheckselect %v", ncase.Op)
}
if ncase.List.Len() == 0 {
// default
if def != nil {
- base.ErrorfAt(ncase.Pos, "multiple defaults in select (first at %v)", def.Line())
+ base.ErrorfAt(ncase.Pos, "multiple defaults in select (first at %v)", ir.Line(def))
} else {
def = ncase
}
switch n.Op {
default:
pos := n.Pos
- if n.Op == ONAME {
+ if n.Op == ir.ONAME {
// We don't have the right position for ONAME nodes (see #15459 and
// others). Using ncase.Pos for now as it will provide the correct
// line number (assuming the expression follows the "case" keyword
// convert x = <-c into OSELRECV(x, <-c).
// remove implicit conversions; the eventual assignment
// will reintroduce them.
- case OAS:
- if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit() {
+ case ir.OAS:
+ if (n.Right.Op == ir.OCONVNOP || n.Right.Op == ir.OCONVIFACE) && n.Right.Implicit() {
n.Right = n.Right.Left
}
- if n.Right.Op != ORECV {
+ if n.Right.Op != ir.ORECV {
base.ErrorfAt(n.Pos, "select assignment must have receive on right hand side")
break
}
- n.Op = OSELRECV
+ n.Op = ir.OSELRECV
// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
- case OAS2RECV:
- if n.Right.Op != ORECV {
+ case ir.OAS2RECV:
+ if n.Right.Op != ir.ORECV {
base.ErrorfAt(n.Pos, "select assignment must have receive on right hand side")
break
}
- n.Op = OSELRECV2
+ n.Op = ir.OSELRECV2
n.Left = n.List.First()
n.List.Set1(n.List.Second())
// convert <-c into OSELRECV(N, <-c)
- case ORECV:
- n = nodl(n.Pos, OSELRECV, nil, n)
+ case ir.ORECV:
+ n = ir.NodAt(n.Pos, ir.OSELRECV, nil, n)
n.SetTypecheck(1)
ncase.Left = n
- case OSEND:
+ case ir.OSEND:
break
}
}
base.Pos = lno
}
-func walkselect(sel *Node) {
+func walkselect(sel *ir.Node) {
lno := setlineno(sel)
if sel.Nbody.Len() != 0 {
base.Fatalf("double walkselect")
base.Pos = lno
}
-func walkselectcases(cases *Nodes) []*Node {
+func walkselectcases(cases *ir.Nodes) []*ir.Node {
ncas := cases.Len()
sellineno := base.Pos
// optimization: zero-case select
if ncas == 0 {
- return []*Node{mkcall("block", nil, nil)}
+ return []*ir.Node{mkcall("block", nil, nil)}
}
// optimization: one-case select: single op.
default:
base.Fatalf("select %v", n.Op)
- case OSEND:
+ case ir.OSEND:
// already ok
- case OSELRECV, OSELRECV2:
- if n.Op == OSELRECV || n.List.Len() == 0 {
+ case ir.OSELRECV, ir.OSELRECV2:
+ if n.Op == ir.OSELRECV || n.List.Len() == 0 {
if n.Left == nil {
n = n.Right
} else {
- n.Op = OAS
+ n.Op = ir.OAS
}
break
}
if n.Left == nil {
- nblank = typecheck(nblank, ctxExpr|ctxAssign)
- n.Left = nblank
+ ir.BlankNode = typecheck(ir.BlankNode, ctxExpr|ctxAssign)
+ n.Left = ir.BlankNode
}
- n.Op = OAS2
+ n.Op = ir.OAS2
n.List.Prepend(n.Left)
n.Rlist.Set1(n.Right)
n.Right = nil
}
l = append(l, cas.Nbody.Slice()...)
- l = append(l, nod(OBREAK, nil, nil))
+ l = append(l, ir.Nod(ir.OBREAK, nil, nil))
return l
}
// convert case value arguments to addresses.
// this rewrite is used by both the general code and the next optimization.
- var dflt *Node
+ var dflt *ir.Node
for _, cas := range cases.Slice() {
setlineno(cas)
n := cas.Left
continue
}
switch n.Op {
- case OSEND:
- n.Right = nod(OADDR, n.Right, nil)
+ case ir.OSEND:
+ n.Right = ir.Nod(ir.OADDR, n.Right, nil)
n.Right = typecheck(n.Right, ctxExpr)
- case OSELRECV, OSELRECV2:
- if n.Op == OSELRECV2 && n.List.Len() == 0 {
- n.Op = OSELRECV
+ case ir.OSELRECV, ir.OSELRECV2:
+ if n.Op == ir.OSELRECV2 && n.List.Len() == 0 {
+ n.Op = ir.OSELRECV
}
if n.Left != nil {
- n.Left = nod(OADDR, n.Left, nil)
+ n.Left = ir.Nod(ir.OADDR, n.Left, nil)
n.Left = typecheck(n.Left, ctxExpr)
}
}
n := cas.Left
setlineno(n)
- r := nod(OIF, nil, nil)
+ r := ir.Nod(ir.OIF, nil, nil)
r.Ninit.Set(cas.Ninit.Slice())
switch n.Op {
default:
base.Fatalf("select %v", n.Op)
- case OSEND:
+ case ir.OSEND:
// if selectnbsend(c, v) { body } else { default body }
ch := n.Left
- r.Left = mkcall1(chanfn("selectnbsend", 2, ch.Type), types.Types[TBOOL], &r.Ninit, ch, n.Right)
+ r.Left = mkcall1(chanfn("selectnbsend", 2, ch.Type), types.Types[types.TBOOL], &r.Ninit, ch, n.Right)
- case OSELRECV:
+ case ir.OSELRECV:
// if selectnbrecv(&v, c) { body } else { default body }
ch := n.Right.Left
elem := n.Left
if elem == nil {
elem = nodnil()
}
- r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, ch)
+ r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), types.Types[types.TBOOL], &r.Ninit, elem, ch)
- case OSELRECV2:
+ case ir.OSELRECV2:
// if selectnbrecv2(&v, &received, c) { body } else { default body }
ch := n.Right.Left
elem := n.Left
if elem == nil {
elem = nodnil()
}
- receivedp := nod(OADDR, n.List.First(), nil)
+ receivedp := ir.Nod(ir.OADDR, n.List.First(), nil)
receivedp = typecheck(receivedp, ctxExpr)
- r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, receivedp, ch)
+ r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), types.Types[types.TBOOL], &r.Ninit, elem, receivedp, ch)
}
r.Left = typecheck(r.Left, ctxExpr)
r.Nbody.Set(cas.Nbody.Slice())
r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.Nbody.Slice()...))
- return []*Node{r, nod(OBREAK, nil, nil)}
+ return []*ir.Node{r, ir.Nod(ir.OBREAK, nil, nil)}
}
if dflt != nil {
ncas--
}
- casorder := make([]*Node, ncas)
+ casorder := make([]*ir.Node, ncas)
nsends, nrecvs := 0, 0
- var init []*Node
+ var init []*ir.Node
// generate sel-struct
base.Pos = sellineno
selv := temp(types.NewArray(scasetype(), int64(ncas)))
- r := nod(OAS, selv, nil)
+ r := ir.Nod(ir.OAS, selv, nil)
r = typecheck(r, ctxStmt)
init = append(init, r)
// No initialization for order; runtime.selectgo is responsible for that.
- order := temp(types.NewArray(types.Types[TUINT16], 2*int64(ncas)))
+ order := temp(types.NewArray(types.Types[types.TUINT16], 2*int64(ncas)))
- var pc0, pcs *Node
+ var pc0, pcs *ir.Node
if base.Flag.Race {
- pcs = temp(types.NewArray(types.Types[TUINTPTR], int64(ncas)))
- pc0 = typecheck(nod(OADDR, nod(OINDEX, pcs, nodintconst(0)), nil), ctxExpr)
+ pcs = temp(types.NewArray(types.Types[types.TUINTPTR], int64(ncas)))
+ pc0 = typecheck(ir.Nod(ir.OADDR, ir.Nod(ir.OINDEX, pcs, nodintconst(0)), nil), ctxExpr)
} else {
pc0 = nodnil()
}
}
var i int
- var c, elem *Node
+ var c, elem *ir.Node
switch n.Op {
default:
base.Fatalf("select %v", n.Op)
- case OSEND:
+ case ir.OSEND:
i = nsends
nsends++
c = n.Left
elem = n.Right
- case OSELRECV, OSELRECV2:
+ case ir.OSELRECV, ir.OSELRECV2:
nrecvs++
i = ncas - nrecvs
c = n.Right.Left
casorder[i] = cas
- setField := func(f string, val *Node) {
- r := nod(OAS, nodSym(ODOT, nod(OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
+ setField := func(f string, val *ir.Node) {
+ r := ir.Nod(ir.OAS, nodSym(ir.ODOT, ir.Nod(ir.OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
r = typecheck(r, ctxStmt)
init = append(init, r)
}
- c = convnop(c, types.Types[TUNSAFEPTR])
+ c = convnop(c, types.Types[types.TUNSAFEPTR])
setField("c", c)
if elem != nil {
- elem = convnop(elem, types.Types[TUNSAFEPTR])
+ elem = convnop(elem, types.Types[types.TUNSAFEPTR])
setField("elem", elem)
}
// TODO(mdempsky): There should be a cleaner way to
// handle this.
if base.Flag.Race {
- r = mkcall("selectsetpc", nil, nil, nod(OADDR, nod(OINDEX, pcs, nodintconst(int64(i))), nil))
+ r = mkcall("selectsetpc", nil, nil, ir.Nod(ir.OADDR, ir.Nod(ir.OINDEX, pcs, nodintconst(int64(i))), nil))
init = append(init, r)
}
}
// run the select
base.Pos = sellineno
- chosen := temp(types.Types[TINT])
- recvOK := temp(types.Types[TBOOL])
- r = nod(OAS2, nil, nil)
+ chosen := temp(types.Types[types.TINT])
+ recvOK := temp(types.Types[types.TBOOL])
+ r = ir.Nod(ir.OAS2, nil, nil)
r.List.Set2(chosen, recvOK)
fn := syslook("selectgo")
r.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, nodintconst(int64(nsends)), nodintconst(int64(nrecvs)), nodbool(dflt == nil)))
init = append(init, r)
// selv and order are no longer alive after selectgo.
- init = append(init, nod(OVARKILL, selv, nil))
- init = append(init, nod(OVARKILL, order, nil))
+ init = append(init, ir.Nod(ir.OVARKILL, selv, nil))
+ init = append(init, ir.Nod(ir.OVARKILL, order, nil))
if base.Flag.Race {
- init = append(init, nod(OVARKILL, pcs, nil))
+ init = append(init, ir.Nod(ir.OVARKILL, pcs, nil))
}
// dispatch cases
- dispatch := func(cond, cas *Node) {
+ dispatch := func(cond, cas *ir.Node) {
cond = typecheck(cond, ctxExpr)
cond = defaultlit(cond, nil)
- r := nod(OIF, cond, nil)
+ r := ir.Nod(ir.OIF, cond, nil)
- if n := cas.Left; n != nil && n.Op == OSELRECV2 {
- x := nod(OAS, n.List.First(), recvOK)
+ if n := cas.Left; n != nil && n.Op == ir.OSELRECV2 {
+ x := ir.Nod(ir.OAS, n.List.First(), recvOK)
x = typecheck(x, ctxStmt)
r.Nbody.Append(x)
}
r.Nbody.AppendNodes(&cas.Nbody)
- r.Nbody.Append(nod(OBREAK, nil, nil))
+ r.Nbody.Append(ir.Nod(ir.OBREAK, nil, nil))
init = append(init, r)
}
if dflt != nil {
setlineno(dflt)
- dispatch(nod(OLT, chosen, nodintconst(0)), dflt)
+ dispatch(ir.Nod(ir.OLT, chosen, nodintconst(0)), dflt)
}
for i, cas := range casorder {
setlineno(cas)
- dispatch(nod(OEQ, chosen, nodintconst(int64(i))), cas)
+ dispatch(ir.Nod(ir.OEQ, chosen, nodintconst(int64(i))), cas)
}
return init
}
// bytePtrToIndex returns a Node representing "(*byte)(&n[i])".
-func bytePtrToIndex(n *Node, i int64) *Node {
- s := nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil)
- t := types.NewPtr(types.Types[TUINT8])
+func bytePtrToIndex(n *ir.Node, i int64) *ir.Node {
+ s := ir.Nod(ir.OADDR, ir.Nod(ir.OINDEX, n, nodintconst(i)), nil)
+ t := types.NewPtr(types.Types[types.TUINT8])
return convnop(s, t)
}
// Keep in sync with src/runtime/select.go.
func scasetype() *types.Type {
if scase == nil {
- scase = tostruct([]*Node{
- namedfield("c", types.Types[TUNSAFEPTR]),
- namedfield("elem", types.Types[TUNSAFEPTR]),
+ scase = tostruct([]*ir.Node{
+ namedfield("c", types.Types[types.TUNSAFEPTR]),
+ namedfield("elem", types.Types[types.TUNSAFEPTR]),
})
scase.SetNoalg(true)
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/obj"
"fmt"
)
type InitEntry struct {
- Xoffset int64 // struct, array only
- Expr *Node // bytes of run-time computed expressions
+ Xoffset int64 // struct, array only
+ Expr *ir.Node // bytes of run-time computed expressions
}
type InitPlan struct {
type InitSchedule struct {
// out is the ordered list of dynamic initialization
// statements.
- out []*Node
+ out []*ir.Node
- initplans map[*Node]*InitPlan
- inittemps map[*Node]*Node
+ initplans map[*ir.Node]*InitPlan
+ inittemps map[*ir.Node]*ir.Node
}
-func (s *InitSchedule) append(n *Node) {
+func (s *InitSchedule) append(n *ir.Node) {
s.out = append(s.out, n)
}
// staticInit adds an initialization statement n to the schedule.
-func (s *InitSchedule) staticInit(n *Node) {
+func (s *InitSchedule) staticInit(n *ir.Node) {
if !s.tryStaticInit(n) {
if base.Flag.Percent != 0 {
- Dump("nonstatic", n)
+ ir.Dump("nonstatic", n)
}
s.append(n)
}
// tryStaticInit attempts to statically execute an initialization
// statement and reports whether it succeeded.
-func (s *InitSchedule) tryStaticInit(n *Node) bool {
+func (s *InitSchedule) tryStaticInit(n *ir.Node) bool {
// Only worry about simple "l = r" assignments. Multiple
// variable/expression OAS2 assignments have already been
// replaced by multiple simple OAS assignments, and the other
// OAS2* assignments mostly necessitate dynamic execution
// anyway.
- if n.Op != OAS {
+ if n.Op != ir.OAS {
return false
}
- if n.Left.isBlank() && candiscard(n.Right) {
+ if ir.IsBlank(n.Left) && candiscard(n.Right) {
return true
}
lno := setlineno(n)
// like staticassign but we are copying an already
// initialized value r.
-func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
- if r.Op != ONAME && r.Op != OMETHEXPR {
+func (s *InitSchedule) staticcopy(l *ir.Node, r *ir.Node) bool {
+ if r.Op != ir.ONAME && r.Op != ir.OMETHEXPR {
return false
}
- if r.Class() == PFUNC {
+ if r.Class() == ir.PFUNC {
pfuncsym(l, r)
return true
}
- if r.Class() != PEXTERN || r.Sym.Pkg != localpkg {
+ if r.Class() != ir.PEXTERN || r.Sym.Pkg != ir.LocalPkg {
return false
}
if r.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
return false
}
- if r.Name.Defn.Op != OAS {
+ if r.Name.Defn.Op != ir.OAS {
return false
}
if r.Type.IsString() { // perhaps overwritten by cmd/link -X (#34675)
orig := r
r = r.Name.Defn.Right
- for r.Op == OCONVNOP && !types.Identical(r.Type, l.Type) {
+ for r.Op == ir.OCONVNOP && !types.Identical(r.Type, l.Type) {
r = r.Left
}
switch r.Op {
- case ONAME, OMETHEXPR:
+ case ir.ONAME, ir.OMETHEXPR:
if s.staticcopy(l, r) {
return true
}
// We may have skipped past one or more OCONVNOPs, so
// use conv to ensure r is assignable to l (#13263).
- s.append(nod(OAS, l, conv(r, l.Type)))
+ s.append(ir.Nod(ir.OAS, l, conv(r, l.Type)))
return true
- case ONIL:
+ case ir.ONIL:
return true
- case OLITERAL:
+ case ir.OLITERAL:
if isZero(r) {
return true
}
litsym(l, r, int(l.Type.Width))
return true
- case OADDR:
- if a := r.Left; a.Op == ONAME {
+ case ir.OADDR:
+ if a := r.Left; a.Op == ir.ONAME {
addrsym(l, a)
return true
}
- case OPTRLIT:
+ case ir.OPTRLIT:
switch r.Left.Op {
- case OARRAYLIT, OSLICELIT, OSTRUCTLIT, OMAPLIT:
+ case ir.OARRAYLIT, ir.OSLICELIT, ir.OSTRUCTLIT, ir.OMAPLIT:
// copy pointer
addrsym(l, s.inittemps[r])
return true
}
- case OSLICELIT:
+ case ir.OSLICELIT:
// copy slice
a := s.inittemps[r]
slicesym(l, a, r.Right.Int64Val())
return true
- case OARRAYLIT, OSTRUCTLIT:
+ case ir.OARRAYLIT, ir.OSTRUCTLIT:
p := s.initplans[r]
- n := l.copy()
+ n := ir.Copy(l)
for i := range p.E {
e := &p.E[i]
n.Xoffset = l.Xoffset + e.Xoffset
n.Type = e.Expr.Type
- if e.Expr.Op == OLITERAL || e.Expr.Op == ONIL {
+ if e.Expr.Op == ir.OLITERAL || e.Expr.Op == ir.ONIL {
litsym(n, e.Expr, int(n.Type.Width))
continue
}
- ll := n.sepcopy()
+ ll := ir.SepCopy(n)
if s.staticcopy(ll, e.Expr) {
continue
}
// Requires computation, but we're
// copying someone else's computation.
- rr := orig.sepcopy()
+ rr := ir.SepCopy(orig)
rr.Type = ll.Type
rr.Xoffset += e.Xoffset
setlineno(rr)
- s.append(nod(OAS, ll, rr))
+ s.append(ir.Nod(ir.OAS, ll, rr))
}
return true
return false
}
-func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
- for r.Op == OCONVNOP {
+func (s *InitSchedule) staticassign(l *ir.Node, r *ir.Node) bool {
+ for r.Op == ir.OCONVNOP {
r = r.Left
}
switch r.Op {
- case ONAME, OMETHEXPR:
+ case ir.ONAME, ir.OMETHEXPR:
return s.staticcopy(l, r)
- case ONIL:
+ case ir.ONIL:
return true
- case OLITERAL:
+ case ir.OLITERAL:
if isZero(r) {
return true
}
litsym(l, r, int(l.Type.Width))
return true
- case OADDR:
+ case ir.OADDR:
if nam := stataddr(r.Left); nam != nil {
addrsym(l, nam)
return true
}
fallthrough
- case OPTRLIT:
+ case ir.OPTRLIT:
switch r.Left.Op {
- case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT:
+ case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT:
// Init pointer.
a := staticname(r.Left.Type)
// Init underlying literal.
if !s.staticassign(a, r.Left) {
- s.append(nod(OAS, a, r.Left))
+ s.append(ir.Nod(ir.OAS, a, r.Left))
}
return true
}
//dump("not static ptrlit", r);
- case OSTR2BYTES:
- if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
+ case ir.OSTR2BYTES:
+ if l.Class() == ir.PEXTERN && r.Left.Op == ir.OLITERAL {
sval := r.Left.StringVal()
slicebytes(l, sval)
return true
}
- case OSLICELIT:
+ case ir.OSLICELIT:
s.initplan(r)
// Init slice.
bound := r.Right.Int64Val()
l = a
fallthrough
- case OARRAYLIT, OSTRUCTLIT:
+ case ir.OARRAYLIT, ir.OSTRUCTLIT:
s.initplan(r)
p := s.initplans[r]
- n := l.copy()
+ n := ir.Copy(l)
for i := range p.E {
e := &p.E[i]
n.Xoffset = l.Xoffset + e.Xoffset
n.Type = e.Expr.Type
- if e.Expr.Op == OLITERAL || e.Expr.Op == ONIL {
+ if e.Expr.Op == ir.OLITERAL || e.Expr.Op == ir.ONIL {
litsym(n, e.Expr, int(n.Type.Width))
continue
}
setlineno(e.Expr)
- a := n.sepcopy()
+ a := ir.SepCopy(n)
if !s.staticassign(a, e.Expr) {
- s.append(nod(OAS, a, e.Expr))
+ s.append(ir.Nod(ir.OAS, a, e.Expr))
}
}
return true
- case OMAPLIT:
+ case ir.OMAPLIT:
break
- case OCLOSURE:
+ case ir.OCLOSURE:
if hasemptycvars(r) {
if base.Debug.Closure > 0 {
base.WarnfAt(r.Pos, "closure converted to global")
}
closuredebugruntimecheck(r)
- case OCONVIFACE:
+ case ir.OCONVIFACE:
// This logic is mirrored in isStaticCompositeLiteral.
// If you change something here, change it there, and vice versa.
// Determine the underlying concrete type and value we are converting from.
val := r
- for val.Op == OCONVIFACE {
+ for val.Op == ir.OCONVIFACE {
val = val.Left
}
// both words are zero and so there no work to do, so report success.
// If val is non-nil, we have no concrete type to record,
// and we won't be able to statically initialize its value, so report failure.
- return val.Op == ONIL
+ return val.Op == ir.ONIL
}
markTypeUsedInInterface(val.Type, l.Sym.Linksym())
- var itab *Node
+ var itab *ir.Node
if l.Type.IsEmptyInterface() {
itab = typename(val.Type)
} else {
}
// Create a copy of l to modify while we emit data.
- n := l.copy()
+ n := ir.Copy(l)
// Emit itab, advance offset.
addrsym(n, itab.Left) // itab is an OADDR node
// Emit data.
if isdirectiface(val.Type) {
- if val.Op == ONIL {
+ if val.Op == ir.ONIL {
// Nil is zero, nothing to do.
return true
}
// Copy val directly into n.
n.Type = val.Type
setlineno(val)
- a := n.sepcopy()
+ a := ir.SepCopy(n)
if !s.staticassign(a, val) {
- s.append(nod(OAS, a, val))
+ s.append(ir.Nod(ir.OAS, a, val))
}
} else {
// Construct temp to hold val, write pointer to temp into n.
a := staticname(val.Type)
s.inittemps[val] = a
if !s.staticassign(a, val) {
- s.append(nod(OAS, a, val))
+ s.append(ir.Nod(ir.OAS, a, val))
}
addrsym(n, a)
}
// staticname returns a name backed by a (writable) static data symbol.
// Use readonlystaticname for read-only node.
-func staticname(t *types.Type) *Node {
+func staticname(t *types.Type) *ir.Node {
// Don't use lookupN; it interns the resulting string, but these are all unique.
- n := newname(lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
+ n := NewName(lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
statuniqgen++
- addvar(n, t, PEXTERN)
+ addvar(n, t, ir.PEXTERN)
n.Sym.Linksym().Set(obj.AttrLocal, true)
return n
}
// readonlystaticname returns a name backed by a (writable) static data symbol.
-func readonlystaticname(t *types.Type) *Node {
+func readonlystaticname(t *types.Type) *ir.Node {
n := staticname(t)
n.MarkReadonly()
n.Sym.Linksym().Set(obj.AttrContentAddressable, true)
return n
}
-func (n *Node) isSimpleName() bool {
- return (n.Op == ONAME || n.Op == OMETHEXPR) && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
+func isSimpleName(n *ir.Node) bool {
+ return (n.Op == ir.ONAME || n.Op == ir.OMETHEXPR) && n.Class() != ir.PAUTOHEAP && n.Class() != ir.PEXTERN
}
-func litas(l *Node, r *Node, init *Nodes) {
- a := nod(OAS, l, r)
+func litas(l *ir.Node, r *ir.Node, init *ir.Nodes) {
+ a := ir.Nod(ir.OAS, l, r)
a = typecheck(a, ctxStmt)
a = walkexpr(a, init)
init.Append(a)
// getdyn calculates the initGenType for n.
// If top is false, getdyn is recursing.
-func getdyn(n *Node, top bool) initGenType {
+func getdyn(n *ir.Node, top bool) initGenType {
switch n.Op {
default:
- if n.isGoConst() {
+ if isGoConst(n) {
return initConst
}
return initDynamic
- case OSLICELIT:
+ case ir.OSLICELIT:
if !top {
return initDynamic
}
return initDynamic
}
- case OARRAYLIT, OSTRUCTLIT:
+ case ir.OARRAYLIT, ir.OSTRUCTLIT:
}
var mode initGenType
for _, n1 := range n.List.Slice() {
switch n1.Op {
- case OKEY:
+ case ir.OKEY:
n1 = n1.Right
- case OSTRUCTKEY:
+ case ir.OSTRUCTKEY:
n1 = n1.Left
}
mode |= getdyn(n1, false)
}
// isStaticCompositeLiteral reports whether n is a compile-time constant.
-func isStaticCompositeLiteral(n *Node) bool {
+func isStaticCompositeLiteral(n *ir.Node) bool {
switch n.Op {
- case OSLICELIT:
+ case ir.OSLICELIT:
return false
- case OARRAYLIT:
+ case ir.OARRAYLIT:
for _, r := range n.List.Slice() {
- if r.Op == OKEY {
+ if r.Op == ir.OKEY {
r = r.Right
}
if !isStaticCompositeLiteral(r) {
}
}
return true
- case OSTRUCTLIT:
+ case ir.OSTRUCTLIT:
for _, r := range n.List.Slice() {
- if r.Op != OSTRUCTKEY {
+ if r.Op != ir.OSTRUCTKEY {
base.Fatalf("isStaticCompositeLiteral: rhs not OSTRUCTKEY: %v", r)
}
if !isStaticCompositeLiteral(r.Left) {
}
}
return true
- case OLITERAL, ONIL:
+ case ir.OLITERAL, ir.ONIL:
return true
- case OCONVIFACE:
+ case ir.OCONVIFACE:
// See staticassign's OCONVIFACE case for comments.
val := n
- for val.Op == OCONVIFACE {
+ for val.Op == ir.OCONVIFACE {
val = val.Left
}
if val.Type.IsInterface() {
- return val.Op == ONIL
+ return val.Op == ir.ONIL
}
- if isdirectiface(val.Type) && val.Op == ONIL {
+ if isdirectiface(val.Type) && val.Op == ir.ONIL {
return true
}
return isStaticCompositeLiteral(val)
// fixedlit handles struct, array, and slice literals.
// TODO: expand documentation.
-func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes) {
- isBlank := var_ == nblank
- var splitnode func(*Node) (a *Node, value *Node)
+func fixedlit(ctxt initContext, kind initKind, n *ir.Node, 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 OARRAYLIT, OSLICELIT:
+ case ir.OARRAYLIT, ir.OSLICELIT:
var k int64
- splitnode = func(r *Node) (*Node, *Node) {
- if r.Op == OKEY {
+ splitnode = func(r *ir.Node) (*ir.Node, *ir.Node) {
+ if r.Op == ir.OKEY {
k = indexconst(r.Left)
if k < 0 {
base.Fatalf("fixedlit: invalid index %v", r.Left)
}
r = r.Right
}
- a := nod(OINDEX, var_, nodintconst(k))
+ a := ir.Nod(ir.OINDEX, var_, nodintconst(k))
k++
if isBlank {
- a = nblank
+ a = ir.BlankNode
}
return a, r
}
- case OSTRUCTLIT:
- splitnode = func(r *Node) (*Node, *Node) {
- if r.Op != OSTRUCTKEY {
+ case ir.OSTRUCTLIT:
+ splitnode = func(r *ir.Node) (*ir.Node, *ir.Node) {
+ if r.Op != ir.OSTRUCTKEY {
base.Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
}
if r.Sym.IsBlank() || isBlank {
- return nblank, r.Left
+ return ir.BlankNode, r.Left
}
setlineno(r)
- return nodSym(ODOT, var_, r.Sym), r.Left
+ return nodSym(ir.ODOT, var_, r.Sym), r.Left
}
default:
base.Fatalf("fixedlit bad op: %v", n.Op)
for _, r := range n.List.Slice() {
a, value := splitnode(r)
- if a == nblank && candiscard(value) {
+ if a == ir.BlankNode && candiscard(value) {
continue
}
switch value.Op {
- case OSLICELIT:
+ case ir.OSLICELIT:
if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
slicelit(ctxt, value, a, init)
continue
}
- case OARRAYLIT, OSTRUCTLIT:
+ case ir.OARRAYLIT, ir.OSTRUCTLIT:
fixedlit(ctxt, kind, value, a, init)
continue
}
- islit := value.isGoConst()
+ islit := isGoConst(value)
if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
continue
}
// build list of assignments: var[index] = expr
setlineno(a)
- a = nod(OAS, a, value)
+ a = ir.Nod(ir.OAS, a, value)
a = typecheck(a, ctxStmt)
switch kind {
case initKindStatic:
genAsStatic(a)
case initKindDynamic, initKindLocalCode:
- a = orderStmtInPlace(a, map[string][]*Node{})
+ a = orderStmtInPlace(a, map[string][]*ir.Node{})
a = walkstmt(a)
init.Append(a)
default:
}
}
-func isSmallSliceLit(n *Node) bool {
- if n.Op != OSLICELIT {
+func isSmallSliceLit(n *ir.Node) bool {
+ if n.Op != ir.OSLICELIT {
return false
}
return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64Val() <= smallArrayBytes/n.Type.Elem().Width)
}
-func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
+func slicelit(ctxt initContext, n *ir.Node, var_ *ir.Node, init *ir.Nodes) {
// make an array type corresponding the number of elements we have
t := types.NewArray(n.Type.Elem(), n.Right.Int64Val())
dowidth(t)
// copy static to slice
var_ = typecheck(var_, ctxExpr|ctxAssign)
nam := stataddr(var_)
- if nam == nil || nam.Class() != PEXTERN {
+ if nam == nil || nam.Class() != ir.PEXTERN {
base.Fatalf("slicelit: %v", var_)
}
slicesym(nam, vstat, t.NumElem())
// if the literal contains constants,
// make static initialized array (1),(2)
- var vstat *Node
+ var vstat *ir.Node
mode := getdyn(n, true)
if mode&initConst != 0 && !isSmallSliceLit(n) {
vauto := temp(types.NewPtr(t))
// set auto to point at new temp or heap (3 assign)
- var a *Node
+ var a *ir.Node
if x := prealloc[n]; x != nil {
// temp allocated during order.go for dddarg
if !types.Identical(t, x.Type) {
}
if vstat == nil {
- a = nod(OAS, x, nil)
+ a = ir.Nod(ir.OAS, x, nil)
a = typecheck(a, ctxStmt)
init.Append(a) // zero new temp
} else {
// Declare that we're about to initialize all of x.
// (Which happens at the *vauto = vstat below.)
- init.Append(nod(OVARDEF, x, nil))
+ init.Append(ir.Nod(ir.OVARDEF, x, nil))
}
- a = nod(OADDR, x, nil)
+ a = ir.Nod(ir.OADDR, x, nil)
} else if n.Esc == EscNone {
a = temp(t)
if vstat == nil {
- a = nod(OAS, temp(t), nil)
+ a = ir.Nod(ir.OAS, temp(t), nil)
a = typecheck(a, ctxStmt)
init.Append(a) // zero new temp
a = a.Left
} else {
- init.Append(nod(OVARDEF, a, nil))
+ init.Append(ir.Nod(ir.OVARDEF, a, nil))
}
- a = nod(OADDR, a, nil)
+ a = ir.Nod(ir.OADDR, a, nil)
} else {
- a = nod(ONEW, nil, nil)
+ a = ir.Nod(ir.ONEW, nil, nil)
a.List.Set1(typenod(t))
}
- a = nod(OAS, vauto, a)
+ a = ir.Nod(ir.OAS, vauto, a)
a = typecheck(a, ctxStmt)
a = walkexpr(a, init)
init.Append(a)
if vstat != nil {
// copy static to heap (4)
- a = nod(ODEREF, vauto, nil)
+ a = ir.Nod(ir.ODEREF, vauto, nil)
- a = nod(OAS, a, vstat)
+ a = ir.Nod(ir.OAS, a, vstat)
a = typecheck(a, ctxStmt)
a = walkexpr(a, init)
init.Append(a)
// put dynamics into array (5)
var index int64
for _, value := range n.List.Slice() {
- if value.Op == OKEY {
+ if value.Op == ir.OKEY {
index = indexconst(value.Left)
if index < 0 {
base.Fatalf("slicelit: invalid index %v", value.Left)
}
value = value.Right
}
- a := nod(OINDEX, vauto, nodintconst(index))
+ a := ir.Nod(ir.OINDEX, vauto, nodintconst(index))
a.SetBounded(true)
index++
// TODO need to check bounds?
switch value.Op {
- case OSLICELIT:
+ case ir.OSLICELIT:
break
- case OARRAYLIT, OSTRUCTLIT:
+ case ir.OARRAYLIT, ir.OSTRUCTLIT:
k := initKindDynamic
if vstat == nil {
// Generate both static and dynamic initializations.
continue
}
- if vstat != nil && value.isGoConst() { // already set by copy from static value
+ if vstat != nil && isGoConst(value) { // already set by copy from static value
continue
}
// build list of vauto[c] = expr
setlineno(value)
- a = nod(OAS, a, value)
+ a = ir.Nod(ir.OAS, a, value)
a = typecheck(a, ctxStmt)
- a = orderStmtInPlace(a, map[string][]*Node{})
+ a = orderStmtInPlace(a, map[string][]*ir.Node{})
a = walkstmt(a)
init.Append(a)
}
// make slice out of heap (6)
- a = nod(OAS, var_, nod(OSLICE, vauto, nil))
+ a = ir.Nod(ir.OAS, var_, ir.Nod(ir.OSLICE, vauto, nil))
a = typecheck(a, ctxStmt)
- a = orderStmtInPlace(a, map[string][]*Node{})
+ a = orderStmtInPlace(a, map[string][]*ir.Node{})
a = walkstmt(a)
init.Append(a)
}
-func maplit(n *Node, m *Node, init *Nodes) {
+func maplit(n *ir.Node, m *ir.Node, init *ir.Nodes) {
// make the map var
- a := nod(OMAKE, nil, nil)
+ a := ir.Nod(ir.OMAKE, nil, nil)
a.Esc = n.Esc
a.List.Set2(typenod(n.Type), nodintconst(int64(n.List.Len())))
litas(m, a, init)
vstatk := readonlystaticname(tk)
vstate := readonlystaticname(te)
- datak := nod(OARRAYLIT, nil, nil)
- datae := nod(OARRAYLIT, nil, nil)
+ datak := ir.Nod(ir.OARRAYLIT, nil, nil)
+ datae := ir.Nod(ir.OARRAYLIT, nil, nil)
for _, r := range entries {
datak.List.Append(r.Left)
datae.List.Append(r.Right)
// for i = 0; i < len(vstatk); i++ {
// map[vstatk[i]] = vstate[i]
// }
- i := temp(types.Types[TINT])
- rhs := nod(OINDEX, vstate, i)
+ i := temp(types.Types[types.TINT])
+ rhs := ir.Nod(ir.OINDEX, vstate, i)
rhs.SetBounded(true)
- kidx := nod(OINDEX, vstatk, i)
+ kidx := ir.Nod(ir.OINDEX, vstatk, i)
kidx.SetBounded(true)
- lhs := nod(OINDEX, m, kidx)
+ lhs := ir.Nod(ir.OINDEX, m, kidx)
- zero := nod(OAS, i, nodintconst(0))
- cond := nod(OLT, i, nodintconst(tk.NumElem()))
- incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
- body := nod(OAS, lhs, rhs)
+ zero := ir.Nod(ir.OAS, i, nodintconst(0))
+ cond := ir.Nod(ir.OLT, i, nodintconst(tk.NumElem()))
+ incr := ir.Nod(ir.OAS, i, ir.Nod(ir.OADD, i, nodintconst(1)))
+ body := ir.Nod(ir.OAS, lhs, rhs)
- loop := nod(OFOR, cond, incr)
+ loop := ir.Nod(ir.OFOR, cond, incr)
loop.Nbody.Set1(body)
loop.Ninit.Set1(zero)
index, elem := r.Left, r.Right
setlineno(index)
- a := nod(OAS, tmpkey, index)
+ a := ir.Nod(ir.OAS, tmpkey, index)
a = typecheck(a, ctxStmt)
a = walkstmt(a)
init.Append(a)
setlineno(elem)
- a = nod(OAS, tmpelem, elem)
+ a = ir.Nod(ir.OAS, tmpelem, elem)
a = typecheck(a, ctxStmt)
a = walkstmt(a)
init.Append(a)
setlineno(tmpelem)
- a = nod(OAS, nod(OINDEX, m, tmpkey), tmpelem)
+ a = ir.Nod(ir.OAS, ir.Nod(ir.OINDEX, m, tmpkey), tmpelem)
a = typecheck(a, ctxStmt)
a = walkstmt(a)
init.Append(a)
}
- a = nod(OVARKILL, tmpkey, nil)
+ a = ir.Nod(ir.OVARKILL, tmpkey, nil)
a = typecheck(a, ctxStmt)
init.Append(a)
- a = nod(OVARKILL, tmpelem, nil)
+ a = ir.Nod(ir.OVARKILL, tmpelem, nil)
a = typecheck(a, ctxStmt)
init.Append(a)
}
-func anylit(n *Node, var_ *Node, init *Nodes) {
+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 ONAME, OMETHEXPR:
- a := nod(OAS, var_, n)
+ case ir.ONAME, ir.OMETHEXPR:
+ a := ir.Nod(ir.OAS, var_, n)
a = typecheck(a, ctxStmt)
init.Append(a)
- case OPTRLIT:
+ case ir.OPTRLIT:
if !t.IsPtr() {
base.Fatalf("anylit: not ptr")
}
- var r *Node
+ var r *ir.Node
if n.Right != nil {
// n.Right is stack temporary used as backing store.
- init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410)
- r = nod(OADDR, n.Right, nil)
+ init.Append(ir.Nod(ir.OAS, n.Right, nil)) // zero backing store, just in case (#18410)
+ r = ir.Nod(ir.OADDR, n.Right, nil)
r = typecheck(r, ctxExpr)
} else {
- r = nod(ONEW, nil, nil)
+ r = ir.Nod(ir.ONEW, nil, nil)
r.SetTypecheck(1)
r.Type = t
r.Esc = n.Esc
}
r = walkexpr(r, init)
- a := nod(OAS, var_, r)
+ a := ir.Nod(ir.OAS, var_, r)
a = typecheck(a, ctxStmt)
init.Append(a)
- var_ = nod(ODEREF, var_, nil)
+ var_ = ir.Nod(ir.ODEREF, var_, nil)
var_ = typecheck(var_, ctxExpr|ctxAssign)
anylit(n.Left, var_, init)
- case OSTRUCTLIT, OARRAYLIT:
+ case ir.OSTRUCTLIT, ir.OARRAYLIT:
if !t.IsStruct() && !t.IsArray() {
base.Fatalf("anylit: not struct/array")
}
- if var_.isSimpleName() && n.List.Len() > 4 {
+ if isSimpleName(var_) && n.List.Len() > 4 {
// lay out static data
vstat := readonlystaticname(t)
ctxt := inInitFunction
- if n.Op == OARRAYLIT {
+ if n.Op == ir.OARRAYLIT {
ctxt = inNonInitFunction
}
fixedlit(ctxt, initKindStatic, n, vstat, init)
// copy static to var
- a := nod(OAS, var_, vstat)
+ a := ir.Nod(ir.OAS, var_, vstat)
a = typecheck(a, ctxStmt)
a = walkexpr(a, init)
}
var components int64
- if n.Op == OARRAYLIT {
+ if n.Op == ir.OARRAYLIT {
components = t.NumElem()
} else {
components = int64(t.NumFields())
}
// initialization of an array or struct with unspecified components (missing fields or arrays)
- if var_.isSimpleName() || int64(n.List.Len()) < components {
- a := nod(OAS, var_, nil)
+ if isSimpleName(var_) || int64(n.List.Len()) < components {
+ a := ir.Nod(ir.OAS, var_, nil)
a = typecheck(a, ctxStmt)
a = walkexpr(a, init)
init.Append(a)
fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
- case OSLICELIT:
+ case ir.OSLICELIT:
slicelit(inInitFunction, n, var_, init)
- case OMAPLIT:
+ case ir.OMAPLIT:
if !t.IsMap() {
base.Fatalf("anylit: not map")
}
}
}
-func oaslit(n *Node, init *Nodes) bool {
+func oaslit(n *ir.Node, init *ir.Nodes) bool {
if n.Left == nil || n.Right == nil {
// not a special composite literal assignment
return false
// not a special composite literal assignment
return false
}
- if !n.Left.isSimpleName() {
+ if !isSimpleName(n.Left) {
// not a special composite literal assignment
return false
}
// not a special composite literal assignment
return false
- case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
+ case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
if vmatch1(n.Left, n.Right) {
// not a special composite literal assignment
return false
anylit(n.Right, n.Left, init)
}
- n.Op = OEMPTY
+ n.Op = ir.OEMPTY
n.Right = nil
return true
}
-func getlit(lit *Node) int {
+func getlit(lit *ir.Node) int {
if smallintconst(lit) {
return int(lit.Int64Val())
}
}
// stataddr returns the static address of n, if n has one, or else nil.
-func stataddr(n *Node) *Node {
+func stataddr(n *ir.Node) *ir.Node {
if n == nil {
return nil
}
switch n.Op {
- case ONAME, OMETHEXPR:
- return n.sepcopy()
+ case ir.ONAME, ir.OMETHEXPR:
+ return ir.SepCopy(n)
- case ODOT:
+ case ir.ODOT:
nam := stataddr(n.Left)
if nam == nil {
break
nam.Type = n.Type
return nam
- case OINDEX:
+ case ir.OINDEX:
if n.Left.Type.IsSlice() {
break
}
return nil
}
-func (s *InitSchedule) initplan(n *Node) {
+func (s *InitSchedule) initplan(n *ir.Node) {
if s.initplans[n] != nil {
return
}
default:
base.Fatalf("initplan")
- case OARRAYLIT, OSLICELIT:
+ case ir.OARRAYLIT, ir.OSLICELIT:
var k int64
for _, a := range n.List.Slice() {
- if a.Op == OKEY {
+ if a.Op == ir.OKEY {
k = indexconst(a.Left)
if k < 0 {
base.Fatalf("initplan arraylit: invalid index %v", a.Left)
k++
}
- case OSTRUCTLIT:
+ case ir.OSTRUCTLIT:
for _, a := range n.List.Slice() {
- if a.Op != OSTRUCTKEY {
+ if a.Op != ir.OSTRUCTKEY {
base.Fatalf("initplan structlit")
}
if a.Sym.IsBlank() {
s.addvalue(p, a.Xoffset, a.Left)
}
- case OMAPLIT:
+ case ir.OMAPLIT:
for _, a := range n.List.Slice() {
- if a.Op != OKEY {
+ if a.Op != ir.OKEY {
base.Fatalf("initplan maplit")
}
s.addvalue(p, -1, a.Right)
}
}
-func (s *InitSchedule) addvalue(p *InitPlan, xoffset int64, n *Node) {
+func (s *InitSchedule) addvalue(p *InitPlan, xoffset int64, n *ir.Node) {
// special case: zero can be dropped entirely
if isZero(n) {
return
p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n})
}
-func isZero(n *Node) bool {
+func isZero(n *ir.Node) bool {
switch n.Op {
- case ONIL:
+ case ir.ONIL:
return true
- case OLITERAL:
+ case ir.OLITERAL:
switch u := n.Val(); u.Kind() {
case constant.String:
return constant.StringVal(u) == ""
return constant.Sign(u) == 0
}
- case OARRAYLIT:
+ case ir.OARRAYLIT:
for _, n1 := range n.List.Slice() {
- if n1.Op == OKEY {
+ if n1.Op == ir.OKEY {
n1 = n1.Right
}
if !isZero(n1) {
}
return true
- case OSTRUCTLIT:
+ case ir.OSTRUCTLIT:
for _, n1 := range n.List.Slice() {
if !isZero(n1.Left) {
return false
return false
}
-func isvaluelit(n *Node) bool {
- return n.Op == OARRAYLIT || n.Op == OSTRUCTLIT
+func isvaluelit(n *ir.Node) bool {
+ return n.Op == ir.OARRAYLIT || n.Op == ir.OSTRUCTLIT
}
-func genAsStatic(as *Node) {
+func genAsStatic(as *ir.Node) {
if as.Left.Type == nil {
base.Fatalf("genAsStatic as.Left not typechecked")
}
nam := stataddr(as.Left)
- if nam == nil || (nam.Class() != PEXTERN && as.Left != nblank) {
+ if nam == nil || (nam.Class() != ir.PEXTERN && as.Left != ir.BlankNode) {
base.Fatalf("genAsStatic: lhs %v", as.Left)
}
switch {
- case as.Right.Op == OLITERAL:
+ case as.Right.Op == ir.OLITERAL:
litsym(nam, as.Right, int(as.Right.Type.Width))
- case (as.Right.Op == ONAME || as.Right.Op == OMETHEXPR) && as.Right.Class() == PFUNC:
+ case (as.Right.Op == ir.ONAME || as.Right.Op == ir.OMETHEXPR) && as.Right.Class() == ir.PFUNC:
pfuncsym(nam, as.Right)
default:
base.Fatalf("genAsStatic: rhs %v", as.Right)
"bufio"
"bytes"
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/obj"
const maxOpenDefers = 8
// ssaDumpInlined holds all inlined functions when ssaDump contains a function name.
-var ssaDumpInlined []*Node
+var ssaDumpInlined []*ir.Node
func initssaconfig() {
types_ := ssa.NewTypes()
// Generate a few pointer types that are uncommon in the frontend but common in the backend.
// Caching is disabled in the backend, so generating these here avoids allocations.
- _ = types.NewPtr(types.Types[TINTER]) // *interface{}
- _ = types.NewPtr(types.NewPtr(types.Types[TSTRING])) // **string
- _ = types.NewPtr(types.NewSlice(types.Types[TINTER])) // *[]interface{}
- _ = types.NewPtr(types.NewPtr(types.Bytetype)) // **byte
- _ = types.NewPtr(types.NewSlice(types.Bytetype)) // *[]byte
- _ = types.NewPtr(types.NewSlice(types.Types[TSTRING])) // *[]string
- _ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[TUINT8]))) // ***uint8
- _ = types.NewPtr(types.Types[TINT16]) // *int16
- _ = types.NewPtr(types.Types[TINT64]) // *int64
- _ = types.NewPtr(types.Errortype) // *error
+ _ = types.NewPtr(types.Types[types.TINTER]) // *interface{}
+ _ = types.NewPtr(types.NewPtr(types.Types[types.TSTRING])) // **string
+ _ = types.NewPtr(types.NewSlice(types.Types[types.TINTER])) // *[]interface{}
+ _ = types.NewPtr(types.NewPtr(types.Bytetype)) // **byte
+ _ = types.NewPtr(types.NewSlice(types.Bytetype)) // *[]byte
+ _ = types.NewPtr(types.NewSlice(types.Types[types.TSTRING])) // *[]string
+ _ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[types.TUINT8]))) // ***uint8
+ _ = types.NewPtr(types.Types[types.TINT16]) // *int16
+ _ = types.NewPtr(types.Types[types.TINT64]) // *int64
+ _ = types.NewPtr(types.Errortype) // *error
types.NewPtrCacheEnabled = false
ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, base.Ctxt, base.Flag.N == 0)
ssaConfig.SoftFloat = thearch.SoftFloat
// function/method/interface call), where the receiver of a method call is
// considered as the 0th parameter. This does not include the receiver of an
// interface call.
-func getParam(n *Node, i int) *types.Field {
+func getParam(n *ir.Node, i int) *types.Field {
t := n.Left.Type
- if n.Op == OCALLMETH {
+ if n.Op == ir.OCALLMETH {
if i == 0 {
return t.Recv()
}
// - Size of the argument
// - Offset of where argument should be placed in the args frame when making call
func (s *state) emitOpenDeferInfo() {
- x := base.Ctxt.Lookup(s.curfn.Func.lsym.Name + ".opendefer")
- s.curfn.Func.lsym.Func().OpenCodedDeferInfo = x
+ x := base.Ctxt.Lookup(s.curfn.Func.LSym.Name + ".opendefer")
+ s.curfn.Func.LSym.Func().OpenCodedDeferInfo = x
off := 0
// Compute maxargsize (max size of arguments for all defers)
// buildssa builds an SSA function for fn.
// worker indicates which of the backend workers is doing the processing.
-func buildssa(fn *Node, worker int) *ssa.Func {
- name := fn.funcname()
+func buildssa(fn *ir.Node, worker int) *ssa.Func {
+ name := ir.FuncName(fn)
printssa := false
if ssaDump != "" { // match either a simple name e.g. "(*Reader).Reset", or a package.name e.g. "compress/gzip.(*Reader).Reset"
printssa = name == ssaDump || base.Ctxt.Pkgpath+"."+name == ssaDump
var astBuf *bytes.Buffer
if printssa {
astBuf = &bytes.Buffer{}
- fdumplist(astBuf, "buildssa-enter", fn.Func.Enter)
- fdumplist(astBuf, "buildssa-body", fn.Nbody)
- fdumplist(astBuf, "buildssa-exit", fn.Func.Exit)
+ ir.FDumpList(astBuf, "buildssa-enter", fn.Func.Enter)
+ ir.FDumpList(astBuf, "buildssa-body", fn.Nbody)
+ ir.FDumpList(astBuf, "buildssa-exit", fn.Func.Exit)
if ssaDumpStdout {
fmt.Println("generating SSA for", name)
fmt.Print(astBuf.String())
defer s.popLine()
s.hasdefer = fn.Func.HasDefer()
- if fn.Func.Pragma&CgoUnsafeArgs != 0 {
+ if fn.Func.Pragma&ir.CgoUnsafeArgs != 0 {
s.cgoUnsafeArgs = true
}
s.f.Name = name
s.f.DebugTest = s.f.DebugHashMatch("GOSSAHASH")
s.f.PrintOrHtmlSSA = printssa
- if fn.Func.Pragma&Nosplit != 0 {
+ if fn.Func.Pragma&ir.Nosplit != 0 {
s.f.NoSplit = true
}
s.panics = map[funcLine]*ssa.Block{}
// Allocate starting values
s.labels = map[string]*ssaLabel{}
- s.labeledNodes = map[*Node]*ssaLabel{}
- s.fwdVars = map[*Node]*ssa.Value{}
+ s.labeledNodes = map[*ir.Node]*ssaLabel{}
+ s.fwdVars = map[*ir.Node]*ssa.Value{}
s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
s.hasOpenDefers = base.Flag.N == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
s.hasOpenDefers = false
}
if s.hasOpenDefers &&
- s.curfn.Func.numReturns*s.curfn.Func.numDefers > 15 {
+ s.curfn.Func.NumReturns*s.curfn.Func.NumDefers > 15 {
// Since we are generating defer calls at every exit for
// open-coded defers, skip doing open-coded defers if there are
// too many returns (especially if there are multiple defers).
s.hasOpenDefers = false
}
- s.sp = s.entryNewValue0(ssa.OpSP, types.Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
- s.sb = s.entryNewValue0(ssa.OpSB, types.Types[TUINTPTR])
+ s.sp = s.entryNewValue0(ssa.OpSP, types.Types[types.TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
+ s.sb = s.entryNewValue0(ssa.OpSB, types.Types[types.TUINTPTR])
s.startBlock(s.f.Entry)
s.vars[memVar] = s.startmem
// Create the deferBits variable and stack slot. deferBits is a
// bitmask showing which of the open-coded defers in this function
// have been activated.
- deferBitsTemp := tempAt(src.NoXPos, s.curfn, types.Types[TUINT8])
+ deferBitsTemp := tempAt(src.NoXPos, s.curfn, types.Types[types.TUINT8])
s.deferBitsTemp = deferBitsTemp
// For this value, AuxInt is initialized to zero by default
- startDeferBits := s.entryNewValue0(ssa.OpConst8, types.Types[TUINT8])
+ startDeferBits := s.entryNewValue0(ssa.OpConst8, types.Types[types.TUINT8])
s.vars[deferBitsVar] = startDeferBits
s.deferBitsAddr = s.addr(deferBitsTemp)
- s.store(types.Types[TUINT8], s.deferBitsAddr, startDeferBits)
+ s.store(types.Types[types.TUINT8], s.deferBitsAddr, startDeferBits)
// Make sure that the deferBits stack slot is kept alive (for use
// by panics) and stores to deferBits are not eliminated, even if
// all checking code on deferBits in the function exit can be
}
// Generate addresses of local declarations
- s.decladdrs = map[*Node]*ssa.Value{}
+ s.decladdrs = map[*ir.Node]*ssa.Value{}
var args []ssa.Param
var results []ssa.Param
for _, n := range fn.Func.Dcl {
switch n.Class() {
- case PPARAM:
+ case ir.PPARAM:
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
args = append(args, ssa.Param{Type: n.Type, Offset: int32(n.Xoffset)})
- case PPARAMOUT:
+ case ir.PPARAMOUT:
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
results = append(results, ssa.Param{Type: n.Type, Offset: int32(n.Xoffset)})
if s.canSSA(n) {
// the function.
s.returns = append(s.returns, n)
}
- case PAUTO:
+ case ir.PAUTO:
// processed at each use, to prevent Addr coming
// before the decl.
- case PAUTOHEAP:
+ case ir.PAUTOHEAP:
// moved to heap - already handled by frontend
- case PFUNC:
+ case ir.PFUNC:
// local function - already handled by frontend
default:
s.Fatalf("local variable with class %v unimplemented", n.Class())
// Populate SSAable arguments.
for _, n := range fn.Func.Dcl {
- if n.Class() == PPARAM && s.canSSA(n) {
+ if n.Class() == ir.PPARAM && s.canSSA(n) {
v := s.newValue0A(ssa.OpArg, n.Type, n)
s.vars[n] = v
s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself.
return s.f
}
-func dumpSourcesColumn(writer *ssa.HTMLWriter, fn *Node) {
+func dumpSourcesColumn(writer *ssa.HTMLWriter, fn *ir.Node) {
// Read sources of target function fn.
fname := base.Ctxt.PosTable.Pos(fn.Pos).Filename()
targetFn, err := readFuncLines(fname, fn.Pos.Line(), fn.Func.Endlineno.Line())
// Information about each open-coded defer.
type openDeferInfo struct {
// The ODEFER node representing the function call of the defer
- n *Node
+ n *ir.Node
// If defer call is closure call, the address of the argtmp where the
// closure is stored.
closure *ssa.Value
// The node representing the argtmp where the closure is stored - used for
// function, method, or interface call, to store a closure that panic
// processing can use for this defer.
- closureNode *Node
+ closureNode *ir.Node
// If defer call is interface call, the address of the argtmp where the
// receiver is stored
rcvr *ssa.Value
// The node representing the argtmp where the receiver is stored
- rcvrNode *Node
+ rcvrNode *ir.Node
// The addresses of the argtmps where the evaluated arguments of the defer
// function call are stored.
argVals []*ssa.Value
// The nodes representing the argtmps where the args of the defer are stored
- argNodes []*Node
+ argNodes []*ir.Node
}
type state struct {
f *ssa.Func
// Node for function
- curfn *Node
+ curfn *ir.Node
// labels and labeled control flow nodes (OFOR, OFORUNTIL, OSWITCH, OSELECT) in f
labels map[string]*ssaLabel
- labeledNodes map[*Node]*ssaLabel
+ labeledNodes map[*ir.Node]*ssaLabel
// unlabeled break and continue statement tracking
breakTo *ssa.Block // current target for plain break statement
// variable assignments in the current block (map from variable symbol to ssa value)
// *Node is the unique identifier (an ONAME Node) for the variable.
// TODO: keep a single varnum map, then make all of these maps slices instead?
- vars map[*Node]*ssa.Value
+ vars map[*ir.Node]*ssa.Value
// fwdVars are variables that are used before they are defined in the current block.
// This map exists just to coalesce multiple references into a single FwdRef op.
// *Node is the unique identifier (an ONAME Node) for the variable.
- fwdVars map[*Node]*ssa.Value
+ fwdVars map[*ir.Node]*ssa.Value
// all defined variables at the end of each block. Indexed by block ID.
- defvars []map[*Node]*ssa.Value
+ defvars []map[*ir.Node]*ssa.Value
// addresses of PPARAM and PPARAMOUT variables.
- decladdrs map[*Node]*ssa.Value
+ decladdrs map[*ir.Node]*ssa.Value
// starting values. Memory, stack pointer, and globals pointer
startmem *ssa.Value
sb *ssa.Value
// value representing address of where deferBits autotmp is stored
deferBitsAddr *ssa.Value
- deferBitsTemp *Node
+ deferBitsTemp *ir.Node
// line number stack. The current line number is top of stack
line []src.XPos
panics map[funcLine]*ssa.Block
// list of PPARAMOUT (return) variables.
- returns []*Node
+ returns []*ir.Node
cgoUnsafeArgs bool
hasdefer bool // whether the function contains a defer statement
func (s *state) Warnl(pos src.XPos, msg string, args ...interface{}) { s.f.Warnl(pos, msg, args...) }
func (s *state) Debug_checknil() bool { return s.f.Frontend().Debug_checknil() }
-func ssaMarker(name string) *Node {
- return newname(&types.Sym{Name: name})
+func ssaMarker(name string) *ir.Node {
+ return NewName(&types.Sym{Name: name})
}
var (
s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
}
s.curBlock = b
- s.vars = map[*Node]*ssa.Value{}
+ s.vars = map[*ir.Node]*ssa.Value{}
for n := range s.fwdVars {
delete(s.fwdVars, n)
}
return s.f.ConstEmptyString(t)
}
func (s *state) constBool(c bool) *ssa.Value {
- return s.f.ConstBool(types.Types[TBOOL], c)
+ return s.f.ConstBool(types.Types[types.TBOOL], c)
}
func (s *state) constInt8(t *types.Type, c int8) *ssa.Value {
return s.f.ConstInt8(t, c)
args := []*ssa.Value{addr}
if needWidth {
- args = append(args, s.constInt(types.Types[TUINTPTR], w))
+ args = append(args, s.constInt(types.Types[types.TUINTPTR], w))
}
s.rtcall(fn, true, nil, args...)
}
}
// stmtList converts the statement list n to SSA and adds it to s.
-func (s *state) stmtList(l Nodes) {
+func (s *state) stmtList(l ir.Nodes) {
for _, n := range l.Slice() {
s.stmt(n)
}
}
// stmt converts the statement n to SSA and adds it to s.
-func (s *state) stmt(n *Node) {
- if !(n.Op == OVARKILL || n.Op == OVARLIVE || n.Op == OVARDEF) {
+func (s *state) stmt(n *ir.Node) {
+ if !(n.Op == ir.OVARKILL || n.Op == ir.OVARLIVE || n.Op == ir.OVARDEF) {
// OVARKILL, OVARLIVE, and OVARDEF are invisible to the programmer, so we don't use their line numbers to avoid confusion in debugging.
s.pushLine(n.Pos)
defer s.popLine()
// If s.curBlock is nil, and n isn't a label (which might have an associated goto somewhere),
// then this code is dead. Stop here.
- if s.curBlock == nil && n.Op != OLABEL {
+ if s.curBlock == nil && n.Op != ir.OLABEL {
return
}
s.stmtList(n.Ninit)
switch n.Op {
- case OBLOCK:
+ case ir.OBLOCK:
s.stmtList(n.List)
// No-ops
- case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
+ case ir.OEMPTY, ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL:
// Expression statements
- case OCALLFUNC:
+ case ir.OCALLFUNC:
if isIntrinsicCall(n) {
s.intrinsicCall(n)
return
}
fallthrough
- case OCALLMETH, OCALLINTER:
+ case ir.OCALLMETH, ir.OCALLINTER:
s.callResult(n, callNormal)
- if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class() == PFUNC {
+ if n.Op == ir.OCALLFUNC && n.Left.Op == ir.ONAME && n.Left.Class() == ir.PFUNC {
if fn := n.Left.Sym.Name; base.Flag.CompilingRuntime && fn == "throw" ||
n.Left.Sym.Pkg == Runtimepkg && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap") {
m := s.mem()
// go through SSA.
}
}
- case ODEFER:
+ case ir.ODEFER:
if base.Debug.Defer > 0 {
var defertype string
if s.hasOpenDefers {
}
s.callResult(n.Left, d)
}
- case OGO:
+ case ir.OGO:
s.callResult(n.Left, callGo)
- case OAS2DOTTYPE:
+ case ir.OAS2DOTTYPE:
res, resok := s.dottype(n.Right, true)
deref := false
if !canSSAType(n.Right.Type) {
s.assign(n.List.Second(), resok, false, 0)
return
- case OAS2FUNC:
+ case ir.OAS2FUNC:
// We come here only when it is an intrinsic call returning two values.
if !isIntrinsicCall(n.Right) {
s.Fatalf("non-intrinsic AS2FUNC not expanded %v", n.Right)
s.assign(n.List.Second(), v2, false, 0)
return
- case ODCL:
- if n.Left.Class() == PAUTOHEAP {
+ case ir.ODCL:
+ if n.Left.Class() == ir.PAUTOHEAP {
s.Fatalf("DCL %v", n)
}
- case OLABEL:
+ case ir.OLABEL:
sym := n.Sym
lab := s.label(sym)
// Associate label with its control flow node, if any
- if ctl := n.labeledControl(); ctl != nil {
+ if ctl := labeledControl(n); ctl != nil {
s.labeledNodes[ctl] = lab
}
}
s.startBlock(lab.target)
- case OGOTO:
+ case ir.OGOTO:
sym := n.Sym
lab := s.label(sym)
b.Pos = s.lastPos.WithIsStmt() // Do this even if b is an empty block.
b.AddEdgeTo(lab.target)
- case OAS:
- if n.Left == n.Right && n.Left.Op == ONAME {
+ case ir.OAS:
+ if n.Left == n.Right && n.Left.Op == ir.ONAME {
// An x=x assignment. No point in doing anything
// here. In addition, skipping this assignment
// prevents generating:
rhs := n.Right
if rhs != nil {
switch rhs.Op {
- case OSTRUCTLIT, OARRAYLIT, OSLICELIT:
+ case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT:
// All literals with nonzero fields have already been
// rewritten during walk. Any that remain are just T{}
// or equivalents. Use the zero value.
s.Fatalf("literal with nonzero value in SSA: %v", rhs)
}
rhs = nil
- case OAPPEND:
+ case ir.OAPPEND:
// Check whether we're writing the result of an append back to the same slice.
// If so, we handle it specially to avoid write barriers on the fast
// (non-growth) path.
}
}
- if n.Left.isBlank() {
+ if ir.IsBlank(n.Left) {
// _ = rhs
// Just evaluate rhs for side-effects.
if rhs != nil {
}
var skip skipMask
- if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) {
+ if rhs != nil && (rhs.Op == ir.OSLICE || rhs.Op == ir.OSLICE3 || rhs.Op == ir.OSLICESTR) && samesafeexpr(rhs.Left, n.Left) {
// We're assigning a slicing operation back to its source.
// Don't write back fields we aren't changing. See issue #14855.
i, j, k := rhs.SliceBounds()
- if i != nil && (i.Op == OLITERAL && i.Val().Kind() == constant.Int && i.Int64Val() == 0) {
+ if i != nil && (i.Op == ir.OLITERAL && i.Val().Kind() == constant.Int && i.Int64Val() == 0) {
// [0:...] is the same as [:...]
i = nil
}
s.assign(n.Left, r, deref, skip)
- case OIF:
- if Isconst(n.Left, constant.Bool) {
+ case ir.OIF:
+ if ir.IsConst(n.Left, constant.Bool) {
s.stmtList(n.Left.Ninit)
if n.Left.BoolVal() {
s.stmtList(n.Nbody)
}
s.startBlock(bEnd)
- case ORETURN:
+ case ir.ORETURN:
s.stmtList(n.List)
b := s.exit()
b.Pos = s.lastPos.WithIsStmt()
- case ORETJMP:
+ case ir.ORETJMP:
s.stmtList(n.List)
b := s.exit()
b.Kind = ssa.BlockRetJmp // override BlockRet
b.Aux = n.Sym.Linksym()
- case OCONTINUE, OBREAK:
+ case ir.OCONTINUE, ir.OBREAK:
var to *ssa.Block
if n.Sym == nil {
// plain break/continue
switch n.Op {
- case OCONTINUE:
+ case ir.OCONTINUE:
to = s.continueTo
- case OBREAK:
+ case ir.OBREAK:
to = s.breakTo
}
} else {
sym := n.Sym
lab := s.label(sym)
switch n.Op {
- case OCONTINUE:
+ case ir.OCONTINUE:
to = lab.continueTarget
- case OBREAK:
+ case ir.OBREAK:
to = lab.breakTarget
}
}
b.Pos = s.lastPos.WithIsStmt() // Do this even if b is an empty block.
b.AddEdgeTo(to)
- case OFOR, OFORUNTIL:
+ case ir.OFOR, ir.OFORUNTIL:
// OFOR: for Ninit; Left; Right { Nbody }
// cond (Left); body (Nbody); incr (Right)
//
// first, jump to condition test (OFOR) or body (OFORUNTIL)
b := s.endBlock()
- if n.Op == OFOR {
+ if n.Op == ir.OFOR {
b.AddEdgeTo(bCond)
// generate code to test condition
s.startBlock(bCond)
if n.Right != nil {
s.stmt(n.Right)
}
- if n.Op == OFOR {
+ if n.Op == ir.OFOR {
if b := s.endBlock(); b != nil {
b.AddEdgeTo(bCond)
// It can happen that bIncr ends in a block containing only VARKILL,
// and that muddles the debugging experience.
- if n.Op != OFORUNTIL && b.Pos == src.NoXPos {
+ if n.Op != ir.OFORUNTIL && b.Pos == src.NoXPos {
b.Pos = bCond.Pos
}
}
s.startBlock(bEnd)
- case OSWITCH, OSELECT:
+ case ir.OSWITCH, ir.OSELECT:
// These have been mostly rewritten by the front end into their Nbody fields.
// Our main task is to correctly hook up any break statements.
bEnd := s.f.NewBlock(ssa.BlockPlain)
}
s.startBlock(bEnd)
- case OVARDEF:
+ case ir.OVARDEF:
if !s.canSSA(n.Left) {
s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, n.Left, s.mem(), false)
}
- case OVARKILL:
+ case ir.OVARKILL:
// Insert a varkill op to record that a variable is no longer live.
// We only care about liveness info at call sites, so putting the
// varkill in the store chain is enough to keep it correctly ordered
s.vars[memVar] = s.newValue1Apos(ssa.OpVarKill, types.TypeMem, n.Left, s.mem(), false)
}
- case OVARLIVE:
+ case ir.OVARLIVE:
// Insert a varlive op to record that a variable is still live.
if !n.Left.Name.Addrtaken() {
s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left)
}
switch n.Left.Class() {
- case PAUTO, PPARAM, PPARAMOUT:
+ case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
default:
s.Fatalf("VARLIVE variable %v must be Auto or Arg", n.Left)
}
s.vars[memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, n.Left, s.mem())
- case OCHECKNIL:
+ case ir.OCHECKNIL:
p := s.expr(n.Left)
s.nilCheck(p)
- case OINLMARK:
+ case ir.OINLMARK:
s.newValue1I(ssa.OpInlMark, types.TypeVoid, n.Xoffset, s.mem())
default:
}
type opAndType struct {
- op Op
+ op ir.Op
etype types.EType
}
var opToSSA = map[opAndType]ssa.Op{
- opAndType{OADD, TINT8}: ssa.OpAdd8,
- opAndType{OADD, TUINT8}: ssa.OpAdd8,
- opAndType{OADD, TINT16}: ssa.OpAdd16,
- opAndType{OADD, TUINT16}: ssa.OpAdd16,
- opAndType{OADD, TINT32}: ssa.OpAdd32,
- opAndType{OADD, TUINT32}: ssa.OpAdd32,
- opAndType{OADD, TINT64}: ssa.OpAdd64,
- opAndType{OADD, TUINT64}: ssa.OpAdd64,
- opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
- opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
-
- opAndType{OSUB, TINT8}: ssa.OpSub8,
- opAndType{OSUB, TUINT8}: ssa.OpSub8,
- opAndType{OSUB, TINT16}: ssa.OpSub16,
- opAndType{OSUB, TUINT16}: ssa.OpSub16,
- opAndType{OSUB, TINT32}: ssa.OpSub32,
- opAndType{OSUB, TUINT32}: ssa.OpSub32,
- opAndType{OSUB, TINT64}: ssa.OpSub64,
- opAndType{OSUB, TUINT64}: ssa.OpSub64,
- opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
- opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
-
- opAndType{ONOT, TBOOL}: ssa.OpNot,
-
- opAndType{ONEG, TINT8}: ssa.OpNeg8,
- opAndType{ONEG, TUINT8}: ssa.OpNeg8,
- opAndType{ONEG, TINT16}: ssa.OpNeg16,
- opAndType{ONEG, TUINT16}: ssa.OpNeg16,
- opAndType{ONEG, TINT32}: ssa.OpNeg32,
- opAndType{ONEG, TUINT32}: ssa.OpNeg32,
- opAndType{ONEG, TINT64}: ssa.OpNeg64,
- opAndType{ONEG, TUINT64}: ssa.OpNeg64,
- opAndType{ONEG, TFLOAT32}: ssa.OpNeg32F,
- opAndType{ONEG, TFLOAT64}: ssa.OpNeg64F,
-
- opAndType{OBITNOT, TINT8}: ssa.OpCom8,
- opAndType{OBITNOT, TUINT8}: ssa.OpCom8,
- opAndType{OBITNOT, TINT16}: ssa.OpCom16,
- opAndType{OBITNOT, TUINT16}: ssa.OpCom16,
- opAndType{OBITNOT, TINT32}: ssa.OpCom32,
- opAndType{OBITNOT, TUINT32}: ssa.OpCom32,
- opAndType{OBITNOT, TINT64}: ssa.OpCom64,
- opAndType{OBITNOT, TUINT64}: ssa.OpCom64,
-
- opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
- opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
- opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
- opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
-
- opAndType{OMUL, TINT8}: ssa.OpMul8,
- opAndType{OMUL, TUINT8}: ssa.OpMul8,
- opAndType{OMUL, TINT16}: ssa.OpMul16,
- opAndType{OMUL, TUINT16}: ssa.OpMul16,
- opAndType{OMUL, TINT32}: ssa.OpMul32,
- opAndType{OMUL, TUINT32}: ssa.OpMul32,
- opAndType{OMUL, TINT64}: ssa.OpMul64,
- opAndType{OMUL, TUINT64}: ssa.OpMul64,
- opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
- opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
-
- opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
- opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
-
- opAndType{ODIV, TINT8}: ssa.OpDiv8,
- opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
- opAndType{ODIV, TINT16}: ssa.OpDiv16,
- opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
- opAndType{ODIV, TINT32}: ssa.OpDiv32,
- opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
- opAndType{ODIV, TINT64}: ssa.OpDiv64,
- opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
-
- opAndType{OMOD, TINT8}: ssa.OpMod8,
- opAndType{OMOD, TUINT8}: ssa.OpMod8u,
- opAndType{OMOD, TINT16}: ssa.OpMod16,
- opAndType{OMOD, TUINT16}: ssa.OpMod16u,
- opAndType{OMOD, TINT32}: ssa.OpMod32,
- opAndType{OMOD, TUINT32}: ssa.OpMod32u,
- opAndType{OMOD, TINT64}: ssa.OpMod64,
- opAndType{OMOD, TUINT64}: ssa.OpMod64u,
-
- opAndType{OAND, TINT8}: ssa.OpAnd8,
- opAndType{OAND, TUINT8}: ssa.OpAnd8,
- opAndType{OAND, TINT16}: ssa.OpAnd16,
- opAndType{OAND, TUINT16}: ssa.OpAnd16,
- opAndType{OAND, TINT32}: ssa.OpAnd32,
- opAndType{OAND, TUINT32}: ssa.OpAnd32,
- opAndType{OAND, TINT64}: ssa.OpAnd64,
- opAndType{OAND, TUINT64}: ssa.OpAnd64,
-
- opAndType{OOR, TINT8}: ssa.OpOr8,
- opAndType{OOR, TUINT8}: ssa.OpOr8,
- opAndType{OOR, TINT16}: ssa.OpOr16,
- opAndType{OOR, TUINT16}: ssa.OpOr16,
- opAndType{OOR, TINT32}: ssa.OpOr32,
- opAndType{OOR, TUINT32}: ssa.OpOr32,
- opAndType{OOR, TINT64}: ssa.OpOr64,
- opAndType{OOR, TUINT64}: ssa.OpOr64,
-
- opAndType{OXOR, TINT8}: ssa.OpXor8,
- opAndType{OXOR, TUINT8}: ssa.OpXor8,
- opAndType{OXOR, TINT16}: ssa.OpXor16,
- opAndType{OXOR, TUINT16}: ssa.OpXor16,
- opAndType{OXOR, TINT32}: ssa.OpXor32,
- opAndType{OXOR, TUINT32}: ssa.OpXor32,
- opAndType{OXOR, TINT64}: ssa.OpXor64,
- opAndType{OXOR, TUINT64}: ssa.OpXor64,
-
- opAndType{OEQ, TBOOL}: ssa.OpEqB,
- opAndType{OEQ, TINT8}: ssa.OpEq8,
- opAndType{OEQ, TUINT8}: ssa.OpEq8,
- opAndType{OEQ, TINT16}: ssa.OpEq16,
- opAndType{OEQ, TUINT16}: ssa.OpEq16,
- opAndType{OEQ, TINT32}: ssa.OpEq32,
- opAndType{OEQ, TUINT32}: ssa.OpEq32,
- opAndType{OEQ, TINT64}: ssa.OpEq64,
- opAndType{OEQ, TUINT64}: ssa.OpEq64,
- opAndType{OEQ, TINTER}: ssa.OpEqInter,
- opAndType{OEQ, TSLICE}: ssa.OpEqSlice,
- opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
- opAndType{OEQ, TMAP}: ssa.OpEqPtr,
- opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
- opAndType{OEQ, TPTR}: ssa.OpEqPtr,
- opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
- opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
- opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
- opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
-
- opAndType{ONE, TBOOL}: ssa.OpNeqB,
- opAndType{ONE, TINT8}: ssa.OpNeq8,
- opAndType{ONE, TUINT8}: ssa.OpNeq8,
- opAndType{ONE, TINT16}: ssa.OpNeq16,
- opAndType{ONE, TUINT16}: ssa.OpNeq16,
- opAndType{ONE, TINT32}: ssa.OpNeq32,
- opAndType{ONE, TUINT32}: ssa.OpNeq32,
- opAndType{ONE, TINT64}: ssa.OpNeq64,
- opAndType{ONE, TUINT64}: ssa.OpNeq64,
- opAndType{ONE, TINTER}: ssa.OpNeqInter,
- opAndType{ONE, TSLICE}: ssa.OpNeqSlice,
- opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
- opAndType{ONE, TMAP}: ssa.OpNeqPtr,
- opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
- opAndType{ONE, TPTR}: ssa.OpNeqPtr,
- opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
- opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
- opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
- opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
-
- opAndType{OLT, TINT8}: ssa.OpLess8,
- opAndType{OLT, TUINT8}: ssa.OpLess8U,
- opAndType{OLT, TINT16}: ssa.OpLess16,
- opAndType{OLT, TUINT16}: ssa.OpLess16U,
- opAndType{OLT, TINT32}: ssa.OpLess32,
- opAndType{OLT, TUINT32}: ssa.OpLess32U,
- opAndType{OLT, TINT64}: ssa.OpLess64,
- opAndType{OLT, TUINT64}: ssa.OpLess64U,
- opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
- opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
-
- opAndType{OLE, TINT8}: ssa.OpLeq8,
- opAndType{OLE, TUINT8}: ssa.OpLeq8U,
- opAndType{OLE, TINT16}: ssa.OpLeq16,
- opAndType{OLE, TUINT16}: ssa.OpLeq16U,
- opAndType{OLE, TINT32}: ssa.OpLeq32,
- opAndType{OLE, TUINT32}: ssa.OpLeq32U,
- opAndType{OLE, TINT64}: ssa.OpLeq64,
- opAndType{OLE, TUINT64}: ssa.OpLeq64U,
- opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
- opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
+ opAndType{ir.OADD, types.TINT8}: ssa.OpAdd8,
+ opAndType{ir.OADD, types.TUINT8}: ssa.OpAdd8,
+ opAndType{ir.OADD, types.TINT16}: ssa.OpAdd16,
+ opAndType{ir.OADD, types.TUINT16}: ssa.OpAdd16,
+ opAndType{ir.OADD, types.TINT32}: ssa.OpAdd32,
+ opAndType{ir.OADD, types.TUINT32}: ssa.OpAdd32,
+ opAndType{ir.OADD, types.TINT64}: ssa.OpAdd64,
+ opAndType{ir.OADD, types.TUINT64}: ssa.OpAdd64,
+ opAndType{ir.OADD, types.TFLOAT32}: ssa.OpAdd32F,
+ opAndType{ir.OADD, types.TFLOAT64}: ssa.OpAdd64F,
+
+ opAndType{ir.OSUB, types.TINT8}: ssa.OpSub8,
+ opAndType{ir.OSUB, types.TUINT8}: ssa.OpSub8,
+ opAndType{ir.OSUB, types.TINT16}: ssa.OpSub16,
+ opAndType{ir.OSUB, types.TUINT16}: ssa.OpSub16,
+ opAndType{ir.OSUB, types.TINT32}: ssa.OpSub32,
+ opAndType{ir.OSUB, types.TUINT32}: ssa.OpSub32,
+ opAndType{ir.OSUB, types.TINT64}: ssa.OpSub64,
+ opAndType{ir.OSUB, types.TUINT64}: ssa.OpSub64,
+ opAndType{ir.OSUB, types.TFLOAT32}: ssa.OpSub32F,
+ opAndType{ir.OSUB, types.TFLOAT64}: ssa.OpSub64F,
+
+ opAndType{ir.ONOT, types.TBOOL}: ssa.OpNot,
+
+ opAndType{ir.ONEG, types.TINT8}: ssa.OpNeg8,
+ opAndType{ir.ONEG, types.TUINT8}: ssa.OpNeg8,
+ opAndType{ir.ONEG, types.TINT16}: ssa.OpNeg16,
+ opAndType{ir.ONEG, types.TUINT16}: ssa.OpNeg16,
+ opAndType{ir.ONEG, types.TINT32}: ssa.OpNeg32,
+ opAndType{ir.ONEG, types.TUINT32}: ssa.OpNeg32,
+ opAndType{ir.ONEG, types.TINT64}: ssa.OpNeg64,
+ opAndType{ir.ONEG, types.TUINT64}: ssa.OpNeg64,
+ opAndType{ir.ONEG, types.TFLOAT32}: ssa.OpNeg32F,
+ opAndType{ir.ONEG, types.TFLOAT64}: ssa.OpNeg64F,
+
+ opAndType{ir.OBITNOT, types.TINT8}: ssa.OpCom8,
+ opAndType{ir.OBITNOT, types.TUINT8}: ssa.OpCom8,
+ opAndType{ir.OBITNOT, types.TINT16}: ssa.OpCom16,
+ opAndType{ir.OBITNOT, types.TUINT16}: ssa.OpCom16,
+ opAndType{ir.OBITNOT, types.TINT32}: ssa.OpCom32,
+ opAndType{ir.OBITNOT, types.TUINT32}: ssa.OpCom32,
+ opAndType{ir.OBITNOT, types.TINT64}: ssa.OpCom64,
+ opAndType{ir.OBITNOT, types.TUINT64}: ssa.OpCom64,
+
+ opAndType{ir.OIMAG, types.TCOMPLEX64}: ssa.OpComplexImag,
+ opAndType{ir.OIMAG, types.TCOMPLEX128}: ssa.OpComplexImag,
+ opAndType{ir.OREAL, types.TCOMPLEX64}: ssa.OpComplexReal,
+ opAndType{ir.OREAL, types.TCOMPLEX128}: ssa.OpComplexReal,
+
+ opAndType{ir.OMUL, types.TINT8}: ssa.OpMul8,
+ opAndType{ir.OMUL, types.TUINT8}: ssa.OpMul8,
+ opAndType{ir.OMUL, types.TINT16}: ssa.OpMul16,
+ opAndType{ir.OMUL, types.TUINT16}: ssa.OpMul16,
+ opAndType{ir.OMUL, types.TINT32}: ssa.OpMul32,
+ opAndType{ir.OMUL, types.TUINT32}: ssa.OpMul32,
+ opAndType{ir.OMUL, types.TINT64}: ssa.OpMul64,
+ opAndType{ir.OMUL, types.TUINT64}: ssa.OpMul64,
+ opAndType{ir.OMUL, types.TFLOAT32}: ssa.OpMul32F,
+ opAndType{ir.OMUL, types.TFLOAT64}: ssa.OpMul64F,
+
+ opAndType{ir.ODIV, types.TFLOAT32}: ssa.OpDiv32F,
+ opAndType{ir.ODIV, types.TFLOAT64}: ssa.OpDiv64F,
+
+ opAndType{ir.ODIV, types.TINT8}: ssa.OpDiv8,
+ opAndType{ir.ODIV, types.TUINT8}: ssa.OpDiv8u,
+ opAndType{ir.ODIV, types.TINT16}: ssa.OpDiv16,
+ opAndType{ir.ODIV, types.TUINT16}: ssa.OpDiv16u,
+ opAndType{ir.ODIV, types.TINT32}: ssa.OpDiv32,
+ opAndType{ir.ODIV, types.TUINT32}: ssa.OpDiv32u,
+ opAndType{ir.ODIV, types.TINT64}: ssa.OpDiv64,
+ opAndType{ir.ODIV, types.TUINT64}: ssa.OpDiv64u,
+
+ opAndType{ir.OMOD, types.TINT8}: ssa.OpMod8,
+ opAndType{ir.OMOD, types.TUINT8}: ssa.OpMod8u,
+ opAndType{ir.OMOD, types.TINT16}: ssa.OpMod16,
+ opAndType{ir.OMOD, types.TUINT16}: ssa.OpMod16u,
+ opAndType{ir.OMOD, types.TINT32}: ssa.OpMod32,
+ opAndType{ir.OMOD, types.TUINT32}: ssa.OpMod32u,
+ opAndType{ir.OMOD, types.TINT64}: ssa.OpMod64,
+ opAndType{ir.OMOD, types.TUINT64}: ssa.OpMod64u,
+
+ opAndType{ir.OAND, types.TINT8}: ssa.OpAnd8,
+ opAndType{ir.OAND, types.TUINT8}: ssa.OpAnd8,
+ opAndType{ir.OAND, types.TINT16}: ssa.OpAnd16,
+ opAndType{ir.OAND, types.TUINT16}: ssa.OpAnd16,
+ opAndType{ir.OAND, types.TINT32}: ssa.OpAnd32,
+ opAndType{ir.OAND, types.TUINT32}: ssa.OpAnd32,
+ opAndType{ir.OAND, types.TINT64}: ssa.OpAnd64,
+ opAndType{ir.OAND, types.TUINT64}: ssa.OpAnd64,
+
+ opAndType{ir.OOR, types.TINT8}: ssa.OpOr8,
+ opAndType{ir.OOR, types.TUINT8}: ssa.OpOr8,
+ opAndType{ir.OOR, types.TINT16}: ssa.OpOr16,
+ opAndType{ir.OOR, types.TUINT16}: ssa.OpOr16,
+ opAndType{ir.OOR, types.TINT32}: ssa.OpOr32,
+ opAndType{ir.OOR, types.TUINT32}: ssa.OpOr32,
+ opAndType{ir.OOR, types.TINT64}: ssa.OpOr64,
+ opAndType{ir.OOR, types.TUINT64}: ssa.OpOr64,
+
+ opAndType{ir.OXOR, types.TINT8}: ssa.OpXor8,
+ opAndType{ir.OXOR, types.TUINT8}: ssa.OpXor8,
+ opAndType{ir.OXOR, types.TINT16}: ssa.OpXor16,
+ opAndType{ir.OXOR, types.TUINT16}: ssa.OpXor16,
+ opAndType{ir.OXOR, types.TINT32}: ssa.OpXor32,
+ opAndType{ir.OXOR, types.TUINT32}: ssa.OpXor32,
+ opAndType{ir.OXOR, types.TINT64}: ssa.OpXor64,
+ opAndType{ir.OXOR, types.TUINT64}: ssa.OpXor64,
+
+ opAndType{ir.OEQ, types.TBOOL}: ssa.OpEqB,
+ opAndType{ir.OEQ, types.TINT8}: ssa.OpEq8,
+ opAndType{ir.OEQ, types.TUINT8}: ssa.OpEq8,
+ opAndType{ir.OEQ, types.TINT16}: ssa.OpEq16,
+ opAndType{ir.OEQ, types.TUINT16}: ssa.OpEq16,
+ opAndType{ir.OEQ, types.TINT32}: ssa.OpEq32,
+ opAndType{ir.OEQ, types.TUINT32}: ssa.OpEq32,
+ opAndType{ir.OEQ, types.TINT64}: ssa.OpEq64,
+ opAndType{ir.OEQ, types.TUINT64}: ssa.OpEq64,
+ opAndType{ir.OEQ, types.TINTER}: ssa.OpEqInter,
+ opAndType{ir.OEQ, types.TSLICE}: ssa.OpEqSlice,
+ opAndType{ir.OEQ, types.TFUNC}: ssa.OpEqPtr,
+ opAndType{ir.OEQ, types.TMAP}: ssa.OpEqPtr,
+ opAndType{ir.OEQ, types.TCHAN}: ssa.OpEqPtr,
+ opAndType{ir.OEQ, types.TPTR}: ssa.OpEqPtr,
+ opAndType{ir.OEQ, types.TUINTPTR}: ssa.OpEqPtr,
+ opAndType{ir.OEQ, types.TUNSAFEPTR}: ssa.OpEqPtr,
+ opAndType{ir.OEQ, types.TFLOAT64}: ssa.OpEq64F,
+ opAndType{ir.OEQ, types.TFLOAT32}: ssa.OpEq32F,
+
+ opAndType{ir.ONE, types.TBOOL}: ssa.OpNeqB,
+ opAndType{ir.ONE, types.TINT8}: ssa.OpNeq8,
+ opAndType{ir.ONE, types.TUINT8}: ssa.OpNeq8,
+ opAndType{ir.ONE, types.TINT16}: ssa.OpNeq16,
+ opAndType{ir.ONE, types.TUINT16}: ssa.OpNeq16,
+ opAndType{ir.ONE, types.TINT32}: ssa.OpNeq32,
+ opAndType{ir.ONE, types.TUINT32}: ssa.OpNeq32,
+ opAndType{ir.ONE, types.TINT64}: ssa.OpNeq64,
+ opAndType{ir.ONE, types.TUINT64}: ssa.OpNeq64,
+ opAndType{ir.ONE, types.TINTER}: ssa.OpNeqInter,
+ opAndType{ir.ONE, types.TSLICE}: ssa.OpNeqSlice,
+ opAndType{ir.ONE, types.TFUNC}: ssa.OpNeqPtr,
+ opAndType{ir.ONE, types.TMAP}: ssa.OpNeqPtr,
+ opAndType{ir.ONE, types.TCHAN}: ssa.OpNeqPtr,
+ opAndType{ir.ONE, types.TPTR}: ssa.OpNeqPtr,
+ opAndType{ir.ONE, types.TUINTPTR}: ssa.OpNeqPtr,
+ opAndType{ir.ONE, types.TUNSAFEPTR}: ssa.OpNeqPtr,
+ opAndType{ir.ONE, types.TFLOAT64}: ssa.OpNeq64F,
+ opAndType{ir.ONE, types.TFLOAT32}: ssa.OpNeq32F,
+
+ opAndType{ir.OLT, types.TINT8}: ssa.OpLess8,
+ opAndType{ir.OLT, types.TUINT8}: ssa.OpLess8U,
+ opAndType{ir.OLT, types.TINT16}: ssa.OpLess16,
+ opAndType{ir.OLT, types.TUINT16}: ssa.OpLess16U,
+ opAndType{ir.OLT, types.TINT32}: ssa.OpLess32,
+ opAndType{ir.OLT, types.TUINT32}: ssa.OpLess32U,
+ opAndType{ir.OLT, types.TINT64}: ssa.OpLess64,
+ opAndType{ir.OLT, types.TUINT64}: ssa.OpLess64U,
+ opAndType{ir.OLT, types.TFLOAT64}: ssa.OpLess64F,
+ opAndType{ir.OLT, types.TFLOAT32}: ssa.OpLess32F,
+
+ opAndType{ir.OLE, types.TINT8}: ssa.OpLeq8,
+ opAndType{ir.OLE, types.TUINT8}: ssa.OpLeq8U,
+ opAndType{ir.OLE, types.TINT16}: ssa.OpLeq16,
+ opAndType{ir.OLE, types.TUINT16}: ssa.OpLeq16U,
+ opAndType{ir.OLE, types.TINT32}: ssa.OpLeq32,
+ opAndType{ir.OLE, types.TUINT32}: ssa.OpLeq32U,
+ opAndType{ir.OLE, types.TINT64}: ssa.OpLeq64,
+ opAndType{ir.OLE, types.TUINT64}: ssa.OpLeq64U,
+ opAndType{ir.OLE, types.TFLOAT64}: ssa.OpLeq64F,
+ opAndType{ir.OLE, types.TFLOAT32}: ssa.OpLeq32F,
}
func (s *state) concreteEtype(t *types.Type) types.EType {
switch e {
default:
return e
- case TINT:
+ case types.TINT:
if s.config.PtrSize == 8 {
- return TINT64
+ return types.TINT64
}
- return TINT32
- case TUINT:
+ return types.TINT32
+ case types.TUINT:
if s.config.PtrSize == 8 {
- return TUINT64
+ return types.TUINT64
}
- return TUINT32
- case TUINTPTR:
+ return types.TUINT32
+ case types.TUINTPTR:
if s.config.PtrSize == 8 {
- return TUINT64
+ return types.TUINT64
}
- return TUINT32
+ return types.TUINT32
}
}
-func (s *state) ssaOp(op Op, t *types.Type) ssa.Op {
+func (s *state) ssaOp(op ir.Op, t *types.Type) ssa.Op {
etype := s.concreteEtype(t)
x, ok := opToSSA[opAndType{op, etype}]
if !ok {
func floatForComplex(t *types.Type) *types.Type {
switch t.Etype {
- case TCOMPLEX64:
- return types.Types[TFLOAT32]
- case TCOMPLEX128:
- return types.Types[TFLOAT64]
+ case types.TCOMPLEX64:
+ return types.Types[types.TFLOAT32]
+ case types.TCOMPLEX128:
+ return types.Types[types.TFLOAT64]
}
base.Fatalf("unexpected type: %v", t)
return nil
func complexForFloat(t *types.Type) *types.Type {
switch t.Etype {
- case TFLOAT32:
- return types.Types[TCOMPLEX64]
- case TFLOAT64:
- return types.Types[TCOMPLEX128]
+ case types.TFLOAT32:
+ return types.Types[types.TCOMPLEX64]
+ case types.TFLOAT64:
+ return types.Types[types.TCOMPLEX128]
}
base.Fatalf("unexpected type: %v", t)
return nil
}
type opAndTwoTypes struct {
- op Op
+ op ir.Op
etype1 types.EType
etype2 types.EType
}
var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
- twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
- twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
- twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
- twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
-
- twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
- twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
- twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
- twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
-
- twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
- twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
- twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
- twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
-
- twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
- twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
- twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
- twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
+ twoTypes{types.TINT8, types.TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, types.TINT32},
+ twoTypes{types.TINT16, types.TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, types.TINT32},
+ twoTypes{types.TINT32, types.TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, types.TINT32},
+ twoTypes{types.TINT64, types.TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, types.TINT64},
+
+ twoTypes{types.TINT8, types.TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, types.TINT32},
+ twoTypes{types.TINT16, types.TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, types.TINT32},
+ twoTypes{types.TINT32, types.TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, types.TINT32},
+ twoTypes{types.TINT64, types.TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, types.TINT64},
+
+ twoTypes{types.TFLOAT32, types.TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, types.TINT32},
+ twoTypes{types.TFLOAT32, types.TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, types.TINT32},
+ twoTypes{types.TFLOAT32, types.TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, types.TINT32},
+ twoTypes{types.TFLOAT32, types.TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, types.TINT64},
+
+ twoTypes{types.TFLOAT64, types.TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, types.TINT32},
+ twoTypes{types.TFLOAT64, types.TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, types.TINT32},
+ twoTypes{types.TFLOAT64, types.TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, types.TINT32},
+ twoTypes{types.TFLOAT64, types.TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, types.TINT64},
// unsigned
- twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
- twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
- twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
- twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
-
- twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
- twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
- twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
- twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
-
- twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
- twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
- twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
- twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
-
- twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
- twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
- twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
- twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
+ twoTypes{types.TUINT8, types.TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, types.TINT32},
+ twoTypes{types.TUINT16, types.TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, types.TINT32},
+ twoTypes{types.TUINT32, types.TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, types.TINT64}, // go wide to dodge unsigned
+ twoTypes{types.TUINT64, types.TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, types.TUINT64}, // Cvt64Uto32F, branchy code expansion instead
+
+ twoTypes{types.TUINT8, types.TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, types.TINT32},
+ twoTypes{types.TUINT16, types.TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, types.TINT32},
+ twoTypes{types.TUINT32, types.TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, types.TINT64}, // go wide to dodge unsigned
+ twoTypes{types.TUINT64, types.TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, types.TUINT64}, // Cvt64Uto64F, branchy code expansion instead
+
+ twoTypes{types.TFLOAT32, types.TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, types.TINT32},
+ twoTypes{types.TFLOAT32, types.TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, types.TINT32},
+ twoTypes{types.TFLOAT32, types.TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, types.TINT64}, // go wide to dodge unsigned
+ twoTypes{types.TFLOAT32, types.TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, types.TUINT64}, // Cvt32Fto64U, branchy code expansion instead
+
+ twoTypes{types.TFLOAT64, types.TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, types.TINT32},
+ twoTypes{types.TFLOAT64, types.TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, types.TINT32},
+ twoTypes{types.TFLOAT64, types.TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, types.TINT64}, // go wide to dodge unsigned
+ twoTypes{types.TFLOAT64, types.TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, types.TUINT64}, // Cvt64Fto64U, branchy code expansion instead
// float
- twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
- twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpRound64F, ssa.OpCopy, TFLOAT64},
- twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpRound32F, ssa.OpCopy, TFLOAT32},
- twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
+ twoTypes{types.TFLOAT64, types.TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, types.TFLOAT32},
+ twoTypes{types.TFLOAT64, types.TFLOAT64}: twoOpsAndType{ssa.OpRound64F, ssa.OpCopy, types.TFLOAT64},
+ twoTypes{types.TFLOAT32, types.TFLOAT32}: twoOpsAndType{ssa.OpRound32F, ssa.OpCopy, types.TFLOAT32},
+ twoTypes{types.TFLOAT32, types.TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, types.TFLOAT64},
}
// this map is used only for 32-bit arch, and only includes the difference
// on 32-bit arch, don't use int64<->float conversion for uint32
var fpConvOpToSSA32 = map[twoTypes]twoOpsAndType{
- twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto32F, TUINT32},
- twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto64F, TUINT32},
- twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto32U, ssa.OpCopy, TUINT32},
- twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto32U, ssa.OpCopy, TUINT32},
+ twoTypes{types.TUINT32, types.TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto32F, types.TUINT32},
+ twoTypes{types.TUINT32, types.TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto64F, types.TUINT32},
+ twoTypes{types.TFLOAT32, types.TUINT32}: twoOpsAndType{ssa.OpCvt32Fto32U, ssa.OpCopy, types.TUINT32},
+ twoTypes{types.TFLOAT64, types.TUINT32}: twoOpsAndType{ssa.OpCvt64Fto32U, ssa.OpCopy, types.TUINT32},
}
// uint64<->float conversions, only on machines that have instructions for that
var uint64fpConvOpToSSA = map[twoTypes]twoOpsAndType{
- twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64Uto32F, TUINT64},
- twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64Uto64F, TUINT64},
- twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpCvt32Fto64U, ssa.OpCopy, TUINT64},
- twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpCvt64Fto64U, ssa.OpCopy, TUINT64},
+ twoTypes{types.TUINT64, types.TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64Uto32F, types.TUINT64},
+ twoTypes{types.TUINT64, types.TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64Uto64F, types.TUINT64},
+ twoTypes{types.TFLOAT32, types.TUINT64}: twoOpsAndType{ssa.OpCvt32Fto64U, ssa.OpCopy, types.TUINT64},
+ twoTypes{types.TFLOAT64, types.TUINT64}: twoOpsAndType{ssa.OpCvt64Fto64U, ssa.OpCopy, types.TUINT64},
}
var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
- opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
- opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
- opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
- opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
- opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
- opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
- opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
- opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
-
- opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
- opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
- opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
- opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
- opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
- opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
- opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
- opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
-
- opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
- opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
- opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
- opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
- opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
- opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
- opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
- opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
-
- opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
- opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
- opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
- opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
- opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
- opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
- opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
- opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
-
- opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
- opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
- opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
- opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
- opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
- opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
- opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
- opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
-
- opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
- opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
- opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
- opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
- opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
- opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
- opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
- opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
-
- opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
- opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
- opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
- opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
- opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
- opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
- opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
- opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
-
- opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
- opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
- opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
- opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
- opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
- opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
- opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
- opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
-}
-
-func (s *state) ssaShiftOp(op Op, t *types.Type, u *types.Type) ssa.Op {
+ opAndTwoTypes{ir.OLSH, types.TINT8, types.TUINT8}: ssa.OpLsh8x8,
+ opAndTwoTypes{ir.OLSH, types.TUINT8, types.TUINT8}: ssa.OpLsh8x8,
+ opAndTwoTypes{ir.OLSH, types.TINT8, types.TUINT16}: ssa.OpLsh8x16,
+ opAndTwoTypes{ir.OLSH, types.TUINT8, types.TUINT16}: ssa.OpLsh8x16,
+ opAndTwoTypes{ir.OLSH, types.TINT8, types.TUINT32}: ssa.OpLsh8x32,
+ opAndTwoTypes{ir.OLSH, types.TUINT8, types.TUINT32}: ssa.OpLsh8x32,
+ opAndTwoTypes{ir.OLSH, types.TINT8, types.TUINT64}: ssa.OpLsh8x64,
+ opAndTwoTypes{ir.OLSH, types.TUINT8, types.TUINT64}: ssa.OpLsh8x64,
+
+ opAndTwoTypes{ir.OLSH, types.TINT16, types.TUINT8}: ssa.OpLsh16x8,
+ opAndTwoTypes{ir.OLSH, types.TUINT16, types.TUINT8}: ssa.OpLsh16x8,
+ opAndTwoTypes{ir.OLSH, types.TINT16, types.TUINT16}: ssa.OpLsh16x16,
+ opAndTwoTypes{ir.OLSH, types.TUINT16, types.TUINT16}: ssa.OpLsh16x16,
+ opAndTwoTypes{ir.OLSH, types.TINT16, types.TUINT32}: ssa.OpLsh16x32,
+ opAndTwoTypes{ir.OLSH, types.TUINT16, types.TUINT32}: ssa.OpLsh16x32,
+ opAndTwoTypes{ir.OLSH, types.TINT16, types.TUINT64}: ssa.OpLsh16x64,
+ opAndTwoTypes{ir.OLSH, types.TUINT16, types.TUINT64}: ssa.OpLsh16x64,
+
+ opAndTwoTypes{ir.OLSH, types.TINT32, types.TUINT8}: ssa.OpLsh32x8,
+ opAndTwoTypes{ir.OLSH, types.TUINT32, types.TUINT8}: ssa.OpLsh32x8,
+ opAndTwoTypes{ir.OLSH, types.TINT32, types.TUINT16}: ssa.OpLsh32x16,
+ opAndTwoTypes{ir.OLSH, types.TUINT32, types.TUINT16}: ssa.OpLsh32x16,
+ opAndTwoTypes{ir.OLSH, types.TINT32, types.TUINT32}: ssa.OpLsh32x32,
+ opAndTwoTypes{ir.OLSH, types.TUINT32, types.TUINT32}: ssa.OpLsh32x32,
+ opAndTwoTypes{ir.OLSH, types.TINT32, types.TUINT64}: ssa.OpLsh32x64,
+ opAndTwoTypes{ir.OLSH, types.TUINT32, types.TUINT64}: ssa.OpLsh32x64,
+
+ opAndTwoTypes{ir.OLSH, types.TINT64, types.TUINT8}: ssa.OpLsh64x8,
+ opAndTwoTypes{ir.OLSH, types.TUINT64, types.TUINT8}: ssa.OpLsh64x8,
+ opAndTwoTypes{ir.OLSH, types.TINT64, types.TUINT16}: ssa.OpLsh64x16,
+ opAndTwoTypes{ir.OLSH, types.TUINT64, types.TUINT16}: ssa.OpLsh64x16,
+ opAndTwoTypes{ir.OLSH, types.TINT64, types.TUINT32}: ssa.OpLsh64x32,
+ opAndTwoTypes{ir.OLSH, types.TUINT64, types.TUINT32}: ssa.OpLsh64x32,
+ opAndTwoTypes{ir.OLSH, types.TINT64, types.TUINT64}: ssa.OpLsh64x64,
+ opAndTwoTypes{ir.OLSH, types.TUINT64, types.TUINT64}: ssa.OpLsh64x64,
+
+ opAndTwoTypes{ir.ORSH, types.TINT8, types.TUINT8}: ssa.OpRsh8x8,
+ opAndTwoTypes{ir.ORSH, types.TUINT8, types.TUINT8}: ssa.OpRsh8Ux8,
+ opAndTwoTypes{ir.ORSH, types.TINT8, types.TUINT16}: ssa.OpRsh8x16,
+ opAndTwoTypes{ir.ORSH, types.TUINT8, types.TUINT16}: ssa.OpRsh8Ux16,
+ opAndTwoTypes{ir.ORSH, types.TINT8, types.TUINT32}: ssa.OpRsh8x32,
+ opAndTwoTypes{ir.ORSH, types.TUINT8, types.TUINT32}: ssa.OpRsh8Ux32,
+ opAndTwoTypes{ir.ORSH, types.TINT8, types.TUINT64}: ssa.OpRsh8x64,
+ opAndTwoTypes{ir.ORSH, types.TUINT8, types.TUINT64}: ssa.OpRsh8Ux64,
+
+ opAndTwoTypes{ir.ORSH, types.TINT16, types.TUINT8}: ssa.OpRsh16x8,
+ opAndTwoTypes{ir.ORSH, types.TUINT16, types.TUINT8}: ssa.OpRsh16Ux8,
+ opAndTwoTypes{ir.ORSH, types.TINT16, types.TUINT16}: ssa.OpRsh16x16,
+ opAndTwoTypes{ir.ORSH, types.TUINT16, types.TUINT16}: ssa.OpRsh16Ux16,
+ opAndTwoTypes{ir.ORSH, types.TINT16, types.TUINT32}: ssa.OpRsh16x32,
+ opAndTwoTypes{ir.ORSH, types.TUINT16, types.TUINT32}: ssa.OpRsh16Ux32,
+ opAndTwoTypes{ir.ORSH, types.TINT16, types.TUINT64}: ssa.OpRsh16x64,
+ opAndTwoTypes{ir.ORSH, types.TUINT16, types.TUINT64}: ssa.OpRsh16Ux64,
+
+ opAndTwoTypes{ir.ORSH, types.TINT32, types.TUINT8}: ssa.OpRsh32x8,
+ opAndTwoTypes{ir.ORSH, types.TUINT32, types.TUINT8}: ssa.OpRsh32Ux8,
+ opAndTwoTypes{ir.ORSH, types.TINT32, types.TUINT16}: ssa.OpRsh32x16,
+ opAndTwoTypes{ir.ORSH, types.TUINT32, types.TUINT16}: ssa.OpRsh32Ux16,
+ opAndTwoTypes{ir.ORSH, types.TINT32, types.TUINT32}: ssa.OpRsh32x32,
+ opAndTwoTypes{ir.ORSH, types.TUINT32, types.TUINT32}: ssa.OpRsh32Ux32,
+ opAndTwoTypes{ir.ORSH, types.TINT32, types.TUINT64}: ssa.OpRsh32x64,
+ opAndTwoTypes{ir.ORSH, types.TUINT32, types.TUINT64}: ssa.OpRsh32Ux64,
+
+ opAndTwoTypes{ir.ORSH, types.TINT64, types.TUINT8}: ssa.OpRsh64x8,
+ opAndTwoTypes{ir.ORSH, types.TUINT64, types.TUINT8}: ssa.OpRsh64Ux8,
+ opAndTwoTypes{ir.ORSH, types.TINT64, types.TUINT16}: ssa.OpRsh64x16,
+ opAndTwoTypes{ir.ORSH, types.TUINT64, types.TUINT16}: ssa.OpRsh64Ux16,
+ opAndTwoTypes{ir.ORSH, types.TINT64, types.TUINT32}: ssa.OpRsh64x32,
+ opAndTwoTypes{ir.ORSH, types.TUINT64, types.TUINT32}: ssa.OpRsh64Ux32,
+ opAndTwoTypes{ir.ORSH, types.TINT64, types.TUINT64}: ssa.OpRsh64x64,
+ opAndTwoTypes{ir.ORSH, types.TUINT64, types.TUINT64}: ssa.OpRsh64Ux64,
+}
+
+func (s *state) ssaShiftOp(op ir.Op, t *types.Type, u *types.Type) ssa.Op {
etype1 := s.concreteEtype(t)
etype2 := s.concreteEtype(u)
x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
}
// expr converts the expression n to ssa, adds it to s and returns the ssa result.
-func (s *state) expr(n *Node) *ssa.Value {
+func (s *state) expr(n *ir.Node) *ssa.Value {
if hasUniquePos(n) {
// ONAMEs and named OLITERALs have the line number
// of the decl, not the use. See issue 14742.
s.stmtList(n.Ninit)
switch n.Op {
- case OBYTES2STRTMP:
+ case ir.OBYTES2STRTMP:
slice := s.expr(n.Left)
ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice)
- len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice)
+ len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
return s.newValue2(ssa.OpStringMake, n.Type, ptr, len)
- case OSTR2BYTESTMP:
+ case ir.OSTR2BYTESTMP:
str := s.expr(n.Left)
ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, str)
- len := s.newValue1(ssa.OpStringLen, types.Types[TINT], str)
+ len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], str)
return s.newValue3(ssa.OpSliceMake, n.Type, ptr, len, len)
- case OCFUNC:
+ case ir.OCFUNC:
aux := n.Left.Sym.Linksym()
return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
- case OMETHEXPR:
+ case ir.OMETHEXPR:
sym := funcsym(n.Sym).Linksym()
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), sym, s.sb)
- case ONAME:
- if n.Class() == PFUNC {
+ case ir.ONAME:
+ if n.Class() == ir.PFUNC {
// "value" of a function is the address of the function's closure
sym := funcsym(n.Sym).Linksym()
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), sym, s.sb)
}
addr := s.addr(n)
return s.load(n.Type, addr)
- case OCLOSUREVAR:
+ case ir.OCLOSUREVAR:
addr := s.addr(n)
return s.load(n.Type, addr)
- case ONIL:
+ case ir.ONIL:
t := n.Type
switch {
case t.IsSlice():
default:
return s.constNil(t)
}
- case OLITERAL:
+ case ir.OLITERAL:
switch u := n.Val(); u.Kind() {
case constant.Int:
- i := int64Val(n.Type, u)
+ i := ir.Int64Val(n.Type, u)
switch n.Type.Size() {
case 1:
return s.constInt8(n.Type, int8(i))
im, _ := constant.Float64Val(constant.Imag(u))
switch n.Type.Size() {
case 8:
- pt := types.Types[TFLOAT32]
+ pt := types.Types[types.TFLOAT32]
return s.newValue2(ssa.OpComplexMake, n.Type,
s.constFloat32(pt, re),
s.constFloat32(pt, im))
case 16:
- pt := types.Types[TFLOAT64]
+ pt := types.Types[types.TFLOAT64]
return s.newValue2(ssa.OpComplexMake, n.Type,
s.constFloat64(pt, re),
s.constFloat64(pt, im))
s.Fatalf("unhandled OLITERAL %v", u.Kind())
return nil
}
- case OCONVNOP:
+ case ir.OCONVNOP:
to := n.Type
from := n.Left.Type
v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
// CONVNOP closure
- if to.Etype == TFUNC && from.IsPtrShaped() {
+ if to.Etype == types.TFUNC && from.IsPtrShaped() {
return v
}
}
// map <--> *hmap
- if to.Etype == TMAP && from.IsPtr() &&
+ if to.Etype == types.TMAP && from.IsPtr() &&
to.MapType().Hmap == from.Elem() {
return v
}
// integer, same width, same sign
return v
- case OCONV:
+ case ir.OCONV:
x := s.expr(n.Left)
ft := n.Left.Type // from type
tt := n.Type // to type
- if ft.IsBoolean() && tt.IsKind(TUINT8) {
+ if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
// Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
return s.newValue1(ssa.OpCopy, n.Type, x)
}
s.Fatalf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype)
return nil
- case ODOTTYPE:
+ case ir.ODOTTYPE:
res, _ := s.dottype(n, false)
return res
// binary ops
- case OLT, OEQ, ONE, OLE, OGE, OGT:
+ case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
a := s.expr(n.Left)
b := s.expr(n.Right)
if n.Left.Type.IsComplex() {
pt := floatForComplex(n.Left.Type)
- op := s.ssaOp(OEQ, pt)
- r := s.newValueOrSfCall2(op, types.Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
- i := s.newValueOrSfCall2(op, types.Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
- c := s.newValue2(ssa.OpAndB, types.Types[TBOOL], r, i)
+ op := s.ssaOp(ir.OEQ, pt)
+ r := s.newValueOrSfCall2(op, types.Types[types.TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
+ i := s.newValueOrSfCall2(op, types.Types[types.TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
+ c := s.newValue2(ssa.OpAndB, types.Types[types.TBOOL], r, i)
switch n.Op {
- case OEQ:
+ case ir.OEQ:
return c
- case ONE:
- return s.newValue1(ssa.OpNot, types.Types[TBOOL], c)
+ case ir.ONE:
+ return s.newValue1(ssa.OpNot, types.Types[types.TBOOL], c)
default:
s.Fatalf("ordered complex compare %v", n.Op)
}
// Convert OGE and OGT into OLE and OLT.
op := n.Op
switch op {
- case OGE:
- op, a, b = OLE, b, a
- case OGT:
- op, a, b = OLT, b, a
+ case ir.OGE:
+ op, a, b = ir.OLE, b, a
+ case ir.OGT:
+ op, a, b = ir.OLT, b, a
}
if n.Left.Type.IsFloat() {
// float comparison
- return s.newValueOrSfCall2(s.ssaOp(op, n.Left.Type), types.Types[TBOOL], a, b)
+ return s.newValueOrSfCall2(s.ssaOp(op, n.Left.Type), types.Types[types.TBOOL], a, b)
}
// integer comparison
- return s.newValue2(s.ssaOp(op, n.Left.Type), types.Types[TBOOL], a, b)
- case OMUL:
+ return s.newValue2(s.ssaOp(op, n.Left.Type), types.Types[types.TBOOL], a, b)
+ case ir.OMUL:
a := s.expr(n.Left)
b := s.expr(n.Right)
if n.Type.IsComplex() {
mulop := ssa.OpMul64F
addop := ssa.OpAdd64F
subop := ssa.OpSub64F
- pt := floatForComplex(n.Type) // Could be Float32 or Float64
- wt := types.Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
+ pt := floatForComplex(n.Type) // Could be Float32 or Float64
+ wt := types.Types[types.TFLOAT64] // Compute in Float64 to minimize cancellation error
areal := s.newValue1(ssa.OpComplexReal, pt, a)
breal := s.newValue1(ssa.OpComplexReal, pt, b)
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
- case ODIV:
+ case ir.ODIV:
a := s.expr(n.Left)
b := s.expr(n.Right)
if n.Type.IsComplex() {
addop := ssa.OpAdd64F
subop := ssa.OpSub64F
divop := ssa.OpDiv64F
- pt := floatForComplex(n.Type) // Could be Float32 or Float64
- wt := types.Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
+ pt := floatForComplex(n.Type) // Could be Float32 or Float64
+ wt := types.Types[types.TFLOAT64] // Compute in Float64 to minimize cancellation error
areal := s.newValue1(ssa.OpComplexReal, pt, a)
breal := s.newValue1(ssa.OpComplexReal, pt, b)
return s.newValueOrSfCall2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
}
return s.intDivide(n, a, b)
- case OMOD:
+ case ir.OMOD:
a := s.expr(n.Left)
b := s.expr(n.Right)
return s.intDivide(n, a, b)
- case OADD, OSUB:
+ case ir.OADD, ir.OSUB:
a := s.expr(n.Left)
b := s.expr(n.Right)
if n.Type.IsComplex() {
return s.newValueOrSfCall2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
}
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
- case OAND, OOR, OXOR:
+ case ir.OAND, ir.OOR, ir.OXOR:
a := s.expr(n.Left)
b := s.expr(n.Right)
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
- case OANDNOT:
+ case ir.OANDNOT:
a := s.expr(n.Left)
b := s.expr(n.Right)
- b = s.newValue1(s.ssaOp(OBITNOT, b.Type), b.Type, b)
- return s.newValue2(s.ssaOp(OAND, n.Type), a.Type, a, b)
- case OLSH, ORSH:
+ b = s.newValue1(s.ssaOp(ir.OBITNOT, b.Type), b.Type, b)
+ return s.newValue2(s.ssaOp(ir.OAND, n.Type), a.Type, a, b)
+ case ir.OLSH, ir.ORSH:
a := s.expr(n.Left)
b := s.expr(n.Right)
bt := b.Type
if bt.IsSigned() {
- cmp := s.newValue2(s.ssaOp(OLE, bt), types.Types[TBOOL], s.zeroVal(bt), b)
+ cmp := s.newValue2(s.ssaOp(ir.OLE, bt), types.Types[types.TBOOL], s.zeroVal(bt), b)
s.check(cmp, panicshift)
bt = bt.ToUnsigned()
}
return s.newValue2(s.ssaShiftOp(n.Op, n.Type, bt), a.Type, a, b)
- case OANDAND, OOROR:
+ case ir.OANDAND, ir.OOROR:
// To implement OANDAND (and OOROR), we introduce a
// new temporary variable to hold the result. The
// variable is associated with the OANDAND node in the
bRight := s.f.NewBlock(ssa.BlockPlain)
bResult := s.f.NewBlock(ssa.BlockPlain)
- if n.Op == OANDAND {
+ if n.Op == ir.OANDAND {
b.AddEdgeTo(bRight)
b.AddEdgeTo(bResult)
- } else if n.Op == OOROR {
+ } else if n.Op == ir.OOROR {
b.AddEdgeTo(bResult)
b.AddEdgeTo(bRight)
}
b.AddEdgeTo(bResult)
s.startBlock(bResult)
- return s.variable(n, types.Types[TBOOL])
- case OCOMPLEX:
+ return s.variable(n, types.Types[types.TBOOL])
+ case ir.OCOMPLEX:
r := s.expr(n.Left)
i := s.expr(n.Right)
return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
// unary ops
- case ONEG:
+ case ir.ONEG:
a := s.expr(n.Left)
if n.Type.IsComplex() {
tp := floatForComplex(n.Type)
s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
}
return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
- case ONOT, OBITNOT:
+ case ir.ONOT, ir.OBITNOT:
a := s.expr(n.Left)
return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
- case OIMAG, OREAL:
+ case ir.OIMAG, ir.OREAL:
a := s.expr(n.Left)
return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
- case OPLUS:
+ case ir.OPLUS:
return s.expr(n.Left)
- case OADDR:
+ case ir.OADDR:
return s.addr(n.Left)
- case ORESULT:
+ case ir.ORESULT:
if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
// Do the old thing
addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
return s.rawLoad(n.Type, addr)
}
- case ODEREF:
+ case ir.ODEREF:
p := s.exprPtr(n.Left, n.Bounded(), n.Pos)
return s.load(n.Type, p)
- case ODOT:
- if n.Left.Op == OSTRUCTLIT {
+ case ir.ODOT:
+ if n.Left.Op == ir.OSTRUCTLIT {
// All literals with nonzero fields have already been
// rewritten during walk. Any that remain are just T{}
// or equivalents. Use the zero value.
v := s.expr(n.Left)
return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
- case ODOTPTR:
+ case ir.ODOTPTR:
p := s.exprPtr(n.Left, n.Bounded(), n.Pos)
p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type), n.Xoffset, p)
return s.load(n.Type, p)
- case OINDEX:
+ case ir.OINDEX:
switch {
case n.Left.Type.IsString():
- if n.Bounded() && Isconst(n.Left, constant.String) && Isconst(n.Right, constant.Int) {
+ if n.Bounded() && ir.IsConst(n.Left, constant.String) && ir.IsConst(n.Right, constant.Int) {
// Replace "abc"[1] with 'b'.
// Delayed until now because "abc"[1] is not an ideal constant.
// See test/fixedbugs/issue11370.go.
- return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(n.Left.StringVal()[n.Right.Int64Val()])))
+ return s.newValue0I(ssa.OpConst8, types.Types[types.TUINT8], int64(int8(n.Left.StringVal()[n.Right.Int64Val()])))
}
a := s.expr(n.Left)
i := s.expr(n.Right)
- len := s.newValue1(ssa.OpStringLen, types.Types[TINT], a)
+ len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], a)
i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
ptrtyp := s.f.Config.Types.BytePtr
ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
- if Isconst(n.Right, constant.Int) {
+ if ir.IsConst(n.Right, constant.Int) {
ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64Val(), ptr)
} else {
ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
}
- return s.load(types.Types[TUINT8], ptr)
+ return s.load(types.Types[types.TUINT8], ptr)
case n.Left.Type.IsSlice():
p := s.addr(n)
return s.load(n.Left.Type.Elem(), p)
if bound == 0 {
// Bounds check will never succeed. Might as well
// use constants for the bounds check.
- z := s.constInt(types.Types[TINT], 0)
+ z := s.constInt(types.Types[types.TINT], 0)
s.boundsCheck(z, z, ssa.BoundsIndex, false)
// The return value won't be live, return junk.
return s.newValue0(ssa.OpUnknown, n.Type)
}
- len := s.constInt(types.Types[TINT], bound)
+ len := s.constInt(types.Types[types.TINT], bound)
s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded()) // checks i == 0
return s.newValue1I(ssa.OpArraySelect, n.Type, 0, a)
}
return nil
}
- case OLEN, OCAP:
+ case ir.OLEN, ir.OCAP:
switch {
case n.Left.Type.IsSlice():
op := ssa.OpSliceLen
- if n.Op == OCAP {
+ if n.Op == ir.OCAP {
op = ssa.OpSliceCap
}
- return s.newValue1(op, types.Types[TINT], s.expr(n.Left))
+ return s.newValue1(op, types.Types[types.TINT], s.expr(n.Left))
case n.Left.Type.IsString(): // string; not reachable for OCAP
- return s.newValue1(ssa.OpStringLen, types.Types[TINT], s.expr(n.Left))
+ return s.newValue1(ssa.OpStringLen, types.Types[types.TINT], s.expr(n.Left))
case n.Left.Type.IsMap(), n.Left.Type.IsChan():
return s.referenceTypeBuiltin(n, s.expr(n.Left))
default: // array
- return s.constInt(types.Types[TINT], n.Left.Type.NumElem())
+ return s.constInt(types.Types[types.TINT], n.Left.Type.NumElem())
}
- case OSPTR:
+ case ir.OSPTR:
a := s.expr(n.Left)
if n.Left.Type.IsSlice() {
return s.newValue1(ssa.OpSlicePtr, n.Type, a)
return s.newValue1(ssa.OpStringPtr, n.Type, a)
}
- case OITAB:
+ case ir.OITAB:
a := s.expr(n.Left)
return s.newValue1(ssa.OpITab, n.Type, a)
- case OIDATA:
+ case ir.OIDATA:
a := s.expr(n.Left)
return s.newValue1(ssa.OpIData, n.Type, a)
- case OEFACE:
+ case ir.OEFACE:
tab := s.expr(n.Left)
data := s.expr(n.Right)
return s.newValue2(ssa.OpIMake, n.Type, tab, data)
- case OSLICEHEADER:
+ case ir.OSLICEHEADER:
p := s.expr(n.Left)
l := s.expr(n.List.First())
c := s.expr(n.List.Second())
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
- case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
+ case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
v := s.expr(n.Left)
var i, j, k *ssa.Value
low, high, max := n.SliceBounds()
p, l, c := s.slice(v, i, j, k, n.Bounded())
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
- case OSLICESTR:
+ case ir.OSLICESTR:
v := s.expr(n.Left)
var i, j *ssa.Value
low, high, _ := n.SliceBounds()
p, l, _ := s.slice(v, i, j, nil, n.Bounded())
return s.newValue2(ssa.OpStringMake, n.Type, p, l)
- case OCALLFUNC:
+ case ir.OCALLFUNC:
if isIntrinsicCall(n) {
return s.intrinsicCall(n)
}
fallthrough
- case OCALLINTER, OCALLMETH:
+ case ir.OCALLINTER, ir.OCALLMETH:
return s.callResult(n, callNormal)
- case OGETG:
+ case ir.OGETG:
return s.newValue1(ssa.OpGetG, n.Type, s.mem())
- case OAPPEND:
+ case ir.OAPPEND:
return s.append(n, false)
- case OSTRUCTLIT, OARRAYLIT:
+ case ir.OSTRUCTLIT, ir.OARRAYLIT:
// All literals with nonzero fields have already been
// rewritten during walk. Any that remain are just T{}
// or equivalents. Use the zero value.
}
return s.zeroVal(n.Type)
- case ONEWOBJ:
+ case ir.ONEWOBJ:
if n.Type.Elem().Size() == 0 {
return s.newValue1A(ssa.OpAddr, n.Type, zerobaseSym, s.sb)
}
// If inplace is true, it writes the result of the OAPPEND expression n
// back to the slice being appended to, and returns nil.
// inplace MUST be set to false if the slice can be SSA'd.
-func (s *state) append(n *Node, inplace bool) *ssa.Value {
+func (s *state) append(n *ir.Node, inplace bool) *ssa.Value {
// If inplace is false, process as expression "append(s, e1, e2, e3)":
//
// ptr, len, cap := s
// Decide if we need to grow
nargs := int64(n.List.Len() - 1)
p := s.newValue1(ssa.OpSlicePtr, pt, slice)
- l := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice)
- c := s.newValue1(ssa.OpSliceCap, types.Types[TINT], slice)
- nl := s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], l, s.constInt(types.Types[TINT], nargs))
+ l := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
+ c := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], slice)
+ nl := s.newValue2(s.ssaOp(ir.OADD, types.Types[types.TINT]), types.Types[types.TINT], l, s.constInt(types.Types[types.TINT], nargs))
- cmp := s.newValue2(s.ssaOp(OLT, types.Types[TUINT]), types.Types[types.TBOOL], c, nl)
+ cmp := s.newValue2(s.ssaOp(ir.OLT, types.Types[types.TUINT]), types.Types[types.TBOOL], c, nl)
s.vars[ptrVar] = p
if !inplace {
// Call growslice
s.startBlock(grow)
taddr := s.expr(n.Left)
- r := s.rtcall(growslice, true, []*types.Type{pt, types.Types[TINT], types.Types[TINT]}, taddr, p, l, c, nl)
+ r := s.rtcall(growslice, true, []*types.Type{pt, types.Types[types.TINT], types.Types[types.TINT]}, taddr, p, l, c, nl)
if inplace {
- if sn.Op == ONAME && sn.Class() != PEXTERN {
+ if sn.Op == ir.ONAME && sn.Class() != ir.PEXTERN {
// Tell liveness we're about to build a new slice
s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
}
capaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, sliceCapOffset, addr)
- s.store(types.Types[TINT], capaddr, r[2])
+ s.store(types.Types[types.TINT], capaddr, r[2])
s.store(pt, addr, r[0])
// load the value we just stored to avoid having to spill it
s.vars[ptrVar] = s.load(pt, addr)
s.vars[lenVar] = r[1] // avoid a spill in the fast path
} else {
s.vars[ptrVar] = r[0]
- s.vars[newlenVar] = s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], r[1], s.constInt(types.Types[TINT], nargs))
+ s.vars[newlenVar] = s.newValue2(s.ssaOp(ir.OADD, types.Types[types.TINT]), types.Types[types.TINT], r[1], s.constInt(types.Types[types.TINT], nargs))
s.vars[capVar] = r[2]
}
s.startBlock(assign)
if inplace {
- l = s.variable(lenVar, types.Types[TINT]) // generates phi for len
- nl = s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], l, s.constInt(types.Types[TINT], nargs))
+ l = s.variable(lenVar, types.Types[types.TINT]) // generates phi for len
+ nl = s.newValue2(s.ssaOp(ir.OADD, types.Types[types.TINT]), types.Types[types.TINT], l, s.constInt(types.Types[types.TINT], nargs))
lenaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, sliceLenOffset, addr)
- s.store(types.Types[TINT], lenaddr, nl)
+ s.store(types.Types[types.TINT], lenaddr, nl)
}
// Evaluate args
p = s.variable(ptrVar, pt) // generates phi for ptr
if !inplace {
- nl = s.variable(newlenVar, types.Types[TINT]) // generates phi for nl
- c = s.variable(capVar, types.Types[TINT]) // generates phi for cap
+ nl = s.variable(newlenVar, types.Types[types.TINT]) // generates phi for nl
+ c = s.variable(capVar, types.Types[types.TINT]) // generates phi for cap
}
p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
for i, arg := range args {
- addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(types.Types[TINT], int64(i)))
+ addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(types.Types[types.TINT], int64(i)))
if arg.store {
s.storeType(et, addr, arg.v, 0, true)
} else {
// if cond is true and no if cond is false.
// This function is intended to handle && and || better than just calling
// s.expr(cond) and branching on the result.
-func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
+func (s *state) condBranch(cond *ir.Node, yes, no *ssa.Block, likely int8) {
switch cond.Op {
- case OANDAND:
+ case ir.OANDAND:
mid := s.f.NewBlock(ssa.BlockPlain)
s.stmtList(cond.Ninit)
s.condBranch(cond.Left, mid, no, max8(likely, 0))
// the likeliness of the first branch.
// TODO: have the frontend give us branch prediction hints for
// OANDAND and OOROR nodes (if it ever has such info).
- case OOROR:
+ case ir.OOROR:
mid := s.f.NewBlock(ssa.BlockPlain)
s.stmtList(cond.Ninit)
s.condBranch(cond.Left, yes, mid, min8(likely, 0))
// Note: if likely==-1, then both recursive calls pass -1.
// If likely==1, then we don't have enough info to decide
// the likelihood of the first branch.
- case ONOT:
+ case ir.ONOT:
s.stmtList(cond.Ninit)
s.condBranch(cond.Left, no, yes, -likely)
return
// If deref is true, then we do left = *right instead (and right has already been nil-checked).
// If deref is true and right == nil, just do left = 0.
// skip indicates assignments (at the top level) that can be avoided.
-func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask) {
- if left.Op == ONAME && left.isBlank() {
+func (s *state) assign(left *ir.Node, right *ssa.Value, deref bool, skip skipMask) {
+ if left.Op == ir.ONAME && ir.IsBlank(left) {
return
}
t := left.Type
if deref {
s.Fatalf("can SSA LHS %v but not RHS %s", left, right)
}
- if left.Op == ODOT {
+ if left.Op == ir.ODOT {
// We're assigning to a field of an ssa-able value.
// We need to build a new structure with the new value for the
// field we're assigning and the old values for the other fields.
// TODO: do we need to update named values here?
return
}
- if left.Op == OINDEX && left.Left.Type.IsArray() {
+ if left.Op == ir.OINDEX && left.Left.Type.IsArray() {
s.pushLine(left.Pos)
defer s.popLine()
// We're assigning to an element of an ssa-able array.
if n == 0 {
// The bounds check must fail. Might as well
// ignore the actual index and just use zeros.
- z := s.constInt(types.Types[TINT], 0)
+ z := s.constInt(types.Types[types.TINT], 0)
s.boundsCheck(z, z, ssa.BoundsIndex, false)
return
}
s.Fatalf("assigning to non-1-length array")
}
// Rewrite to a = [1]{v}
- len := s.constInt(types.Types[TINT], 1)
+ len := s.constInt(types.Types[types.TINT], 1)
s.boundsCheck(i, len, ssa.BoundsIndex, false) // checks i == 0
v := s.newValue1(ssa.OpArrayMake1, t, right)
s.assign(left.Left, v, false, 0)
// If this assignment clobbers an entire local variable, then emit
// OpVarDef so liveness analysis knows the variable is redefined.
- if base := clobberBase(left); base.Op == ONAME && base.Class() != PEXTERN && skip == 0 {
+ if base := clobberBase(left); base.Op == ir.ONAME && base.Class() != ir.PEXTERN && skip == 0 {
s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, base, s.mem(), !base.IsAutoTmp())
}
// is valid, even though they have type uintptr (#19168).
// Mark it pointer type to signal the writebarrier pass to
// insert a write barrier.
- t = types.Types[TUNSAFEPTR]
+ t = types.Types[types.TUNSAFEPTR]
}
if deref {
// Treat as a mem->mem move.
case t.IsComplex():
switch t.Size() {
case 8:
- z := s.constFloat32(types.Types[TFLOAT32], 0)
+ z := s.constFloat32(types.Types[types.TFLOAT32], 0)
return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
case 16:
- z := s.constFloat64(types.Types[TFLOAT64], 0)
+ z := s.constFloat64(types.Types[types.TFLOAT64], 0)
return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
default:
s.Fatalf("bad sized complex type %v", t)
func softfloatInit() {
// Some of these operations get transformed by sfcall.
softFloatOps = map[ssa.Op]sfRtCallDef{
- ssa.OpAdd32F: sfRtCallDef{sysfunc("fadd32"), TFLOAT32},
- ssa.OpAdd64F: sfRtCallDef{sysfunc("fadd64"), TFLOAT64},
- ssa.OpSub32F: sfRtCallDef{sysfunc("fadd32"), TFLOAT32},
- ssa.OpSub64F: sfRtCallDef{sysfunc("fadd64"), TFLOAT64},
- ssa.OpMul32F: sfRtCallDef{sysfunc("fmul32"), TFLOAT32},
- ssa.OpMul64F: sfRtCallDef{sysfunc("fmul64"), TFLOAT64},
- ssa.OpDiv32F: sfRtCallDef{sysfunc("fdiv32"), TFLOAT32},
- ssa.OpDiv64F: sfRtCallDef{sysfunc("fdiv64"), TFLOAT64},
-
- ssa.OpEq64F: sfRtCallDef{sysfunc("feq64"), TBOOL},
- ssa.OpEq32F: sfRtCallDef{sysfunc("feq32"), TBOOL},
- ssa.OpNeq64F: sfRtCallDef{sysfunc("feq64"), TBOOL},
- ssa.OpNeq32F: sfRtCallDef{sysfunc("feq32"), TBOOL},
- ssa.OpLess64F: sfRtCallDef{sysfunc("fgt64"), TBOOL},
- ssa.OpLess32F: sfRtCallDef{sysfunc("fgt32"), TBOOL},
- ssa.OpLeq64F: sfRtCallDef{sysfunc("fge64"), TBOOL},
- ssa.OpLeq32F: sfRtCallDef{sysfunc("fge32"), TBOOL},
-
- ssa.OpCvt32to32F: sfRtCallDef{sysfunc("fint32to32"), TFLOAT32},
- ssa.OpCvt32Fto32: sfRtCallDef{sysfunc("f32toint32"), TINT32},
- ssa.OpCvt64to32F: sfRtCallDef{sysfunc("fint64to32"), TFLOAT32},
- ssa.OpCvt32Fto64: sfRtCallDef{sysfunc("f32toint64"), TINT64},
- ssa.OpCvt64Uto32F: sfRtCallDef{sysfunc("fuint64to32"), TFLOAT32},
- ssa.OpCvt32Fto64U: sfRtCallDef{sysfunc("f32touint64"), TUINT64},
- ssa.OpCvt32to64F: sfRtCallDef{sysfunc("fint32to64"), TFLOAT64},
- ssa.OpCvt64Fto32: sfRtCallDef{sysfunc("f64toint32"), TINT32},
- ssa.OpCvt64to64F: sfRtCallDef{sysfunc("fint64to64"), TFLOAT64},
- ssa.OpCvt64Fto64: sfRtCallDef{sysfunc("f64toint64"), TINT64},
- ssa.OpCvt64Uto64F: sfRtCallDef{sysfunc("fuint64to64"), TFLOAT64},
- ssa.OpCvt64Fto64U: sfRtCallDef{sysfunc("f64touint64"), TUINT64},
- ssa.OpCvt32Fto64F: sfRtCallDef{sysfunc("f32to64"), TFLOAT64},
- ssa.OpCvt64Fto32F: sfRtCallDef{sysfunc("f64to32"), TFLOAT32},
+ ssa.OpAdd32F: sfRtCallDef{sysfunc("fadd32"), types.TFLOAT32},
+ ssa.OpAdd64F: sfRtCallDef{sysfunc("fadd64"), types.TFLOAT64},
+ ssa.OpSub32F: sfRtCallDef{sysfunc("fadd32"), types.TFLOAT32},
+ ssa.OpSub64F: sfRtCallDef{sysfunc("fadd64"), types.TFLOAT64},
+ ssa.OpMul32F: sfRtCallDef{sysfunc("fmul32"), types.TFLOAT32},
+ ssa.OpMul64F: sfRtCallDef{sysfunc("fmul64"), types.TFLOAT64},
+ ssa.OpDiv32F: sfRtCallDef{sysfunc("fdiv32"), types.TFLOAT32},
+ ssa.OpDiv64F: sfRtCallDef{sysfunc("fdiv64"), types.TFLOAT64},
+
+ ssa.OpEq64F: sfRtCallDef{sysfunc("feq64"), types.TBOOL},
+ ssa.OpEq32F: sfRtCallDef{sysfunc("feq32"), types.TBOOL},
+ ssa.OpNeq64F: sfRtCallDef{sysfunc("feq64"), types.TBOOL},
+ ssa.OpNeq32F: sfRtCallDef{sysfunc("feq32"), types.TBOOL},
+ ssa.OpLess64F: sfRtCallDef{sysfunc("fgt64"), types.TBOOL},
+ ssa.OpLess32F: sfRtCallDef{sysfunc("fgt32"), types.TBOOL},
+ ssa.OpLeq64F: sfRtCallDef{sysfunc("fge64"), types.TBOOL},
+ ssa.OpLeq32F: sfRtCallDef{sysfunc("fge32"), types.TBOOL},
+
+ ssa.OpCvt32to32F: sfRtCallDef{sysfunc("fint32to32"), types.TFLOAT32},
+ ssa.OpCvt32Fto32: sfRtCallDef{sysfunc("f32toint32"), types.TINT32},
+ ssa.OpCvt64to32F: sfRtCallDef{sysfunc("fint64to32"), types.TFLOAT32},
+ ssa.OpCvt32Fto64: sfRtCallDef{sysfunc("f32toint64"), types.TINT64},
+ ssa.OpCvt64Uto32F: sfRtCallDef{sysfunc("fuint64to32"), types.TFLOAT32},
+ ssa.OpCvt32Fto64U: sfRtCallDef{sysfunc("f32touint64"), types.TUINT64},
+ ssa.OpCvt32to64F: sfRtCallDef{sysfunc("fint32to64"), types.TFLOAT64},
+ ssa.OpCvt64Fto32: sfRtCallDef{sysfunc("f64toint32"), types.TINT32},
+ ssa.OpCvt64to64F: sfRtCallDef{sysfunc("fint64to64"), types.TFLOAT64},
+ ssa.OpCvt64Fto64: sfRtCallDef{sysfunc("f64toint64"), types.TINT64},
+ ssa.OpCvt64Uto64F: sfRtCallDef{sysfunc("fuint64to64"), types.TFLOAT64},
+ ssa.OpCvt64Fto64U: sfRtCallDef{sysfunc("f64touint64"), types.TUINT64},
+ ssa.OpCvt32Fto64F: sfRtCallDef{sysfunc("f32to64"), types.TFLOAT64},
+ ssa.OpCvt64Fto32F: sfRtCallDef{sysfunc("f64to32"), types.TFLOAT32},
}
}
args[0], args[1] = args[1], args[0]
case ssa.OpSub32F,
ssa.OpSub64F:
- args[1] = s.newValue1(s.ssaOp(ONEG, types.Types[callDef.rtype]), args[1].Type, args[1])
+ args[1] = s.newValue1(s.ssaOp(ir.ONEG, types.Types[callDef.rtype]), args[1].Type, args[1])
}
result := s.rtcall(callDef.rtfn, true, []*types.Type{types.Types[callDef.rtype]}, args...)[0]
// An intrinsicBuilder converts a call node n into an ssa value that
// implements that call as an intrinsic. args is a list of arguments to the func.
-type intrinsicBuilder func(s *state, n *Node, args []*ssa.Value) *ssa.Value
+type intrinsicBuilder func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value
type intrinsicKey struct {
arch *sys.Arch
/******** runtime ********/
if !instrumenting {
add("runtime", "slicebytetostringtmp",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
// Compiler frontend optimizations emit OBYTES2STRTMP nodes
// for the backend instead of slicebytetostringtmp calls
// when not instrumenting.
all...)
}
addF("runtime/internal/math", "MulUintptr",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
if s.config.PtrSize == 4 {
- return s.newValue2(ssa.OpMul32uover, types.NewTuple(types.Types[TUINT], types.Types[TUINT]), args[0], args[1])
+ return s.newValue2(ssa.OpMul32uover, types.NewTuple(types.Types[types.TUINT], types.Types[types.TUINT]), args[0], args[1])
}
- return s.newValue2(ssa.OpMul64uover, types.NewTuple(types.Types[TUINT], types.Types[TUINT]), args[0], args[1])
+ return s.newValue2(ssa.OpMul64uover, types.NewTuple(types.Types[types.TUINT], types.Types[types.TUINT]), args[0], args[1])
},
sys.AMD64, sys.I386, sys.MIPS64)
add("runtime", "KeepAlive",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
data := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, args[0])
s.vars[memVar] = s.newValue2(ssa.OpKeepAlive, types.TypeMem, data, s.mem())
return nil
},
all...)
add("runtime", "getclosureptr",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
return s.newValue0(ssa.OpGetClosurePtr, s.f.Config.Types.Uintptr)
},
all...)
add("runtime", "getcallerpc",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
return s.newValue0(ssa.OpGetCallerPC, s.f.Config.Types.Uintptr)
},
all...)
add("runtime", "getcallersp",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
return s.newValue0(ssa.OpGetCallerSP, s.f.Config.Types.Uintptr)
},
all...)
/******** runtime/internal/sys ********/
addF("runtime/internal/sys", "Ctz32",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpCtz32, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz32, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
addF("runtime/internal/sys", "Ctz64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpCtz64, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz64, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
addF("runtime/internal/sys", "Bswap32",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBswap32, types.Types[TUINT32], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBswap32, types.Types[types.TUINT32], args[0])
},
sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
addF("runtime/internal/sys", "Bswap64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBswap64, types.Types[TUINT64], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBswap64, types.Types[types.TUINT64], args[0])
},
sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
/******** runtime/internal/atomic ********/
addF("runtime/internal/atomic", "Load",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue2(ssa.OpAtomicLoad32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoad32, types.NewTuple(types.Types[types.TUINT32], types.TypeMem), args[0], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT32], v)
},
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Load8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue2(ssa.OpAtomicLoad8, types.NewTuple(types.Types[TUINT8], types.TypeMem), args[0], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoad8, types.NewTuple(types.Types[types.TUINT8], types.TypeMem), args[0], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT8], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT8], v)
},
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Load64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue2(ssa.OpAtomicLoad64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoad64, types.NewTuple(types.Types[types.TUINT64], types.TypeMem), args[0], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT64], v)
},
sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "LoadAcq",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue2(ssa.OpAtomicLoadAcq32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoadAcq32, types.NewTuple(types.Types[types.TUINT32], types.TypeMem), args[0], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT32], v)
},
sys.PPC64, sys.S390X)
addF("runtime/internal/atomic", "LoadAcq64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue2(ssa.OpAtomicLoadAcq64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoadAcq64, types.NewTuple(types.Types[types.TUINT64], types.TypeMem), args[0], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT64], v)
},
sys.PPC64)
addF("runtime/internal/atomic", "Loadp",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
return s.newValue1(ssa.OpSelect0, s.f.Config.Types.BytePtr, v)
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Store",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicStore32, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Store8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicStore8, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Store64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicStore64, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "StorepNoWB",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicStorePtrNoWB, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "StoreRel",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicStoreRel32, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.PPC64, sys.S390X)
addF("runtime/internal/atomic", "StoreRel64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicStoreRel64, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.PPC64)
addF("runtime/internal/atomic", "Xchg",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue3(ssa.OpAtomicExchange32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], args[1], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue3(ssa.OpAtomicExchange32, types.NewTuple(types.Types[types.TUINT32], types.TypeMem), args[0], args[1], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT32], v)
},
sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Xchg64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue3(ssa.OpAtomicExchange64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue3(ssa.OpAtomicExchange64, types.NewTuple(types.Types[types.TUINT64], types.TypeMem), args[0], args[1], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT64], v)
},
sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
- type atomicOpEmitter func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType)
+ type atomicOpEmitter func(s *state, n *ir.Node, args []*ssa.Value, op ssa.Op, typ types.EType)
makeAtomicGuardedIntrinsicARM64 := func(op0, op1 ssa.Op, typ, rtyp types.EType, emit atomicOpEmitter) intrinsicBuilder {
- return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
// Target Atomic feature is identified by dynamic detection
- addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), arm64HasATOMICS, s.sb)
- v := s.load(types.Types[TBOOL], addr)
+ addr := s.entryNewValue1A(ssa.OpAddr, types.Types[types.TBOOL].PtrTo(), arm64HasATOMICS, s.sb)
+ v := s.load(types.Types[types.TBOOL], addr)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(v)
// Merge results.
s.startBlock(bEnd)
- if rtyp == TNIL {
+ if rtyp == types.TNIL {
return nil
} else {
return s.variable(n, types.Types[rtyp])
}
}
- atomicXchgXaddEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
+ atomicXchgXaddEmitterARM64 := func(s *state, n *ir.Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
v := s.newValue3(op, types.NewTuple(types.Types[typ], types.TypeMem), args[0], args[1], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[typ], v)
}
addF("runtime/internal/atomic", "Xchg",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicExchange32, ssa.OpAtomicExchange32Variant, TUINT32, TUINT32, atomicXchgXaddEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicExchange32, ssa.OpAtomicExchange32Variant, types.TUINT32, types.TUINT32, atomicXchgXaddEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "Xchg64",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicExchange64, ssa.OpAtomicExchange64Variant, TUINT64, TUINT64, atomicXchgXaddEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicExchange64, ssa.OpAtomicExchange64Variant, types.TUINT64, types.TUINT64, atomicXchgXaddEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "Xadd",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue3(ssa.OpAtomicAdd32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], args[1], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue3(ssa.OpAtomicAdd32, types.NewTuple(types.Types[types.TUINT32], types.TypeMem), args[0], args[1], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT32], v)
},
sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Xadd64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.newValue3(ssa.OpAtomicAdd64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue3(ssa.OpAtomicAdd64, types.NewTuple(types.Types[types.TUINT64], types.TypeMem), args[0], args[1], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
- return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT64], v)
},
sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Xadd",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, TUINT32, TUINT32, atomicXchgXaddEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, types.TUINT32, types.TUINT32, atomicXchgXaddEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "Xadd64",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, TUINT64, TUINT64, atomicXchgXaddEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, types.TUINT64, types.TUINT64, atomicXchgXaddEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "Cas",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[types.TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
return s.newValue1(ssa.OpSelect0, types.Types[types.TBOOL], v)
},
sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "Cas64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
v := s.newValue4(ssa.OpAtomicCompareAndSwap64, types.NewTuple(types.Types[types.TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
return s.newValue1(ssa.OpSelect0, types.Types[types.TBOOL], v)
},
sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
addF("runtime/internal/atomic", "CasRel",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[types.TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
return s.newValue1(ssa.OpSelect0, types.Types[types.TBOOL], v)
},
sys.PPC64)
- atomicCasEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
+ atomicCasEmitterARM64 := func(s *state, n *ir.Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
v := s.newValue4(op, types.NewTuple(types.Types[types.TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[typ], v)
}
addF("runtime/internal/atomic", "Cas",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicCompareAndSwap32, ssa.OpAtomicCompareAndSwap32Variant, TUINT32, TBOOL, atomicCasEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicCompareAndSwap32, ssa.OpAtomicCompareAndSwap32Variant, types.TUINT32, types.TBOOL, atomicCasEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "Cas64",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicCompareAndSwap64, ssa.OpAtomicCompareAndSwap64Variant, TUINT64, TBOOL, atomicCasEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicCompareAndSwap64, ssa.OpAtomicCompareAndSwap64Variant, types.TUINT64, types.TBOOL, atomicCasEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "And8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicAnd8, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
addF("runtime/internal/atomic", "And",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicAnd32, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
addF("runtime/internal/atomic", "Or8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
addF("runtime/internal/atomic", "Or",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
s.vars[memVar] = s.newValue3(ssa.OpAtomicOr32, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
- atomicAndOrEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
+ atomicAndOrEmitterARM64 := func(s *state, n *ir.Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
s.vars[memVar] = s.newValue3(op, types.TypeMem, args[0], args[1], s.mem())
}
addF("runtime/internal/atomic", "And8",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAnd8, ssa.OpAtomicAnd8Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAnd8, ssa.OpAtomicAnd8Variant, types.TNIL, types.TNIL, atomicAndOrEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "And",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAnd32, ssa.OpAtomicAnd32Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAnd32, ssa.OpAtomicAnd32Variant, types.TNIL, types.TNIL, atomicAndOrEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "Or8",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicOr8, ssa.OpAtomicOr8Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicOr8, ssa.OpAtomicOr8Variant, types.TNIL, types.TNIL, atomicAndOrEmitterARM64),
sys.ARM64)
addF("runtime/internal/atomic", "Or",
- makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicOr32, ssa.OpAtomicOr32Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicOr32, ssa.OpAtomicOr32Variant, types.TNIL, types.TNIL, atomicAndOrEmitterARM64),
sys.ARM64)
alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...)
/******** math ********/
addF("math", "Sqrt",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpSqrt, types.Types[TFLOAT64], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpSqrt, types.Types[types.TFLOAT64], args[0])
},
sys.I386, sys.AMD64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X, sys.Wasm)
addF("math", "Trunc",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpTrunc, types.Types[TFLOAT64], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpTrunc, types.Types[types.TFLOAT64], args[0])
},
sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
addF("math", "Ceil",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpCeil, types.Types[TFLOAT64], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCeil, types.Types[types.TFLOAT64], args[0])
},
sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
addF("math", "Floor",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpFloor, types.Types[TFLOAT64], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpFloor, types.Types[types.TFLOAT64], args[0])
},
sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
addF("math", "Round",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpRound, types.Types[TFLOAT64], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpRound, types.Types[types.TFLOAT64], args[0])
},
sys.ARM64, sys.PPC64, sys.S390X)
addF("math", "RoundToEven",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpRoundToEven, types.Types[TFLOAT64], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpRoundToEven, types.Types[types.TFLOAT64], args[0])
},
sys.ARM64, sys.S390X, sys.Wasm)
addF("math", "Abs",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpAbs, types.Types[TFLOAT64], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpAbs, types.Types[types.TFLOAT64], args[0])
},
sys.ARM64, sys.ARM, sys.PPC64, sys.Wasm)
addF("math", "Copysign",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue2(ssa.OpCopysign, types.Types[TFLOAT64], args[0], args[1])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpCopysign, types.Types[types.TFLOAT64], args[0], args[1])
},
sys.PPC64, sys.Wasm)
addF("math", "FMA",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue3(ssa.OpFMA, types.Types[TFLOAT64], args[0], args[1], args[2])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue3(ssa.OpFMA, types.Types[types.TFLOAT64], args[0], args[1], args[2])
},
sys.ARM64, sys.PPC64, sys.S390X)
addF("math", "FMA",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
if !s.config.UseFMA {
s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
- return s.variable(n, types.Types[TFLOAT64])
+ return s.variable(n, types.Types[types.TFLOAT64])
}
- v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[TBOOL], x86HasFMA)
+ v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[types.TBOOL], x86HasFMA)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(v)
// We have the intrinsic - use it directly.
s.startBlock(bTrue)
- s.vars[n] = s.newValue3(ssa.OpFMA, types.Types[TFLOAT64], args[0], args[1], args[2])
+ s.vars[n] = s.newValue3(ssa.OpFMA, types.Types[types.TFLOAT64], args[0], args[1], args[2])
s.endBlock().AddEdgeTo(bEnd)
// Call the pure Go version.
// Merge results.
s.startBlock(bEnd)
- return s.variable(n, types.Types[TFLOAT64])
+ return s.variable(n, types.Types[types.TFLOAT64])
},
sys.AMD64)
addF("math", "FMA",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
if !s.config.UseFMA {
s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
- return s.variable(n, types.Types[TFLOAT64])
+ return s.variable(n, types.Types[types.TFLOAT64])
}
- addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), armHasVFPv4, s.sb)
- v := s.load(types.Types[TBOOL], addr)
+ addr := s.entryNewValue1A(ssa.OpAddr, types.Types[types.TBOOL].PtrTo(), armHasVFPv4, s.sb)
+ v := s.load(types.Types[types.TBOOL], addr)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(v)
// We have the intrinsic - use it directly.
s.startBlock(bTrue)
- s.vars[n] = s.newValue3(ssa.OpFMA, types.Types[TFLOAT64], args[0], args[1], args[2])
+ s.vars[n] = s.newValue3(ssa.OpFMA, types.Types[types.TFLOAT64], args[0], args[1], args[2])
s.endBlock().AddEdgeTo(bEnd)
// Call the pure Go version.
// Merge results.
s.startBlock(bEnd)
- return s.variable(n, types.Types[TFLOAT64])
+ return s.variable(n, types.Types[types.TFLOAT64])
},
sys.ARM)
- makeRoundAMD64 := func(op ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[TBOOL], x86HasSSE41)
+ makeRoundAMD64 := func(op ssa.Op) func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[types.TBOOL], x86HasSSE41)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(v)
// We have the intrinsic - use it directly.
s.startBlock(bTrue)
- s.vars[n] = s.newValue1(op, types.Types[TFLOAT64], args[0])
+ s.vars[n] = s.newValue1(op, types.Types[types.TFLOAT64], args[0])
s.endBlock().AddEdgeTo(bEnd)
// Call the pure Go version.
// Merge results.
s.startBlock(bEnd)
- return s.variable(n, types.Types[TFLOAT64])
+ return s.variable(n, types.Types[types.TFLOAT64])
}
}
addF("math", "RoundToEven",
/******** math/bits ********/
addF("math/bits", "TrailingZeros64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpCtz64, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz64, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
addF("math/bits", "TrailingZeros32",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpCtz32, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz32, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
addF("math/bits", "TrailingZeros16",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- x := s.newValue1(ssa.OpZeroExt16to32, types.Types[TUINT32], args[0])
- c := s.constInt32(types.Types[TUINT32], 1<<16)
- y := s.newValue2(ssa.OpOr32, types.Types[TUINT32], x, c)
- return s.newValue1(ssa.OpCtz32, types.Types[TINT], y)
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ x := s.newValue1(ssa.OpZeroExt16to32, types.Types[types.TUINT32], args[0])
+ c := s.constInt32(types.Types[types.TUINT32], 1<<16)
+ y := s.newValue2(ssa.OpOr32, types.Types[types.TUINT32], x, c)
+ return s.newValue1(ssa.OpCtz32, types.Types[types.TINT], y)
},
sys.MIPS)
addF("math/bits", "TrailingZeros16",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpCtz16, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz16, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.I386, sys.ARM, sys.ARM64, sys.Wasm)
addF("math/bits", "TrailingZeros16",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- x := s.newValue1(ssa.OpZeroExt16to64, types.Types[TUINT64], args[0])
- c := s.constInt64(types.Types[TUINT64], 1<<16)
- y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c)
- return s.newValue1(ssa.OpCtz64, types.Types[TINT], y)
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ x := s.newValue1(ssa.OpZeroExt16to64, types.Types[types.TUINT64], args[0])
+ c := s.constInt64(types.Types[types.TUINT64], 1<<16)
+ y := s.newValue2(ssa.OpOr64, types.Types[types.TUINT64], x, c)
+ return s.newValue1(ssa.OpCtz64, types.Types[types.TINT], y)
},
sys.S390X, sys.PPC64)
addF("math/bits", "TrailingZeros8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0])
- c := s.constInt32(types.Types[TUINT32], 1<<8)
- y := s.newValue2(ssa.OpOr32, types.Types[TUINT32], x, c)
- return s.newValue1(ssa.OpCtz32, types.Types[TINT], y)
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ x := s.newValue1(ssa.OpZeroExt8to32, types.Types[types.TUINT32], args[0])
+ c := s.constInt32(types.Types[types.TUINT32], 1<<8)
+ y := s.newValue2(ssa.OpOr32, types.Types[types.TUINT32], x, c)
+ return s.newValue1(ssa.OpCtz32, types.Types[types.TINT], y)
},
sys.MIPS)
addF("math/bits", "TrailingZeros8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpCtz8, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz8, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.ARM, sys.ARM64, sys.Wasm)
addF("math/bits", "TrailingZeros8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- x := s.newValue1(ssa.OpZeroExt8to64, types.Types[TUINT64], args[0])
- c := s.constInt64(types.Types[TUINT64], 1<<8)
- y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c)
- return s.newValue1(ssa.OpCtz64, types.Types[TINT], y)
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ x := s.newValue1(ssa.OpZeroExt8to64, types.Types[types.TUINT64], args[0])
+ c := s.constInt64(types.Types[types.TUINT64], 1<<8)
+ y := s.newValue2(ssa.OpOr64, types.Types[types.TUINT64], x, c)
+ return s.newValue1(ssa.OpCtz64, types.Types[types.TINT], y)
},
sys.S390X)
alias("math/bits", "ReverseBytes64", "runtime/internal/sys", "Bswap64", all...)
// ReverseBytes inlines correctly, no need to intrinsify it.
// ReverseBytes16 lowers to a rotate, no need for anything special here.
addF("math/bits", "Len64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBitLen64, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitLen64, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
addF("math/bits", "Len32",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.ARM64)
addF("math/bits", "Len32",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
if s.config.PtrSize == 4 {
- return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0])
+ return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], args[0])
}
- x := s.newValue1(ssa.OpZeroExt32to64, types.Types[TUINT64], args[0])
- return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+ x := s.newValue1(ssa.OpZeroExt32to64, types.Types[types.TUINT64], args[0])
+ return s.newValue1(ssa.OpBitLen64, types.Types[types.TINT], x)
},
sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
addF("math/bits", "Len16",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
if s.config.PtrSize == 4 {
- x := s.newValue1(ssa.OpZeroExt16to32, types.Types[TUINT32], args[0])
- return s.newValue1(ssa.OpBitLen32, types.Types[TINT], x)
+ x := s.newValue1(ssa.OpZeroExt16to32, types.Types[types.TUINT32], args[0])
+ return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], x)
}
- x := s.newValue1(ssa.OpZeroExt16to64, types.Types[TUINT64], args[0])
- return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+ x := s.newValue1(ssa.OpZeroExt16to64, types.Types[types.TUINT64], args[0])
+ return s.newValue1(ssa.OpBitLen64, types.Types[types.TINT], x)
},
sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
addF("math/bits", "Len16",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBitLen16, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitLen16, types.Types[types.TINT], args[0])
},
sys.AMD64)
addF("math/bits", "Len8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
if s.config.PtrSize == 4 {
- x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0])
- return s.newValue1(ssa.OpBitLen32, types.Types[TINT], x)
+ x := s.newValue1(ssa.OpZeroExt8to32, types.Types[types.TUINT32], args[0])
+ return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], x)
}
- x := s.newValue1(ssa.OpZeroExt8to64, types.Types[TUINT64], args[0])
- return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+ x := s.newValue1(ssa.OpZeroExt8to64, types.Types[types.TUINT64], args[0])
+ return s.newValue1(ssa.OpBitLen64, types.Types[types.TINT], x)
},
sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
addF("math/bits", "Len8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBitLen8, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitLen8, types.Types[types.TINT], args[0])
},
sys.AMD64)
addF("math/bits", "Len",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
if s.config.PtrSize == 4 {
- return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0])
+ return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], args[0])
}
- return s.newValue1(ssa.OpBitLen64, types.Types[TINT], args[0])
+ return s.newValue1(ssa.OpBitLen64, types.Types[types.TINT], args[0])
},
sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
// LeadingZeros is handled because it trivially calls Len.
addF("math/bits", "Reverse64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitRev64, types.Types[types.TINT], args[0])
},
sys.ARM64)
addF("math/bits", "Reverse32",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBitRev32, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitRev32, types.Types[types.TINT], args[0])
},
sys.ARM64)
addF("math/bits", "Reverse16",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBitRev16, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitRev16, types.Types[types.TINT], args[0])
},
sys.ARM64)
addF("math/bits", "Reverse8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpBitRev8, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitRev8, types.Types[types.TINT], args[0])
},
sys.ARM64)
addF("math/bits", "Reverse",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
if s.config.PtrSize == 4 {
- return s.newValue1(ssa.OpBitRev32, types.Types[TINT], args[0])
+ return s.newValue1(ssa.OpBitRev32, types.Types[types.TINT], args[0])
}
- return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0])
+ return s.newValue1(ssa.OpBitRev64, types.Types[types.TINT], args[0])
},
sys.ARM64)
addF("math/bits", "RotateLeft8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue2(ssa.OpRotateLeft8, types.Types[TUINT8], args[0], args[1])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpRotateLeft8, types.Types[types.TUINT8], args[0], args[1])
},
sys.AMD64)
addF("math/bits", "RotateLeft16",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue2(ssa.OpRotateLeft16, types.Types[TUINT16], args[0], args[1])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpRotateLeft16, types.Types[types.TUINT16], args[0], args[1])
},
sys.AMD64)
addF("math/bits", "RotateLeft32",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue2(ssa.OpRotateLeft32, types.Types[TUINT32], args[0], args[1])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpRotateLeft32, types.Types[types.TUINT32], args[0], args[1])
},
sys.AMD64, sys.ARM, sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
addF("math/bits", "RotateLeft64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue2(ssa.OpRotateLeft64, types.Types[TUINT64], args[0], args[1])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpRotateLeft64, types.Types[types.TUINT64], args[0], args[1])
},
sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
alias("math/bits", "RotateLeft", "math/bits", "RotateLeft64", p8...)
- makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[TBOOL], x86HasPOPCNT)
+ makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[types.TBOOL], x86HasPOPCNT)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(v)
if s.config.PtrSize == 4 {
op = op32
}
- s.vars[n] = s.newValue1(op, types.Types[TINT], args[0])
+ s.vars[n] = s.newValue1(op, types.Types[types.TINT], args[0])
s.endBlock().AddEdgeTo(bEnd)
// Call the pure Go version.
// Merge results.
s.startBlock(bEnd)
- return s.variable(n, types.Types[TINT])
+ return s.variable(n, types.Types[types.TINT])
}
}
addF("math/bits", "OnesCount64",
makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount64),
sys.AMD64)
addF("math/bits", "OnesCount64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpPopCount64, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpPopCount64, types.Types[types.TINT], args[0])
},
sys.PPC64, sys.ARM64, sys.S390X, sys.Wasm)
addF("math/bits", "OnesCount32",
makeOnesCountAMD64(ssa.OpPopCount32, ssa.OpPopCount32),
sys.AMD64)
addF("math/bits", "OnesCount32",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpPopCount32, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpPopCount32, types.Types[types.TINT], args[0])
},
sys.PPC64, sys.ARM64, sys.S390X, sys.Wasm)
addF("math/bits", "OnesCount16",
makeOnesCountAMD64(ssa.OpPopCount16, ssa.OpPopCount16),
sys.AMD64)
addF("math/bits", "OnesCount16",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpPopCount16, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpPopCount16, types.Types[types.TINT], args[0])
},
sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
addF("math/bits", "OnesCount8",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue1(ssa.OpPopCount8, types.Types[TINT], args[0])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpPopCount8, types.Types[types.TINT], args[0])
},
sys.S390X, sys.PPC64, sys.Wasm)
addF("math/bits", "OnesCount",
makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32),
sys.AMD64)
addF("math/bits", "Mul64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1])
},
sys.AMD64, sys.ARM64, sys.PPC64, sys.S390X, sys.MIPS64)
alias("math/bits", "Mul", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchS390X, sys.ArchMIPS64, sys.ArchMIPS64LE)
addF("math/bits", "Add64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue3(ssa.OpAdd64carry, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue3(ssa.OpAdd64carry, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1], args[2])
},
sys.AMD64, sys.ARM64, sys.PPC64, sys.S390X)
alias("math/bits", "Add", "math/bits", "Add64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchS390X)
addF("math/bits", "Sub64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue3(ssa.OpSub64borrow, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue3(ssa.OpSub64borrow, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1], args[2])
},
sys.AMD64, sys.ARM64, sys.S390X)
alias("math/bits", "Sub", "math/bits", "Sub64", sys.ArchAMD64, sys.ArchARM64, sys.ArchS390X)
addF("math/bits", "Div64",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
// check for divide-by-zero/overflow and panic with appropriate message
- cmpZero := s.newValue2(s.ssaOp(ONE, types.Types[TUINT64]), types.Types[TBOOL], args[2], s.zeroVal(types.Types[TUINT64]))
+ cmpZero := s.newValue2(s.ssaOp(ir.ONE, types.Types[types.TUINT64]), types.Types[types.TBOOL], args[2], s.zeroVal(types.Types[types.TUINT64]))
s.check(cmpZero, panicdivide)
- cmpOverflow := s.newValue2(s.ssaOp(OLT, types.Types[TUINT64]), types.Types[TBOOL], args[0], args[2])
+ cmpOverflow := s.newValue2(s.ssaOp(ir.OLT, types.Types[types.TUINT64]), types.Types[types.TBOOL], args[0], args[2])
s.check(cmpOverflow, panicoverflow)
- return s.newValue3(ssa.OpDiv128u, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
+ return s.newValue3(ssa.OpDiv128u, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1], args[2])
},
sys.AMD64)
alias("math/bits", "Div", "math/bits", "Div64", sys.ArchAMD64)
/******** math/big ********/
add("math/big", "mulWW",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1])
+ func(s *state, n *ir.Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1])
},
sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64LE, sys.ArchPPC64, sys.ArchS390X)
}
return nil
}
pkg := sym.Pkg.Path
- if sym.Pkg == localpkg {
+ if sym.Pkg == ir.LocalPkg {
pkg = base.Ctxt.Pkgpath
}
if base.Flag.Race && pkg == "sync/atomic" {
return intrinsics[intrinsicKey{thearch.LinkArch.Arch, pkg, fn}]
}
-func isIntrinsicCall(n *Node) bool {
+func isIntrinsicCall(n *ir.Node) bool {
if n == nil || n.Left == nil {
return false
}
}
// intrinsicCall converts a call to a recognized intrinsic function into the intrinsic SSA operation.
-func (s *state) intrinsicCall(n *Node) *ssa.Value {
+func (s *state) intrinsicCall(n *ir.Node) *ssa.Value {
v := findIntrinsic(n.Left.Sym)(s, n, s.intrinsicArgs(n))
if ssa.IntrinsicsDebug > 0 {
x := v
}
// intrinsicArgs extracts args from n, evaluates them to SSA values, and returns them.
-func (s *state) intrinsicArgs(n *Node) []*ssa.Value {
+func (s *state) intrinsicArgs(n *ir.Node) []*ssa.Value {
// Construct map of temps; see comments in s.call about the structure of n.
- temps := map[*Node]*ssa.Value{}
+ temps := map[*ir.Node]*ssa.Value{}
for _, a := range n.List.Slice() {
- if a.Op != OAS {
+ if a.Op != ir.OAS {
s.Fatalf("non-assignment as a temp function argument %v", a.Op)
}
l, r := a.Left, a.Right
- if l.Op != ONAME {
+ if l.Op != ir.ONAME {
s.Fatalf("non-ONAME temp function argument %v", a.Op)
}
// Evaluate and store to "temporary".
// call. We will also record funcdata information on where the args are stored
// (as well as the deferBits variable), and this will enable us to run the proper
// defer calls during panics.
-func (s *state) openDeferRecord(n *Node) {
+func (s *state) openDeferRecord(n *ir.Node) {
// Do any needed expression evaluation for the args (including the
// receiver, if any). This may be evaluating something like 'autotmp_3 =
// once.mutex'. Such a statement will create a mapping in s.vars[] from
s.stmtList(n.List)
var args []*ssa.Value
- var argNodes []*Node
+ var argNodes []*ir.Node
opendefer := &openDeferInfo{
n: n,
}
fn := n.Left
- if n.Op == OCALLFUNC {
+ if n.Op == ir.OCALLFUNC {
// We must always store the function value in a stack slot for the
// runtime panic code to use. But in the defer exit code, we will
// call the function directly if it is a static function.
closureVal := s.expr(fn)
closure := s.openDeferSave(nil, fn.Type, closureVal)
- opendefer.closureNode = closure.Aux.(*Node)
- if !(fn.Op == ONAME && fn.Class() == PFUNC) {
+ opendefer.closureNode = closure.Aux.(*ir.Node)
+ if !(fn.Op == ir.ONAME && fn.Class() == ir.PFUNC) {
opendefer.closure = closure
}
- } else if n.Op == OCALLMETH {
- if fn.Op != ODOTMETH {
+ } else if n.Op == ir.OCALLMETH {
+ if fn.Op != ir.ODOTMETH {
base.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
}
closureVal := s.getMethodClosure(fn)
// runtime panic code to use. But in the defer exit code, we will
// call the method directly.
closure := s.openDeferSave(nil, fn.Type, closureVal)
- opendefer.closureNode = closure.Aux.(*Node)
+ opendefer.closureNode = closure.Aux.(*ir.Node)
} else {
- if fn.Op != ODOTINTER {
+ if fn.Op != ir.ODOTINTER {
base.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
}
closure, rcvr := s.getClosureAndRcvr(fn)
// Important to get the receiver type correct, so it is recognized
// as a pointer for GC purposes.
opendefer.rcvr = s.openDeferSave(nil, fn.Type.Recv().Type, rcvr)
- opendefer.closureNode = opendefer.closure.Aux.(*Node)
- opendefer.rcvrNode = opendefer.rcvr.Aux.(*Node)
+ opendefer.closureNode = opendefer.closure.Aux.(*ir.Node)
+ opendefer.rcvrNode = opendefer.rcvr.Aux.(*ir.Node)
}
for _, argn := range n.Rlist.Slice() {
var v *ssa.Value
v = s.openDeferSave(argn, argn.Type, nil)
}
args = append(args, v)
- argNodes = append(argNodes, v.Aux.(*Node))
+ argNodes = append(argNodes, v.Aux.(*ir.Node))
}
opendefer.argVals = args
opendefer.argNodes = argNodes
// Update deferBits only after evaluation and storage to stack of
// args/receiver/interface is successful.
- bitvalue := s.constInt8(types.Types[TUINT8], 1<<uint(index))
- newDeferBits := s.newValue2(ssa.OpOr8, types.Types[TUINT8], s.variable(deferBitsVar, types.Types[TUINT8]), bitvalue)
+ bitvalue := s.constInt8(types.Types[types.TUINT8], 1<<uint(index))
+ newDeferBits := s.newValue2(ssa.OpOr8, types.Types[types.TUINT8], s.variable(deferBitsVar, types.Types[types.TUINT8]), bitvalue)
s.vars[deferBitsVar] = newDeferBits
- s.store(types.Types[TUINT8], s.deferBitsAddr, newDeferBits)
+ s.store(types.Types[types.TUINT8], s.deferBitsAddr, newDeferBits)
}
// openDeferSave generates SSA nodes to store a value (with type t) for an
// type t is non-SSAable, then n must be non-nil (and val should be nil) and n is
// evaluated (via s.addr() below) to get the value that is to be stored. The
// function returns an SSA value representing a pointer to the autotmp location.
-func (s *state) openDeferSave(n *Node, t *types.Type, val *ssa.Value) *ssa.Value {
+func (s *state) openDeferSave(n *ir.Node, t *types.Type, val *ssa.Value) *ssa.Value {
canSSA := canSSAType(t)
var pos src.XPos
if canSSA {
s.startBlock(deferExit)
s.lastDeferExit = deferExit
s.lastDeferCount = len(s.openDefers)
- zeroval := s.constInt8(types.Types[TUINT8], 0)
+ zeroval := s.constInt8(types.Types[types.TUINT8], 0)
testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
// Test for and run defers in reverse order
for i := len(s.openDefers) - 1; i >= 0; i-- {
bCond := s.f.NewBlock(ssa.BlockPlain)
bEnd := s.f.NewBlock(ssa.BlockPlain)
- deferBits := s.variable(deferBitsVar, types.Types[TUINT8])
+ deferBits := s.variable(deferBitsVar, types.Types[types.TUINT8])
// Generate code to check if the bit associated with the current
// defer is set.
- bitval := s.constInt8(types.Types[TUINT8], 1<<uint(i))
- andval := s.newValue2(ssa.OpAnd8, types.Types[TUINT8], deferBits, bitval)
- eqVal := s.newValue2(ssa.OpEq8, types.Types[TBOOL], andval, zeroval)
+ bitval := s.constInt8(types.Types[types.TUINT8], 1<<uint(i))
+ andval := s.newValue2(ssa.OpAnd8, types.Types[types.TUINT8], deferBits, bitval)
+ eqVal := s.newValue2(ssa.OpEq8, types.Types[types.TBOOL], andval, zeroval)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(eqVal)
// Clear this bit in deferBits and force store back to stack, so
// we will not try to re-run this defer call if this defer call panics.
- nbitval := s.newValue1(ssa.OpCom8, types.Types[TUINT8], bitval)
- maskedval := s.newValue2(ssa.OpAnd8, types.Types[TUINT8], deferBits, nbitval)
- s.store(types.Types[TUINT8], s.deferBitsAddr, maskedval)
+ nbitval := s.newValue1(ssa.OpCom8, types.Types[types.TUINT8], bitval)
+ maskedval := s.newValue2(ssa.OpAnd8, types.Types[types.TUINT8], deferBits, nbitval)
+ s.store(types.Types[types.TUINT8], s.deferBitsAddr, maskedval)
// Use this value for following tests, so we keep previous
// bits cleared.
s.vars[deferBitsVar] = maskedval
// rcvr in case of OCALLINTER
v := s.load(r.rcvr.Type.Elem(), r.rcvr)
addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
- ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart)})
if testLateExpansion {
callArgs = append(callArgs, v)
} else {
- s.store(types.Types[TUINTPTR], addr, v)
+ s.store(types.Types[types.TUINTPTR], addr, v)
}
}
for j, argAddrVal := range r.argVals {
if r.closure != nil {
v := s.load(r.closure.Type.Elem(), r.closure)
s.maybeNilCheckClosure(v, callDefer)
- codeptr := s.rawLoad(types.Types[TUINTPTR], v)
+ codeptr := s.rawLoad(types.Types[types.TUINTPTR], v)
aux := ssa.ClosureAuxCall(ACArgs, ACResults)
if testLateExpansion {
callArgs = append(callArgs, s.mem())
}
}
-func (s *state) callResult(n *Node, k callKind) *ssa.Value {
+func (s *state) callResult(n *ir.Node, k callKind) *ssa.Value {
return s.call(n, k, false)
}
-func (s *state) callAddr(n *Node, k callKind) *ssa.Value {
+func (s *state) callAddr(n *ir.Node, k callKind) *ssa.Value {
return s.call(n, k, true)
}
// Calls the function n using the specified call type.
// Returns the address of the return value (or nil if none).
-func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
+func (s *state) call(n *ir.Node, k callKind, returnResultAddr bool) *ssa.Value {
s.prevCall = nil
var sym *types.Sym // target symbol (if static)
var closure *ssa.Value // ptr to closure to run (if dynamic)
testLateExpansion := false
switch n.Op {
- case OCALLFUNC:
+ case ir.OCALLFUNC:
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
- if k == callNormal && fn.Op == ONAME && fn.Class() == PFUNC {
+ if k == callNormal && fn.Op == ir.ONAME && fn.Class() == ir.PFUNC {
sym = fn.Sym
break
}
// not the point of defer statement.
s.maybeNilCheckClosure(closure, k)
}
- case OCALLMETH:
- if fn.Op != ODOTMETH {
+ case ir.OCALLMETH:
+ if fn.Op != ir.ODOTMETH {
s.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
}
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
closure = s.getMethodClosure(fn)
// Note: receiver is already present in n.Rlist, so we don't
// want to set it here.
- case OCALLINTER:
- if fn.Op != ODOTINTER {
+ case ir.OCALLINTER:
+ if fn.Op != ir.ODOTINTER {
s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
}
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
var iclosure *ssa.Value
iclosure, rcvr = s.getClosureAndRcvr(fn)
if k == callNormal {
- codeptr = s.load(types.Types[TUINTPTR], iclosure)
+ codeptr = s.load(types.Types[types.TUINTPTR], iclosure)
} else {
closure = iclosure
}
// Must match reflect.go:deferstruct and src/runtime/runtime2.go:_defer.
// 0: siz
- s.store(types.Types[TUINT32],
- s.newValue1I(ssa.OpOffPtr, types.Types[TUINT32].PtrTo(), t.FieldOff(0), addr),
- s.constInt32(types.Types[TUINT32], int32(stksize)))
+ s.store(types.Types[types.TUINT32],
+ s.newValue1I(ssa.OpOffPtr, types.Types[types.TUINT32].PtrTo(), t.FieldOff(0), addr),
+ s.constInt32(types.Types[types.TUINT32], int32(stksize)))
// 1: started, set in deferprocStack
// 2: heap, set in deferprocStack
// 3: openDefer
// Set receiver (for interface calls). Always a pointer.
if rcvr != nil {
p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr)
- s.store(types.Types[TUINTPTR], p, rcvr)
+ s.store(types.Types[types.TUINTPTR], p, rcvr)
}
// Set receiver (for method calls).
- if n.Op == OCALLMETH {
+ if n.Op == ir.OCALLMETH {
f := ft.Recv()
s.storeArgWithBase(args[0], f.Type, addr, off+f.Offset)
args = args[1:]
}
// Call runtime.deferprocStack with pointer to _defer record.
- ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(base.Ctxt.FixedFrameSize())})
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(base.Ctxt.FixedFrameSize())})
aux := ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults)
if testLateExpansion {
callArgs = append(callArgs, addr, s.mem())
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
call.AddArgs(callArgs...)
} else {
- arg0 := s.constOffPtrSP(types.Types[TUINTPTR], base.Ctxt.FixedFrameSize())
- s.store(types.Types[TUINTPTR], arg0, addr)
+ arg0 := s.constOffPtrSP(types.Types[types.TUINTPTR], base.Ctxt.FixedFrameSize())
+ s.store(types.Types[types.TUINTPTR], arg0, addr)
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
}
if stksize < int64(Widthptr) {
// Defer/go args.
if k != callNormal {
// Write argsize and closure (args to newproc/deferproc).
- argsize := s.constInt32(types.Types[TUINT32], int32(stksize))
- ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINT32], Offset: int32(argStart)})
+ argsize := s.constInt32(types.Types[types.TUINT32], int32(stksize))
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINT32], Offset: int32(argStart)})
if testLateExpansion {
callArgs = append(callArgs, argsize)
} else {
addr := s.constOffPtrSP(s.f.Config.Types.UInt32Ptr, argStart)
- s.store(types.Types[TUINT32], addr, argsize)
+ s.store(types.Types[types.TUINT32], addr, argsize)
}
- ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart) + int32(Widthptr)})
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart) + int32(Widthptr)})
if testLateExpansion {
callArgs = append(callArgs, closure)
} else {
addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart+int64(Widthptr))
- s.store(types.Types[TUINTPTR], addr, closure)
+ s.store(types.Types[types.TUINTPTR], addr, closure)
}
stksize += 2 * int64(Widthptr)
argStart += 2 * int64(Widthptr)
// Set receiver (for interface calls).
if rcvr != nil {
addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
- ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart)})
if testLateExpansion {
callArgs = append(callArgs, rcvr)
} else {
- s.store(types.Types[TUINTPTR], addr, rcvr)
+ s.store(types.Types[types.TUINTPTR], addr, rcvr)
}
}
// Write args.
t := n.Left.Type
args := n.Rlist.Slice()
- if n.Op == OCALLMETH {
+ if n.Op == ir.OCALLMETH {
f := t.Recv()
ACArg, arg := s.putArg(args[0], f.Type, argStart+f.Offset, testLateExpansion)
ACArgs = append(ACArgs, ACArg)
// can't always figure that out currently, and it's
// critical that we not clobber any arguments already
// stored onto the stack.
- codeptr = s.rawLoad(types.Types[TUINTPTR], closure)
+ codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure)
if testLateExpansion {
aux := ssa.ClosureAuxCall(ACArgs, ACResults)
call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
}
// getMethodClosure returns a value representing the closure for a method call
-func (s *state) getMethodClosure(fn *Node) *ssa.Value {
+func (s *state) getMethodClosure(fn *ir.Node) *ssa.Value {
// Make a name n2 for the function.
// fn.Sym might be sync.(*Mutex).Unlock.
// Make a PFUNC node out of that, then evaluate it.
// We get back an SSA value representing &sync.(*Mutex).Unlock·f.
// We can then pass that to defer or go.
- n2 := newnamel(fn.Pos, fn.Sym)
+ n2 := ir.NewNameAt(fn.Pos, fn.Sym)
n2.Name.Curfn = s.curfn
- n2.SetClass(PFUNC)
+ n2.SetClass(ir.PFUNC)
// n2.Sym already existed, so it's already marked as a function.
n2.Pos = fn.Pos
- n2.Type = types.Types[TUINT8] // fake type for a static closure. Could use runtime.funcval if we had it.
+ n2.Type = types.Types[types.TUINT8] // fake type for a static closure. Could use runtime.funcval if we had it.
return s.expr(n2)
}
// getClosureAndRcvr returns values for the appropriate closure and receiver of an
// interface call
-func (s *state) getClosureAndRcvr(fn *Node) (*ssa.Value, *ssa.Value) {
+func (s *state) getClosureAndRcvr(fn *ir.Node) (*ssa.Value, *ssa.Value) {
i := s.expr(fn.Left)
- itab := s.newValue1(ssa.OpITab, types.Types[TUINTPTR], i)
+ itab := s.newValue1(ssa.OpITab, types.Types[types.TUINTPTR], i)
s.nilCheck(itab)
itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab
closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
// -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
func etypesign(e types.EType) int8 {
switch e {
- case TINT8, TINT16, TINT32, TINT64, TINT:
+ case types.TINT8, types.TINT16, types.TINT32, types.TINT64, types.TINT:
return -1
- case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
+ case types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINT, types.TUINTPTR, types.TUNSAFEPTR:
return +1
}
return 0
// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
// The value that the returned Value represents is guaranteed to be non-nil.
-func (s *state) addr(n *Node) *ssa.Value {
- if n.Op != ONAME {
+func (s *state) addr(n *ir.Node) *ssa.Value {
+ if n.Op != ir.ONAME {
s.pushLine(n.Pos)
defer s.popLine()
}
t := types.NewPtr(n.Type)
switch n.Op {
- case ONAME:
+ case ir.ONAME:
switch n.Class() {
- case PEXTERN:
+ case ir.PEXTERN:
// global variable
v := s.entryNewValue1A(ssa.OpAddr, t, n.Sym.Linksym(), s.sb)
// TODO: Make OpAddr use AuxInt as well as Aux.
v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
}
return v
- case PPARAM:
+ case ir.PPARAM:
// parameter slot
v := s.decladdrs[n]
if v != nil {
}
s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
return nil
- case PAUTO:
+ case ir.PAUTO:
return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), !n.IsAutoTmp())
- case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
+ case ir.PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
// ensure that we reuse symbols for out parameters so
// that cse works on their addresses
return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
s.Fatalf("variable address class %v not implemented", n.Class())
return nil
}
- case ORESULT:
+ case ir.ORESULT:
// load return from callee
if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
return s.constOffPtrSP(t, n.Xoffset)
x := s.newValue1I(ssa.OpSelectNAddr, t, which, s.prevCall)
return x
- case OINDEX:
+ case ir.OINDEX:
if n.Left.Type.IsSlice() {
a := s.expr(n.Left)
i := s.expr(n.Right)
- len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], a)
+ len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], a)
i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
p := s.newValue1(ssa.OpSlicePtr, t, a)
return s.newValue2(ssa.OpPtrIndex, t, p, i)
} else { // array
a := s.addr(n.Left)
i := s.expr(n.Right)
- len := s.constInt(types.Types[TINT], n.Left.Type.NumElem())
+ len := s.constInt(types.Types[types.TINT], n.Left.Type.NumElem())
i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.Left.Type.Elem()), a, i)
}
- case ODEREF:
+ case ir.ODEREF:
return s.exprPtr(n.Left, n.Bounded(), n.Pos)
- case ODOT:
+ case ir.ODOT:
p := s.addr(n.Left)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
- case ODOTPTR:
+ case ir.ODOTPTR:
p := s.exprPtr(n.Left, n.Bounded(), n.Pos)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
- case OCLOSUREVAR:
+ case ir.OCLOSUREVAR:
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr))
- case OCONVNOP:
+ case ir.OCONVNOP:
addr := s.addr(n.Left)
return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
- case OCALLFUNC, OCALLINTER, OCALLMETH:
+ case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
return s.callAddr(n, callNormal)
- case ODOTTYPE:
+ case ir.ODOTTYPE:
v, _ := s.dottype(n, false)
if v.Op != ssa.OpLoad {
s.Fatalf("dottype of non-load")
// canSSA reports whether n is SSA-able.
// n must be an ONAME (or an ODOT sequence with an ONAME base).
-func (s *state) canSSA(n *Node) bool {
+func (s *state) canSSA(n *ir.Node) bool {
if base.Flag.N != 0 {
return false
}
- for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) {
+ for n.Op == ir.ODOT || (n.Op == ir.OINDEX && n.Left.Type.IsArray()) {
n = n.Left
}
- if n.Op != ONAME {
+ if n.Op != ir.ONAME {
return false
}
if n.Name.Addrtaken() {
return false
}
- if n.isParamHeapCopy() {
+ if isParamHeapCopy(n) {
return false
}
- if n.Class() == PAUTOHEAP {
+ if n.Class() == ir.PAUTOHEAP {
s.Fatalf("canSSA of PAUTOHEAP %v", n)
}
switch n.Class() {
- case PEXTERN:
+ case ir.PEXTERN:
return false
- case PPARAMOUT:
+ case ir.PPARAMOUT:
if s.hasdefer {
// TODO: handle this case? Named return values must be
// in memory so that the deferred function can see them.
return false
}
}
- if n.Class() == PPARAM && n.Sym != nil && n.Sym.Name == ".this" {
+ if n.Class() == ir.PPARAM && n.Sym != nil && n.Sym.Name == ".this" {
// wrappers generated by genwrapper need to update
// the .this pointer in place.
// TODO: treat as a PPARAMOUT?
return false
}
switch t.Etype {
- case TARRAY:
+ case types.TARRAY:
// We can't do larger arrays because dynamic indexing is
// not supported on SSA variables.
// TODO: allow if all indexes are constant.
return canSSAType(t.Elem())
}
return false
- case TSTRUCT:
+ case types.TSTRUCT:
if t.NumFields() > ssa.MaxStruct {
return false
}
}
// exprPtr evaluates n to a pointer and nil-checks it.
-func (s *state) exprPtr(n *Node, bounded bool, lineno src.XPos) *ssa.Value {
+func (s *state) exprPtr(n *ir.Node, bounded bool, lineno src.XPos) *ssa.Value {
p := s.expr(n)
if bounded || n.NonNil() {
if s.f.Frontend().Debug_checknil() && lineno.Line() > 1 {
var cmp *ssa.Value
if kind == ssa.BoundsIndex || kind == ssa.BoundsIndexU {
- cmp = s.newValue2(ssa.OpIsInBounds, types.Types[TBOOL], idx, len)
+ cmp = s.newValue2(ssa.OpIsInBounds, types.Types[types.TBOOL], idx, len)
} else {
- cmp = s.newValue2(ssa.OpIsSliceInBounds, types.Types[TBOOL], idx, len)
+ cmp = s.newValue2(ssa.OpIsSliceInBounds, types.Types[types.TBOOL], idx, len)
}
b := s.endBlock()
b.Kind = ssa.BlockIf
if kind != ssa.BoundsIndex && kind != ssa.BoundsIndexU {
op = ssa.OpSpectreSliceIndex
}
- idx = s.newValue2(op, types.Types[TINT], idx, len)
+ idx = s.newValue2(op, types.Types[types.TINT], idx, len)
}
return idx
s.startBlock(bNext)
}
-func (s *state) intDivide(n *Node, a, b *ssa.Value) *ssa.Value {
+func (s *state) intDivide(n *ir.Node, a, b *ssa.Value) *ssa.Value {
needcheck := true
switch b.Op {
case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64:
}
if needcheck {
// do a size-appropriate check for zero
- cmp := s.newValue2(s.ssaOp(ONE, n.Type), types.Types[TBOOL], b, s.zeroVal(n.Type))
+ cmp := s.newValue2(s.ssaOp(ir.ONE, n.Type), types.Types[types.TBOOL], b, s.zeroVal(n.Type))
s.check(cmp, panicdivide)
}
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
if skip&skipLen != 0 {
return
}
- len := s.newValue1(ssa.OpStringLen, types.Types[TINT], right)
+ len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], right)
lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
- s.store(types.Types[TINT], lenAddr, len)
+ s.store(types.Types[types.TINT], lenAddr, len)
case t.IsSlice():
if skip&skipLen == 0 {
- len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], right)
+ len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], right)
lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
- s.store(types.Types[TINT], lenAddr, len)
+ s.store(types.Types[types.TINT], lenAddr, len)
}
if skip&skipCap == 0 {
- cap := s.newValue1(ssa.OpSliceCap, types.Types[TINT], right)
+ cap := s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], right)
capAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, 2*s.config.PtrSize, left)
- s.store(types.Types[TINT], capAddr, cap)
+ s.store(types.Types[types.TINT], capAddr, cap)
}
case t.IsInterface():
// itab field doesn't need a write barrier (even though it is a pointer).
itab := s.newValue1(ssa.OpITab, s.f.Config.Types.BytePtr, right)
- s.store(types.Types[TUINTPTR], left, itab)
+ s.store(types.Types[types.TUINTPTR], left, itab)
case t.IsStruct():
n := t.NumFields()
for i := 0; i < n; i++ {
// putArg evaluates n for the purpose of passing it as an argument to a function and returns the corresponding Param for the call.
// If forLateExpandedCall is true, it returns the argument value to pass to the call operation.
// If forLateExpandedCall is false, then the value is stored at the specified stack offset, and the returned value is nil.
-func (s *state) putArg(n *Node, t *types.Type, off int64, forLateExpandedCall bool) (ssa.Param, *ssa.Value) {
+func (s *state) putArg(n *ir.Node, t *types.Type, off int64, forLateExpandedCall bool) (ssa.Param, *ssa.Value) {
var a *ssa.Value
if forLateExpandedCall {
if !canSSAType(t) {
return ssa.Param{Type: t, Offset: int32(off)}, a
}
-func (s *state) storeArgWithBase(n *Node, t *types.Type, base *ssa.Value, off int64) {
+func (s *state) storeArgWithBase(n *ir.Node, t *types.Type, base *ssa.Value, off int64) {
pt := types.NewPtr(t)
var addr *ssa.Value
if base == s.sp {
switch {
case t.IsSlice():
ptr = s.newValue1(ssa.OpSlicePtr, types.NewPtr(t.Elem()), v)
- len = s.newValue1(ssa.OpSliceLen, types.Types[TINT], v)
- cap = s.newValue1(ssa.OpSliceCap, types.Types[TINT], v)
+ len = s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], v)
+ cap = s.newValue1(ssa.OpSliceCap, types.Types[types.TINT], v)
case t.IsString():
- ptr = s.newValue1(ssa.OpStringPtr, types.NewPtr(types.Types[TUINT8]), v)
- len = s.newValue1(ssa.OpStringLen, types.Types[TINT], v)
+ ptr = s.newValue1(ssa.OpStringPtr, types.NewPtr(types.Types[types.TUINT8]), v)
+ len = s.newValue1(ssa.OpStringLen, types.Types[types.TINT], v)
cap = len
case t.IsPtr():
if !t.Elem().IsArray() {
}
s.nilCheck(v)
ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), v)
- len = s.constInt(types.Types[TINT], t.Elem().NumElem())
+ len = s.constInt(types.Types[types.TINT], t.Elem().NumElem())
cap = len
default:
s.Fatalf("bad type in slice %v\n", t)
// Set default values
if i == nil {
- i = s.constInt(types.Types[TINT], 0)
+ i = s.constInt(types.Types[types.TINT], 0)
}
if j == nil {
j = len
}
// Word-sized integer operations.
- subOp := s.ssaOp(OSUB, types.Types[TINT])
- mulOp := s.ssaOp(OMUL, types.Types[TINT])
- andOp := s.ssaOp(OAND, types.Types[TINT])
+ subOp := s.ssaOp(ir.OSUB, types.Types[types.TINT])
+ mulOp := s.ssaOp(ir.OMUL, types.Types[types.TINT])
+ andOp := s.ssaOp(ir.OAND, types.Types[types.TINT])
// Calculate the length (rlen) and capacity (rcap) of the new slice.
// For strings the capacity of the result is unimportant. However,
// we use rcap to test if we've generated a zero-length slice.
// Use length of strings for that.
- rlen := s.newValue2(subOp, types.Types[TINT], j, i)
+ rlen := s.newValue2(subOp, types.Types[types.TINT], j, i)
rcap := rlen
if j != k && !t.IsString() {
- rcap = s.newValue2(subOp, types.Types[TINT], k, i)
+ rcap = s.newValue2(subOp, types.Types[types.TINT], k, i)
}
if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 {
//
// Where mask(x) is 0 if x==0 and -1 if x>0 and stride is the width
// of the element type.
- stride := s.constInt(types.Types[TINT], ptr.Type.Elem().Width)
+ stride := s.constInt(types.Types[types.TINT], ptr.Type.Elem().Width)
// The delta is the number of bytes to offset ptr by.
- delta := s.newValue2(mulOp, types.Types[TINT], i, stride)
+ delta := s.newValue2(mulOp, types.Types[types.TINT], i, stride)
// If we're slicing to the point where the capacity is zero,
// zero out the delta.
- mask := s.newValue1(ssa.OpSlicemask, types.Types[TINT], rcap)
- delta = s.newValue2(andOp, types.Types[TINT], delta, mask)
+ mask := s.newValue1(ssa.OpSlicemask, types.Types[types.TINT], rcap)
+ delta = s.newValue2(andOp, types.Types[types.TINT], delta, mask)
// Compute rptr = ptr + delta.
rptr := s.newValue2(ssa.OpAddPtr, ptr.Type, ptr, delta)
one: (*state).constInt64,
}
-func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) uint64Tofloat64(n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
return s.uint64Tofloat(&u64_f64, n, x, ft, tt)
}
-func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) uint64Tofloat32(n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
return s.uint64Tofloat(&u64_f32, n, x, ft, tt)
}
-func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
// if x >= 0 {
// result = (floatY) x
// } else {
// equal to 10000000001; that rounds up, and the 1 cannot
// be lost else it would round down if the LSB of the
// candidate mantissa is 0.
- cmp := s.newValue2(cvttab.leq, types.Types[TBOOL], s.zeroVal(ft), x)
+ cmp := s.newValue2(cvttab.leq, types.Types[types.TBOOL], s.zeroVal(ft), x)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(cmp)
cvtF2F: ssa.OpCvt64Fto32F,
}
-func (s *state) uint32Tofloat64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) uint32Tofloat64(n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
return s.uint32Tofloat(&u32_f64, n, x, ft, tt)
}
-func (s *state) uint32Tofloat32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) uint32Tofloat32(n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
return s.uint32Tofloat(&u32_f32, n, x, ft, tt)
}
-func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
// if x >= 0 {
// result = floatY(x)
// } else {
// result = floatY(float64(x) + (1<<32))
// }
- cmp := s.newValue2(ssa.OpLeq32, types.Types[TBOOL], s.zeroVal(ft), x)
+ cmp := s.newValue2(ssa.OpLeq32, types.Types[types.TBOOL], s.zeroVal(ft), x)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(cmp)
b.AddEdgeTo(bElse)
s.startBlock(bElse)
- a1 := s.newValue1(ssa.OpCvt32to64F, types.Types[TFLOAT64], x)
- twoToThe32 := s.constFloat64(types.Types[TFLOAT64], float64(1<<32))
- a2 := s.newValue2(ssa.OpAdd64F, types.Types[TFLOAT64], a1, twoToThe32)
+ a1 := s.newValue1(ssa.OpCvt32to64F, types.Types[types.TFLOAT64], x)
+ twoToThe32 := s.constFloat64(types.Types[types.TFLOAT64], float64(1<<32))
+ a2 := s.newValue2(ssa.OpAdd64F, types.Types[types.TFLOAT64], a1, twoToThe32)
a3 := s.newValue1(cvttab.cvtF2F, tt, a2)
s.vars[n] = a3
}
// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
-func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
+func (s *state) referenceTypeBuiltin(n *ir.Node, x *ssa.Value) *ssa.Value {
if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
s.Fatalf("node must be a map or a channel")
}
// return *(((*int)n)+1)
// }
lenType := n.Type
- nilValue := s.constNil(types.Types[TUINTPTR])
- cmp := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], x, nilValue)
+ nilValue := s.constNil(types.Types[types.TUINTPTR])
+ cmp := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], x, nilValue)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(cmp)
b.AddEdgeTo(bElse)
s.startBlock(bElse)
switch n.Op {
- case OLEN:
+ case ir.OLEN:
// length is stored in the first word for map/chan
s.vars[n] = s.load(lenType, x)
- case OCAP:
+ case ir.OCAP:
// capacity is stored in the second word for chan
sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
s.vars[n] = s.load(lenType, sw)
cutoff: 1 << 31,
}
-func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) float32ToUint64(n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
return s.floatToUint(&f32_u64, n, x, ft, tt)
}
-func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) float64ToUint64(n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
return s.floatToUint(&f64_u64, n, x, ft, tt)
}
-func (s *state) float32ToUint32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) float32ToUint32(n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
return s.floatToUint(&f32_u32, n, x, ft, tt)
}
-func (s *state) float64ToUint32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) float64ToUint32(n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
return s.floatToUint(&f64_u32, n, x, ft, tt)
}
-func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+func (s *state) floatToUint(cvttab *f2uCvtTab, n *ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
// cutoff:=1<<(intY_Size-1)
// if x < floatX(cutoff) {
// result = uintY(x)
// result = z | -(cutoff)
// }
cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff))
- cmp := s.newValue2(cvttab.ltf, types.Types[TBOOL], x, cutoff)
+ cmp := s.newValue2(cvttab.ltf, types.Types[types.TBOOL], x, cutoff)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(cmp)
// dottype generates SSA for a type assertion node.
// commaok indicates whether to panic or return a bool.
// If commaok is false, resok will be nil.
-func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
+func (s *state) dottype(n *ir.Node, commaok bool) (res, resok *ssa.Value) {
iface := s.expr(n.Left) // input interface
target := s.expr(n.Right) // target type
byteptr := s.f.Config.Types.BytePtr
// Get itab/type field from input.
itab := s.newValue1(ssa.OpITab, byteptr, iface)
// Conversion succeeds iff that field is not nil.
- cond := s.newValue2(ssa.OpNeqPtr, types.Types[TBOOL], itab, s.constNil(byteptr))
+ cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
if n.Left.Type.IsEmptyInterface() && commaok {
// Converting empty interface to empty interface with ,ok is just a nil check.
}
if n.Left.Type.IsEmptyInterface() {
if commaok {
- call := s.rtcall(assertE2I2, true, []*types.Type{n.Type, types.Types[TBOOL]}, target, iface)
+ call := s.rtcall(assertE2I2, true, []*types.Type{n.Type, types.Types[types.TBOOL]}, target, iface)
return call[0], call[1]
}
return s.rtcall(assertE2I, true, []*types.Type{n.Type}, target, iface)[0], nil
}
if commaok {
- call := s.rtcall(assertI2I2, true, []*types.Type{n.Type, types.Types[TBOOL]}, target, iface)
+ call := s.rtcall(assertI2I2, true, []*types.Type{n.Type, types.Types[types.TBOOL]}, target, iface)
return call[0], call[1]
}
return s.rtcall(assertI2I, true, []*types.Type{n.Type}, target, iface)[0], nil
targetITab = s.expr(n.List.First())
}
- var tmp *Node // temporary for use with large types
+ var tmp *ir.Node // temporary for use with large types
var addr *ssa.Value // address of tmp
if commaok && !canSSAType(n.Type) {
// unSSAable type, use temporary.
addr = s.addr(tmp)
}
- cond := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], itab, targetITab)
+ cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, targetITab)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(cond)
}
// variable returns the value of a variable at the current location.
-func (s *state) variable(name *Node, t *types.Type) *ssa.Value {
+func (s *state) variable(name *ir.Node, t *types.Type) *ssa.Value {
v := s.vars[name]
if v != nil {
return v
return s.variable(memVar, types.TypeMem)
}
-func (s *state) addNamedValue(n *Node, v *ssa.Value) {
- if n.Class() == Pxxx {
+func (s *state) addNamedValue(n *ir.Node, v *ssa.Value) {
+ if n.Class() == ir.Pxxx {
// Don't track our marker nodes (memVar etc.).
return
}
// Don't track temporary variables.
return
}
- if n.Class() == PPARAMOUT {
+ if n.Class() == ir.PPARAMOUT {
// Don't track named output values. This prevents return values
// from being assigned too early. See #14591 and #14762. TODO: allow this.
return
}
- if n.Class() == PAUTO && n.Xoffset != 0 {
+ if n.Class() == ir.PAUTO && n.Xoffset != 0 {
s.Fatalf("AUTO var with offset %v %d", n, n.Xoffset)
}
loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
bstart []*obj.Prog
// Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include PPC and Sparc V8.
- ScratchFpMem *Node
+ ScratchFpMem *ir.Node
maxarg int64 // largest frame size for arguments to calls made by the function
}
// byXoffset implements sort.Interface for []*Node using Xoffset as the ordering.
-type byXoffset []*Node
+type byXoffset []*ir.Node
func (s byXoffset) Len() int { return len(s) }
func (s byXoffset) Less(i, j int) bool { return s[i].Xoffset < s[j].Xoffset }
func (s byXoffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func emitStackObjects(e *ssafn, pp *Progs) {
- var vars []*Node
+ var vars []*ir.Node
for _, n := range e.curfn.Func.Dcl {
if livenessShouldTrack(n) && n.Name.Addrtaken() {
vars = append(vars, n)
// Populate the stack object data.
// Format must match runtime/stack.go:stackObjectRecord.
- x := e.curfn.Func.lsym.Func().StackObjects
+ x := e.curfn.Func.LSym.Func().StackObjects
off := 0
off = duintptr(x, off, uint64(len(vars)))
for _, v := range vars {
s.livenessMap = liveness(e, f, pp)
emitStackObjects(e, pp)
- openDeferInfo := e.curfn.Func.lsym.Func().OpenCodedDeferInfo
+ openDeferInfo := e.curfn.Func.LSym.Func().OpenCodedDeferInfo
if openDeferInfo != nil {
// This function uses open-coded defers -- write out the funcdata
// info that we computed at the end of genssa.
// some of the inline marks.
// Use this instruction instead.
p.Pos = p.Pos.WithIsStmt() // promote position to a statement
- pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[m])
+ pp.curfn.Func.LSym.Func().AddInlMark(p, inlMarks[m])
// Make the inline mark a real nop, so it doesn't generate any code.
m.As = obj.ANOP
m.Pos = src.NoXPos
// Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction).
for _, p := range inlMarkList {
if p.As != obj.ANOP {
- pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[p])
+ pp.curfn.Func.LSym.Func().AddInlMark(p, inlMarks[p])
}
}
}
}
return bstart[b].Pc
case ssa.BlockEnd.ID:
- return e.curfn.Func.lsym.Size
+ return e.curfn.Func.LSym.Size
default:
return valueToProgAfter[v].Pc
}
if !n.Name.Needzero() {
continue
}
- if n.Class() != PAUTO {
+ if n.Class() != ir.PAUTO {
e.Fatalf(n.Pos, "needzero class %d", n.Class())
}
if n.Type.Size()%int64(Widthptr) != 0 || n.Xoffset%int64(Widthptr) != 0 || n.Type.Size() == 0 {
case *obj.LSym:
a.Name = obj.NAME_EXTERN
a.Sym = n
- case *Node:
- if n.Class() == PPARAM || n.Class() == PPARAMOUT {
+ case *ir.Node:
+ if n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT {
a.Name = obj.NAME_PARAM
a.Sym = n.Orig.Sym.Linksym()
a.Offset += n.Xoffset
// high word and branch to out-of-bounds failure if it is not 0.
var lo *ssa.Value
if idx.Type.IsSigned() {
- lo = s.newValue1(ssa.OpInt64Lo, types.Types[TINT], idx)
+ lo = s.newValue1(ssa.OpInt64Lo, types.Types[types.TINT], idx)
} else {
- lo = s.newValue1(ssa.OpInt64Lo, types.Types[TUINT], idx)
+ lo = s.newValue1(ssa.OpInt64Lo, types.Types[types.TUINT], idx)
}
if bounded || base.Flag.B != 0 {
return lo
}
bNext := s.f.NewBlock(ssa.BlockPlain)
bPanic := s.f.NewBlock(ssa.BlockExit)
- hi := s.newValue1(ssa.OpInt64Hi, types.Types[TUINT32], idx)
- cmp := s.newValue2(ssa.OpEq32, types.Types[TBOOL], hi, s.constInt32(types.Types[TUINT32], 0))
+ hi := s.newValue1(ssa.OpInt64Hi, types.Types[types.TUINT32], idx)
+ cmp := s.newValue2(ssa.OpEq32, types.Types[types.TBOOL], hi, s.constInt32(types.Types[types.TUINT32], 0))
if !idx.Type.IsSigned() {
switch kind {
case ssa.BoundsIndex:
s.Fatalf("bad unsigned index extension %s", idx.Type)
}
}
- return s.newValue1(op, types.Types[TINT], idx)
+ return s.newValue1(op, types.Types[types.TINT], idx)
}
// CheckLoweredPhi checks that regalloc and stackalloc correctly handled phi values.
// AutoVar returns a *Node and int64 representing the auto variable and offset within it
// where v should be spilled.
-func AutoVar(v *ssa.Value) (*Node, int64) {
+func AutoVar(v *ssa.Value) (*ir.Node, int64) {
loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
if v.Type.Size() > loc.Type.Size() {
v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
}
- return loc.N.(*Node), loc.Off
+ return loc.N.(*ir.Node), loc.Off
}
func AddrAuto(a *obj.Addr, v *ssa.Value) {
a.Sym = n.Sym.Linksym()
a.Reg = int16(thearch.REGSP)
a.Offset = n.Xoffset + off
- if n.Class() == PPARAM || n.Class() == PPARAMOUT {
+ if n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT {
a.Name = obj.NAME_PARAM
} else {
a.Name = obj.NAME_AUTO
}
// fieldIdx finds the index of the field referred to by the ODOT node n.
-func fieldIdx(n *Node) int {
+func fieldIdx(n *ir.Node) int {
t := n.Left.Type
f := n.Sym
if !t.IsStruct() {
// ssafn holds frontend information about a function that the backend is processing.
// It also exports a bunch of compiler services for the ssa backend.
type ssafn struct {
- curfn *Node
+ curfn *ir.Node
strings map[string]*obj.LSym // map from constant string to data symbols
- scratchFpMem *Node // temp for floating point register / memory moves on some architectures
+ scratchFpMem *ir.Node // temp for floating point register / memory moves on some architectures
stksize int64 // stack size for current frame
stkptrsize int64 // prefix of stack containing pointers
log bool // print ssa debug to the stdout
}
func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
- ptrType := types.NewPtr(types.Types[TUINT8])
- lenType := types.Types[TINT]
+ ptrType := types.NewPtr(types.Types[types.TUINT8])
+ lenType := types.Types[types.TINT]
// Split this string up into two separate variables.
p := e.SplitSlot(&name, ".ptr", 0, ptrType)
l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
}
func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
- n := name.N.(*Node)
- u := types.Types[TUINTPTR]
- t := types.NewPtr(types.Types[TUINT8])
+ n := name.N.(*ir.Node)
+ u := types.Types[types.TUINTPTR]
+ t := types.NewPtr(types.Types[types.TUINT8])
// Split this interface up into two separate variables.
f := ".itab"
if n.Type.IsEmptyInterface() {
func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
ptrType := types.NewPtr(name.Type.Elem())
- lenType := types.Types[TINT]
+ lenType := types.Types[types.TINT]
p := e.SplitSlot(&name, ".ptr", 0, ptrType)
l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
c := e.SplitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
s := name.Type.Size() / 2
var t *types.Type
if s == 8 {
- t = types.Types[TFLOAT64]
+ t = types.Types[types.TFLOAT64]
} else {
- t = types.Types[TFLOAT32]
+ t = types.Types[types.TFLOAT32]
}
r := e.SplitSlot(&name, ".real", 0, t)
i := e.SplitSlot(&name, ".imag", t.Size(), t)
func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
var t *types.Type
if name.Type.IsSigned() {
- t = types.Types[TINT32]
+ t = types.Types[types.TINT32]
} else {
- t = types.Types[TUINT32]
+ t = types.Types[types.TUINT32]
}
if thearch.LinkArch.ByteOrder == binary.BigEndian {
- return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
+ return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[types.TUINT32])
}
- return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[TUINT32])
+ return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[types.TUINT32])
}
func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
}
func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
- n := name.N.(*Node)
+ n := name.N.(*ir.Node)
at := name.Type
if at.NumElem() != 1 {
e.Fatalf(n.Pos, "bad array size")
// SplitSlot returns a slot representing the data of parent starting at offset.
func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
- node := parent.N.(*Node)
+ node := parent.N.(*ir.Node)
- if node.Class() != PAUTO || node.Name.Addrtaken() {
+ if node.Class() != ir.PAUTO || node.Name.Addrtaken() {
// addressed things and non-autos retain their parents (i.e., cannot truly be split)
return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
}
- s := &types.Sym{Name: node.Sym.Name + suffix, Pkg: localpkg}
- n := newnamel(parent.N.(*Node).Pos, s)
- s.Def = asTypesNode(n)
- asNode(s.Def).Name.SetUsed(true)
+ s := &types.Sym{Name: node.Sym.Name + suffix, Pkg: ir.LocalPkg}
+ n := ir.NewNameAt(parent.N.(*ir.Node).Pos, s)
+ s.Def = ir.AsTypesNode(n)
+ ir.AsNode(s.Def).Name.SetUsed(true)
n.Type = t
- n.SetClass(PAUTO)
+ n.SetClass(ir.PAUTO)
n.Esc = EscNever
n.Name.Curfn = e.curfn
e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
// Fatal reports a compiler error and exits.
func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...interface{}) {
base.Pos = pos
- nargs := append([]interface{}{e.curfn.funcname()}, args...)
+ nargs := append([]interface{}{ir.FuncName(e.curfn)}, args...)
base.Fatalf("'%s': "+msg, nargs...)
}
}
func (e *ssafn) SetWBPos(pos src.XPos) {
- e.curfn.Func.setWBPos(pos)
+ e.curfn.Func.SetWBPos(pos)
}
func (e *ssafn) MyImportPath() string {
return base.Ctxt.Pkgpath
}
-func (n *Node) Typ() *types.Type {
- return n.Type
-}
-func (n *Node) StorageClass() ssa.StorageClass {
- switch n.Class() {
- case PPARAM:
- return ssa.ClassParam
- case PPARAMOUT:
- return ssa.ClassParamOut
- case PAUTO:
- return ssa.ClassAuto
- default:
- base.Fatalf("untranslatable storage class for %v: %s", n, n.Class())
- return 0
- }
-}
-
-func clobberBase(n *Node) *Node {
- if n.Op == ODOT && n.Left.Type.NumFields() == 1 {
+func clobberBase(n *ir.Node) *ir.Node {
+ if n.Op == ir.ODOT && n.Left.Type.NumFields() == 1 {
return clobberBase(n.Left)
}
- if n.Op == OINDEX && n.Left.Type.IsArray() && n.Left.Type.NumElem() == 1 {
+ if n.Op == ir.OINDEX && n.Left.Type.IsArray() && n.Left.Type.NumElem() == 1 {
return clobberBase(n.Left)
}
return n
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"crypto/md5"
// It's primarily used to distinguish references to named objects,
// whose Pos will point back to their declaration position rather than
// their usage position.
-func hasUniquePos(n *Node) bool {
+func hasUniquePos(n *ir.Node) bool {
switch n.Op {
- case ONAME, OPACK:
+ case ir.ONAME, ir.OPACK:
return false
- case OLITERAL, ONIL, OTYPE:
+ case ir.OLITERAL, ir.ONIL, ir.OTYPE:
if n.Sym != nil {
return false
}
return true
}
-func setlineno(n *Node) src.XPos {
+func setlineno(n *ir.Node) src.XPos {
lno := base.Pos
if n != nil && hasUniquePos(n) {
base.Pos = n.Pos
}
func lookup(name string) *types.Sym {
- return localpkg.Lookup(name)
+ return ir.LocalPkg.Lookup(name)
}
// lookupN looks up the symbol starting with prefix and ending with
var buf [20]byte // plenty long enough for all current users
copy(buf[:], prefix)
b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
- return localpkg.LookupBytes(b)
+ return ir.LocalPkg.LookupBytes(b)
}
// autolabel generates a new Name node for use with
// find all the exported symbols in package opkg
// and make them available in the current package
-func importdot(opkg *types.Pkg, pack *Node) {
+func importdot(opkg *types.Pkg, pack *ir.Node) {
n := 0
for _, s := range opkg.Syms {
if s.Def == nil {
s1.Def = s.Def
s1.Block = s.Block
- if asNode(s1.Def).Name == nil {
- Dump("s1def", asNode(s1.Def))
+ if ir.AsNode(s1.Def).Name == nil {
+ ir.Dump("s1def", ir.AsNode(s1.Def))
base.Fatalf("missing Name")
}
- asNode(s1.Def).Name.Pack = pack
+ ir.AsNode(s1.Def).Name.Pack = pack
s1.Origpkg = opkg
n++
}
}
}
-func nod(op Op, nleft, nright *Node) *Node {
- return nodl(base.Pos, op, nleft, nright)
-}
-
-func nodl(pos src.XPos, op Op, nleft, nright *Node) *Node {
- var n *Node
- switch op {
- case ODCLFUNC:
- var x struct {
- n Node
- f Func
- }
- n = &x.n
- n.Func = &x.f
- n.Func.Decl = n
- case ONAME:
- base.Fatalf("use newname instead")
- case OLABEL, OPACK:
- var x struct {
- n Node
- m Name
- }
- n = &x.n
- n.Name = &x.m
- default:
- n = new(Node)
- }
- n.Op = op
- n.Left = nleft
- n.Right = nright
- n.Pos = pos
- n.Xoffset = BADWIDTH
- n.Orig = n
- return n
-}
-
// newname returns a new ONAME Node associated with symbol s.
-func newname(s *types.Sym) *Node {
- n := newnamel(base.Pos, s)
+func NewName(s *types.Sym) *ir.Node {
+ n := ir.NewNameAt(base.Pos, s)
n.Name.Curfn = Curfn
return n
}
-// newnamel returns a new ONAME Node associated with symbol s at position pos.
-// The caller is responsible for setting n.Name.Curfn.
-func newnamel(pos src.XPos, s *types.Sym) *Node {
- if s == nil {
- base.Fatalf("newnamel nil")
- }
-
- var x struct {
- n Node
- m Name
- p Param
- }
- n := &x.n
- n.Name = &x.m
- n.Name.Param = &x.p
-
- n.Op = ONAME
- n.Pos = pos
- n.Orig = n
-
- n.Sym = s
- return n
-}
-
// nodSym makes a Node with Op op and with the Left field set to left
// and the Sym field set to sym. This is for ODOT and friends.
-func nodSym(op Op, left *Node, sym *types.Sym) *Node {
+func nodSym(op ir.Op, left *ir.Node, sym *types.Sym) *ir.Node {
return nodlSym(base.Pos, op, left, sym)
}
// nodlSym makes a Node with position Pos, with Op op, and with the Left field set to left
// and the Sym field set to sym. This is for ODOT and friends.
-func nodlSym(pos src.XPos, op Op, left *Node, sym *types.Sym) *Node {
- n := nodl(pos, op, left, nil)
+func nodlSym(pos src.XPos, op ir.Op, left *ir.Node, sym *types.Sym) *ir.Node {
+ n := ir.NodAt(pos, op, left, nil)
n.Sym = sym
return n
}
-// rawcopy returns a shallow copy of n.
-// Note: copy or sepcopy (rather than rawcopy) is usually the
-// correct choice (see comment with Node.copy, below).
-func (n *Node) rawcopy() *Node {
- copy := *n
- return ©
-}
-
-// sepcopy returns a separate shallow copy of n, with the copy's
-// Orig pointing to itself.
-func (n *Node) sepcopy() *Node {
- copy := *n
- copy.Orig = ©
- return ©
-}
-
-// copy returns shallow copy of n and adjusts the copy's Orig if
-// necessary: In general, if n.Orig points to itself, the copy's
-// Orig should point to itself as well. Otherwise, if n is modified,
-// the copy's Orig node appears modified, too, and then doesn't
-// represent the original node anymore.
-// (This caused the wrong complit Op to be used when printing error
-// messages; see issues #26855, #27765).
-func (n *Node) copy() *Node {
- copy := *n
- if n.Orig == n {
- copy.Orig = ©
- }
- return ©
-}
-
// methcmp sorts methods by symbol.
type methcmp []*types.Field
func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x methcmp) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) }
-func nodintconst(v int64) *Node {
- return nodlit(constant.MakeInt64(v))
+func nodintconst(v int64) *ir.Node {
+ return ir.NewLiteral(constant.MakeInt64(v))
}
-func nodnil() *Node {
- n := nod(ONIL, nil, nil)
- n.Type = types.Types[TNIL]
+func nodnil() *ir.Node {
+ n := ir.Nod(ir.ONIL, nil, nil)
+ n.Type = types.Types[types.TNIL]
return n
}
-func nodbool(b bool) *Node {
- return nodlit(constant.MakeBool(b))
+func nodbool(b bool) *ir.Node {
+ return ir.NewLiteral(constant.MakeBool(b))
}
-func nodstr(s string) *Node {
- return nodlit(constant.MakeString(s))
+func nodstr(s string) *ir.Node {
+ return ir.NewLiteral(constant.MakeString(s))
}
// treecopy recursively copies n, with the exception of
// ONAME, OLITERAL, OTYPE, and ONONAME leaves.
// If pos.IsKnown(), it sets the source position of newly
// allocated nodes to pos.
-func treecopy(n *Node, pos src.XPos) *Node {
+func treecopy(n *ir.Node, pos src.XPos) *ir.Node {
if n == nil {
return nil
}
switch n.Op {
default:
- m := n.sepcopy()
+ m := ir.SepCopy(n)
m.Left = treecopy(n.Left, pos)
m.Right = treecopy(n.Right, pos)
m.List.Set(listtreecopy(n.List.Slice(), pos))
if pos.IsKnown() {
m.Pos = pos
}
- if m.Name != nil && n.Op != ODCLFIELD {
- Dump("treecopy", n)
+ if m.Name != nil && n.Op != ir.ODCLFIELD {
+ ir.Dump("treecopy", n)
base.Fatalf("treecopy Name")
}
return m
- case OPACK:
+ case ir.OPACK:
// OPACK nodes are never valid in const value declarations,
// but allow them like any other declared symbol to avoid
// crashing (golang.org/issue/11361).
fallthrough
- case ONAME, ONONAME, OLITERAL, ONIL, OTYPE:
+ case ir.ONAME, ir.ONONAME, ir.OLITERAL, ir.ONIL, ir.OTYPE:
return n
}
}
-// isNil reports whether n represents the universal untyped zero value "nil".
-func (n *Node) isNil() bool {
- // Check n.Orig because constant propagation may produce typed nil constants,
- // which don't exist in the Go spec.
- return n.Orig.Op == ONIL
-}
-
func isptrto(t *types.Type, et types.EType) bool {
if t == nil {
return false
return true
}
-func (n *Node) isBlank() bool {
- if n == nil {
- return false
- }
- return n.Sym.IsBlank()
-}
-
// methtype returns the underlying type, if any,
// that owns methods with receiver parameter t.
// The result is either a named type or an anonymous struct.
return t
}
switch t.Etype {
- case TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRING, TSTRUCT:
+ case types.TARRAY, types.TCHAN, types.TFUNC, types.TMAP, types.TSLICE, types.TSTRING, types.TSTRUCT:
return t
}
return nil
// If so, return op code to use in conversion.
// If not, return OXXX. In this case, the string return parameter may
// hold a reason why. In all other cases, it'll be the empty string.
-func assignop(src, dst *types.Type) (Op, string) {
+func assignop(src, dst *types.Type) (ir.Op, string) {
if src == dst {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
- if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil {
- return OXXX, ""
+ if src == nil || dst == nil || src.Etype == types.TFORW || dst.Etype == types.TFORW || src.Orig == nil || dst.Orig == nil {
+ return ir.OXXX, ""
}
// 1. src type is identical to dst.
if types.Identical(src, dst) {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
// 2. src and dst have identical underlying types
if src.IsEmptyInterface() {
// Conversion between two empty interfaces
// requires no code.
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() {
// Conversion between two types, at least one unnamed,
// needs no conversion. The exception is nonempty interfaces
// which need to have their itab updated.
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
}
// 3. dst is an interface type and src implements dst.
- if dst.IsInterface() && src.Etype != TNIL {
+ if dst.IsInterface() && src.Etype != types.TNIL {
var missing, have *types.Field
var ptr int
if implements(src, dst, &missing, &have, &ptr) {
- return OCONVIFACE, ""
+ return ir.OCONVIFACE, ""
}
// we'll have complained about this method anyway, suppress spurious messages.
if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
- return OCONVIFACE, ""
+ return ir.OCONVIFACE, ""
}
var why string
- if isptrto(src, TINTER) {
+ if isptrto(src, types.TINTER) {
why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
} else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
}
- return OXXX, why
+ return ir.OXXX, why
}
- if isptrto(dst, TINTER) {
+ if isptrto(dst, types.TINTER) {
why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
- return OXXX, why
+ return ir.OXXX, why
}
- if src.IsInterface() && dst.Etype != TBLANK {
+ if src.IsInterface() && dst.Etype != types.TBLANK {
var missing, have *types.Field
var ptr int
var why string
if implements(dst, src, &missing, &have, &ptr) {
why = ": need type assertion"
}
- return OXXX, why
+ return ir.OXXX, why
}
// 4. src is a bidirectional channel value, dst is a channel type,
// either src or dst is not a named type.
if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
if types.Identical(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
}
// 5. src is the predeclared identifier nil and dst is a nillable type.
- if src.Etype == TNIL {
+ if src.Etype == types.TNIL {
switch dst.Etype {
- case TPTR,
- TFUNC,
- TMAP,
- TCHAN,
- TINTER,
- TSLICE:
- return OCONVNOP, ""
+ case types.TPTR,
+ types.TFUNC,
+ types.TMAP,
+ types.TCHAN,
+ types.TINTER,
+ types.TSLICE:
+ return ir.OCONVNOP, ""
}
}
// 6. rule about untyped constants - already converted by defaultlit.
// 7. Any typed value can be assigned to the blank identifier.
- if dst.Etype == TBLANK {
- return OCONVNOP, ""
+ if dst.Etype == types.TBLANK {
+ return ir.OCONVNOP, ""
}
- return OXXX, ""
+ return ir.OXXX, ""
}
// Can we convert a value of type src to a value of type dst?
// If not, return OXXX. In this case, the string return parameter may
// hold a reason why. In all other cases, it'll be the empty string.
// srcConstant indicates whether the value of type src is a constant.
-func convertop(srcConstant bool, src, dst *types.Type) (Op, string) {
+func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
if src == dst {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
if src == nil || dst == nil {
- return OXXX, ""
+ return ir.OXXX, ""
}
// Conversions from regular to go:notinheap are not allowed
// (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
- return OXXX, why
+ return ir.OXXX, why
}
// (b) Disallow string to []T where T is go:notinheap.
if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Etype == types.Bytetype.Etype || dst.Elem().Etype == types.Runetype.Etype) {
why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
- return OXXX, why
+ return ir.OXXX, why
}
// 1. src can be assigned to dst.
op, why := assignop(src, dst)
- if op != OXXX {
+ if op != ir.OXXX {
return op, why
}
// with the good message from assignop.
// Otherwise clear the error.
if src.IsInterface() || dst.IsInterface() {
- return OXXX, why
+ return ir.OXXX, why
}
// 2. Ignoring struct tags, src and dst have identical underlying types.
if types.IdenticalIgnoreTags(src.Orig, dst.Orig) {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
// 3. src and dst are unnamed pointer types and, ignoring struct tags,
// their base types have identical underlying types.
if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil {
if types.IdenticalIgnoreTags(src.Elem().Orig, dst.Elem().Orig) {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
}
// 4. src and dst are both integer or floating point types.
if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
if simtype[src.Etype] == simtype[dst.Etype] {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
- return OCONV, ""
+ return ir.OCONV, ""
}
// 5. src and dst are both complex types.
if src.IsComplex() && dst.IsComplex() {
if simtype[src.Etype] == simtype[dst.Etype] {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
- return OCONV, ""
+ return ir.OCONV, ""
}
// Special case for constant conversions: any numeric
// conversion is potentially okay. We'll validate further
// within evconst. See #38117.
if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
- return OCONV, ""
+ return ir.OCONV, ""
}
// 6. src is an integer or has type []byte or []rune
// and dst is a string type.
if src.IsInteger() && dst.IsString() {
- return ORUNESTR, ""
+ return ir.ORUNESTR, ""
}
if src.IsSlice() && dst.IsString() {
if src.Elem().Etype == types.Bytetype.Etype {
- return OBYTES2STR, ""
+ return ir.OBYTES2STR, ""
}
if src.Elem().Etype == types.Runetype.Etype {
- return ORUNES2STR, ""
+ return ir.ORUNES2STR, ""
}
}
// String to slice.
if src.IsString() && dst.IsSlice() {
if dst.Elem().Etype == types.Bytetype.Etype {
- return OSTR2BYTES, ""
+ return ir.OSTR2BYTES, ""
}
if dst.Elem().Etype == types.Runetype.Etype {
- return OSTR2RUNES, ""
+ return ir.OSTR2RUNES, ""
}
}
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
// src is map and dst is a pointer to corresponding hmap.
// This rule is needed for the implementation detail that
// go gc maps are implemented as a pointer to a hmap struct.
- if src.Etype == TMAP && dst.IsPtr() &&
+ if src.Etype == types.TMAP && dst.IsPtr() &&
src.MapType().Hmap == dst.Elem() {
- return OCONVNOP, ""
+ return ir.OCONVNOP, ""
}
- return OXXX, ""
+ return ir.OXXX, ""
}
-func assignconv(n *Node, t *types.Type, context string) *Node {
+func assignconv(n *ir.Node, t *types.Type, context string) *ir.Node {
return assignconvfn(n, t, func() string { return context })
}
// Convert node n for assignment to type t.
-func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
+func assignconvfn(n *ir.Node, t *types.Type, context func() string) *ir.Node {
if n == nil || n.Type == nil || n.Type.Broke() {
return n
}
- if t.Etype == TBLANK && n.Type.Etype == TNIL {
+ if t.Etype == types.TBLANK && n.Type.Etype == types.TNIL {
base.Errorf("use of untyped nil")
}
if n.Type == nil {
return n
}
- if t.Etype == TBLANK {
+ if t.Etype == types.TBLANK {
return n
}
// Convert ideal bool from comparison to plain bool
// if the next step is non-bool (like interface{}).
if n.Type == types.UntypedBool && !t.IsBoolean() {
- if n.Op == ONAME || n.Op == OLITERAL {
- r := nod(OCONVNOP, n, nil)
- r.Type = types.Types[TBOOL]
+ if n.Op == ir.ONAME || n.Op == ir.OLITERAL {
+ r := ir.Nod(ir.OCONVNOP, n, nil)
+ r.Type = types.Types[types.TBOOL]
r.SetTypecheck(1)
r.SetImplicit(true)
n = r
}
op, why := assignop(n.Type, t)
- if op == OXXX {
+ if op == ir.OXXX {
base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why)
- op = OCONV
+ op = ir.OCONV
}
- r := nod(op, n, nil)
+ r := ir.Nod(op, n, nil)
r.Type = t
r.SetTypecheck(1)
r.SetImplicit(true)
return r
}
-// IsMethod reports whether n is a method.
-// n must be a function or a method.
-func (n *Node) IsMethod() bool {
- return n.Type.Recv() != nil
-}
-
-// SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max].
-// n must be a slice expression. max is nil if n is a simple slice expression.
-func (n *Node) SliceBounds() (low, high, max *Node) {
- if n.List.Len() == 0 {
- return nil, nil, nil
- }
-
- switch n.Op {
- case OSLICE, OSLICEARR, OSLICESTR:
- s := n.List.Slice()
- return s[0], s[1], nil
- case OSLICE3, OSLICE3ARR:
- s := n.List.Slice()
- return s[0], s[1], s[2]
- }
- base.Fatalf("SliceBounds op %v: %v", n.Op, n)
- return nil, nil, nil
-}
-
-// SetSliceBounds sets n's slice bounds, where n is a slice expression.
-// n must be a slice expression. If max is non-nil, n must be a full slice expression.
-func (n *Node) SetSliceBounds(low, high, max *Node) {
- switch n.Op {
- case OSLICE, OSLICEARR, OSLICESTR:
- if max != nil {
- base.Fatalf("SetSliceBounds %v given three bounds", n.Op)
- }
- s := n.List.Slice()
- if s == nil {
- if low == nil && high == nil {
- return
- }
- n.List.Set2(low, high)
- return
- }
- s[0] = low
- s[1] = high
- return
- case OSLICE3, OSLICE3ARR:
- s := n.List.Slice()
- if s == nil {
- if low == nil && high == nil && max == nil {
- return
- }
- n.List.Set3(low, high, max)
- return
- }
- s[0] = low
- s[1] = high
- s[2] = max
- return
- }
- base.Fatalf("SetSliceBounds op %v: %v", n.Op, n)
-}
-
-// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
-// o must be a slicing op.
-func (o Op) IsSlice3() bool {
- switch o {
- case OSLICE, OSLICEARR, OSLICESTR:
- return false
- case OSLICE3, OSLICE3ARR:
- return true
- }
- base.Fatalf("IsSlice3 op %v", o)
- return false
-}
-
// backingArrayPtrLen extracts the pointer and length from a slice or string.
// This constructs two nodes referring to n, so n must be a cheapexpr.
-func (n *Node) backingArrayPtrLen() (ptr, len *Node) {
- var init Nodes
+func backingArrayPtrLen(n *ir.Node) (ptr, len *ir.Node) {
+ var init ir.Nodes
c := cheapexpr(n, &init)
if c != n || init.Len() != 0 {
base.Fatalf("backingArrayPtrLen not cheap: %v", n)
}
- ptr = nod(OSPTR, n, nil)
+ ptr = ir.Nod(ir.OSPTR, n, nil)
if n.Type.IsString() {
- ptr.Type = types.Types[TUINT8].PtrTo()
+ ptr.Type = types.Types[types.TUINT8].PtrTo()
} else {
ptr.Type = n.Type.Elem().PtrTo()
}
- len = nod(OLEN, n, nil)
- len.Type = types.Types[TINT]
+ len = ir.Nod(ir.OLEN, n, nil)
+ len.Type = types.Types[types.TINT]
return ptr, len
}
// labeledControl returns the control flow Node (for, switch, select)
// associated with the label n, if any.
-func (n *Node) labeledControl() *Node {
- if n.Op != OLABEL {
+func labeledControl(n *ir.Node) *ir.Node {
+ if n.Op != ir.OLABEL {
base.Fatalf("labeledControl %v", n.Op)
}
ctl := n.Name.Defn
return nil
}
switch ctl.Op {
- case OFOR, OFORUNTIL, OSWITCH, OSELECT:
+ case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OSELECT:
return ctl
}
return nil
}
-func syslook(name string) *Node {
+func syslook(name string) *ir.Node {
s := Runtimepkg.Lookup(name)
if s == nil || s.Def == nil {
base.Fatalf("syslook: can't find runtime.%s", name)
}
- return asNode(s.Def)
+ return ir.AsNode(s.Def)
}
// typehash computes a hash value for type t to use in type switch statements.
// updateHasCall checks whether expression n contains any function
// calls and sets the n.HasCall flag if so.
-func updateHasCall(n *Node) {
+func updateHasCall(n *ir.Node) {
if n == nil {
return
}
n.SetHasCall(calcHasCall(n))
}
-func calcHasCall(n *Node) bool {
+func calcHasCall(n *ir.Node) bool {
if n.Ninit.Len() != 0 {
// TODO(mdempsky): This seems overly conservative.
return true
}
switch n.Op {
- case OLITERAL, ONIL, ONAME, OTYPE:
+ case ir.OLITERAL, ir.ONIL, ir.ONAME, ir.OTYPE:
if n.HasCall() {
base.Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n)
}
return false
- case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
+ case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
return true
- case OANDAND, OOROR:
+ case ir.OANDAND, ir.OOROR:
// hard with instrumented code
if instrumenting {
return true
}
- case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR,
- ODEREF, ODOTPTR, ODOTTYPE, ODIV, OMOD:
+ case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR,
+ ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD:
// These ops might panic, make sure they are done
// before we start marshaling args for a call. See issue 16760.
return true
// When using soft-float, these ops might be rewritten to function calls
// so we ensure they are evaluated first.
- case OADD, OSUB, ONEG, OMUL:
+ case ir.OADD, ir.OSUB, ir.ONEG, ir.OMUL:
if thearch.SoftFloat && (isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) {
return true
}
- case OLT, OEQ, ONE, OLE, OGE, OGT:
+ case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
if thearch.SoftFloat && (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype]) {
return true
}
- case OCONV:
+ case ir.OCONV:
if thearch.SoftFloat && ((isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) || (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype])) {
return true
}
return false
}
-func badtype(op Op, tl, tr *types.Type) {
+func badtype(op ir.Op, tl, tr *types.Type) {
var s string
if tl != nil {
s += fmt.Sprintf("\n\t%v", tl)
// brcom returns !(op).
// For example, brcom(==) is !=.
-func brcom(op Op) Op {
+func brcom(op ir.Op) ir.Op {
switch op {
- case OEQ:
- return ONE
- case ONE:
- return OEQ
- case OLT:
- return OGE
- case OGT:
- return OLE
- case OLE:
- return OGT
- case OGE:
- return OLT
+ case ir.OEQ:
+ return ir.ONE
+ case ir.ONE:
+ return ir.OEQ
+ case ir.OLT:
+ return ir.OGE
+ case ir.OGT:
+ return ir.OLE
+ case ir.OLE:
+ return ir.OGT
+ case ir.OGE:
+ return ir.OLT
}
base.Fatalf("brcom: no com for %v\n", op)
return op
// brrev returns reverse(op).
// For example, Brrev(<) is >.
-func brrev(op Op) Op {
+func brrev(op ir.Op) ir.Op {
switch op {
- case OEQ:
- return OEQ
- case ONE:
- return ONE
- case OLT:
- return OGT
- case OGT:
- return OLT
- case OLE:
- return OGE
- case OGE:
- return OLE
+ case ir.OEQ:
+ return ir.OEQ
+ case ir.ONE:
+ return ir.ONE
+ case ir.OLT:
+ return ir.OGT
+ case ir.OGT:
+ return ir.OLT
+ case ir.OLE:
+ return ir.OGE
+ case ir.OGE:
+ return ir.OLE
}
base.Fatalf("brrev: no rev for %v\n", op)
return op
// return side effect-free n, appending side effects to init.
// result is assignable if n is.
-func safeexpr(n *Node, init *Nodes) *Node {
+func safeexpr(n *ir.Node, init *ir.Nodes) *ir.Node {
if n == nil {
return nil
}
}
switch n.Op {
- case ONAME, OLITERAL, ONIL:
+ case ir.ONAME, ir.OLITERAL, ir.ONIL:
return n
- case ODOT, OLEN, OCAP:
+ case ir.ODOT, ir.OLEN, ir.OCAP:
l := safeexpr(n.Left, init)
if l == n.Left {
return n
}
- r := n.copy()
+ r := ir.Copy(n)
r.Left = l
r = typecheck(r, ctxExpr)
r = walkexpr(r, init)
return r
- case ODOTPTR, ODEREF:
+ case ir.ODOTPTR, ir.ODEREF:
l := safeexpr(n.Left, init)
if l == n.Left {
return n
}
- a := n.copy()
+ a := ir.Copy(n)
a.Left = l
a = walkexpr(a, init)
return a
- case OINDEX, OINDEXMAP:
+ case ir.OINDEX, ir.OINDEXMAP:
l := safeexpr(n.Left, init)
r := safeexpr(n.Right, init)
if l == n.Left && r == n.Right {
return n
}
- a := n.copy()
+ a := ir.Copy(n)
a.Left = l
a.Right = r
a = walkexpr(a, init)
return a
- case OSTRUCTLIT, OARRAYLIT, OSLICELIT:
+ case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT:
if isStaticCompositeLiteral(n) {
return n
}
return cheapexpr(n, init)
}
-func copyexpr(n *Node, t *types.Type, init *Nodes) *Node {
+func copyexpr(n *ir.Node, t *types.Type, init *ir.Nodes) *ir.Node {
l := temp(t)
- a := nod(OAS, l, n)
+ a := ir.Nod(ir.OAS, l, n)
a = typecheck(a, ctxStmt)
a = walkexpr(a, init)
init.Append(a)
// return side-effect free and cheap n, appending side effects to init.
// result may not be assignable.
-func cheapexpr(n *Node, init *Nodes) *Node {
+func cheapexpr(n *ir.Node, init *ir.Nodes) *ir.Node {
switch n.Op {
- case ONAME, OLITERAL, ONIL:
+ case ir.ONAME, ir.OLITERAL, ir.ONIL:
return n
}
// find missing fields that
// will give shortest unique addressing.
// modify the tree with missing type names.
-func adddot(n *Node) *Node {
+func adddot(n *ir.Node) *ir.Node {
n.Left = typecheck(n.Left, ctxType|ctxExpr)
if n.Left.Diag() {
n.SetDiag(true)
return n
}
- if n.Left.Op == OTYPE {
+ if n.Left.Op == ir.OTYPE {
return n
}
case path != nil:
// rebuild elided dots
for c := len(path) - 1; c >= 0; c-- {
- n.Left = nodSym(ODOT, n.Left, path[c].field.Sym)
+ n.Left = nodSym(ir.ODOT, n.Left, path[c].field.Sym)
n.Left.SetImplicit(true)
}
case ambig:
}
// Given funarg struct list, return list of ODCLFIELD Node fn args.
-func structargs(tl *types.Type, mustname bool) []*Node {
- var args []*Node
+func structargs(tl *types.Type, mustname bool) []*ir.Node {
+ var args []*ir.Node
gen := 0
for _, t := range tl.Fields().Slice() {
s := t.Sym
// Only generate (*T).M wrappers for T.M in T's own package.
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
- rcvr.Elem().Sym != nil && rcvr.Elem().Sym.Pkg != localpkg {
+ rcvr.Elem().Sym != nil && rcvr.Elem().Sym.Pkg != ir.LocalPkg {
return
}
// Only generate I.M wrappers for I in I's own package
// but keep doing it for error.Error (was issue #29304).
- if rcvr.IsInterface() && rcvr.Sym != nil && rcvr.Sym.Pkg != localpkg && rcvr != types.Errortype {
+ if rcvr.IsInterface() && rcvr.Sym != nil && rcvr.Sym.Pkg != ir.LocalPkg && rcvr != types.Errortype {
return
}
base.Pos = autogeneratedPos
- dclcontext = PEXTERN
+ dclcontext = ir.PEXTERN
- tfn := nod(OTFUNC, nil, nil)
+ tfn := ir.Nod(ir.OTFUNC, nil, nil)
tfn.Left = namedfield(".this", rcvr)
tfn.List.Set(structargs(method.Type.Params(), true))
tfn.Rlist.Set(structargs(method.Type.Results(), false))
fn := dclfunc(newnam, tfn)
fn.Func.SetDupok(true)
- nthis := asNode(tfn.Type.Recv().Nname)
+ nthis := ir.AsNode(tfn.Type.Recv().Nname)
methodrcvr := method.Type.Recv().Type
// generate nil pointer check for better error
if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
// generating wrapper from *T to T.
- n := nod(OIF, nil, nil)
- n.Left = nod(OEQ, nthis, nodnil())
- call := nod(OCALL, syslook("panicwrap"), nil)
+ n := ir.Nod(ir.OIF, nil, nil)
+ n.Left = ir.Nod(ir.OEQ, nthis, nodnil())
+ call := ir.Nod(ir.OCALL, syslook("panicwrap"), nil)
n.Nbody.Set1(call)
fn.Nbody.Append(n)
}
- dot := adddot(nodSym(OXDOT, nthis, method.Sym))
+ dot := adddot(nodSym(ir.OXDOT, nthis, method.Sym))
// generate call
// It's not possible to use a tail call when dynamic linking on ppc64le. The
dot = dot.Left // skip final .M
// TODO(mdempsky): Remove dependency on dotlist.
if !dotlist[0].field.Type.IsPtr() {
- dot = nod(OADDR, dot, nil)
+ dot = ir.Nod(ir.OADDR, dot, nil)
}
- as := nod(OAS, nthis, convnop(dot, rcvr))
+ as := ir.Nod(ir.OAS, nthis, convnop(dot, rcvr))
fn.Nbody.Append(as)
- fn.Nbody.Append(nodSym(ORETJMP, nil, methodSym(methodrcvr, method.Sym)))
+ fn.Nbody.Append(nodSym(ir.ORETJMP, nil, methodSym(methodrcvr, method.Sym)))
} else {
fn.Func.SetWrapper(true) // ignore frame for panic+recover matching
- call := nod(OCALL, dot, nil)
+ call := ir.Nod(ir.OCALL, dot, nil)
call.List.Set(paramNnames(tfn.Type))
call.SetIsDDD(tfn.Type.IsVariadic())
if method.Type.NumResults() > 0 {
- n := nod(ORETURN, nil, nil)
+ n := ir.Nod(ir.ORETURN, nil, nil)
n.List.Set1(call)
call = n
}
}
if false && base.Flag.LowerR != 0 {
- dumplist("genwrapper body", fn.Nbody)
+ ir.DumpList("genwrapper body", fn.Nbody)
}
funcbody()
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil {
inlcalls(fn)
}
- escapeFuncs([]*Node{fn}, false)
+ escapeFuncs([]*ir.Node{fn}, false)
Curfn = nil
xtop = append(xtop, fn)
}
-func paramNnames(ft *types.Type) []*Node {
- args := make([]*Node, ft.NumParams())
+func paramNnames(ft *types.Type) []*ir.Node {
+ args := make([]*ir.Node, ft.NumParams())
for i, f := range ft.Params().FieldSlice() {
- args[i] = asNode(f.Nname)
+ args[i] = ir.AsNode(f.Nname)
}
return args
}
-func hashmem(t *types.Type) *Node {
+func hashmem(t *types.Type) *ir.Node {
sym := Runtimepkg.Lookup("memhash")
- n := newname(sym)
+ n := NewName(sym)
setNodeNameFunc(n)
- n.Type = functype(nil, []*Node{
+ n.Type = functype(nil, []*ir.Node{
anonfield(types.NewPtr(t)),
- anonfield(types.Types[TUINTPTR]),
- anonfield(types.Types[TUINTPTR]),
- }, []*Node{
- anonfield(types.Types[TUINTPTR]),
+ anonfield(types.Types[types.TUINTPTR]),
+ anonfield(types.Types[types.TUINTPTR]),
+ }, []*ir.Node{
+ anonfield(types.Types[types.TUINTPTR]),
})
return n
}
return true
}
-func listtreecopy(l []*Node, pos src.XPos) []*Node {
- var out []*Node
+func listtreecopy(l []*ir.Node, pos src.XPos) []*ir.Node {
+ var out []*ir.Node
for _, n := range l {
out = append(out, treecopy(n, pos))
}
return out
}
-func liststmt(l []*Node) *Node {
- n := nod(OBLOCK, nil, nil)
+func liststmt(l []*ir.Node) *ir.Node {
+ n := ir.Nod(ir.OBLOCK, nil, nil)
n.List.Set(l)
if len(l) != 0 {
n.Pos = l[0].Pos
return n
}
-func ngotype(n *Node) *types.Sym {
+func ngotype(n *ir.Node) *types.Sym {
if n.Type != nil {
return typenamesym(n.Type)
}
// The result of addinit MUST be assigned back to n, e.g.
// n.Left = addinit(n.Left, init)
-func addinit(n *Node, init []*Node) *Node {
+func addinit(n *ir.Node, init []*ir.Node) *ir.Node {
if len(init) == 0 {
return n
}
- if n.mayBeShared() {
+ if ir.MayBeShared(n) {
// Introduce OCONVNOP to hold init list.
- n = nod(OCONVNOP, n, nil)
+ n = ir.Nod(ir.OCONVNOP, n, nil)
n.Type = n.Left.Type
n.SetTypecheck(1)
}
}
switch t.Etype {
- case TPTR:
+ case types.TPTR:
// Pointers to notinheap types must be stored indirectly. See issue 42076.
return !t.Elem().NotInHeap()
- case TCHAN,
- TMAP,
- TFUNC,
- TUNSAFEPTR:
+ case types.TCHAN,
+ types.TMAP,
+ types.TFUNC,
+ types.TUNSAFEPTR:
return true
- case TARRAY:
+ case types.TARRAY:
// Array of 1 direct iface type can be direct.
return t.NumElem() == 1 && isdirectiface(t.Elem())
- case TSTRUCT:
+ case types.TSTRUCT:
// Struct with 1 field of direct iface type can be direct.
return t.NumFields() == 1 && isdirectiface(t.Field(0).Type)
}
}
// itabType loads the _type field from a runtime.itab struct.
-func itabType(itab *Node) *Node {
- typ := nodSym(ODOTPTR, itab, nil)
- typ.Type = types.NewPtr(types.Types[TUINT8])
+func itabType(itab *ir.Node) *ir.Node {
+ typ := nodSym(ir.ODOTPTR, itab, nil)
+ typ.Type = types.NewPtr(types.Types[types.TUINT8])
typ.SetTypecheck(1)
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
typ.SetBounded(true) // guaranteed not to fault
// ifaceData loads the data field from an interface.
// The concrete type must be known to have type t.
// It follows the pointer if !isdirectiface(t).
-func ifaceData(pos src.XPos, n *Node, t *types.Type) *Node {
+func ifaceData(pos src.XPos, n *ir.Node, t *types.Type) *ir.Node {
if t.IsInterface() {
base.Fatalf("ifaceData interface: %v", t)
}
- ptr := nodlSym(pos, OIDATA, n, nil)
+ ptr := nodlSym(pos, ir.OIDATA, n, nil)
if isdirectiface(t) {
ptr.Type = t
ptr.SetTypecheck(1)
}
ptr.Type = types.NewPtr(t)
ptr.SetTypecheck(1)
- ind := nodl(pos, ODEREF, ptr, nil)
+ ind := ir.NodAt(pos, ir.ODEREF, ptr, nil)
ind.Type = t
ind.SetTypecheck(1)
ind.SetBounded(true)
// typePos returns the position associated with t.
// This is where t was declared or where it appeared as a type expression.
func typePos(t *types.Type) src.XPos {
- n := asNode(t.Nod)
+ n := ir.AsNode(t.Nod)
if n == nil || !n.Pos.IsKnown() {
base.Fatalf("bad type: %v", t)
}
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"go/constant"
)
// typecheckswitch typechecks a switch statement.
-func typecheckswitch(n *Node) {
+func typecheckswitch(n *ir.Node) {
typecheckslice(n.Ninit.Slice(), ctxStmt)
- if n.Left != nil && n.Left.Op == OTYPESW {
+ if n.Left != nil && n.Left.Op == ir.OTYPESW {
typecheckTypeSwitch(n)
} else {
typecheckExprSwitch(n)
}
}
-func typecheckTypeSwitch(n *Node) {
+func typecheckTypeSwitch(n *ir.Node) {
n.Left.Right = typecheck(n.Left.Right, ctxExpr)
t := n.Left.Right.Type
if t != nil && !t.IsInterface() {
// We don't actually declare the type switch's guarded
// declaration itself. So if there are no cases, we won't
// notice that it went unused.
- if v := n.Left.Left; v != nil && !v.isBlank() && n.List.Len() == 0 {
+ if v := n.Left.Left; v != nil && !ir.IsBlank(v) && n.List.Len() == 0 {
base.ErrorfAt(v.Pos, "%v declared but not used", v.Sym)
}
- var defCase, nilCase *Node
+ var defCase, nilCase *ir.Node
var ts typeSet
for _, ncase := range n.List.Slice() {
ls := ncase.List.Slice()
if len(ls) == 0 { // default:
if defCase != nil {
- base.ErrorfAt(ncase.Pos, "multiple defaults in switch (first at %v)", defCase.Line())
+ base.ErrorfAt(ncase.Pos, "multiple defaults in switch (first at %v)", ir.Line(defCase))
} else {
defCase = ncase
}
var missing, have *types.Field
var ptr int
switch {
- case n1.isNil(): // case nil:
+ case ir.IsNil(n1): // case nil:
if nilCase != nil {
- base.ErrorfAt(ncase.Pos, "multiple nil cases in type switch (first at %v)", nilCase.Line())
+ base.ErrorfAt(ncase.Pos, "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
} else {
nilCase = ncase
}
- case n1.Op != OTYPE:
+ case n1.Op != ir.OTYPE:
base.ErrorfAt(ncase.Pos, "%L is not a type", n1)
case !n1.Type.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr) && !missing.Broke():
if have != nil && !have.Broke() {
}
}
- if n1.Op == OTYPE {
+ if n1.Op == ir.OTYPE {
ts.add(ncase.Pos, n1.Type)
}
}
// Assign the clause variable's type.
vt := t
if len(ls) == 1 {
- if ls[0].Op == OTYPE {
+ if ls[0].Op == ir.OTYPE {
vt = ls[0].Type
- } else if !ls[0].isNil() {
+ } else if !ir.IsNil(ls[0]) {
// Invalid single-type case;
// mark variable as broken.
vt = nil
s.m[ls] = append(prevs, typeSetEntry{pos, typ})
}
-func typecheckExprSwitch(n *Node) {
- t := types.Types[TBOOL]
+func typecheckExprSwitch(n *ir.Node) {
+ t := types.Types[types.TBOOL]
if n.Left != nil {
n.Left = typecheck(n.Left, ctxExpr)
n.Left = defaultlit(n.Left, nil)
switch {
case t.IsMap():
nilonly = "map"
- case t.Etype == TFUNC:
+ case t.Etype == types.TFUNC:
nilonly = "func"
case t.IsSlice():
nilonly = "slice"
}
}
- var defCase *Node
+ var defCase *ir.Node
var cs constSet
for _, ncase := range n.List.Slice() {
ls := ncase.List.Slice()
if len(ls) == 0 { // default:
if defCase != nil {
- base.ErrorfAt(ncase.Pos, "multiple defaults in switch (first at %v)", defCase.Line())
+ base.ErrorfAt(ncase.Pos, "multiple defaults in switch (first at %v)", ir.Line(defCase))
} else {
defCase = ncase
}
continue
}
- if nilonly != "" && !n1.isNil() {
+ if nilonly != "" && !ir.IsNil(n1) {
base.ErrorfAt(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
} else if t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type) {
base.ErrorfAt(ncase.Pos, "invalid case %L in switch (incomparable type)", n1)
} else {
op1, _ := assignop(n1.Type, t)
op2, _ := assignop(t, n1.Type)
- if op1 == OXXX && op2 == OXXX {
+ if op1 == ir.OXXX && op2 == ir.OXXX {
if n.Left != nil {
base.ErrorfAt(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
} else {
}
// walkswitch walks a switch statement.
-func walkswitch(sw *Node) {
+func walkswitch(sw *ir.Node) {
// Guard against double walk, see #25776.
if sw.List.Len() == 0 && sw.Nbody.Len() > 0 {
return // Was fatal, but eliminating every possible source of double-walking is hard
}
- if sw.Left != nil && sw.Left.Op == OTYPESW {
+ if sw.Left != nil && sw.Left.Op == ir.OTYPESW {
walkTypeSwitch(sw)
} else {
walkExprSwitch(sw)
// walkExprSwitch generates an AST implementing sw. sw is an
// expression switch.
-func walkExprSwitch(sw *Node) {
+func walkExprSwitch(sw *ir.Node) {
lno := setlineno(sw)
cond := sw.Left
// because walkexpr will lower the string
// conversion into a runtime call.
// See issue 24937 for more discussion.
- if cond.Op == OBYTES2STR && allCaseExprsAreSideEffectFree(sw) {
- cond.Op = OBYTES2STRTMP
+ if cond.Op == ir.OBYTES2STR && allCaseExprsAreSideEffectFree(sw) {
+ cond.Op = ir.OBYTES2STRTMP
}
cond = walkexpr(cond, &sw.Ninit)
- if cond.Op != OLITERAL && cond.Op != ONIL {
+ if cond.Op != ir.OLITERAL && cond.Op != ir.ONIL {
cond = copyexpr(cond, cond.Type, &sw.Nbody)
}
exprname: cond,
}
- var defaultGoto *Node
- var body Nodes
+ var defaultGoto *ir.Node
+ var body ir.Nodes
for _, ncase := range sw.List.Slice() {
label := autolabel(".s")
- jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label))
+ jmp := npos(ncase.Pos, nodSym(ir.OGOTO, nil, label))
// Process case dispatch.
if ncase.List.Len() == 0 {
}
// Process body.
- body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label)))
+ body.Append(npos(ncase.Pos, nodSym(ir.OLABEL, nil, label)))
body.Append(ncase.Nbody.Slice()...)
if fall, pos := hasFall(ncase.Nbody.Slice()); !fall {
- br := nod(OBREAK, nil, nil)
+ br := ir.Nod(ir.OBREAK, nil, nil)
br.Pos = pos
body.Append(br)
}
sw.List.Set(nil)
if defaultGoto == nil {
- br := nod(OBREAK, nil, nil)
+ br := ir.Nod(ir.OBREAK, nil, nil)
br.Pos = br.Pos.WithNotStmt()
defaultGoto = br
}
// An exprSwitch walks an expression switch.
type exprSwitch struct {
- exprname *Node // value being switched on
+ exprname *ir.Node // value being switched on
- done Nodes
+ done ir.Nodes
clauses []exprClause
}
type exprClause struct {
pos src.XPos
- lo, hi *Node
- jmp *Node
+ lo, hi *ir.Node
+ jmp *ir.Node
}
-func (s *exprSwitch) Add(pos src.XPos, expr, jmp *Node) {
+func (s *exprSwitch) Add(pos src.XPos, expr, jmp *ir.Node) {
c := exprClause{pos: pos, lo: expr, hi: expr, jmp: jmp}
- if okforcmp[s.exprname.Type.Etype] && expr.Op == OLITERAL {
+ if okforcmp[s.exprname.Type.Etype] && expr.Op == ir.OLITERAL {
s.clauses = append(s.clauses, c)
return
}
s.flush()
}
-func (s *exprSwitch) Emit(out *Nodes) {
+func (s *exprSwitch) Emit(out *ir.Nodes) {
s.flush()
out.AppendNodes(&s.done)
}
// Perform two-level binary search.
binarySearch(len(runs), &s.done,
- func(i int) *Node {
- return nod(OLE, nod(OLEN, s.exprname, nil), nodintconst(runLen(runs[i-1])))
+ func(i int) *ir.Node {
+ return ir.Nod(ir.OLE, ir.Nod(ir.OLEN, s.exprname, nil), nodintconst(runLen(runs[i-1])))
},
- func(i int, nif *Node) {
+ func(i int, nif *ir.Node) {
run := runs[i]
- nif.Left = nod(OEQ, nod(OLEN, s.exprname, nil), nodintconst(runLen(run)))
+ nif.Left = ir.Nod(ir.OEQ, ir.Nod(ir.OLEN, s.exprname, nil), nodintconst(runLen(run)))
s.search(run, &nif.Nbody)
},
)
s.search(cc, &s.done)
}
-func (s *exprSwitch) search(cc []exprClause, out *Nodes) {
+func (s *exprSwitch) search(cc []exprClause, out *ir.Nodes) {
binarySearch(len(cc), out,
- func(i int) *Node {
- return nod(OLE, s.exprname, cc[i-1].hi)
+ func(i int) *ir.Node {
+ return ir.Nod(ir.OLE, s.exprname, cc[i-1].hi)
},
- func(i int, nif *Node) {
+ func(i int, nif *ir.Node) {
c := &cc[i]
nif.Left = c.test(s.exprname)
nif.Nbody.Set1(c.jmp)
)
}
-func (c *exprClause) test(exprname *Node) *Node {
+func (c *exprClause) test(exprname *ir.Node) *ir.Node {
// Integer range.
if c.hi != c.lo {
- low := nodl(c.pos, OGE, exprname, c.lo)
- high := nodl(c.pos, OLE, exprname, c.hi)
- return nodl(c.pos, OANDAND, low, high)
+ low := ir.NodAt(c.pos, ir.OGE, exprname, c.lo)
+ high := ir.NodAt(c.pos, ir.OLE, exprname, c.hi)
+ return ir.NodAt(c.pos, ir.OANDAND, low, high)
}
// Optimize "switch true { ...}" and "switch false { ... }".
- if Isconst(exprname, constant.Bool) && !c.lo.Type.IsInterface() {
+ if ir.IsConst(exprname, constant.Bool) && !c.lo.Type.IsInterface() {
if exprname.BoolVal() {
return c.lo
} else {
- return nodl(c.pos, ONOT, c.lo, nil)
+ return ir.NodAt(c.pos, ir.ONOT, c.lo, nil)
}
}
- return nodl(c.pos, OEQ, exprname, c.lo)
+ return ir.NodAt(c.pos, ir.OEQ, exprname, c.lo)
}
-func allCaseExprsAreSideEffectFree(sw *Node) bool {
+func allCaseExprsAreSideEffectFree(sw *ir.Node) bool {
// In theory, we could be more aggressive, allowing any
// side-effect-free expressions in cases, but it's a bit
// tricky because some of that information is unavailable due
// enough.
for _, ncase := range sw.List.Slice() {
- if ncase.Op != OCASE {
+ if ncase.Op != ir.OCASE {
base.Fatalf("switch string(byteslice) bad op: %v", ncase.Op)
}
for _, v := range ncase.List.Slice() {
- if v.Op != OLITERAL {
+ if v.Op != ir.OLITERAL {
return false
}
}
}
// hasFall reports whether stmts ends with a "fallthrough" statement.
-func hasFall(stmts []*Node) (bool, src.XPos) {
+func hasFall(stmts []*ir.Node) (bool, src.XPos) {
// Search backwards for the index of the fallthrough
// statement. Do not assume it'll be in the last
// position, since in some cases (e.g. when the statement
// nodes will be at the end of the list.
i := len(stmts) - 1
- for i >= 0 && stmts[i].Op == OVARKILL {
+ for i >= 0 && stmts[i].Op == ir.OVARKILL {
i--
}
if i < 0 {
return false, src.NoXPos
}
- return stmts[i].Op == OFALL, stmts[i].Pos
+ return stmts[i].Op == ir.OFALL, stmts[i].Pos
}
// walkTypeSwitch generates an AST that implements sw, where sw is a
// type switch.
-func walkTypeSwitch(sw *Node) {
+func walkTypeSwitch(sw *ir.Node) {
var s typeSwitch
s.facename = sw.Left.Right
sw.Left = nil
s.facename = walkexpr(s.facename, &sw.Ninit)
s.facename = copyexpr(s.facename, s.facename.Type, &sw.Nbody)
- s.okname = temp(types.Types[TBOOL])
+ s.okname = temp(types.Types[types.TBOOL])
// Get interface descriptor word.
// For empty interfaces this will be the type.
// For non-empty interfaces this will be the itab.
- itab := nod(OITAB, s.facename, nil)
+ itab := ir.Nod(ir.OITAB, s.facename, nil)
// For empty interfaces, do:
// if e._type == nil {
// }
// h := e._type.hash
// Use a similar strategy for non-empty interfaces.
- ifNil := nod(OIF, nil, nil)
- ifNil.Left = nod(OEQ, itab, nodnil())
+ ifNil := ir.Nod(ir.OIF, nil, nil)
+ ifNil.Left = ir.Nod(ir.OEQ, itab, nodnil())
base.Pos = base.Pos.WithNotStmt() // disable statement marks after the first check.
ifNil.Left = typecheck(ifNil.Left, ctxExpr)
ifNil.Left = defaultlit(ifNil.Left, nil)
sw.Nbody.Append(ifNil)
// Load hash from type or itab.
- dotHash := nodSym(ODOTPTR, itab, nil)
- dotHash.Type = types.Types[TUINT32]
+ dotHash := nodSym(ir.ODOTPTR, itab, nil)
+ dotHash.Type = types.Types[types.TUINT32]
dotHash.SetTypecheck(1)
if s.facename.Type.IsEmptyInterface() {
dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
dotHash.SetBounded(true) // guaranteed not to fault
s.hashname = copyexpr(dotHash, dotHash.Type, &sw.Nbody)
- br := nod(OBREAK, nil, nil)
- var defaultGoto, nilGoto *Node
- var body Nodes
+ br := ir.Nod(ir.OBREAK, nil, nil)
+ var defaultGoto, nilGoto *ir.Node
+ var body ir.Nodes
for _, ncase := range sw.List.Slice() {
- var caseVar *Node
+ var caseVar *ir.Node
if ncase.Rlist.Len() != 0 {
caseVar = ncase.Rlist.First()
}
// we initialize the case variable as part of the type assertion.
// In other cases, we initialize it in the body.
var singleType *types.Type
- if ncase.List.Len() == 1 && ncase.List.First().Op == OTYPE {
+ if ncase.List.Len() == 1 && ncase.List.First().Op == ir.OTYPE {
singleType = ncase.List.First().Type
}
caseVarInitialized := false
label := autolabel(".s")
- jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label))
+ jmp := npos(ncase.Pos, nodSym(ir.OGOTO, nil, label))
if ncase.List.Len() == 0 { // default:
if defaultGoto != nil {
}
for _, n1 := range ncase.List.Slice() {
- if n1.isNil() { // case nil:
+ if ir.IsNil(n1) { // case nil:
if nilGoto != nil {
base.Fatalf("duplicate nil case not detected during typechecking")
}
}
}
- body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label)))
+ body.Append(npos(ncase.Pos, nodSym(ir.OLABEL, nil, label)))
if caseVar != nil && !caseVarInitialized {
val := s.facename
if singleType != nil {
}
val = ifaceData(ncase.Pos, s.facename, singleType)
}
- l := []*Node{
- nodl(ncase.Pos, ODCL, caseVar, nil),
- nodl(ncase.Pos, OAS, caseVar, val),
+ l := []*ir.Node{
+ ir.NodAt(ncase.Pos, ir.ODCL, caseVar, nil),
+ ir.NodAt(ncase.Pos, ir.OAS, caseVar, val),
}
typecheckslice(l, ctxStmt)
body.Append(l...)
// A typeSwitch walks a type switch.
type typeSwitch struct {
// Temporary variables (i.e., ONAMEs) used by type switch dispatch logic:
- facename *Node // value being type-switched on
- hashname *Node // type hash of the value being type-switched on
- okname *Node // boolean used for comma-ok type assertions
+ facename *ir.Node // value being type-switched on
+ hashname *ir.Node // type hash of the value being type-switched on
+ okname *ir.Node // boolean used for comma-ok type assertions
- done Nodes
+ done ir.Nodes
clauses []typeClause
}
type typeClause struct {
hash uint32
- body Nodes
+ body ir.Nodes
}
-func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *Node) {
- var body Nodes
+func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *ir.Node) {
+ var body ir.Nodes
if caseVar != nil {
- l := []*Node{
- nodl(pos, ODCL, caseVar, nil),
- nodl(pos, OAS, caseVar, nil),
+ l := []*ir.Node{
+ ir.NodAt(pos, ir.ODCL, caseVar, nil),
+ ir.NodAt(pos, ir.OAS, caseVar, nil),
}
typecheckslice(l, ctxStmt)
body.Append(l...)
} else {
- caseVar = nblank
+ caseVar = ir.BlankNode
}
// cv, ok = iface.(type)
- as := nodl(pos, OAS2, nil, nil)
+ as := ir.NodAt(pos, ir.OAS2, nil, nil)
as.List.Set2(caseVar, s.okname) // cv, ok =
- dot := nodl(pos, ODOTTYPE, s.facename, nil)
+ dot := ir.NodAt(pos, ir.ODOTTYPE, s.facename, nil)
dot.Type = typ // iface.(type)
as.Rlist.Set1(dot)
as = typecheck(as, ctxStmt)
body.Append(as)
// if ok { goto label }
- nif := nodl(pos, OIF, nil, nil)
+ nif := ir.NodAt(pos, ir.OIF, nil, nil)
nif.Left = s.okname
nif.Nbody.Set1(jmp)
body.Append(nif)
s.done.AppendNodes(&body)
}
-func (s *typeSwitch) Emit(out *Nodes) {
+func (s *typeSwitch) Emit(out *ir.Nodes) {
s.flush()
out.AppendNodes(&s.done)
}
cc = merged
binarySearch(len(cc), &s.done,
- func(i int) *Node {
- return nod(OLE, s.hashname, nodintconst(int64(cc[i-1].hash)))
+ func(i int) *ir.Node {
+ return ir.Nod(ir.OLE, s.hashname, nodintconst(int64(cc[i-1].hash)))
},
- func(i int, nif *Node) {
+ func(i int, nif *ir.Node) {
// TODO(mdempsky): Omit hash equality check if
// there's only one type.
c := cc[i]
- nif.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash)))
+ nif.Left = ir.Nod(ir.OEQ, s.hashname, nodintconst(int64(c.hash)))
nif.Nbody.AppendNodes(&c.body)
},
)
//
// leaf(i, nif) should setup nif (an OIF node) to test case i. In
// particular, it should set nif.Left and nif.Nbody.
-func binarySearch(n int, out *Nodes, less func(i int) *Node, leaf func(i int, nif *Node)) {
+func binarySearch(n int, out *ir.Nodes, less func(i int) *ir.Node, leaf func(i int, nif *ir.Node)) {
const binarySearchMin = 4 // minimum number of cases for binary search
- var do func(lo, hi int, out *Nodes)
- do = func(lo, hi int, out *Nodes) {
+ var do func(lo, hi int, out *ir.Nodes)
+ do = func(lo, hi int, out *ir.Nodes) {
n := hi - lo
if n < binarySearchMin {
for i := lo; i < hi; i++ {
- nif := nod(OIF, nil, nil)
+ nif := ir.Nod(ir.OIF, nil, nil)
leaf(i, nif)
base.Pos = base.Pos.WithNotStmt()
nif.Left = typecheck(nif.Left, ctxExpr)
}
half := lo + n/2
- nif := nod(OIF, nil, nil)
+ nif := ir.Nod(ir.OIF, nil, nil)
nif.Left = less(half)
base.Pos = base.Pos.WithNotStmt()
nif.Left = typecheck(nif.Left, ctxExpr)
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"fmt"
"go/constant"
var traceIndent []byte
var skipDowidthForTracing bool
-func tracePrint(title string, n *Node) func(np **Node) {
+func tracePrint(title string, n *ir.Node) func(np **ir.Node) {
indent := traceIndent
// guard against nil
fmt.Printf("%s: %s%s %p %s %v tc=%d\n", pos, indent, title, n, op, n, tc)
traceIndent = append(traceIndent, ". "...)
- return func(np **Node) {
+ return func(np **ir.Node) {
traceIndent = traceIndent[:len(traceIndent)-2]
// if we have a result, use that
// marks variables that escape the local frame.
// rewrites n.Op to be more specific in some cases.
-var typecheckdefstack []*Node
+var typecheckdefstack []*ir.Node
// resolve ONONAME to definition, if any.
-func resolve(n *Node) (res *Node) {
- if n == nil || n.Op != ONONAME {
+func resolve(n *ir.Node) (res *ir.Node) {
+ if n == nil || n.Op != ir.ONONAME {
return n
}
defer tracePrint("resolve", n)(&res)
}
- if n.Sym.Pkg != localpkg {
+ if n.Sym.Pkg != ir.LocalPkg {
if inimport {
base.Fatalf("recursive inimport")
}
return n
}
- r := asNode(n.Sym.Def)
+ r := ir.AsNode(n.Sym.Def)
if r == nil {
return n
}
- if r.Op == OIOTA {
+ if r.Op == ir.OIOTA {
if x := getIotaValue(); x >= 0 {
return nodintconst(x)
}
return r
}
-func typecheckslice(l []*Node, top int) {
+func typecheckslice(l []*ir.Node, top int) {
for i := range l {
l[i] = typecheck(l[i], top)
}
}
var _typekind = []string{
- TINT: "int",
- TUINT: "uint",
- TINT8: "int8",
- TUINT8: "uint8",
- TINT16: "int16",
- TUINT16: "uint16",
- TINT32: "int32",
- TUINT32: "uint32",
- TINT64: "int64",
- TUINT64: "uint64",
- TUINTPTR: "uintptr",
- TCOMPLEX64: "complex64",
- TCOMPLEX128: "complex128",
- TFLOAT32: "float32",
- TFLOAT64: "float64",
- TBOOL: "bool",
- TSTRING: "string",
- TPTR: "pointer",
- TUNSAFEPTR: "unsafe.Pointer",
- TSTRUCT: "struct",
- TINTER: "interface",
- TCHAN: "chan",
- TMAP: "map",
- TARRAY: "array",
- TSLICE: "slice",
- TFUNC: "func",
- TNIL: "nil",
- TIDEAL: "untyped number",
+ types.TINT: "int",
+ types.TUINT: "uint",
+ types.TINT8: "int8",
+ types.TUINT8: "uint8",
+ types.TINT16: "int16",
+ types.TUINT16: "uint16",
+ types.TINT32: "int32",
+ types.TUINT32: "uint32",
+ types.TINT64: "int64",
+ types.TUINT64: "uint64",
+ types.TUINTPTR: "uintptr",
+ types.TCOMPLEX64: "complex64",
+ types.TCOMPLEX128: "complex128",
+ types.TFLOAT32: "float32",
+ types.TFLOAT64: "float64",
+ types.TBOOL: "bool",
+ types.TSTRING: "string",
+ types.TPTR: "pointer",
+ types.TUNSAFEPTR: "unsafe.Pointer",
+ types.TSTRUCT: "struct",
+ types.TINTER: "interface",
+ types.TCHAN: "chan",
+ types.TMAP: "map",
+ types.TARRAY: "array",
+ types.TSLICE: "slice",
+ types.TFUNC: "func",
+ types.TNIL: "nil",
+ types.TIDEAL: "untyped number",
}
func typekind(t *types.Type) string {
return fmt.Sprintf("etype=%d", et)
}
-func cycleFor(start *Node) []*Node {
+func cycleFor(start *ir.Node) []*ir.Node {
// Find the start node in typecheck_tcstack.
// We know that it must exist because each time we mark
// a node with n.SetTypecheck(2) we push it on the stack,
}
// collect all nodes with same Op
- var cycle []*Node
+ var cycle []*ir.Node
for _, n := range typecheck_tcstack[i:] {
if n.Op == start.Op {
cycle = append(cycle, n)
return cycle
}
-func cycleTrace(cycle []*Node) string {
+func cycleTrace(cycle []*ir.Node) string {
var s string
for i, n := range cycle {
- s += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cycle[(i+1)%len(cycle)])
+ s += fmt.Sprintf("\n\t%v: %v uses %v", ir.Line(n), n, cycle[(i+1)%len(cycle)])
}
return s
}
-var typecheck_tcstack []*Node
+var typecheck_tcstack []*ir.Node
// typecheck type checks node n.
// The result of typecheck MUST be assigned back to n, e.g.
// n.Left = typecheck(n.Left, top)
-func typecheck(n *Node, top int) (res *Node) {
+func typecheck(n *ir.Node, top int) (res *ir.Node) {
// cannot type check until all the source has been parsed
if !typecheckok {
base.Fatalf("early typecheck")
lno := setlineno(n)
// Skip over parens.
- for n.Op == OPAREN {
+ for n.Op == ir.OPAREN {
n = n.Left
}
// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
if n.Typecheck() == 1 {
switch n.Op {
- case ONAME, OTYPE, OLITERAL, OPACK:
+ case ir.ONAME, ir.OTYPE, ir.OLITERAL, ir.OPACK:
break
default:
// otherwise a stack trace of typechecking.
switch n.Op {
// We can already diagnose variables used as types.
- case ONAME:
+ case ir.ONAME:
if top&(ctxExpr|ctxType) == ctxType {
base.Errorf("%v is not a type", n)
}
- case OTYPE:
+ case ir.OTYPE:
// Only report a type cycle if we are expecting a type.
// Otherwise let other code report an error.
if top&ctxType == ctxType {
base.ErrorfAt(n.Pos, "invalid recursive type alias %v%s", n, cycleTrace(cycle))
}
- case OLITERAL:
+ case ir.OLITERAL:
if top&(ctxExpr|ctxType) == ctxType {
base.Errorf("%v is not a type", n)
break
var trace string
for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
x := typecheck_tcstack[i]
- trace += fmt.Sprintf("\n\t%v %v", x.Line(), x)
+ trace += fmt.Sprintf("\n\t%v %v", ir.Line(x), x)
}
base.Errorf("typechecking loop involving %v%s", n, trace)
}
// value of type int (see also checkmake for comparison).
// The result of indexlit MUST be assigned back to n, e.g.
// n.Left = indexlit(n.Left)
-func indexlit(n *Node) *Node {
- if n != nil && n.Type != nil && n.Type.Etype == TIDEAL {
- return defaultlit(n, types.Types[TINT])
+func indexlit(n *ir.Node) *ir.Node {
+ if n != nil && n.Type != nil && n.Type.Etype == types.TIDEAL {
+ return defaultlit(n, types.Types[types.TINT])
}
return n
}
// The result of typecheck1 MUST be assigned back to n, e.g.
// n.Left = typecheck1(n.Left, top)
-func typecheck1(n *Node, top int) (res *Node) {
+func typecheck1(n *ir.Node, top int) (res *ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheck1", n)(&res)
}
switch n.Op {
- case OLITERAL, ONAME, ONONAME, OTYPE:
+ case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE:
if n.Sym == nil {
break
}
- if n.Op == ONAME && n.SubOp() != 0 && top&ctxCallee == 0 {
+ if n.Op == ir.ONAME && n.SubOp() != 0 && top&ctxCallee == 0 {
base.Errorf("use of builtin %v not in function call", n.Sym)
n.Type = nil
return n
}
typecheckdef(n)
- if n.Op == ONONAME {
+ if n.Op == ir.ONONAME {
n.Type = nil
return n
}
switch n.Op {
// until typecheck is complete, do nothing.
default:
- Dump("typecheck", n)
+ ir.Dump("typecheck", n)
base.Fatalf("typecheck %v", n.Op)
// names
- case OLITERAL:
+ case ir.OLITERAL:
ok |= ctxExpr
if n.Type == nil && n.Val().Kind() == constant.String {
base.Fatalf("string literal missing type")
}
- case ONIL, ONONAME:
+ case ir.ONIL, ir.ONONAME:
ok |= ctxExpr
- case ONAME:
+ case ir.ONAME:
if n.Name.Decldepth == 0 {
n.Name.Decldepth = decldepth
}
if top&ctxAssign == 0 {
// not a write to the variable
- if n.isBlank() {
+ if ir.IsBlank(n) {
base.Errorf("cannot use _ as value")
n.Type = nil
return n
ok |= ctxExpr
- case OPACK:
+ case ir.OPACK:
base.Errorf("use of package %v without selector", n.Sym)
n.Type = nil
return n
- case ODDD:
+ case ir.ODDD:
break
// types (ODEREF is with exprs)
- case OTYPE:
+ case ir.OTYPE:
ok |= ctxType
if n.Type == nil {
return n
}
- case OTARRAY:
+ case ir.OTARRAY:
ok |= ctxType
r := typecheck(n.Right, ctxType)
if r.Type == nil {
var t *types.Type
if n.Left == nil {
t = types.NewSlice(r.Type)
- } else if n.Left.Op == ODDD {
+ } else if n.Left.Op == ir.ODDD {
if !n.Diag() {
n.SetDiag(true)
base.Errorf("use of [...] array outside of array literal")
} else {
n.Left = indexlit(typecheck(n.Left, ctxExpr))
l := n.Left
- if consttype(l) != constant.Int {
+ if ir.ConstType(l) != constant.Int {
switch {
case l.Type == nil:
// Error already reported elsewhere.
- case l.Type.IsInteger() && l.Op != OLITERAL:
+ case l.Type.IsInteger() && l.Op != ir.OLITERAL:
base.Errorf("non-constant array bound %v", l)
default:
base.Errorf("invalid array bound %v", l)
}
v := l.Val()
- if doesoverflow(v, types.Types[TINT]) {
+ if doesoverflow(v, types.Types[types.TINT]) {
base.Errorf("array bound is too large")
n.Type = nil
return n
n.Right = nil
checkwidth(t)
- case OTMAP:
+ case ir.OTMAP:
ok |= ctxType
n.Left = typecheck(n.Left, ctxType)
n.Right = typecheck(n.Right, ctxType)
n.Left = nil
n.Right = nil
- case OTCHAN:
+ case ir.OTCHAN:
ok |= ctxType
n.Left = typecheck(n.Left, ctxType)
l := n.Left
n.Left = nil
n.ResetAux()
- case OTSTRUCT:
+ case ir.OTSTRUCT:
ok |= ctxType
setTypeNode(n, tostruct(n.List.Slice()))
n.List.Set(nil)
- case OTINTER:
+ case ir.OTINTER:
ok |= ctxType
setTypeNode(n, tointerface(n.List.Slice()))
- case OTFUNC:
+ case ir.OTFUNC:
ok |= ctxType
setTypeNode(n, functype(n.Left, n.List.Slice(), n.Rlist.Slice()))
n.Left = nil
n.Rlist.Set(nil)
// type or expr
- case ODEREF:
+ case ir.ODEREF:
n.Left = typecheck(n.Left, ctxExpr|ctxType)
l := n.Left
t := l.Type
n.Type = nil
return n
}
- if l.Op == OTYPE {
+ if l.Op == ir.OTYPE {
ok |= ctxType
setTypeNode(n, types.NewPtr(l.Type))
n.Left = nil
n.Type = t.Elem()
// arithmetic exprs
- case OASOP,
- OADD,
- OAND,
- OANDAND,
- OANDNOT,
- ODIV,
- OEQ,
- OGE,
- OGT,
- OLE,
- OLT,
- OLSH,
- ORSH,
- OMOD,
- OMUL,
- ONE,
- OOR,
- OOROR,
- OSUB,
- OXOR:
- var l *Node
- var op Op
- var r *Node
- if n.Op == OASOP {
+ case ir.OASOP,
+ ir.OADD,
+ ir.OAND,
+ ir.OANDAND,
+ ir.OANDNOT,
+ ir.ODIV,
+ ir.OEQ,
+ ir.OGE,
+ ir.OGT,
+ ir.OLE,
+ ir.OLT,
+ ir.OLSH,
+ ir.ORSH,
+ ir.OMOD,
+ ir.OMUL,
+ ir.ONE,
+ ir.OOR,
+ ir.OOROR,
+ ir.OSUB,
+ ir.OXOR:
+ var l *ir.Node
+ var op ir.Op
+ var r *ir.Node
+ if n.Op == ir.OASOP {
ok |= ctxStmt
n.Left = typecheck(n.Left, ctxExpr)
n.Right = typecheck(n.Right, ctxExpr)
}
op = n.Op
}
- if op == OLSH || op == ORSH {
- r = defaultlit(r, types.Types[TUINT])
+ if op == ir.OLSH || op == ir.ORSH {
+ r = defaultlit(r, types.Types[types.TUINT])
n.Right = r
t := r.Type
if !t.IsInteger() {
return n
}
t = l.Type
- if t != nil && t.Etype != TIDEAL && !t.IsInteger() {
+ if t != nil && t.Etype != types.TIDEAL && !t.IsInteger() {
base.Errorf("invalid operation: %v (shift of type %v)", n, t)
n.Type = nil
return n
// no defaultlit for left
// the outer context gives the type
n.Type = l.Type
- if (l.Type == types.UntypedFloat || l.Type == types.UntypedComplex) && r.Op == OLITERAL {
+ if (l.Type == types.UntypedFloat || l.Type == types.UntypedComplex) && r.Op == ir.OLITERAL {
n.Type = types.UntypedInt
}
// For "x == x && len(s)", it's better to report that "len(s)" (type int)
// can't be used with "&&" than to report that "x == x" (type untyped bool)
// can't be converted to int (see issue #41500).
- if n.Op == OANDAND || n.Op == OOROR {
+ if n.Op == ir.OANDAND || n.Op == ir.OOROR {
if !n.Left.Type.IsBoolean() {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(n.Left.Type))
n.Type = nil
return n
}
t := l.Type
- if t.Etype == TIDEAL {
+ if t.Etype == types.TIDEAL {
t = r.Type
}
et := t.Etype
- if et == TIDEAL {
- et = TINT
+ if et == types.TIDEAL {
+ et = types.TINT
}
- aop := OXXX
- if iscmp[n.Op] && t.Etype != TIDEAL && !types.Identical(l.Type, r.Type) {
+ aop := ir.OXXX
+ if iscmp[n.Op] && t.Etype != types.TIDEAL && !types.Identical(l.Type, r.Type) {
// comparison is okay as long as one side is
// assignable to the other. convert so they have
// the same type.
// in that case, check comparability of the concrete type.
// The conversion allocates, so only do it if the concrete type is huge.
converted := false
- if r.Type.Etype != TBLANK {
+ if r.Type.Etype != types.TBLANK {
aop, _ = assignop(l.Type, r.Type)
- if aop != OXXX {
+ if aop != ir.OXXX {
if r.Type.IsInterface() && !l.Type.IsInterface() && !IsComparable(l.Type) {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
n.Type = nil
dowidth(l.Type)
if r.Type.IsInterface() == l.Type.IsInterface() || l.Type.Width >= 1<<16 {
- l = nod(aop, l, nil)
+ l = ir.Nod(aop, l, nil)
l.Type = r.Type
l.SetTypecheck(1)
n.Left = l
}
}
- if !converted && l.Type.Etype != TBLANK {
+ if !converted && l.Type.Etype != types.TBLANK {
aop, _ = assignop(r.Type, l.Type)
- if aop != OXXX {
+ if aop != ir.OXXX {
if l.Type.IsInterface() && !r.Type.IsInterface() && !IsComparable(r.Type) {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
n.Type = nil
dowidth(r.Type)
if r.Type.IsInterface() == l.Type.IsInterface() || r.Type.Width >= 1<<16 {
- r = nod(aop, r, nil)
+ r = ir.Nod(aop, r, nil)
r.Type = l.Type
r.SetTypecheck(1)
n.Right = r
et = t.Etype
}
- if t.Etype != TIDEAL && !types.Identical(l.Type, r.Type) {
+ if t.Etype != types.TIDEAL && !types.Identical(l.Type, r.Type) {
l, r = defaultlit2(l, r, true)
if l.Type == nil || r.Type == nil {
n.Type = nil
}
}
- if t.Etype == TIDEAL {
+ if t.Etype == types.TIDEAL {
t = mixUntyped(l.Type, r.Type)
}
if dt := defaultType(t); !okfor[op][dt.Etype] {
return n
}
- if l.Type.IsSlice() && !l.isNil() && !r.isNil() {
+ if l.Type.IsSlice() && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (slice can only be compared to nil)", n)
n.Type = nil
return n
}
- if l.Type.IsMap() && !l.isNil() && !r.isNil() {
+ if l.Type.IsMap() && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (map can only be compared to nil)", n)
n.Type = nil
return n
}
- if l.Type.Etype == TFUNC && !l.isNil() && !r.isNil() {
+ if l.Type.Etype == types.TFUNC && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (func can only be compared to nil)", n)
n.Type = nil
return n
t = types.UntypedBool
n.Type = t
n = evalConst(n)
- if n.Op != OLITERAL {
+ if n.Op != ir.OLITERAL {
l, r = defaultlit2(l, r, true)
n.Left = l
n.Right = r
}
}
- if et == TSTRING && n.Op == OADD {
+ if et == types.TSTRING && n.Op == ir.OADD {
// create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
- if l.Op == OADDSTR {
+ if l.Op == ir.OADDSTR {
orig := n
n = l
n.Pos = orig.Pos
} else {
- n = nodl(n.Pos, OADDSTR, nil, nil)
+ n = ir.NodAt(n.Pos, ir.OADDSTR, nil, nil)
n.List.Set1(l)
}
- if r.Op == OADDSTR {
+ if r.Op == ir.OADDSTR {
n.List.AppendNodes(&r.List)
} else {
n.List.Append(r)
}
}
- if (op == ODIV || op == OMOD) && Isconst(r, constant.Int) {
+ if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
if constant.Sign(r.Val()) == 0 {
base.Errorf("division by zero")
n.Type = nil
n.Type = t
- case OBITNOT, ONEG, ONOT, OPLUS:
+ case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
l := n.Left
n.Type = t
// exprs
- case OADDR:
+ case ir.OADDR:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
}
switch n.Left.Op {
- case OARRAYLIT, OMAPLIT, OSLICELIT, OSTRUCTLIT:
- n.Op = OPTRLIT
+ case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
+ n.Op = ir.OPTRLIT
default:
checklvalue(n.Left, "take the address of")
r := outervalue(n.Left)
- if r.Op == ONAME {
+ if r.Op == ir.ONAME {
if r.Orig != r {
base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
}
n.Type = types.NewPtr(n.Left.Type)
- case OCOMPLIT:
+ case ir.OCOMPLIT:
ok |= ctxExpr
n = typecheckcomplit(n)
if n.Type == nil {
return n
}
- case OXDOT, ODOT:
- if n.Op == OXDOT {
+ case ir.OXDOT, ir.ODOT:
+ if n.Op == ir.OXDOT {
n = adddot(n)
- n.Op = ODOT
+ n.Op = ir.ODOT
if n.Left == nil {
n.Type = nil
return n
t := n.Left.Type
if t == nil {
- base.UpdateErrorDot(n.Line(), n.Left.String(), n.String())
+ base.UpdateErrorDot(ir.Line(n), n.Left.String(), n.String())
n.Type = nil
return n
}
s := n.Sym
- if n.Left.Op == OTYPE {
+ if n.Left.Op == ir.OTYPE {
n = typecheckMethodExpr(n)
if n.Type == nil {
return n
n.Type = nil
return n
}
- n.Op = ODOTPTR
+ n.Op = ir.ODOTPTR
checkwidth(t)
}
}
switch n.Op {
- case ODOTINTER, ODOTMETH:
+ case ir.ODOTINTER, ir.ODOTMETH:
if top&ctxCallee != 0 {
ok |= ctxCallee
} else {
ok |= ctxExpr
}
- case ODOTTYPE:
+ case ir.ODOTTYPE:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
n.Left = defaultlit(n.Left, nil)
}
}
- case OINDEX:
+ case ir.OINDEX:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
n.Left = defaultlit(n.Left, nil)
n.Type = nil
return n
- case TSTRING, TARRAY, TSLICE:
+ case types.TSTRING, types.TARRAY, types.TSLICE:
n.Right = indexlit(n.Right)
if t.IsString() {
n.Type = types.Bytetype
break
}
- if !n.Bounded() && Isconst(n.Right, constant.Int) {
+ if !n.Bounded() && ir.IsConst(n.Right, constant.Int) {
x := n.Right.Val()
if constant.Sign(x) < 0 {
base.Errorf("invalid %s index %v (index must be non-negative)", why, n.Right)
} else if t.IsArray() && constant.Compare(x, token.GEQ, constant.MakeInt64(t.NumElem())) {
base.Errorf("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem())
- } else if Isconst(n.Left, constant.String) && constant.Compare(x, token.GEQ, constant.MakeInt64(int64(len(n.Left.StringVal())))) {
+ } else if ir.IsConst(n.Left, constant.String) && constant.Compare(x, token.GEQ, constant.MakeInt64(int64(len(n.Left.StringVal())))) {
base.Errorf("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.StringVal()))
- } else if doesoverflow(x, types.Types[TINT]) {
+ } else if doesoverflow(x, types.Types[types.TINT]) {
base.Errorf("invalid %s index %v (index too large)", why, n.Right)
}
}
- case TMAP:
+ case types.TMAP:
n.Right = assignconv(n.Right, t.Key(), "map index")
n.Type = t.Elem()
- n.Op = OINDEXMAP
+ n.Op = ir.OINDEXMAP
n.ResetAux()
}
- case ORECV:
+ case ir.ORECV:
ok |= ctxStmt | ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
n.Left = defaultlit(n.Left, nil)
n.Type = t.Elem()
- case OSEND:
+ case ir.OSEND:
ok |= ctxStmt
n.Left = typecheck(n.Left, ctxExpr)
n.Right = typecheck(n.Right, ctxExpr)
}
n.Type = nil
- case OSLICEHEADER:
+ case ir.OSLICEHEADER:
// Errors here are Fatalf instead of Errorf because only the compiler
// can construct an OSLICEHEADER node.
// Components used in OSLICEHEADER that are supplied by parsed source code
n.Left = typecheck(n.Left, ctxExpr)
l := typecheck(n.List.First(), ctxExpr)
c := typecheck(n.List.Second(), ctxExpr)
- l = defaultlit(l, types.Types[TINT])
- c = defaultlit(c, types.Types[TINT])
+ l = defaultlit(l, types.Types[types.TINT])
+ c = defaultlit(c, types.Types[types.TINT])
- if Isconst(l, constant.Int) && l.Int64Val() < 0 {
+ if ir.IsConst(l, constant.Int) && l.Int64Val() < 0 {
base.Fatalf("len for OSLICEHEADER must be non-negative")
}
- if Isconst(c, constant.Int) && c.Int64Val() < 0 {
+ if ir.IsConst(c, constant.Int) && c.Int64Val() < 0 {
base.Fatalf("cap for OSLICEHEADER must be non-negative")
}
- if Isconst(l, constant.Int) && Isconst(c, constant.Int) && constant.Compare(l.Val(), token.GTR, c.Val()) {
+ if ir.IsConst(l, constant.Int) && ir.IsConst(c, constant.Int) && constant.Compare(l.Val(), token.GTR, c.Val()) {
base.Fatalf("len larger than cap for OSLICEHEADER")
}
n.List.SetFirst(l)
n.List.SetSecond(c)
- case OMAKESLICECOPY:
+ case ir.OMAKESLICECOPY:
// Errors here are Fatalf instead of Errorf because only the compiler
// can construct an OMAKESLICECOPY node.
// Components used in OMAKESCLICECOPY that are supplied by parsed source code
n.Left = typecheck(n.Left, ctxExpr)
n.Right = typecheck(n.Right, ctxExpr)
- n.Left = defaultlit(n.Left, types.Types[TINT])
+ n.Left = defaultlit(n.Left, types.Types[types.TINT])
- if !n.Left.Type.IsInteger() && n.Type.Etype != TIDEAL {
+ if !n.Left.Type.IsInteger() && n.Type.Etype != types.TIDEAL {
base.Errorf("non-integer len argument in OMAKESLICECOPY")
}
- if Isconst(n.Left, constant.Int) {
- if doesoverflow(n.Left.Val(), types.Types[TINT]) {
+ if ir.IsConst(n.Left, constant.Int) {
+ if doesoverflow(n.Left.Val(), types.Types[types.TINT]) {
base.Fatalf("len for OMAKESLICECOPY too large")
}
if constant.Sign(n.Left.Val()) < 0 {
}
}
- case OSLICE, OSLICE3:
+ case ir.OSLICE, ir.OSLICE3:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
low, high, max := n.SliceBounds()
return n
}
- n.Left = nod(OADDR, n.Left, nil)
+ n.Left = ir.Nod(ir.OADDR, n.Left, nil)
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxExpr)
l = n.Left
return n
}
n.Type = t
- n.Op = OSLICESTR
+ n.Op = ir.OSLICESTR
} else if t.IsPtr() && t.Elem().IsArray() {
tp = t.Elem()
n.Type = types.NewSlice(tp.Elem())
dowidth(n.Type)
if hasmax {
- n.Op = OSLICE3ARR
+ n.Op = ir.OSLICE3ARR
} else {
- n.Op = OSLICEARR
+ n.Op = ir.OSLICEARR
}
} else if t.IsSlice() {
n.Type = t
}
// call and call like
- case OCALL:
+ case ir.OCALL:
typecheckslice(n.Ninit.Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907)
n.Left = typecheck(n.Left, ctxExpr|ctxType|ctxCallee)
if n.Left.Diag() {
l := n.Left
- if l.Op == ONAME && l.SubOp() != 0 {
- if n.IsDDD() && l.SubOp() != OAPPEND {
+ if l.Op == ir.ONAME && l.SubOp() != 0 {
+ if n.IsDDD() && l.SubOp() != ir.OAPPEND {
base.Errorf("invalid use of ... with builtin %v", l)
}
n.Left = defaultlit(n.Left, nil)
l = n.Left
- if l.Op == OTYPE {
+ if l.Op == ir.OTYPE {
if n.IsDDD() {
if !l.Type.Broke() {
base.Errorf("invalid use of ... in type conversion to %v", l.Type)
// turn CALL(type, arg) into CONV(arg) w/ type
n.Left = nil
- n.Op = OCONV
+ n.Op = ir.OCONV
n.Type = l.Type
if !onearg(n, "conversion to %v", l.Type) {
n.Type = nil
checkwidth(t)
switch l.Op {
- case ODOTINTER:
- n.Op = OCALLINTER
+ case ir.ODOTINTER:
+ n.Op = ir.OCALLINTER
- case ODOTMETH:
- n.Op = OCALLMETH
+ case ir.ODOTMETH:
+ n.Op = ir.OCALLMETH
// typecheckaste was used here but there wasn't enough
// information further down the call chain to know if we
}
default:
- n.Op = OCALLFUNC
- if t.Etype != TFUNC {
+ n.Op = ir.OCALLFUNC
+ if t.Etype != types.TFUNC {
name := l.String()
if isBuiltinFuncName(name) && l.Name.Defn != nil {
// be more specific when the function
}
}
- typecheckaste(OCALL, n.Left, n.IsDDD(), t.Params(), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) })
+ typecheckaste(ir.OCALL, n.Left, n.IsDDD(), t.Params(), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) })
ok |= ctxStmt
if t.NumResults() == 0 {
break
if t.NumResults() == 1 {
n.Type = l.Type.Results().Field(0).Type
- if n.Op == OCALLFUNC && n.Left.Op == ONAME && isRuntimePkg(n.Left.Sym.Pkg) && n.Left.Sym.Name == "getg" {
+ if n.Op == ir.OCALLFUNC && n.Left.Op == ir.ONAME && isRuntimePkg(n.Left.Sym.Pkg) && n.Left.Sym.Name == "getg" {
// Emit code for runtime.getg() directly instead of calling function.
// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
// so that the ordering pass can make sure to preserve the semantics of the original code
// (in particular, the exact time of the function call) by introducing temporaries.
// In this case, we know getg() always returns the same result within a given function
// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
- n.Op = OGETG
+ n.Op = ir.OGETG
}
break
n.Type = l.Type.Results()
- case OALIGNOF, OOFFSETOF, OSIZEOF:
+ case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
ok |= ctxExpr
if !onearg(n, "%v", n.Op) {
n.Type = nil
return n
}
- n.Type = types.Types[TUINTPTR]
+ n.Type = types.Types[types.TUINTPTR]
- case OCAP, OLEN:
+ case ir.OCAP, ir.OLEN:
ok |= ctxExpr
if !onearg(n, "%v", n.Op) {
n.Type = nil
}
var ok bool
- if n.Op == OLEN {
+ if n.Op == ir.OLEN {
ok = okforlen[t.Etype]
} else {
ok = okforcap[t.Etype]
return n
}
- n.Type = types.Types[TINT]
+ n.Type = types.Types[types.TINT]
- case OREAL, OIMAG:
+ case ir.OREAL, ir.OIMAG:
ok |= ctxExpr
if !onearg(n, "%v", n.Op) {
n.Type = nil
// Determine result type.
switch t.Etype {
- case TIDEAL:
+ case types.TIDEAL:
n.Type = types.UntypedFloat
- case TCOMPLEX64:
- n.Type = types.Types[TFLOAT32]
- case TCOMPLEX128:
- n.Type = types.Types[TFLOAT64]
+ case types.TCOMPLEX64:
+ n.Type = types.Types[types.TFLOAT32]
+ case types.TCOMPLEX128:
+ n.Type = types.Types[types.TFLOAT64]
default:
base.Errorf("invalid argument %L for %v", l, n.Op)
n.Type = nil
return n
}
- case OCOMPLEX:
+ case ir.OCOMPLEX:
ok |= ctxExpr
typecheckargs(n)
if !twoarg(n) {
n.Type = nil
return n
- case TIDEAL:
+ case types.TIDEAL:
t = types.UntypedComplex
- case TFLOAT32:
- t = types.Types[TCOMPLEX64]
+ case types.TFLOAT32:
+ t = types.Types[types.TCOMPLEX64]
- case TFLOAT64:
- t = types.Types[TCOMPLEX128]
+ case types.TFLOAT64:
+ t = types.Types[types.TCOMPLEX128]
}
n.Type = t
- case OCLOSE:
+ case ir.OCLOSE:
if !onearg(n, "%v", n.Op) {
n.Type = nil
return n
ok |= ctxStmt
- case ODELETE:
+ case ir.ODELETE:
ok |= ctxStmt
typecheckargs(n)
args := n.List
args.SetSecond(assignconv(r, l.Type.Key(), "delete"))
- case OAPPEND:
+ case ir.OAPPEND:
ok |= ctxExpr
typecheckargs(n)
args := n.List
n.Type = t
if !t.IsSlice() {
- if args.First().isNil() {
+ if ir.IsNil(args.First()) {
base.Errorf("first argument to append must be typed slice; have untyped nil")
n.Type = nil
return n
return n
}
- if t.Elem().IsKind(TUINT8) && args.Second().Type.IsString() {
- args.SetSecond(defaultlit(args.Second(), types.Types[TSTRING]))
+ if t.Elem().IsKind(types.TUINT8) && args.Second().Type.IsString() {
+ args.SetSecond(defaultlit(args.Second(), types.Types[types.TSTRING]))
break
}
checkwidth(as[i].Type) // ensure width is calculated for backend
}
- case OCOPY:
+ case ir.OCOPY:
ok |= ctxStmt | ctxExpr
typecheckargs(n)
if !twoarg(n) {
n.Type = nil
return n
}
- n.Type = types.Types[TINT]
+ n.Type = types.Types[types.TINT]
if n.Left.Type == nil || n.Right.Type == nil {
n.Type = nil
return n
return n
}
- case OCONV:
+ case ir.OCONV:
ok |= ctxExpr
checkwidth(n.Type) // ensure width is calculated for backend
n.Left = typecheck(n.Left, ctxExpr)
n.Type = nil
return n
}
- op, why := convertop(n.Left.Op == OLITERAL, t, n.Type)
+ op, why := convertop(n.Left.Op == ir.OLITERAL, t, n.Type)
n.Op = op
- if n.Op == OXXX {
+ if n.Op == ir.OXXX {
if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() {
base.Errorf("cannot convert %L to type %v%s", n.Left, n.Type, why)
n.SetDiag(true)
}
- n.Op = OCONV
+ n.Op = ir.OCONV
n.Type = nil
return n
}
switch n.Op {
- case OCONVNOP:
+ case ir.OCONVNOP:
if t.Etype == n.Type.Etype {
switch t.Etype {
- case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128:
+ case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
// Floating point casts imply rounding and
// so the conversion must be kept.
- n.Op = OCONV
+ n.Op = ir.OCONV
}
}
// do not convert to []byte literal. See CL 125796.
// generated code and compiler memory footprint is better without it.
- case OSTR2BYTES:
+ case ir.OSTR2BYTES:
break
- case OSTR2RUNES:
- if n.Left.Op == OLITERAL {
+ case ir.OSTR2RUNES:
+ if n.Left.Op == ir.OLITERAL {
n = stringtoruneslit(n)
}
}
- case OMAKE:
+ case ir.OMAKE:
ok |= ctxExpr
args := n.List.Slice()
if len(args) == 0 {
n.Type = nil
return n
- case TSLICE:
+ case types.TSLICE:
if i >= len(args) {
base.Errorf("missing len argument to make(%v)", t)
n.Type = nil
l = args[i]
i++
l = typecheck(l, ctxExpr)
- var r *Node
+ var r *ir.Node
if i < len(args) {
r = args[i]
i++
n.Type = nil
return n
}
- if Isconst(l, constant.Int) && r != nil && Isconst(r, constant.Int) && constant.Compare(l.Val(), token.GTR, r.Val()) {
+ if ir.IsConst(l, constant.Int) && r != nil && ir.IsConst(r, constant.Int) && constant.Compare(l.Val(), token.GTR, r.Val()) {
base.Errorf("len larger than cap in make(%v)", t)
n.Type = nil
return n
n.Left = l
n.Right = r
- n.Op = OMAKESLICE
+ n.Op = ir.OMAKESLICE
- case TMAP:
+ case types.TMAP:
if i < len(args) {
l = args[i]
i++
l = typecheck(l, ctxExpr)
- l = defaultlit(l, types.Types[TINT])
+ l = defaultlit(l, types.Types[types.TINT])
if l.Type == nil {
n.Type = nil
return n
} else {
n.Left = nodintconst(0)
}
- n.Op = OMAKEMAP
+ n.Op = ir.OMAKEMAP
- case TCHAN:
+ case types.TCHAN:
l = nil
if i < len(args) {
l = args[i]
i++
l = typecheck(l, ctxExpr)
- l = defaultlit(l, types.Types[TINT])
+ l = defaultlit(l, types.Types[types.TINT])
if l.Type == nil {
n.Type = nil
return n
} else {
n.Left = nodintconst(0)
}
- n.Op = OMAKECHAN
+ n.Op = ir.OMAKECHAN
}
if i < len(args) {
base.Errorf("too many arguments to make(%v)", t)
- n.Op = OMAKE
+ n.Op = ir.OMAKE
n.Type = nil
return n
}
n.Type = t
- case ONEW:
+ case ir.ONEW:
ok |= ctxExpr
args := n.List
if args.Len() == 0 {
n.Left = l
n.Type = types.NewPtr(t)
- case OPRINT, OPRINTN:
+ case ir.OPRINT, ir.OPRINTN:
ok |= ctxStmt
typecheckargs(n)
ls := n.List.Slice()
for i1, n1 := range ls {
// Special case for print: int constant is int64, not int.
- if Isconst(n1, constant.Int) {
- ls[i1] = defaultlit(ls[i1], types.Types[TINT64])
+ if ir.IsConst(n1, constant.Int) {
+ ls[i1] = defaultlit(ls[i1], types.Types[types.TINT64])
} else {
ls[i1] = defaultlit(ls[i1], nil)
}
}
- case OPANIC:
+ case ir.OPANIC:
ok |= ctxStmt
if !onearg(n, "panic") {
n.Type = nil
return n
}
n.Left = typecheck(n.Left, ctxExpr)
- n.Left = defaultlit(n.Left, types.Types[TINTER])
+ n.Left = defaultlit(n.Left, types.Types[types.TINTER])
if n.Left.Type == nil {
n.Type = nil
return n
}
- case ORECOVER:
+ case ir.ORECOVER:
ok |= ctxExpr | ctxStmt
if n.List.Len() != 0 {
base.Errorf("too many arguments to recover")
return n
}
- n.Type = types.Types[TINTER]
+ n.Type = types.Types[types.TINTER]
- case OCLOSURE:
+ case ir.OCLOSURE:
ok |= ctxExpr
typecheckclosure(n, top)
if n.Type == nil {
return n
}
- case OITAB:
+ case ir.OITAB:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
t := n.Left.Type
if !t.IsInterface() {
base.Fatalf("OITAB of %v", t)
}
- n.Type = types.NewPtr(types.Types[TUINTPTR])
+ n.Type = types.NewPtr(types.Types[types.TUINTPTR])
- case OIDATA:
+ case ir.OIDATA:
// Whoever creates the OIDATA node must know a priori the concrete type at that moment,
// usually by just having checked the OITAB.
base.Fatalf("cannot typecheck interface data %v", n)
- case OSPTR:
+ case ir.OSPTR:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
t := n.Left.Type
base.Fatalf("OSPTR of %v", t)
}
if t.IsString() {
- n.Type = types.NewPtr(types.Types[TUINT8])
+ n.Type = types.NewPtr(types.Types[types.TUINT8])
} else {
n.Type = types.NewPtr(t.Elem())
}
- case OCLOSUREVAR:
+ case ir.OCLOSUREVAR:
ok |= ctxExpr
- case OCFUNC:
+ case ir.OCFUNC:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
- n.Type = types.Types[TUINTPTR]
+ n.Type = types.Types[types.TUINTPTR]
- case OCONVNOP:
+ case ir.OCONVNOP:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
// statements
- case OAS:
+ case ir.OAS:
ok |= ctxStmt
typecheckas(n)
// Code that creates temps does not bother to set defn, so do it here.
- if n.Left.Op == ONAME && n.Left.IsAutoTmp() {
+ if n.Left.Op == ir.ONAME && n.Left.IsAutoTmp() {
n.Left.Name.Defn = n
}
- case OAS2:
+ case ir.OAS2:
ok |= ctxStmt
typecheckas2(n)
- case OBREAK,
- OCONTINUE,
- ODCL,
- OEMPTY,
- OGOTO,
- OFALL,
- OVARKILL,
- OVARLIVE:
+ case ir.OBREAK,
+ ir.OCONTINUE,
+ ir.ODCL,
+ ir.OEMPTY,
+ ir.OGOTO,
+ ir.OFALL,
+ ir.OVARKILL,
+ ir.OVARLIVE:
ok |= ctxStmt
- case OLABEL:
+ case ir.OLABEL:
ok |= ctxStmt
decldepth++
if n.Sym.IsBlank() {
// Empty identifier is valid but useless.
// Eliminate now to simplify life later.
// See issues 7538, 11589, 11593.
- n.Op = OEMPTY
+ n.Op = ir.OEMPTY
n.Left = nil
}
- case ODEFER:
+ case ir.ODEFER:
ok |= ctxStmt
n.Left = typecheck(n.Left, ctxStmt|ctxExpr)
if !n.Left.Diag() {
checkdefergo(n)
}
- case OGO:
+ case ir.OGO:
ok |= ctxStmt
n.Left = typecheck(n.Left, ctxStmt|ctxExpr)
checkdefergo(n)
- case OFOR, OFORUNTIL:
+ case ir.OFOR, ir.OFORUNTIL:
ok |= ctxStmt
typecheckslice(n.Ninit.Slice(), ctxStmt)
decldepth++
}
}
n.Right = typecheck(n.Right, ctxStmt)
- if n.Op == OFORUNTIL {
+ if n.Op == ir.OFORUNTIL {
typecheckslice(n.List.Slice(), ctxStmt)
}
typecheckslice(n.Nbody.Slice(), ctxStmt)
decldepth--
- case OIF:
+ case ir.OIF:
ok |= ctxStmt
typecheckslice(n.Ninit.Slice(), ctxStmt)
n.Left = typecheck(n.Left, ctxExpr)
typecheckslice(n.Nbody.Slice(), ctxStmt)
typecheckslice(n.Rlist.Slice(), ctxStmt)
- case ORETURN:
+ case ir.ORETURN:
ok |= ctxStmt
typecheckargs(n)
if Curfn == nil {
if Curfn.Type.FuncType().Outnamed && n.List.Len() == 0 {
break
}
- typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" })
+ typecheckaste(ir.ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" })
- case ORETJMP:
+ case ir.ORETJMP:
ok |= ctxStmt
- case OSELECT:
+ case ir.OSELECT:
ok |= ctxStmt
typecheckselect(n)
- case OSWITCH:
+ case ir.OSWITCH:
ok |= ctxStmt
typecheckswitch(n)
- case ORANGE:
+ case ir.ORANGE:
ok |= ctxStmt
typecheckrange(n)
- case OTYPESW:
+ case ir.OTYPESW:
base.Errorf("use of .(type) outside type switch")
n.Type = nil
return n
- case ODCLFUNC:
+ case ir.ODCLFUNC:
ok |= ctxStmt
typecheckfunc(n)
- case ODCLCONST:
+ case ir.ODCLCONST:
ok |= ctxStmt
n.Left = typecheck(n.Left, ctxExpr)
- case ODCLTYPE:
+ case ir.ODCLTYPE:
ok |= ctxStmt
n.Left = typecheck(n.Left, ctxType)
checkwidth(n.Left.Type)
}
t := n.Type
- if t != nil && !t.IsFuncArgStruct() && n.Op != OTYPE {
+ if t != nil && !t.IsFuncArgStruct() && n.Op != ir.OTYPE {
switch t.Etype {
- case TFUNC, // might have TANY; wait until it's called
- TANY, TFORW, TIDEAL, TNIL, TBLANK:
+ case types.TFUNC, // might have TANY; wait until it's called
+ types.TANY, types.TFORW, types.TIDEAL, types.TNIL, types.TBLANK:
break
default:
}
n = evalConst(n)
- if n.Op == OTYPE && top&ctxType == 0 {
+ if n.Op == ir.OTYPE && top&ctxType == 0 {
if !n.Type.Broke() {
base.Errorf("type %v is not an expression", n.Type)
}
return n
}
- if top&(ctxExpr|ctxType) == ctxType && n.Op != OTYPE {
+ if top&(ctxExpr|ctxType) == ctxType && n.Op != ir.OTYPE {
base.Errorf("%v is not a type", n)
n.Type = nil
return n
return n
}
-func typecheckargs(n *Node) {
+func typecheckargs(n *ir.Node) {
if n.List.Len() != 1 || n.IsDDD() {
typecheckslice(n.List.Slice(), ctxExpr)
return
// Save n as n.Orig for fmt.go.
if n.Orig == n {
- n.Orig = n.sepcopy()
+ n.Orig = ir.SepCopy(n)
}
- as := nod(OAS2, nil, nil)
+ as := ir.Nod(ir.OAS2, nil, nil)
as.Rlist.AppendNodes(&n.List)
// If we're outside of function context, then this call will
}
for _, f := range t.FieldSlice() {
t := temp(f.Type)
- as.Ninit.Append(nod(ODCL, t, nil))
+ as.Ninit.Append(ir.Nod(ir.ODCL, t, nil))
as.List.Append(t)
n.List.Append(t)
}
n.Ninit.Append(as)
}
-func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
+func checksliceindex(l *ir.Node, r *ir.Node, tp *types.Type) bool {
t := r.Type
if t == nil {
return false
return false
}
- if r.Op == OLITERAL {
+ if r.Op == ir.OLITERAL {
x := r.Val()
if constant.Sign(x) < 0 {
base.Errorf("invalid slice index %v (index must be non-negative)", r)
} else if tp != nil && tp.NumElem() >= 0 && constant.Compare(x, token.GTR, constant.MakeInt64(tp.NumElem())) {
base.Errorf("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem())
return false
- } else if Isconst(l, constant.String) && constant.Compare(x, token.GTR, constant.MakeInt64(int64(len(l.StringVal())))) {
+ } else if ir.IsConst(l, constant.String) && constant.Compare(x, token.GTR, constant.MakeInt64(int64(len(l.StringVal())))) {
base.Errorf("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.StringVal()))
return false
- } else if doesoverflow(x, types.Types[TINT]) {
+ } else if doesoverflow(x, types.Types[types.TINT]) {
base.Errorf("invalid slice index %v (index too large)", r)
return false
}
return true
}
-func checksliceconst(lo *Node, hi *Node) bool {
- if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && constant.Compare(lo.Val(), token.GTR, hi.Val()) {
+func checksliceconst(lo *ir.Node, hi *ir.Node) bool {
+ if lo != nil && hi != nil && lo.Op == ir.OLITERAL && hi.Op == ir.OLITERAL && constant.Compare(lo.Val(), token.GTR, hi.Val()) {
base.Errorf("invalid slice index: %v > %v", lo, hi)
return false
}
return true
}
-func checkdefergo(n *Node) {
+func checkdefergo(n *ir.Node) {
what := "defer"
- if n.Op == OGO {
+ if n.Op == ir.OGO {
what = "go"
}
switch n.Left.Op {
// ok
- case OCALLINTER,
- OCALLMETH,
- OCALLFUNC,
- OCLOSE,
- OCOPY,
- ODELETE,
- OPANIC,
- OPRINT,
- OPRINTN,
- ORECOVER:
+ case ir.OCALLINTER,
+ ir.OCALLMETH,
+ ir.OCALLFUNC,
+ ir.OCLOSE,
+ ir.OCOPY,
+ ir.ODELETE,
+ ir.OPANIC,
+ ir.OPRINT,
+ ir.OPRINTN,
+ ir.ORECOVER:
return
- case OAPPEND,
- OCAP,
- OCOMPLEX,
- OIMAG,
- OLEN,
- OMAKE,
- OMAKESLICE,
- OMAKECHAN,
- OMAKEMAP,
- ONEW,
- OREAL,
- OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
- if n.Left.Orig != nil && n.Left.Orig.Op == OCONV {
+ case ir.OAPPEND,
+ ir.OCAP,
+ ir.OCOMPLEX,
+ ir.OIMAG,
+ ir.OLEN,
+ ir.OMAKE,
+ ir.OMAKESLICE,
+ ir.OMAKECHAN,
+ ir.OMAKEMAP,
+ ir.ONEW,
+ ir.OREAL,
+ ir.OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
+ if n.Left.Orig != nil && n.Left.Orig.Op == ir.OCONV {
break
}
base.ErrorfAt(n.Pos, "%s discards result of %v", what, n.Left)
// The result of implicitstar MUST be assigned back to n, e.g.
// n.Left = implicitstar(n.Left)
-func implicitstar(n *Node) *Node {
+func implicitstar(n *ir.Node) *ir.Node {
// insert implicit * if needed for fixed array
t := n.Type
if t == nil || !t.IsPtr() {
if !t.IsArray() {
return n
}
- n = nod(ODEREF, n, nil)
+ n = ir.Nod(ir.ODEREF, n, nil)
n.SetImplicit(true)
n = typecheck(n, ctxExpr)
return n
}
-func onearg(n *Node, f string, args ...interface{}) bool {
+func onearg(n *ir.Node, f string, args ...interface{}) bool {
if n.Left != nil {
return true
}
return true
}
-func twoarg(n *Node) bool {
+func twoarg(n *ir.Node) bool {
if n.Left != nil {
return true
}
return true
}
-func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field {
+func lookdot1(errnode *ir.Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field {
var r *types.Field
for _, f := range fs.Slice() {
if dostrcmp != 0 && f.Sym.Name == s.Name {
// typecheckMethodExpr checks selector expressions (ODOT) where the
// base expression is a type expression (OTYPE).
-func typecheckMethodExpr(n *Node) (res *Node) {
+func typecheckMethodExpr(n *ir.Node) (res *ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckMethodExpr", n)(&res)
}
return n
}
- n.Op = OMETHEXPR
+ n.Op = ir.OMETHEXPR
if n.Name == nil {
- n.Name = new(Name)
+ n.Name = new(ir.Name)
}
- n.Right = newname(n.Sym)
+ n.Right = NewName(n.Sym)
n.Sym = methodSym(t, n.Sym)
n.Type = methodfunc(m.Type, n.Left.Type)
n.Xoffset = 0
- n.SetClass(PFUNC)
+ n.SetClass(ir.PFUNC)
n.SetOpt(m)
// methodSym already marked n.Sym as a function.
// Issue 25065. Make sure that we emit the symbol for a local method.
- if base.Ctxt.Flag_dynlink && !inimport && (t.Sym == nil || t.Sym.Pkg == localpkg) {
+ if base.Ctxt.Flag_dynlink && !inimport && (t.Sym == nil || t.Sym.Pkg == ir.LocalPkg) {
makefuncsym(n.Sym)
}
return t
}
-func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
+func lookdot(n *ir.Node, t *types.Type, dostrcmp int) *types.Field {
s := n.Sym
dowidth(t)
if f2 != nil {
base.Errorf("%v is both field and method", n.Sym)
}
- if f1.Offset == BADWIDTH {
+ if f1.Offset == types.BADWIDTH {
base.Fatalf("lookdot badwidth %v %p", f1, f1)
}
n.Xoffset = f1.Offset
n.Type = f1.Type
if t.IsInterface() {
if n.Left.Type.IsPtr() {
- n.Left = nod(ODEREF, n.Left, nil) // implicitstar
+ n.Left = ir.Nod(ir.ODEREF, n.Left, nil) // implicitstar
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxExpr)
}
- n.Op = ODOTINTER
+ n.Op = ir.ODOTINTER
} else {
n.SetOpt(f1)
}
if !types.Identical(rcvr, tt) {
if rcvr.IsPtr() && types.Identical(rcvr.Elem(), tt) {
checklvalue(n.Left, "call pointer method on")
- n.Left = nod(OADDR, n.Left, nil)
+ n.Left = ir.Nod(ir.OADDR, n.Left, nil)
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxType|ctxExpr)
} else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
- n.Left = nod(ODEREF, n.Left, nil)
+ n.Left = ir.Nod(ir.ODEREF, n.Left, nil)
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxType|ctxExpr)
} else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) {
if rcvr.IsPtr() && !tt.Elem().IsPtr() {
break
}
- n.Left = nod(ODEREF, n.Left, nil)
+ n.Left = ir.Nod(ir.ODEREF, n.Left, nil)
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxType|ctxExpr)
tt = tt.Elem()
pll := n
ll := n.Left
- for ll.Left != nil && (ll.Op == ODOT || ll.Op == ODOTPTR || ll.Op == ODEREF) {
+ for ll.Left != nil && (ll.Op == ir.ODOT || ll.Op == ir.ODOTPTR || ll.Op == ir.ODEREF) {
pll = ll
ll = ll.Left
}
- if pll.Implicit() && ll.Type.IsPtr() && ll.Type.Sym != nil && asNode(ll.Type.Sym.Def) != nil && asNode(ll.Type.Sym.Def).Op == OTYPE {
+ if pll.Implicit() && ll.Type.IsPtr() && ll.Type.Sym != nil && ir.AsNode(ll.Type.Sym.Def) != nil && ir.AsNode(ll.Type.Sym.Def).Op == ir.OTYPE {
// It is invalid to automatically dereference a named pointer type when selecting a method.
// Make n.Left == ll to clarify error message.
n.Left = ll
n.Sym = methodSym(n.Left.Type, f2.Sym)
n.Xoffset = f2.Offset
n.Type = f2.Type
- n.Op = ODOTMETH
+ n.Op = ir.ODOTMETH
n.SetOpt(f2)
return f2
return nil
}
-func nokeys(l Nodes) bool {
+func nokeys(l ir.Nodes) bool {
for _, n := range l.Slice() {
- if n.Op == OKEY || n.Op == OSTRUCTKEY {
+ if n.Op == ir.OKEY || n.Op == ir.OSTRUCTKEY {
return false
}
}
}
// typecheck assignment: type list = expression list
-func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) {
+func typecheckaste(op ir.Op, call *ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes, desc func() string) {
var t *types.Type
var i int
return
}
- var n *Node
+ var n *ir.Node
if nl.Len() == 1 {
n = nl.First()
}
// call is the expression being called, not the overall call.
// Method expressions have the form T.M, and the compiler has
// rewritten those to ONAME nodes but left T in Left.
- if call.Op == OMETHEXPR {
+ if call.Op == ir.OMETHEXPR {
base.Errorf("not enough arguments in call to method expression %v%s", call, details)
} else {
base.Errorf("not enough arguments in call to %v%s", call, details)
}
}
-func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string {
+func errorDetails(nl ir.Nodes, tstruct *types.Type, isddd bool) string {
// If we don't know any type at a call site, let's suppress any return
// message signatures. See Issue https://golang.org/issues/19012.
if tstruct == nil {
return ""
}
}
- return fmt.Sprintf("\n\thave %s\n\twant %v", nl.sigerr(isddd), tstruct)
+ return fmt.Sprintf("\n\thave %s\n\twant %v", fmtSignature(nl, isddd), tstruct)
}
// sigrepr is a type's representation to the outside world,
return "bool"
}
- if t.Etype == TIDEAL {
+ if t.Etype == types.TIDEAL {
// "untyped number" is not commonly used
// outside of the compiler, so let's use "number".
// TODO(mdempsky): Revisit this.
}
// sigerr returns the signature of the types at the call or return.
-func (nl Nodes) sigerr(isddd bool) string {
+func fmtSignature(nl ir.Nodes, isddd bool) string {
if nl.Len() < 1 {
return "()"
}
// iscomptype reports whether type t is a composite literal type.
func iscomptype(t *types.Type) bool {
switch t.Etype {
- case TARRAY, TSLICE, TSTRUCT, TMAP:
+ case types.TARRAY, types.TSLICE, types.TSTRUCT, types.TMAP:
return true
default:
return false
// pushtype adds elided type information for composite literals if
// appropriate, and returns the resulting expression.
-func pushtype(n *Node, t *types.Type) *Node {
- if n == nil || n.Op != OCOMPLIT || n.Right != nil {
+func pushtype(n *ir.Node, t *types.Type) *ir.Node {
+ if n == nil || n.Op != ir.OCOMPLIT || n.Right != nil {
return n
}
// For *T, return &T{...}.
n.Right = typenod(t.Elem())
- n = nodl(n.Pos, OADDR, n, nil)
+ n = ir.NodAt(n.Pos, ir.OADDR, n, nil)
n.SetImplicit(true)
}
// The result of typecheckcomplit MUST be assigned back to n, e.g.
// n.Left = typecheckcomplit(n.Left)
-func typecheckcomplit(n *Node) (res *Node) {
+func typecheckcomplit(n *ir.Node) (res *ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckcomplit", n)(&res)
}
}
// Save original node (including n.Right)
- n.Orig = n.copy()
+ n.Orig = ir.Copy(n)
setlineno(n.Right)
// Need to handle [...]T arrays specially.
- if n.Right.Op == OTARRAY && n.Right.Left != nil && n.Right.Left.Op == ODDD {
+ if n.Right.Op == ir.OTARRAY && n.Right.Left != nil && n.Right.Left.Op == ir.ODDD {
n.Right.Right = typecheck(n.Right.Right, ctxType)
if n.Right.Right.Type == nil {
n.Type = nil
length := typecheckarraylit(elemType, -1, n.List.Slice(), "array literal")
- n.Op = OARRAYLIT
+ n.Op = ir.OARRAYLIT
n.Type = types.NewArray(elemType, length)
n.Right = nil
return n
base.Errorf("invalid composite literal type %v", t)
n.Type = nil
- case TARRAY:
+ case types.TARRAY:
typecheckarraylit(t.Elem(), t.NumElem(), n.List.Slice(), "array literal")
- n.Op = OARRAYLIT
+ n.Op = ir.OARRAYLIT
n.Right = nil
- case TSLICE:
+ case types.TSLICE:
length := typecheckarraylit(t.Elem(), -1, n.List.Slice(), "slice literal")
- n.Op = OSLICELIT
+ n.Op = ir.OSLICELIT
n.Right = nodintconst(length)
- case TMAP:
+ case types.TMAP:
var cs constSet
for i3, l := range n.List.Slice() {
setlineno(l)
- if l.Op != OKEY {
+ if l.Op != ir.OKEY {
n.List.SetIndex(i3, typecheck(l, ctxExpr))
base.Errorf("missing key in map literal")
continue
l.Right = assignconv(r, t.Elem(), "map value")
}
- n.Op = OMAPLIT
+ n.Op = ir.OMAPLIT
n.Right = nil
- case TSTRUCT:
+ case types.TSTRUCT:
// Need valid field offsets for Xoffset below.
dowidth(t)
f := t.Field(i)
s := f.Sym
- if s != nil && !types.IsExported(s.Name) && s.Pkg != localpkg {
+ if s != nil && !types.IsExported(s.Name) && s.Pkg != ir.LocalPkg {
base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
}
// No pushtype allowed here. Must name fields for that.
n1 = assignconv(n1, f.Type, "field value")
- n1 = nodSym(OSTRUCTKEY, n1, f.Sym)
+ n1 = nodSym(ir.OSTRUCTKEY, n1, f.Sym)
n1.Xoffset = f.Offset
ls[i] = n1
}
for i, l := range ls {
setlineno(l)
- if l.Op == OKEY {
+ if l.Op == ir.OKEY {
key := l.Left
- l.Op = OSTRUCTKEY
+ l.Op = ir.OSTRUCTKEY
l.Left = l.Right
l.Right = nil
// the field to the right of the dot,
// so s will be non-nil, but an OXDOT
// is never a valid struct literal key.
- if key.Sym == nil || key.Op == OXDOT || key.Sym.IsBlank() {
+ if key.Sym == nil || key.Op == ir.OXDOT || key.Sym.IsBlank() {
base.Errorf("invalid field name %v in struct initializer", key)
l.Left = typecheck(l.Left, ctxExpr)
continue
// package, because of import dot. Redirect to correct sym
// before we do the lookup.
s := key.Sym
- if s.Pkg != localpkg && types.IsExported(s.Name) {
+ if s.Pkg != ir.LocalPkg && types.IsExported(s.Name) {
s1 := lookup(s.Name)
if s1.Origpkg == s.Pkg {
s = s1
l.Sym = s
}
- if l.Op != OSTRUCTKEY {
+ if l.Op != ir.OSTRUCTKEY {
if !errored {
base.Errorf("mixture of field:value and value initializers")
errored = true
}
}
- n.Op = OSTRUCTLIT
+ n.Op = ir.OSTRUCTLIT
n.Right = nil
}
}
// typecheckarraylit type-checks a sequence of slice/array literal elements.
-func typecheckarraylit(elemType *types.Type, bound int64, elts []*Node, ctx string) int64 {
+func typecheckarraylit(elemType *types.Type, bound int64, elts []*ir.Node, ctx string) int64 {
// If there are key/value pairs, create a map to keep seen
// keys so we can check for duplicate indices.
var indices map[int64]bool
for _, elt := range elts {
- if elt.Op == OKEY {
+ if elt.Op == ir.OKEY {
indices = make(map[int64]bool)
break
}
for i, elt := range elts {
setlineno(elt)
r := elts[i]
- var kv *Node
- if elt.Op == OKEY {
+ var kv *ir.Node
+ if elt.Op == ir.OKEY {
elt.Left = typecheck(elt.Left, ctxExpr)
key = indexconst(elt.Left)
if key < 0 {
// visible reports whether sym is exported or locally defined.
func visible(sym *types.Sym) bool {
- return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg)
+ return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == ir.LocalPkg)
}
// nonexported reports whether sym is an unexported field.
}
// lvalue etc
-func islvalue(n *Node) bool {
+func islvalue(n *ir.Node) bool {
switch n.Op {
- case OINDEX:
+ case ir.OINDEX:
if n.Left.Type != nil && n.Left.Type.IsArray() {
return islvalue(n.Left)
}
return false
}
fallthrough
- case ODEREF, ODOTPTR, OCLOSUREVAR:
+ case ir.ODEREF, ir.ODOTPTR, ir.OCLOSUREVAR:
return true
- case ODOT:
+ case ir.ODOT:
return islvalue(n.Left)
- case ONAME:
- if n.Class() == PFUNC {
+ case ir.ONAME:
+ if n.Class() == ir.PFUNC {
return false
}
return true
return false
}
-func checklvalue(n *Node, verb string) {
+func checklvalue(n *ir.Node, verb string) {
if !islvalue(n) {
base.Errorf("cannot %s %v", verb, n)
}
}
-func checkassign(stmt *Node, n *Node) {
+func checkassign(stmt *ir.Node, n *ir.Node) {
// Variables declared in ORANGE are assigned on every iteration.
- if n.Name == nil || n.Name.Defn != stmt || stmt.Op == ORANGE {
+ if n.Name == nil || n.Name.Defn != stmt || stmt.Op == ir.ORANGE {
r := outervalue(n)
- if r.Op == ONAME {
+ if r.Op == ir.ONAME {
r.Name.SetAssigned(true)
if r.Name.IsClosureVar() {
r.Name.Defn.Name.SetAssigned(true)
if islvalue(n) {
return
}
- if n.Op == OINDEXMAP {
+ if n.Op == ir.OINDEXMAP {
n.SetIndexMapLValue(true)
return
}
}
switch {
- case n.Op == ODOT && n.Left.Op == OINDEXMAP:
+ case n.Op == ir.ODOT && n.Left.Op == ir.OINDEXMAP:
base.Errorf("cannot assign to struct field %v in map", n)
- case (n.Op == OINDEX && n.Left.Type.IsString()) || n.Op == OSLICESTR:
+ case (n.Op == ir.OINDEX && n.Left.Type.IsString()) || n.Op == ir.OSLICESTR:
base.Errorf("cannot assign to %v (strings are immutable)", n)
- case n.Op == OLITERAL && n.Sym != nil && n.isGoConst():
+ case n.Op == ir.OLITERAL && n.Sym != nil && isGoConst(n):
base.Errorf("cannot assign to %v (declared const)", n)
default:
base.Errorf("cannot assign to %v", n)
n.Type = nil
}
-func checkassignlist(stmt *Node, l Nodes) {
+func checkassignlist(stmt *ir.Node, l ir.Nodes) {
for _, n := range l.Slice() {
checkassign(stmt, n)
}
// currently OK, since the only place samesafeexpr gets used on an
// lvalue expression is for OSLICE and OAPPEND optimizations, and it
// is correct in those settings.
-func samesafeexpr(l *Node, r *Node) bool {
+func samesafeexpr(l *ir.Node, r *ir.Node) bool {
if l.Op != r.Op || !types.Identical(l.Type, r.Type) {
return false
}
switch l.Op {
- case ONAME, OCLOSUREVAR:
+ case ir.ONAME, ir.OCLOSUREVAR:
return l == r
- case ODOT, ODOTPTR:
+ case ir.ODOT, ir.ODOTPTR:
return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left)
- case ODEREF, OCONVNOP,
- ONOT, OBITNOT, OPLUS, ONEG:
+ case ir.ODEREF, ir.OCONVNOP,
+ ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG:
return samesafeexpr(l.Left, r.Left)
- case OCONV:
+ case ir.OCONV:
// Some conversions can't be reused, such as []byte(str).
// Allow only numeric-ish types. This is a bit conservative.
return issimple[l.Type.Etype] && samesafeexpr(l.Left, r.Left)
- case OINDEX, OINDEXMAP,
- OADD, OSUB, OOR, OXOR, OMUL, OLSH, ORSH, OAND, OANDNOT, ODIV, OMOD:
+ case ir.OINDEX, ir.OINDEXMAP,
+ ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD:
return samesafeexpr(l.Left, r.Left) && samesafeexpr(l.Right, r.Right)
- case OLITERAL:
+ case ir.OLITERAL:
return constant.Compare(l.Val(), token.EQL, r.Val())
- case ONIL:
+ case ir.ONIL:
return true
}
// type check assignment.
// if this assignment is the definition of a var on the left side,
// fill in the var's type.
-func typecheckas(n *Node) {
+func typecheckas(n *ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckas", n)(nil)
}
if n.Left.Typecheck() == 0 {
n.Left = typecheck(n.Left, ctxExpr|ctxAssign)
}
- if !n.Left.isBlank() {
+ if !ir.IsBlank(n.Left) {
checkwidth(n.Left.Type) // ensure width is calculated for backend
}
}
-func checkassignto(src *types.Type, dst *Node) {
- if op, why := assignop(src, dst.Type); op == OXXX {
+func checkassignto(src *types.Type, dst *ir.Node) {
+ if op, why := assignop(src, dst.Type); op == ir.OXXX {
base.Errorf("cannot assign %v to %L in multiple assignment%s", src, dst, why)
return
}
}
-func typecheckas2(n *Node) {
+func typecheckas2(n *ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckas2", n)(nil)
}
}
checkassignlist(n, n.List)
- var l *Node
- var r *Node
+ var l *ir.Node
+ var r *ir.Node
if cl == cr {
// easy
ls := n.List.Slice()
goto out
}
switch r.Op {
- case OCALLMETH, OCALLINTER, OCALLFUNC:
+ case ir.OCALLMETH, ir.OCALLINTER, ir.OCALLFUNC:
if !r.Type.IsFuncArgStruct() {
break
}
if cr != cl {
goto mismatch
}
- n.Op = OAS2FUNC
+ n.Op = ir.OAS2FUNC
n.Right = r
n.Rlist.Set(nil)
for i, l := range n.List.Slice() {
goto out
}
switch r.Op {
- case OINDEXMAP, ORECV, ODOTTYPE:
+ case ir.OINDEXMAP, ir.ORECV, ir.ODOTTYPE:
switch r.Op {
- case OINDEXMAP:
- n.Op = OAS2MAPR
- case ORECV:
- n.Op = OAS2RECV
- case ODOTTYPE:
- n.Op = OAS2DOTTYPE
- r.Op = ODOTTYPE2
+ case ir.OINDEXMAP:
+ n.Op = ir.OAS2MAPR
+ case ir.ORECV:
+ n.Op = ir.OAS2RECV
+ case ir.ODOTTYPE:
+ n.Op = ir.OAS2DOTTYPE
+ r.Op = ir.ODOTTYPE2
}
n.Right = r
n.Rlist.Set(nil)
}
l := n.List.Second()
if l.Type != nil && !l.Type.IsBoolean() {
- checkassignto(types.Types[TBOOL], l)
+ checkassignto(types.Types[types.TBOOL], l)
}
if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil {
- l.Type = types.Types[TBOOL]
+ l.Type = types.Types[types.TBOOL]
}
goto out
}
switch r.Op {
default:
base.Errorf("assignment mismatch: %d variables but %d values", cl, cr)
- case OCALLFUNC, OCALLMETH, OCALLINTER:
+ case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.Left, cr)
}
}
// type check function definition
-func typecheckfunc(n *Node) {
+func typecheckfunc(n *ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckfunc", n)(nil)
}
for _, ln := range n.Func.Dcl {
- if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
+ if ln.Op == ir.ONAME && (ln.Class() == ir.PPARAM || ln.Class() == ir.PPARAMOUT) {
ln.Name.Decldepth = 1
}
}
n.Type = t
rcvr := t.Recv()
if rcvr != nil && n.Func.Shortname != nil {
- m := addmethod(n, n.Func.Shortname, t, true, n.Func.Pragma&Nointerface != 0)
+ m := addmethod(n, n.Func.Shortname, t, true, n.Func.Pragma&ir.Nointerface != 0)
if m == nil {
return
}
n.Func.Nname.Sym = methodSym(rcvr.Type, n.Func.Shortname)
- declare(n.Func.Nname, PFUNC)
+ declare(n.Func.Nname, ir.PFUNC)
}
if base.Ctxt.Flag_dynlink && !inimport && n.Func.Nname != nil {
// The result of stringtoruneslit MUST be assigned back to n, e.g.
// n.Left = stringtoruneslit(n.Left)
-func stringtoruneslit(n *Node) *Node {
- if n.Left.Op != OLITERAL || n.Left.Val().Kind() != constant.String {
+func stringtoruneslit(n *ir.Node) *ir.Node {
+ if n.Left.Op != ir.OLITERAL || n.Left.Val().Kind() != constant.String {
base.Fatalf("stringtoarraylit %v", n)
}
- var l []*Node
+ var l []*ir.Node
i := 0
for _, r := range n.Left.StringVal() {
- l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(r))))
+ l = append(l, ir.Nod(ir.OKEY, nodintconst(int64(i)), nodintconst(int64(r))))
i++
}
- nn := nod(OCOMPLIT, nil, typenod(n.Type))
+ nn := ir.Nod(ir.OCOMPLIT, nil, typenod(n.Type))
nn.List.Set(l)
nn = typecheck(nn, ctxExpr)
return nn
}
-var mapqueue []*Node
+var mapqueue []*ir.Node
func checkMapKeys() {
for _, n := range mapqueue {
}
func setUnderlying(t, underlying *types.Type) {
- if underlying.Etype == TFORW {
+ if underlying.Etype == types.TFORW {
// This type isn't computed yet; when it is, update n.
underlying.ForwardType().Copyto = append(underlying.ForwardType().Copyto, t)
return
}
- n := asNode(t.Nod)
+ n := ir.AsNode(t.Nod)
ft := t.ForwardType()
cache := t.Cache
*t = *underlying
// Restore unnecessarily clobbered attributes.
- t.Nod = asTypesNode(n)
+ t.Nod = ir.AsTypesNode(n)
t.Sym = n.Sym
if n.Name != nil {
t.Vargen = n.Name.Vargen
}
// Propagate go:notinheap pragma from the Name to the Type.
- if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma()&NotInHeap != 0 {
+ if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma()&ir.NotInHeap != 0 {
t.SetNotInHeap(true)
}
}
}
-func typecheckdeftype(n *Node) {
+func typecheckdeftype(n *ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckdeftype", n)(nil)
}
}
}
-func typecheckdef(n *Node) {
+func typecheckdef(n *ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckdef", n)(nil)
}
lno := setlineno(n)
- if n.Op == ONONAME {
+ if n.Op == ir.ONONAME {
if !n.Diag() {
n.SetDiag(true)
default:
base.Fatalf("typecheckdef %v", n.Op)
- case OLITERAL:
+ case ir.OLITERAL:
if n.Name.Param.Ntype != nil {
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, ctxType)
n.Type = n.Name.Param.Ntype.Type
e := n.Name.Defn
n.Name.Defn = nil
if e == nil {
- Dump("typecheckdef nil defn", n)
+ ir.Dump("typecheckdef nil defn", n)
base.ErrorfAt(n.Pos, "xxx")
}
if e.Type == nil {
goto ret
}
- if !e.isGoConst() {
+ if !isGoConst(e) {
if !e.Diag() {
- if e.Op == ONIL {
+ if e.Op == ir.ONIL {
base.ErrorfAt(n.Pos, "const initializer cannot be nil")
} else {
base.ErrorfAt(n.Pos, "const initializer %v is not a constant", e)
t := n.Type
if t != nil {
- if !okforconst[t.Etype] {
+ if !ir.OKForConst[t.Etype] {
base.ErrorfAt(n.Pos, "invalid constant type %v", t)
goto ret
}
n.SetVal(e.Val())
}
- case ONAME:
+ case ir.ONAME:
if n.Name.Param.Ntype != nil {
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, ctxType)
n.Type = n.Name.Param.Ntype.Type
base.Fatalf("var without type, init: %v", n.Sym)
}
- if n.Name.Defn.Op == ONAME {
+ if n.Name.Defn.Op == ir.ONAME {
n.Name.Defn = typecheck(n.Name.Defn, ctxExpr)
n.Type = n.Name.Defn.Type
break
n.Name.Defn = typecheck(n.Name.Defn, ctxStmt) // fills in n.Type
- case OTYPE:
+ case ir.OTYPE:
if p := n.Name.Param; p.Alias() {
// Type alias declaration: Simply use the rhs type - no need
// to create a new type.
// For package-level type aliases, set n.Sym.Def so we can identify
// it as a type alias during export. See also #31959.
if n.Name.Curfn == nil {
- n.Sym.Def = asTypesNode(p.Ntype)
+ n.Sym.Def = ir.AsTypesNode(p.Ntype)
}
}
break
// regular type declaration
defercheckwidth()
n.SetWalkdef(1)
- setTypeNode(n, types.New(TFORW))
+ setTypeNode(n, types.New(types.TFORW))
n.Type.Sym = n.Sym
errorsBefore := base.Errors()
typecheckdeftype(n)
- if n.Type.Etype == TFORW && base.Errors() > errorsBefore {
+ if n.Type.Etype == types.TFORW && base.Errors() > errorsBefore {
// Something went wrong during type-checking,
// but it was reported. Silence future errors.
n.Type.SetBroke(true)
}
ret:
- if n.Op != OLITERAL && n.Type != nil && n.Type.IsUntyped() {
+ if n.Op != ir.OLITERAL && n.Type != nil && n.Type.IsUntyped() {
base.Fatalf("got %v for %v", n.Type, n)
}
last := len(typecheckdefstack) - 1
n.SetWalkdef(1)
}
-func checkmake(t *types.Type, arg string, np **Node) bool {
+func checkmake(t *types.Type, arg string, np **ir.Node) bool {
n := *np
- if !n.Type.IsInteger() && n.Type.Etype != TIDEAL {
+ if !n.Type.IsInteger() && n.Type.Etype != types.TIDEAL {
base.Errorf("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
return false
}
// Do range checks for constants before defaultlit
// to avoid redundant "constant NNN overflows int" errors.
- if n.Op == OLITERAL {
+ if n.Op == ir.OLITERAL {
v := toint(n.Val())
if constant.Sign(v) < 0 {
base.Errorf("negative %s argument in make(%v)", arg, t)
return false
}
- if doesoverflow(v, types.Types[TINT]) {
+ if doesoverflow(v, types.Types[types.TINT]) {
base.Errorf("%s argument too large in make(%v)", arg, t)
return false
}
// are the same as for index expressions. Factor the code better;
// for instance, indexlit might be called here and incorporate some
// of the bounds checks done for make.
- n = defaultlit(n, types.Types[TINT])
+ n = defaultlit(n, types.Types[types.TINT])
*np = n
return true
}
-func markbreak(n *Node, implicit *Node) {
+func markbreak(n *ir.Node, implicit *ir.Node) {
if n == nil {
return
}
switch n.Op {
- case OBREAK:
+ case ir.OBREAK:
if n.Sym == nil {
if implicit != nil {
implicit.SetHasBreak(true)
}
} else {
- lab := asNode(n.Sym.Label)
+ lab := ir.AsNode(n.Sym.Label)
if lab != nil {
lab.SetHasBreak(true)
}
}
- case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE:
+ case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OTYPESW, ir.OSELECT, ir.ORANGE:
implicit = n
fallthrough
default:
}
}
-func markbreaklist(l Nodes, implicit *Node) {
+func markbreaklist(l ir.Nodes, implicit *ir.Node) {
s := l.Slice()
for i := 0; i < len(s); i++ {
n := s[i]
if n == nil {
continue
}
- if n.Op == OLABEL && i+1 < len(s) && n.Name.Defn == s[i+1] {
+ if n.Op == ir.OLABEL && i+1 < len(s) && n.Name.Defn == s[i+1] {
switch n.Name.Defn.Op {
- case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE:
- n.Sym.Label = asTypesNode(n.Name.Defn)
+ case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OTYPESW, ir.OSELECT, ir.ORANGE:
+ n.Sym.Label = ir.AsTypesNode(n.Name.Defn)
markbreak(n.Name.Defn, n.Name.Defn)
n.Sym.Label = nil
i++
}
// isterminating reports whether the Nodes list ends with a terminating statement.
-func (l Nodes) isterminating() bool {
+func isTermNodes(l ir.Nodes) bool {
s := l.Slice()
c := len(s)
if c == 0 {
return false
}
- return s[c-1].isterminating()
+ return isTermNode(s[c-1])
}
// Isterminating reports whether the node n, the last one in a
// statement list, is a terminating statement.
-func (n *Node) isterminating() bool {
+func isTermNode(n *ir.Node) bool {
switch n.Op {
// NOTE: OLABEL is treated as a separate statement,
// not a separate prefix, so skipping to the last statement
// in the block handles the labeled statement case by
// skipping over the label. No case OLABEL here.
- case OBLOCK:
- return n.List.isterminating()
+ case ir.OBLOCK:
+ return isTermNodes(n.List)
- case OGOTO, ORETURN, ORETJMP, OPANIC, OFALL:
+ case ir.OGOTO, ir.ORETURN, ir.ORETJMP, ir.OPANIC, ir.OFALL:
return true
- case OFOR, OFORUNTIL:
+ case ir.OFOR, ir.OFORUNTIL:
if n.Left != nil {
return false
}
}
return true
- case OIF:
- return n.Nbody.isterminating() && n.Rlist.isterminating()
+ case ir.OIF:
+ return isTermNodes(n.Nbody) && isTermNodes(n.Rlist)
- case OSWITCH, OTYPESW, OSELECT:
+ case ir.OSWITCH, ir.OTYPESW, ir.OSELECT:
if n.HasBreak() {
return false
}
def := false
for _, n1 := range n.List.Slice() {
- if !n1.Nbody.isterminating() {
+ if !isTermNodes(n1.Nbody) {
return false
}
if n1.List.Len() == 0 { // default
}
}
- if n.Op != OSELECT && !def {
+ if n.Op != ir.OSELECT && !def {
return false
}
return true
}
// checkreturn makes sure that fn terminates appropriately.
-func checkreturn(fn *Node) {
+func checkreturn(fn *ir.Node) {
if fn.Type.NumResults() != 0 && fn.Nbody.Len() != 0 {
markbreaklist(fn.Nbody, nil)
- if !fn.Nbody.isterminating() {
+ if !isTermNodes(fn.Nbody) {
base.ErrorfAt(fn.Func.Endlineno, "missing return at end of function")
}
}
}
-func deadcode(fn *Node) {
+func deadcode(fn *ir.Node) {
deadcodeslice(&fn.Nbody)
deadcodefn(fn)
}
-func deadcodefn(fn *Node) {
+func deadcodefn(fn *ir.Node) {
if fn.Nbody.Len() == 0 {
return
}
return
}
switch n.Op {
- case OIF:
- if !Isconst(n.Left, constant.Bool) || n.Nbody.Len() > 0 || n.Rlist.Len() > 0 {
+ case ir.OIF:
+ if !ir.IsConst(n.Left, constant.Bool) || n.Nbody.Len() > 0 || n.Rlist.Len() > 0 {
return
}
- case OFOR:
- if !Isconst(n.Left, constant.Bool) || n.Left.BoolVal() {
+ case ir.OFOR:
+ if !ir.IsConst(n.Left, constant.Bool) || n.Left.BoolVal() {
return
}
default:
}
}
- fn.Nbody.Set([]*Node{nod(OEMPTY, nil, nil)})
+ fn.Nbody.Set([]*ir.Node{ir.Nod(ir.OEMPTY, nil, nil)})
}
-func deadcodeslice(nn *Nodes) {
+func deadcodeslice(nn *ir.Nodes) {
var lastLabel = -1
for i, n := range nn.Slice() {
- if n != nil && n.Op == OLABEL {
+ if n != nil && n.Op == ir.OLABEL {
lastLabel = i
}
}
if n == nil {
continue
}
- if n.Op == OIF {
+ if n.Op == ir.OIF {
n.Left = deadcodeexpr(n.Left)
- if Isconst(n.Left, constant.Bool) {
- var body Nodes
+ if ir.IsConst(n.Left, constant.Bool) {
+ var body ir.Nodes
if n.Left.BoolVal() {
- n.Rlist = Nodes{}
+ n.Rlist = ir.Nodes{}
body = n.Nbody
} else {
- n.Nbody = Nodes{}
+ n.Nbody = ir.Nodes{}
body = n.Rlist
}
// If "then" or "else" branch ends with panic or return statement,
// might be the target of a goto. See issue 28616.
if body := body.Slice(); len(body) != 0 {
switch body[(len(body) - 1)].Op {
- case ORETURN, ORETJMP, OPANIC:
+ case ir.ORETURN, ir.ORETJMP, ir.OPANIC:
if i > lastLabel {
cut = true
}
}
}
-func deadcodeexpr(n *Node) *Node {
+func deadcodeexpr(n *ir.Node) *ir.Node {
// Perform dead-code elimination on short-circuited boolean
// expressions involving constants with the intent of
// producing a constant 'if' condition.
switch n.Op {
- case OANDAND:
+ case ir.OANDAND:
n.Left = deadcodeexpr(n.Left)
n.Right = deadcodeexpr(n.Right)
- if Isconst(n.Left, constant.Bool) {
+ if ir.IsConst(n.Left, constant.Bool) {
if n.Left.BoolVal() {
return n.Right // true && x => x
} else {
return n.Left // false && x => false
}
}
- case OOROR:
+ case ir.OOROR:
n.Left = deadcodeexpr(n.Left)
n.Right = deadcodeexpr(n.Right)
- if Isconst(n.Left, constant.Bool) {
+ if ir.IsConst(n.Left, constant.Bool) {
if n.Left.BoolVal() {
return n.Left // true || x => true
} else {
}
// setTypeNode sets n to an OTYPE node representing t.
-func setTypeNode(n *Node, t *types.Type) {
- n.Op = OTYPE
+func setTypeNode(n *ir.Node, t *types.Type) {
+ n.Op = ir.OTYPE
n.Type = t
- n.Type.Nod = asTypesNode(n)
+ n.Type.Nod = ir.AsTypesNode(n)
}
// getIotaValue returns the current value for "iota",
// or -1 if not within a ConstSpec.
func getIotaValue() int64 {
if i := len(typecheckdefstack); i > 0 {
- if x := typecheckdefstack[i-1]; x.Op == OLITERAL {
+ if x := typecheckdefstack[i-1]; x.Op == ir.OLITERAL {
return x.Iota()
}
}
fn := Curfn
if fn == nil {
// Initialization expressions for package-scope variables.
- return localpkg
+ return ir.LocalPkg
}
// TODO(mdempsky): Standardize on either ODCLFUNC or ONAME for
// Curfn, rather than mixing them.
- if fn.Op == ODCLFUNC {
+ if fn.Op == ir.ODCLFUNC {
fn = fn.Func.Nname
}
// MethodName returns the ONAME representing the method
// referenced by expression n, which must be a method selector,
// method expression, or method value.
-func (n *Node) MethodName() *Node {
- return asNode(n.MethodFunc().Nname)
+func methodExprName(n *ir.Node) *ir.Node {
+ return ir.AsNode(methodExprFunc(n).Nname)
}
// MethodFunc is like MethodName, but returns the types.Field instead.
-func (n *Node) MethodFunc() *types.Field {
+func methodExprFunc(n *ir.Node) *types.Field {
switch n.Op {
- case ODOTMETH, OMETHEXPR:
+ case ir.ODOTMETH, ir.OMETHEXPR:
return n.Opt().(*types.Field)
- case OCALLPART:
+ case ir.OCALLPART:
return callpartMethod(n)
}
base.Fatalf("unexpected node: %v (%v)", n, n.Op)
// license that can be found in the LICENSE file.
package gc
-
-import (
- "cmd/compile/internal/types"
-)
-
-// convenience constants
-const (
- Txxx = types.Txxx
-
- TINT8 = types.TINT8
- TUINT8 = types.TUINT8
- TINT16 = types.TINT16
- TUINT16 = types.TUINT16
- TINT32 = types.TINT32
- TUINT32 = types.TUINT32
- TINT64 = types.TINT64
- TUINT64 = types.TUINT64
- TINT = types.TINT
- TUINT = types.TUINT
- TUINTPTR = types.TUINTPTR
-
- TCOMPLEX64 = types.TCOMPLEX64
- TCOMPLEX128 = types.TCOMPLEX128
-
- TFLOAT32 = types.TFLOAT32
- TFLOAT64 = types.TFLOAT64
-
- TBOOL = types.TBOOL
-
- TPTR = types.TPTR
- TFUNC = types.TFUNC
- TSLICE = types.TSLICE
- TARRAY = types.TARRAY
- TSTRUCT = types.TSTRUCT
- TCHAN = types.TCHAN
- TMAP = types.TMAP
- TINTER = types.TINTER
- TFORW = types.TFORW
- TANY = types.TANY
- TSTRING = types.TSTRING
- TUNSAFEPTR = types.TUNSAFEPTR
-
- // pseudo-types for literals
- TIDEAL = types.TIDEAL
- TNIL = types.TNIL
- TBLANK = types.TBLANK
-
- // pseudo-types for frame layout
- TFUNCARGS = types.TFUNCARGS
- TCHANARGS = types.TCHANARGS
-
- NTYPE = types.NTYPE
-)
// TODO(gri) try to eliminate these soon
package gc
-
-import (
- "cmd/compile/internal/types"
- "unsafe"
-)
-
-func asNode(n *types.Node) *Node { return (*Node)(unsafe.Pointer(n)) }
-func asTypesNode(n *Node) *types.Node { return (*types.Node)(unsafe.Pointer(n)) }
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
)
-// builtinpkg is a fake package that declares the universe block.
-var builtinpkg *types.Pkg
-
var basicTypes = [...]struct {
name string
etype types.EType
}{
- {"int8", TINT8},
- {"int16", TINT16},
- {"int32", TINT32},
- {"int64", TINT64},
- {"uint8", TUINT8},
- {"uint16", TUINT16},
- {"uint32", TUINT32},
- {"uint64", TUINT64},
- {"float32", TFLOAT32},
- {"float64", TFLOAT64},
- {"complex64", TCOMPLEX64},
- {"complex128", TCOMPLEX128},
- {"bool", TBOOL},
- {"string", TSTRING},
+ {"int8", types.TINT8},
+ {"int16", types.TINT16},
+ {"int32", types.TINT32},
+ {"int64", types.TINT64},
+ {"uint8", types.TUINT8},
+ {"uint16", types.TUINT16},
+ {"uint32", types.TUINT32},
+ {"uint64", types.TUINT64},
+ {"float32", types.TFLOAT32},
+ {"float64", types.TFLOAT64},
+ {"complex64", types.TCOMPLEX64},
+ {"complex128", types.TCOMPLEX128},
+ {"bool", types.TBOOL},
+ {"string", types.TSTRING},
}
var typedefs = [...]struct {
sameas32 types.EType
sameas64 types.EType
}{
- {"int", TINT, TINT32, TINT64},
- {"uint", TUINT, TUINT32, TUINT64},
- {"uintptr", TUINTPTR, TUINT32, TUINT64},
+ {"int", types.TINT, types.TINT32, types.TINT64},
+ {"uint", types.TUINT, types.TUINT32, types.TUINT64},
+ {"uintptr", types.TUINTPTR, types.TUINT32, types.TUINT64},
}
var builtinFuncs = [...]struct {
name string
- op Op
+ op ir.Op
}{
- {"append", OAPPEND},
- {"cap", OCAP},
- {"close", OCLOSE},
- {"complex", OCOMPLEX},
- {"copy", OCOPY},
- {"delete", ODELETE},
- {"imag", OIMAG},
- {"len", OLEN},
- {"make", OMAKE},
- {"new", ONEW},
- {"panic", OPANIC},
- {"print", OPRINT},
- {"println", OPRINTN},
- {"real", OREAL},
- {"recover", ORECOVER},
+ {"append", ir.OAPPEND},
+ {"cap", ir.OCAP},
+ {"close", ir.OCLOSE},
+ {"complex", ir.OCOMPLEX},
+ {"copy", ir.OCOPY},
+ {"delete", ir.ODELETE},
+ {"imag", ir.OIMAG},
+ {"len", ir.OLEN},
+ {"make", ir.OMAKE},
+ {"new", ir.ONEW},
+ {"panic", ir.OPANIC},
+ {"print", ir.OPRINT},
+ {"println", ir.OPRINTN},
+ {"real", ir.OREAL},
+ {"recover", ir.ORECOVER},
}
// isBuiltinFuncName reports whether name matches a builtin function
var unsafeFuncs = [...]struct {
name string
- op Op
+ op ir.Op
}{
- {"Alignof", OALIGNOF},
- {"Offsetof", OOFFSETOF},
- {"Sizeof", OSIZEOF},
+ {"Alignof", ir.OALIGNOF},
+ {"Offsetof", ir.OOFFSETOF},
+ {"Sizeof", ir.OSIZEOF},
}
// initUniverse initializes the universe block.
if int(etype) >= len(types.Types) {
base.Fatalf("lexinit: %s bad etype", s.name)
}
- s2 := builtinpkg.Lookup(s.name)
+ s2 := ir.BuiltinPkg.Lookup(s.name)
t := types.Types[etype]
if t == nil {
t = types.New(etype)
t.Sym = s2
- if etype != TANY && etype != TSTRING {
+ if etype != types.TANY && etype != types.TSTRING {
dowidth(t)
}
types.Types[etype] = t
}
- s2.Def = asTypesNode(typenod(t))
- asNode(s2.Def).Name = new(Name)
+ s2.Def = ir.AsTypesNode(typenod(t))
+ ir.AsNode(s2.Def).Name = new(ir.Name)
}
for _, s := range &builtinFuncs {
- s2 := builtinpkg.Lookup(s.name)
- s2.Def = asTypesNode(newname(s2))
- asNode(s2.Def).SetSubOp(s.op)
+ s2 := ir.BuiltinPkg.Lookup(s.name)
+ s2.Def = ir.AsTypesNode(NewName(s2))
+ ir.AsNode(s2.Def).SetSubOp(s.op)
}
for _, s := range &unsafeFuncs {
s2 := unsafepkg.Lookup(s.name)
- s2.Def = asTypesNode(newname(s2))
- asNode(s2.Def).SetSubOp(s.op)
+ s2.Def = ir.AsTypesNode(NewName(s2))
+ ir.AsNode(s2.Def).SetSubOp(s.op)
}
- types.UntypedString = types.New(TSTRING)
- types.UntypedBool = types.New(TBOOL)
- types.Types[TANY] = types.New(TANY)
+ types.UntypedString = types.New(types.TSTRING)
+ types.UntypedBool = types.New(types.TBOOL)
+ types.Types[types.TANY] = types.New(types.TANY)
- s := builtinpkg.Lookup("true")
- s.Def = asTypesNode(nodbool(true))
- asNode(s.Def).Sym = lookup("true")
- asNode(s.Def).Name = new(Name)
- asNode(s.Def).Type = types.UntypedBool
+ s := ir.BuiltinPkg.Lookup("true")
+ s.Def = ir.AsTypesNode(nodbool(true))
+ ir.AsNode(s.Def).Sym = lookup("true")
+ ir.AsNode(s.Def).Name = new(ir.Name)
+ ir.AsNode(s.Def).Type = types.UntypedBool
- s = builtinpkg.Lookup("false")
- s.Def = asTypesNode(nodbool(false))
- asNode(s.Def).Sym = lookup("false")
- asNode(s.Def).Name = new(Name)
- asNode(s.Def).Type = types.UntypedBool
+ s = ir.BuiltinPkg.Lookup("false")
+ s.Def = ir.AsTypesNode(nodbool(false))
+ ir.AsNode(s.Def).Sym = lookup("false")
+ ir.AsNode(s.Def).Name = new(ir.Name)
+ ir.AsNode(s.Def).Type = types.UntypedBool
s = lookup("_")
s.Block = -100
- s.Def = asTypesNode(newname(s))
- types.Types[TBLANK] = types.New(TBLANK)
- asNode(s.Def).Type = types.Types[TBLANK]
- nblank = asNode(s.Def)
+ s.Def = ir.AsTypesNode(NewName(s))
+ types.Types[types.TBLANK] = types.New(types.TBLANK)
+ ir.AsNode(s.Def).Type = types.Types[types.TBLANK]
+ ir.BlankNode = ir.AsNode(s.Def)
- s = builtinpkg.Lookup("_")
+ s = ir.BuiltinPkg.Lookup("_")
s.Block = -100
- s.Def = asTypesNode(newname(s))
- types.Types[TBLANK] = types.New(TBLANK)
- asNode(s.Def).Type = types.Types[TBLANK]
-
- types.Types[TNIL] = types.New(TNIL)
- s = builtinpkg.Lookup("nil")
- s.Def = asTypesNode(nodnil())
- asNode(s.Def).Sym = s
- asNode(s.Def).Name = new(Name)
-
- s = builtinpkg.Lookup("iota")
- s.Def = asTypesNode(nod(OIOTA, nil, nil))
- asNode(s.Def).Sym = s
- asNode(s.Def).Name = new(Name)
+ s.Def = ir.AsTypesNode(NewName(s))
+ types.Types[types.TBLANK] = types.New(types.TBLANK)
+ ir.AsNode(s.Def).Type = types.Types[types.TBLANK]
+
+ types.Types[types.TNIL] = types.New(types.TNIL)
+ s = ir.BuiltinPkg.Lookup("nil")
+ s.Def = ir.AsTypesNode(nodnil())
+ ir.AsNode(s.Def).Sym = s
+ ir.AsNode(s.Def).Name = new(ir.Name)
+
+ s = ir.BuiltinPkg.Lookup("iota")
+ s.Def = ir.AsTypesNode(ir.Nod(ir.OIOTA, nil, nil))
+ ir.AsNode(s.Def).Sym = s
+ ir.AsNode(s.Def).Name = new(ir.Name)
}
func typeinit() {
base.Fatalf("typeinit before betypeinit")
}
- for et := types.EType(0); et < NTYPE; et++ {
+ for et := types.EType(0); et < types.NTYPE; et++ {
simtype[et] = et
}
- types.Types[TPTR] = types.New(TPTR)
- dowidth(types.Types[TPTR])
+ types.Types[types.TPTR] = types.New(types.TPTR)
+ dowidth(types.Types[types.TPTR])
- t := types.New(TUNSAFEPTR)
- types.Types[TUNSAFEPTR] = t
+ t := types.New(types.TUNSAFEPTR)
+ types.Types[types.TUNSAFEPTR] = t
t.Sym = unsafepkg.Lookup("Pointer")
- t.Sym.Def = asTypesNode(typenod(t))
- asNode(t.Sym.Def).Name = new(Name)
- dowidth(types.Types[TUNSAFEPTR])
+ t.Sym.Def = ir.AsTypesNode(typenod(t))
+ ir.AsNode(t.Sym.Def).Name = new(ir.Name)
+ dowidth(types.Types[types.TUNSAFEPTR])
- for et := TINT8; et <= TUINT64; et++ {
+ for et := types.TINT8; et <= types.TUINT64; et++ {
isInt[et] = true
}
- isInt[TINT] = true
- isInt[TUINT] = true
- isInt[TUINTPTR] = true
+ isInt[types.TINT] = true
+ isInt[types.TUINT] = true
+ isInt[types.TUINTPTR] = true
- isFloat[TFLOAT32] = true
- isFloat[TFLOAT64] = true
+ isFloat[types.TFLOAT32] = true
+ isFloat[types.TFLOAT64] = true
- isComplex[TCOMPLEX64] = true
- isComplex[TCOMPLEX128] = true
+ isComplex[types.TCOMPLEX64] = true
+ isComplex[types.TCOMPLEX128] = true
// initialize okfor
- for et := types.EType(0); et < NTYPE; et++ {
- if isInt[et] || et == TIDEAL {
+ for et := types.EType(0); et < types.NTYPE; et++ {
+ if isInt[et] || et == types.TIDEAL {
okforeq[et] = true
okforcmp[et] = true
okforarith[et] = true
okforadd[et] = true
okforand[et] = true
- okforconst[et] = true
+ ir.OKForConst[et] = true
issimple[et] = true
}
okforcmp[et] = true
okforadd[et] = true
okforarith[et] = true
- okforconst[et] = true
+ ir.OKForConst[et] = true
issimple[et] = true
}
okforeq[et] = true
okforadd[et] = true
okforarith[et] = true
- okforconst[et] = true
+ ir.OKForConst[et] = true
issimple[et] = true
}
}
- issimple[TBOOL] = true
+ issimple[types.TBOOL] = true
- okforadd[TSTRING] = true
+ okforadd[types.TSTRING] = true
- okforbool[TBOOL] = true
+ okforbool[types.TBOOL] = true
- okforcap[TARRAY] = true
- okforcap[TCHAN] = true
- okforcap[TSLICE] = true
+ okforcap[types.TARRAY] = true
+ okforcap[types.TCHAN] = true
+ okforcap[types.TSLICE] = true
- okforconst[TBOOL] = true
- okforconst[TSTRING] = true
+ ir.OKForConst[types.TBOOL] = true
+ ir.OKForConst[types.TSTRING] = true
- okforlen[TARRAY] = true
- okforlen[TCHAN] = true
- okforlen[TMAP] = true
- okforlen[TSLICE] = true
- okforlen[TSTRING] = true
+ okforlen[types.TARRAY] = true
+ okforlen[types.TCHAN] = true
+ okforlen[types.TMAP] = true
+ okforlen[types.TSLICE] = true
+ okforlen[types.TSTRING] = true
- okforeq[TPTR] = true
- okforeq[TUNSAFEPTR] = true
- okforeq[TINTER] = true
- okforeq[TCHAN] = true
- okforeq[TSTRING] = true
- okforeq[TBOOL] = true
- okforeq[TMAP] = true // nil only; refined in typecheck
- okforeq[TFUNC] = true // nil only; refined in typecheck
- okforeq[TSLICE] = true // nil only; refined in typecheck
- okforeq[TARRAY] = true // only if element type is comparable; refined in typecheck
- okforeq[TSTRUCT] = true // only if all struct fields are comparable; refined in typecheck
+ okforeq[types.TPTR] = true
+ okforeq[types.TUNSAFEPTR] = true
+ okforeq[types.TINTER] = true
+ okforeq[types.TCHAN] = true
+ okforeq[types.TSTRING] = true
+ okforeq[types.TBOOL] = true
+ okforeq[types.TMAP] = true // nil only; refined in typecheck
+ okforeq[types.TFUNC] = true // nil only; refined in typecheck
+ okforeq[types.TSLICE] = true // nil only; refined in typecheck
+ okforeq[types.TARRAY] = true // only if element type is comparable; refined in typecheck
+ okforeq[types.TSTRUCT] = true // only if all struct fields are comparable; refined in typecheck
- okforcmp[TSTRING] = true
+ okforcmp[types.TSTRING] = true
var i int
for i = 0; i < len(okfor); i++ {
}
// binary
- okfor[OADD] = okforadd[:]
- okfor[OAND] = okforand[:]
- okfor[OANDAND] = okforbool[:]
- okfor[OANDNOT] = okforand[:]
- okfor[ODIV] = okforarith[:]
- okfor[OEQ] = okforeq[:]
- okfor[OGE] = okforcmp[:]
- okfor[OGT] = okforcmp[:]
- okfor[OLE] = okforcmp[:]
- okfor[OLT] = okforcmp[:]
- okfor[OMOD] = okforand[:]
- okfor[OMUL] = okforarith[:]
- okfor[ONE] = okforeq[:]
- okfor[OOR] = okforand[:]
- okfor[OOROR] = okforbool[:]
- okfor[OSUB] = okforarith[:]
- okfor[OXOR] = okforand[:]
- okfor[OLSH] = okforand[:]
- okfor[ORSH] = okforand[:]
+ okfor[ir.OADD] = okforadd[:]
+ okfor[ir.OAND] = okforand[:]
+ okfor[ir.OANDAND] = okforbool[:]
+ okfor[ir.OANDNOT] = okforand[:]
+ okfor[ir.ODIV] = okforarith[:]
+ okfor[ir.OEQ] = okforeq[:]
+ okfor[ir.OGE] = okforcmp[:]
+ okfor[ir.OGT] = okforcmp[:]
+ okfor[ir.OLE] = okforcmp[:]
+ okfor[ir.OLT] = okforcmp[:]
+ okfor[ir.OMOD] = okforand[:]
+ okfor[ir.OMUL] = okforarith[:]
+ okfor[ir.ONE] = okforeq[:]
+ okfor[ir.OOR] = okforand[:]
+ okfor[ir.OOROR] = okforbool[:]
+ okfor[ir.OSUB] = okforarith[:]
+ okfor[ir.OXOR] = okforand[:]
+ okfor[ir.OLSH] = okforand[:]
+ okfor[ir.ORSH] = okforand[:]
// unary
- okfor[OBITNOT] = okforand[:]
- okfor[ONEG] = okforarith[:]
- okfor[ONOT] = okforbool[:]
- okfor[OPLUS] = okforarith[:]
+ okfor[ir.OBITNOT] = okforand[:]
+ okfor[ir.ONEG] = okforarith[:]
+ okfor[ir.ONOT] = okforbool[:]
+ okfor[ir.OPLUS] = okforarith[:]
// special
- okfor[OCAP] = okforcap[:]
- okfor[OLEN] = okforlen[:]
+ okfor[ir.OCAP] = okforcap[:]
+ okfor[ir.OLEN] = okforlen[:]
// comparison
- iscmp[OLT] = true
- iscmp[OGT] = true
- iscmp[OGE] = true
- iscmp[OLE] = true
- iscmp[OEQ] = true
- iscmp[ONE] = true
+ iscmp[ir.OLT] = true
+ iscmp[ir.OGT] = true
+ iscmp[ir.OGE] = true
+ iscmp[ir.OLE] = true
+ iscmp[ir.OEQ] = true
+ iscmp[ir.ONE] = true
- types.Types[TINTER] = types.New(TINTER) // empty interface
+ types.Types[types.TINTER] = types.New(types.TINTER) // empty interface
// simple aliases
- simtype[TMAP] = TPTR
- simtype[TCHAN] = TPTR
- simtype[TFUNC] = TPTR
- simtype[TUNSAFEPTR] = TPTR
+ simtype[types.TMAP] = types.TPTR
+ simtype[types.TCHAN] = types.TPTR
+ simtype[types.TFUNC] = types.TPTR
+ simtype[types.TUNSAFEPTR] = types.TPTR
slicePtrOffset = 0
sliceLenOffset = Rnd(slicePtrOffset+int64(Widthptr), int64(Widthptr))
// string is same as slice wo the cap
sizeofString = Rnd(sliceLenOffset+int64(Widthptr), int64(Widthptr))
- dowidth(types.Types[TSTRING])
+ dowidth(types.Types[types.TSTRING])
dowidth(types.UntypedString)
}
func makeErrorInterface() *types.Type {
sig := functypefield(fakeRecvField(), nil, []*types.Field{
- types.NewField(src.NoXPos, nil, types.Types[TSTRING]),
+ types.NewField(src.NoXPos, nil, types.Types[types.TSTRING]),
})
method := types.NewField(src.NoXPos, lookup("Error"), sig)
- t := types.New(TINTER)
+ t := types.New(types.TINTER)
t.SetInterface([]*types.Field{method})
return t
}
func lexinit1() {
// error type
- s := builtinpkg.Lookup("error")
+ s := ir.BuiltinPkg.Lookup("error")
types.Errortype = makeErrorInterface()
types.Errortype.Sym = s
types.Errortype.Orig = makeErrorInterface()
- s.Def = asTypesNode(typenod(types.Errortype))
+ s.Def = ir.AsTypesNode(typenod(types.Errortype))
dowidth(types.Errortype)
// We create separate byte and rune types for better error messages
// type aliases, albeit at the cost of having to deal with it everywhere).
// byte alias
- s = builtinpkg.Lookup("byte")
- types.Bytetype = types.New(TUINT8)
+ s = ir.BuiltinPkg.Lookup("byte")
+ types.Bytetype = types.New(types.TUINT8)
types.Bytetype.Sym = s
- s.Def = asTypesNode(typenod(types.Bytetype))
- asNode(s.Def).Name = new(Name)
+ s.Def = ir.AsTypesNode(typenod(types.Bytetype))
+ ir.AsNode(s.Def).Name = new(ir.Name)
dowidth(types.Bytetype)
// rune alias
- s = builtinpkg.Lookup("rune")
- types.Runetype = types.New(TINT32)
+ s = ir.BuiltinPkg.Lookup("rune")
+ types.Runetype = types.New(types.TINT32)
types.Runetype.Sym = s
- s.Def = asTypesNode(typenod(types.Runetype))
- asNode(s.Def).Name = new(Name)
+ s.Def = ir.AsTypesNode(typenod(types.Runetype))
+ ir.AsNode(s.Def).Name = new(ir.Name)
dowidth(types.Runetype)
// backend-dependent builtin types (e.g. int).
for _, s := range &typedefs {
- s1 := builtinpkg.Lookup(s.name)
+ s1 := ir.BuiltinPkg.Lookup(s.name)
sameas := s.sameas32
if Widthptr == 8 {
t := types.New(s.etype)
t.Sym = s1
types.Types[s.etype] = t
- s1.Def = asTypesNode(typenod(t))
- asNode(s1.Def).Name = new(Name)
- s1.Origpkg = builtinpkg
+ s1.Def = ir.AsTypesNode(typenod(t))
+ ir.AsNode(s1.Def).Name = new(ir.Name)
+ s1.Origpkg = ir.BuiltinPkg
dowidth(t)
}
// that we silently skip symbols that are already declared in the
// package block rather than emitting a redeclared symbol error.
- for _, s := range builtinpkg.Syms {
+ for _, s := range ir.BuiltinPkg.Syms {
if s.Def == nil {
continue
}
s1.Block = s.Block
}
- nodfp = newname(lookup(".fp"))
- nodfp.Type = types.Types[TINT32]
- nodfp.SetClass(PPARAM)
+ nodfp = NewName(lookup(".fp"))
+ nodfp.Type = types.Types[types.TINT32]
+ nodfp.SetClass(ir.PPARAM)
nodfp.Name.SetUsed(true)
}
package gc
-import "cmd/compile/internal/base"
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+)
// evalunsafe evaluates a package unsafe operation and returns the result.
-func evalunsafe(n *Node) int64 {
+func evalunsafe(n *ir.Node) int64 {
switch n.Op {
- case OALIGNOF, OSIZEOF:
+ case ir.OALIGNOF, ir.OSIZEOF:
n.Left = typecheck(n.Left, ctxExpr)
n.Left = defaultlit(n.Left, nil)
tr := n.Left.Type
return 0
}
dowidth(tr)
- if n.Op == OALIGNOF {
+ if n.Op == ir.OALIGNOF {
return int64(tr.Align)
}
return tr.Width
- case OOFFSETOF:
+ case ir.OOFFSETOF:
// must be a selector.
- if n.Left.Op != OXDOT {
+ if n.Left.Op != ir.OXDOT {
base.Errorf("invalid expression %v", n)
return 0
}
return 0
}
switch n.Left.Op {
- case ODOT, ODOTPTR:
+ case ir.ODOT, ir.ODOTPTR:
break
- case OCALLPART:
+ case ir.OCALLPART:
base.Errorf("invalid expression %v: argument is a method value", n)
return 0
default:
var v int64
for r := n.Left; r != sbase; r = r.Left {
switch r.Op {
- case ODOTPTR:
+ case ir.ODOTPTR:
// For Offsetof(s.f), s may itself be a pointer,
// but accessing f must not otherwise involve
// indirection via embedded pointer types.
return 0
}
fallthrough
- case ODOT:
+ case ir.ODOT:
v += r.Xoffset
default:
- Dump("unsafenmagic", n.Left)
+ ir.Dump("unsafenmagic", n.Left)
base.Fatalf("impossible %#v node after dot insertion", r.Op)
}
}
"cmd/compile/internal/base"
)
-// Line returns n's position as a string. If n has been inlined,
-// it uses the outermost position where n has been inlined.
-func (n *Node) Line() string {
- return base.FmtPos(n.Pos)
-}
-
var (
memprofilerate int64
traceHandler func(string)
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/objabi"
const tmpstringbufsize = 32
const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
-func walk(fn *Node) {
+func walk(fn *ir.Node) {
Curfn = fn
errorsBefore := base.Errors()
if base.Flag.W != 0 {
s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym)
- dumplist(s, Curfn.Nbody)
+ ir.DumpList(s, Curfn.Nbody)
}
lno := base.Pos
// Final typecheck for any unused variables.
for i, ln := range fn.Func.Dcl {
- if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) {
+ if ln.Op == ir.ONAME && (ln.Class() == ir.PAUTO || ln.Class() == ir.PAUTOHEAP) {
ln = typecheck(ln, ctxExpr|ctxAssign)
fn.Func.Dcl[i] = ln
}
// Propagate the used flag for typeswitch variables up to the NONAME in its definition.
for _, ln := range fn.Func.Dcl {
- if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Name.Used() {
+ if ln.Op == ir.ONAME && (ln.Class() == ir.PAUTO || ln.Class() == ir.PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == ir.OTYPESW && ln.Name.Used() {
ln.Name.Defn.Left.Name.SetUsed(true)
}
}
for _, ln := range fn.Func.Dcl {
- if ln.Op != ONAME || (ln.Class() != PAUTO && ln.Class() != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Name.Used() {
+ if ln.Op != ir.ONAME || (ln.Class() != ir.PAUTO && ln.Class() != ir.PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Name.Used() {
continue
}
- if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
+ if defn := ln.Name.Defn; defn != nil && defn.Op == ir.OTYPESW {
if defn.Left.Name.Used() {
continue
}
walkstmtlist(Curfn.Nbody.Slice())
if base.Flag.W != 0 {
s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
- dumplist(s, Curfn.Nbody)
+ ir.DumpList(s, Curfn.Nbody)
}
zeroResults()
heapmoves()
if base.Flag.W != 0 && Curfn.Func.Enter.Len() > 0 {
s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
- dumplist(s, Curfn.Func.Enter)
+ ir.DumpList(s, Curfn.Func.Enter)
}
}
-func walkstmtlist(s []*Node) {
+func walkstmtlist(s []*ir.Node) {
for i := range s {
s[i] = walkstmt(s[i])
}
}
-func paramoutheap(fn *Node) bool {
+func paramoutheap(fn *ir.Node) bool {
for _, ln := range fn.Func.Dcl {
switch ln.Class() {
- case PPARAMOUT:
- if ln.isParamStackCopy() || ln.Name.Addrtaken() {
+ case ir.PPARAMOUT:
+ if isParamStackCopy(ln) || ln.Name.Addrtaken() {
return true
}
- case PAUTO:
+ case ir.PAUTO:
// stop early - parameters are over
return false
}
// The result of walkstmt MUST be assigned back to n, e.g.
// n.Left = walkstmt(n.Left)
-func walkstmt(n *Node) *Node {
+func walkstmt(n *ir.Node) *ir.Node {
if n == nil {
return n
}
switch n.Op {
default:
- if n.Op == ONAME {
+ if n.Op == ir.ONAME {
base.Errorf("%v is not a top level statement", n.Sym)
} else {
base.Errorf("%v is not a top level statement", n.Op)
}
- Dump("nottop", n)
-
- case OAS,
- OASOP,
- OAS2,
- OAS2DOTTYPE,
- OAS2RECV,
- OAS2FUNC,
- OAS2MAPR,
- OCLOSE,
- OCOPY,
- OCALLMETH,
- OCALLINTER,
- OCALL,
- OCALLFUNC,
- ODELETE,
- OSEND,
- OPRINT,
- OPRINTN,
- OPANIC,
- OEMPTY,
- ORECOVER,
- OGETG:
+ ir.Dump("nottop", n)
+
+ case ir.OAS,
+ ir.OASOP,
+ ir.OAS2,
+ ir.OAS2DOTTYPE,
+ ir.OAS2RECV,
+ ir.OAS2FUNC,
+ ir.OAS2MAPR,
+ ir.OCLOSE,
+ ir.OCOPY,
+ ir.OCALLMETH,
+ ir.OCALLINTER,
+ ir.OCALL,
+ ir.OCALLFUNC,
+ ir.ODELETE,
+ ir.OSEND,
+ ir.OPRINT,
+ ir.OPRINTN,
+ ir.OPANIC,
+ ir.OEMPTY,
+ ir.ORECOVER,
+ ir.OGETG:
if n.Typecheck() == 0 {
base.Fatalf("missing typecheck: %+v", n)
}
- wascopy := n.Op == OCOPY
+ wascopy := n.Op == ir.OCOPY
init := n.Ninit
n.Ninit.Set(nil)
n = walkexpr(n, &init)
n = addinit(n, init.Slice())
- if wascopy && n.Op == OCONVNOP {
- n.Op = OEMPTY // don't leave plain values as statements.
+ if wascopy && n.Op == ir.OCONVNOP {
+ n.Op = ir.OEMPTY // don't leave plain values as statements.
}
// special case for a receive where we throw away
// the value received.
- case ORECV:
+ case ir.ORECV:
if n.Typecheck() == 0 {
base.Fatalf("missing typecheck: %+v", n)
}
n = addinit(n, init.Slice())
- case OBREAK,
- OCONTINUE,
- OFALL,
- OGOTO,
- OLABEL,
- ODCLCONST,
- ODCLTYPE,
- OCHECKNIL,
- OVARDEF,
- OVARKILL,
- OVARLIVE:
+ case ir.OBREAK,
+ ir.OCONTINUE,
+ ir.OFALL,
+ ir.OGOTO,
+ ir.OLABEL,
+ ir.ODCLCONST,
+ ir.ODCLTYPE,
+ ir.OCHECKNIL,
+ ir.OVARDEF,
+ ir.OVARKILL,
+ ir.OVARLIVE:
break
- case ODCL:
+ case ir.ODCL:
v := n.Left
- if v.Class() == PAUTOHEAP {
+ if v.Class() == ir.PAUTOHEAP {
if base.Flag.CompilingRuntime {
base.Errorf("%v escapes to heap, not allowed in runtime", v)
}
if prealloc[v] == nil {
prealloc[v] = callnew(v.Type)
}
- nn := nod(OAS, v.Name.Param.Heapaddr, prealloc[v])
+ nn := ir.Nod(ir.OAS, v.Name.Param.Heapaddr, prealloc[v])
nn.SetColas(true)
nn = typecheck(nn, ctxStmt)
return walkstmt(nn)
}
- case OBLOCK:
+ case ir.OBLOCK:
walkstmtlist(n.List.Slice())
- case OCASE:
+ case ir.OCASE:
base.Errorf("case statement out of place")
- case ODEFER:
+ case ir.ODEFER:
Curfn.Func.SetHasDefer(true)
- Curfn.Func.numDefers++
- if Curfn.Func.numDefers > maxOpenDefers {
+ Curfn.Func.NumDefers++
+ if Curfn.Func.NumDefers > maxOpenDefers {
// Don't allow open-coded defers if there are more than
// 8 defers in the function, since we use a single
// byte to record active defers.
Curfn.Func.SetOpenCodedDeferDisallowed(true)
}
fallthrough
- case OGO:
+ case ir.OGO:
switch n.Left.Op {
- case OPRINT, OPRINTN:
+ case ir.OPRINT, ir.OPRINTN:
n.Left = wrapCall(n.Left, &n.Ninit)
- case ODELETE:
+ case ir.ODELETE:
if mapfast(n.Left.List.First().Type) == mapslow {
n.Left = wrapCall(n.Left, &n.Ninit)
} else {
n.Left = walkexpr(n.Left, &n.Ninit)
}
- case OCOPY:
+ case ir.OCOPY:
n.Left = copyany(n.Left, &n.Ninit, true)
- case OCALLFUNC, OCALLMETH, OCALLINTER:
+ case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
if n.Left.Nbody.Len() > 0 {
n.Left = wrapCall(n.Left, &n.Ninit)
} else {
n.Left = walkexpr(n.Left, &n.Ninit)
}
- case OFOR, OFORUNTIL:
+ case ir.OFOR, ir.OFORUNTIL:
if n.Left != nil {
walkstmtlist(n.Left.Ninit.Slice())
init := n.Left.Ninit
}
n.Right = walkstmt(n.Right)
- if n.Op == OFORUNTIL {
+ if n.Op == ir.OFORUNTIL {
walkstmtlist(n.List.Slice())
}
walkstmtlist(n.Nbody.Slice())
- case OIF:
+ case ir.OIF:
n.Left = walkexpr(n.Left, &n.Ninit)
walkstmtlist(n.Nbody.Slice())
walkstmtlist(n.Rlist.Slice())
- case ORETURN:
- Curfn.Func.numReturns++
+ case ir.ORETURN:
+ Curfn.Func.NumReturns++
if n.List.Len() == 0 {
break
}
if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
// assign to the function out parameters,
// so that reorder3 can fix up conflicts
- var rl []*Node
+ var rl []*ir.Node
for _, ln := range Curfn.Func.Dcl {
cl := ln.Class()
- if cl == PAUTO || cl == PAUTOHEAP {
+ if cl == ir.PAUTO || cl == ir.PAUTOHEAP {
break
}
- if cl == PPARAMOUT {
- if ln.isParamStackCopy() {
- ln = walkexpr(typecheck(nod(ODEREF, ln.Name.Param.Heapaddr, nil), ctxExpr), nil)
+ if cl == ir.PPARAMOUT {
+ if isParamStackCopy(ln) {
+ ln = walkexpr(typecheck(ir.Nod(ir.ODEREF, ln.Name.Param.Heapaddr, nil), ctxExpr), nil)
}
rl = append(rl, ln)
}
// For each return parameter (lhs), assign the corresponding result (rhs).
lhs := Curfn.Type.Results()
rhs := n.List.Slice()
- res := make([]*Node, lhs.NumFields())
+ res := make([]*ir.Node, lhs.NumFields())
for i, nl := range lhs.FieldSlice() {
- nname := asNode(nl.Nname)
- if nname.isParamHeapCopy() {
+ nname := ir.AsNode(nl.Nname)
+ if isParamHeapCopy(nname) {
nname = nname.Name.Param.Stackcopy
}
- a := nod(OAS, nname, rhs[i])
+ a := ir.Nod(ir.OAS, nname, rhs[i])
res[i] = convas(a, &n.Ninit)
}
n.List.Set(res)
- case ORETJMP:
+ case ir.ORETJMP:
break
- case OINLMARK:
+ case ir.OINLMARK:
break
- case OSELECT:
+ case ir.OSELECT:
walkselect(n)
- case OSWITCH:
+ case ir.OSWITCH:
walkswitch(n)
- case ORANGE:
+ case ir.ORANGE:
n = walkrange(n)
}
- if n.Op == ONAME {
+ if n.Op == ir.ONAME {
base.Fatalf("walkstmt ended up with name: %+v", n)
}
return n
// the types expressions are calculated.
// compile-time constants are evaluated.
// complex side effects like statements are appended to init
-func walkexprlist(s []*Node, init *Nodes) {
+func walkexprlist(s []*ir.Node, init *ir.Nodes) {
for i := range s {
s[i] = walkexpr(s[i], init)
}
}
-func walkexprlistsafe(s []*Node, init *Nodes) {
+func walkexprlistsafe(s []*ir.Node, init *ir.Nodes) {
for i, n := range s {
s[i] = safeexpr(n, init)
s[i] = walkexpr(s[i], init)
}
}
-func walkexprlistcheap(s []*Node, init *Nodes) {
+func walkexprlistcheap(s []*ir.Node, init *ir.Nodes) {
for i, n := range s {
s[i] = cheapexpr(n, init)
s[i] = walkexpr(s[i], init)
return "convT16", false
case from.Size() == 4 && from.Align == 4 && !from.HasPointers():
return "convT32", false
- case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !from.HasPointers():
+ case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers():
return "convT64", false
}
if sc := from.SoleComponent(); sc != nil {
// The result of walkexpr MUST be assigned back to n, e.g.
// n.Left = walkexpr(n.Left, init)
-func walkexpr(n *Node, init *Nodes) *Node {
+func walkexpr(n *ir.Node, init *ir.Nodes) *ir.Node {
if n == nil {
return n
}
// Eagerly checkwidth all expressions for the back end.
if n.Type != nil && !n.Type.WidthCalculated() {
switch n.Type.Etype {
- case TBLANK, TNIL, TIDEAL:
+ case types.TBLANK, types.TNIL, types.TIDEAL:
default:
checkwidth(n.Type)
}
lno := setlineno(n)
if base.Flag.LowerW > 1 {
- Dump("before walk expr", n)
+ ir.Dump("before walk expr", n)
}
if n.Typecheck() != 1 {
base.Fatalf("expression has untyped type: %+v", n)
}
- if n.Op == ONAME && n.Class() == PAUTOHEAP {
- nn := nod(ODEREF, n.Name.Param.Heapaddr, nil)
+ if n.Op == ir.ONAME && n.Class() == ir.PAUTOHEAP {
+ nn := ir.Nod(ir.ODEREF, n.Name.Param.Heapaddr, nil)
nn = typecheck(nn, ctxExpr)
nn = walkexpr(nn, init)
nn.Left.MarkNonNil()
opswitch:
switch n.Op {
default:
- Dump("walk", n)
+ ir.Dump("walk", n)
base.Fatalf("walkexpr: switch 1 unknown op %+S", n)
- case ONONAME, OEMPTY, OGETG, ONEWOBJ, OMETHEXPR:
+ case ir.ONONAME, ir.OEMPTY, ir.OGETG, ir.ONEWOBJ, ir.OMETHEXPR:
- case OTYPE, ONAME, OLITERAL, ONIL:
+ case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL:
// TODO(mdempsky): Just return n; see discussion on CL 38655.
// Perhaps refactor to use Node.mayBeShared for these instead.
// If these return early, make sure to still call
// stringsym for constant strings.
- case ONOT, ONEG, OPLUS, OBITNOT, OREAL, OIMAG, ODOTMETH, ODOTINTER,
- ODEREF, OSPTR, OITAB, OIDATA, OADDR:
+ case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.ODOTMETH, ir.ODOTINTER,
+ ir.ODEREF, ir.OSPTR, ir.OITAB, ir.OIDATA, ir.OADDR:
n.Left = walkexpr(n.Left, init)
- case OEFACE, OAND, OANDNOT, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH:
+ case ir.OEFACE, ir.OAND, ir.OANDNOT, ir.OSUB, ir.OMUL, ir.OADD, ir.OOR, ir.OXOR, ir.OLSH, ir.ORSH:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
- case ODOT, ODOTPTR:
+ case ir.ODOT, ir.ODOTPTR:
usefield(n)
n.Left = walkexpr(n.Left, init)
- case ODOTTYPE, ODOTTYPE2:
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
n.Left = walkexpr(n.Left, init)
// Set up interface type addresses for back end.
n.Right = typename(n.Type)
- if n.Op == ODOTTYPE {
+ if n.Op == ir.ODOTTYPE {
n.Right.Right = typename(n.Left.Type)
}
if !n.Type.IsInterface() && !n.Left.Type.IsEmptyInterface() {
n.List.Set1(itabname(n.Type, n.Left.Type))
}
- case OLEN, OCAP:
+ case ir.OLEN, ir.OCAP:
if isRuneCount(n) {
// Replace len([]rune(string)) with runtime.countrunes(string).
- n = mkcall("countrunes", n.Type, init, conv(n.Left.Left, types.Types[TSTRING]))
+ n = mkcall("countrunes", n.Type, init, conv(n.Left.Left, types.Types[types.TSTRING]))
break
}
n.SetTypecheck(1)
}
- case OCOMPLEX:
+ case ir.OCOMPLEX:
// Use results from call expression as arguments for complex.
if n.Left == nil && n.Right == nil {
n.Left = n.List.First()
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
- case OEQ, ONE, OLT, OLE, OGT, OGE:
+ case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
n = walkcompare(n, init)
- case OANDAND, OOROR:
+ case ir.OANDAND, ir.OOROR:
n.Left = walkexpr(n.Left, init)
// cannot put side effects from n.Right on init,
// because they cannot run before n.Left is checked.
// save elsewhere and store on the eventual n.Right.
- var ll Nodes
+ var ll ir.Nodes
n.Right = walkexpr(n.Right, &ll)
n.Right = addinit(n.Right, ll.Slice())
- case OPRINT, OPRINTN:
+ case ir.OPRINT, ir.OPRINTN:
n = walkprint(n, init)
- case OPANIC:
+ case ir.OPANIC:
n = mkcall("gopanic", nil, init, n.Left)
- case ORECOVER:
- n = mkcall("gorecover", n.Type, init, nod(OADDR, nodfp, nil))
+ case ir.ORECOVER:
+ n = mkcall("gorecover", n.Type, init, ir.Nod(ir.OADDR, nodfp, nil))
- case OCLOSUREVAR, OCFUNC:
+ case ir.OCLOSUREVAR, ir.OCFUNC:
- case OCALLINTER, OCALLFUNC, OCALLMETH:
- if n.Op == OCALLINTER {
+ case ir.OCALLINTER, ir.OCALLFUNC, ir.OCALLMETH:
+ if n.Op == ir.OCALLINTER {
usemethod(n)
markUsedIfaceMethod(n)
}
- if n.Op == OCALLFUNC && n.Left.Op == OCLOSURE {
+ if n.Op == ir.OCALLFUNC && n.Left.Op == ir.OCLOSURE {
// Transform direct call of a closure to call of a normal function.
// transformclosure already did all preparation work.
walkCall(n, init)
- case OAS, OASOP:
+ case ir.OAS, ir.OASOP:
init.AppendNodes(&n.Ninit)
// Recognize m[k] = append(m[k], ...) so we can reuse
// the mapassign call.
- mapAppend := n.Left.Op == OINDEXMAP && n.Right.Op == OAPPEND
+ mapAppend := n.Left.Op == ir.OINDEXMAP && n.Right.Op == ir.OAPPEND
if mapAppend && !samesafeexpr(n.Left, n.Right.List.First()) {
base.Fatalf("not same expressions: %v != %v", n.Left, n.Right.List.First())
}
n.Right.List.SetFirst(n.Left)
}
- if n.Op == OASOP {
+ if n.Op == ir.OASOP {
// Rewrite x op= y into x = x op y.
- n.Right = nod(n.SubOp(), n.Left, n.Right)
+ n.Right = ir.Nod(n.SubOp(), n.Left, n.Right)
n.Right = typecheck(n.Right, ctxExpr)
- n.Op = OAS
+ n.Op = ir.OAS
n.ResetAux()
}
default:
n.Right = walkexpr(n.Right, init)
- case ORECV:
+ case ir.ORECV:
// x = <-c; n.Left is x, n.Right.Left is c.
// order.stmt made sure x is addressable.
n.Right.Left = walkexpr(n.Right.Left, init)
- n1 := nod(OADDR, n.Left, nil)
+ n1 := ir.Nod(ir.OADDR, n.Left, nil)
r := n.Right.Left // the channel
n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, r, n1)
n = walkexpr(n, init)
break opswitch
- case OAPPEND:
+ case ir.OAPPEND:
// x = append(...)
r := n.Right
if r.Type.Elem().NotInHeap() {
r = walkappend(r, init, n)
}
n.Right = r
- if r.Op == OAPPEND {
+ if r.Op == ir.OAPPEND {
// Left in place for back end.
// Do not add a new write barrier.
// Set up address of type for back end.
n = convas(n, init)
}
- case OAS2:
+ case ir.OAS2:
init.AppendNodes(&n.Ninit)
walkexprlistsafe(n.List.Slice(), init)
walkexprlistsafe(n.Rlist.Slice(), init)
- ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
+ ll := ascompatee(ir.OAS, n.List.Slice(), n.Rlist.Slice(), init)
ll = reorder3(ll)
n = liststmt(ll)
// a,b,... = fn()
- case OAS2FUNC:
+ case ir.OAS2FUNC:
init.AppendNodes(&n.Ninit)
r := n.Right
// x, y = <-c
// order.stmt made sure x is addressable or blank.
- case OAS2RECV:
+ case ir.OAS2RECV:
init.AppendNodes(&n.Ninit)
r := n.Right
walkexprlistsafe(n.List.Slice(), init)
r.Left = walkexpr(r.Left, init)
- var n1 *Node
- if n.List.First().isBlank() {
+ var n1 *ir.Node
+ if ir.IsBlank(n.List.First()) {
n1 = nodnil()
} else {
- n1 = nod(OADDR, n.List.First(), nil)
+ n1 = ir.Nod(ir.OADDR, n.List.First(), nil)
}
fn := chanfn("chanrecv2", 2, r.Left.Type)
ok := n.List.Second()
- call := mkcall1(fn, types.Types[TBOOL], init, r.Left, n1)
- n = nod(OAS, ok, call)
+ call := mkcall1(fn, types.Types[types.TBOOL], init, r.Left, n1)
+ n = ir.Nod(ir.OAS, ok, call)
n = typecheck(n, ctxStmt)
// a,b = m[i]
- case OAS2MAPR:
+ case ir.OAS2MAPR:
init.AppendNodes(&n.Ninit)
r := n.Right
t := r.Left.Type
fast := mapfast(t)
- var key *Node
+ var key *ir.Node
if fast != mapslow {
// fast versions take key by value
key = r.Right
} else {
// standard version takes key by reference
// order.expr made sure key is addressable.
- key = nod(OADDR, r.Right, nil)
+ key = ir.Nod(ir.OADDR, r.Right, nil)
}
// from:
// mapaccess2* returns a typed bool, but due to spec changes,
// the boolean result of i.(T) is now untyped so we make it the
// same type as the variable on the lhs.
- if ok := n.List.Second(); !ok.isBlank() && ok.Type.IsBoolean() {
+ if ok := n.List.Second(); !ir.IsBlank(ok) && ok.Type.IsBoolean() {
r.Type.Field(1).Type = ok.Type
}
n.Right = r
- n.Op = OAS2FUNC
+ n.Op = ir.OAS2FUNC
// don't generate a = *var if a is _
- if !a.isBlank() {
+ if !ir.IsBlank(a) {
var_ := temp(types.NewPtr(t.Elem()))
var_.SetTypecheck(1)
var_.MarkNonNil() // mapaccess always returns a non-nil pointer
n.List.SetFirst(var_)
n = walkexpr(n, init)
init.Append(n)
- n = nod(OAS, a, nod(ODEREF, var_, nil))
+ n = ir.Nod(ir.OAS, a, ir.Nod(ir.ODEREF, var_, nil))
}
n = typecheck(n, ctxStmt)
n = walkexpr(n, init)
- case ODELETE:
+ case ir.ODELETE:
init.AppendNodes(&n.Ninit)
map_ := n.List.First()
key := n.List.Second()
fast := mapfast(t)
if fast == mapslow {
// order.stmt made sure key is addressable.
- key = nod(OADDR, key, nil)
+ key = ir.Nod(ir.OADDR, key, nil)
}
n = mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
- case OAS2DOTTYPE:
+ case ir.OAS2DOTTYPE:
walkexprlistsafe(n.List.Slice(), init)
n.Right = walkexpr(n.Right, init)
- case OCONVIFACE:
+ case ir.OCONVIFACE:
n.Left = walkexpr(n.Left, init)
fromType := n.Left.Type
toType := n.Type
- if !fromType.IsInterface() && !Curfn.Func.Nname.isBlank() { // skip unnamed functions (func _())
- markTypeUsedInInterface(fromType, Curfn.Func.lsym)
+ if !fromType.IsInterface() && !ir.IsBlank(Curfn.Func.Nname) { // skip unnamed functions (func _())
+ markTypeUsedInInterface(fromType, Curfn.Func.LSym)
}
// typeword generates the type word of the interface value.
- typeword := func() *Node {
+ typeword := func() *ir.Node {
if toType.IsEmptyInterface() {
return typename(fromType)
}
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
if isdirectiface(fromType) {
- l := nod(OEFACE, typeword(), n.Left)
+ l := ir.Nod(ir.OEFACE, typeword(), n.Left)
l.Type = toType
l.SetTypecheck(n.Typecheck())
n = l
}
if staticuint64s == nil {
- staticuint64s = newname(Runtimepkg.Lookup("staticuint64s"))
- staticuint64s.SetClass(PEXTERN)
+ staticuint64s = NewName(Runtimepkg.Lookup("staticuint64s"))
+ staticuint64s.SetClass(ir.PEXTERN)
// The actual type is [256]uint64, but we use [256*8]uint8 so we can address
// individual bytes.
- staticuint64s.Type = types.NewArray(types.Types[TUINT8], 256*8)
- zerobase = newname(Runtimepkg.Lookup("zerobase"))
- zerobase.SetClass(PEXTERN)
- zerobase.Type = types.Types[TUINTPTR]
+ staticuint64s.Type = types.NewArray(types.Types[types.TUINT8], 256*8)
+ zerobase = NewName(Runtimepkg.Lookup("zerobase"))
+ zerobase.SetClass(ir.PEXTERN)
+ zerobase.Type = types.Types[types.TUINTPTR]
}
// Optimize convT2{E,I} for many cases in which T is not pointer-shaped,
// by using an existing addressable value identical to n.Left
// or creating one on the stack.
- var value *Node
+ var value *ir.Node
switch {
case fromType.Size() == 0:
// n.Left is zero-sized. Use zerobase.
// and staticuint64s[n.Left * 8 + 7] on big-endian.
n.Left = cheapexpr(n.Left, init)
// byteindex widens n.Left so that the multiplication doesn't overflow.
- index := nod(OLSH, byteindex(n.Left), nodintconst(3))
+ index := ir.Nod(ir.OLSH, byteindex(n.Left), nodintconst(3))
if thearch.LinkArch.ByteOrder == binary.BigEndian {
- index = nod(OADD, index, nodintconst(7))
+ index = ir.Nod(ir.OADD, index, nodintconst(7))
}
- value = nod(OINDEX, staticuint64s, index)
+ value = ir.Nod(ir.OINDEX, staticuint64s, index)
value.SetBounded(true)
- case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
+ case n.Left.Class() == ir.PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
// n.Left is a readonly global; use it directly.
value = n.Left
case !fromType.IsInterface() && n.Esc == EscNone && fromType.Width <= 1024:
// n.Left does not escape. Use a stack temporary initialized to n.Left.
value = temp(fromType)
- init.Append(typecheck(nod(OAS, value, n.Left), ctxStmt))
+ init.Append(typecheck(ir.Nod(ir.OAS, value, n.Left), ctxStmt))
}
if value != nil {
// Value is identical to n.Left.
// Construct the interface directly: {type/itab, &value}.
- l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), ctxExpr))
+ l := ir.Nod(ir.OEFACE, typeword(), typecheck(ir.Nod(ir.OADDR, value, nil), ctxExpr))
l.Type = toType
l.SetTypecheck(n.Typecheck())
n = l
if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
// Evaluate the input interface.
c := temp(fromType)
- init.Append(nod(OAS, c, n.Left))
+ init.Append(ir.Nod(ir.OAS, c, n.Left))
// Get the itab out of the interface.
- tmp := temp(types.NewPtr(types.Types[TUINT8]))
- init.Append(nod(OAS, tmp, typecheck(nod(OITAB, c, nil), ctxExpr)))
+ tmp := temp(types.NewPtr(types.Types[types.TUINT8]))
+ init.Append(ir.Nod(ir.OAS, tmp, typecheck(ir.Nod(ir.OITAB, c, nil), ctxExpr)))
// Get the type out of the itab.
- nif := nod(OIF, typecheck(nod(ONE, tmp, nodnil()), ctxExpr), nil)
- nif.Nbody.Set1(nod(OAS, tmp, itabType(tmp)))
+ nif := ir.Nod(ir.OIF, typecheck(ir.Nod(ir.ONE, tmp, nodnil()), ctxExpr), nil)
+ nif.Nbody.Set1(ir.Nod(ir.OAS, tmp, itabType(tmp)))
init.Append(nif)
// Build the result.
- e := nod(OEFACE, tmp, ifaceData(n.Pos, c, types.NewPtr(types.Types[TUINT8])))
+ e := ir.Nod(ir.OEFACE, tmp, ifaceData(n.Pos, c, types.NewPtr(types.Types[types.TUINT8])))
e.Type = toType // assign type manually, typecheck doesn't understand OEFACE.
e.SetTypecheck(1)
n = e
dowidth(fromType)
fn = substArgTypes(fn, fromType)
dowidth(fn.Type)
- call := nod(OCALL, fn, nil)
+ call := ir.Nod(ir.OCALL, fn, nil)
call.List.Set1(n.Left)
call = typecheck(call, ctxExpr)
call = walkexpr(call, init)
call = safeexpr(call, init)
- e := nod(OEFACE, typeword(), call)
+ e := ir.Nod(ir.OEFACE, typeword(), call)
e.Type = toType
e.SetTypecheck(1)
n = e
break
}
- var tab *Node
+ var tab *ir.Node
if fromType.IsInterface() {
// convI2I
tab = typename(toType)
if !islvalue(v) {
v = copyexpr(v, v.Type, init)
}
- v = nod(OADDR, v, nil)
+ v = ir.Nod(ir.OADDR, v, nil)
}
dowidth(fromType)
fn := syslook(fnname)
fn = substArgTypes(fn, fromType, toType)
dowidth(fn.Type)
- n = nod(OCALL, fn, nil)
+ n = ir.Nod(ir.OCALL, fn, nil)
n.List.Set2(tab, v)
n = typecheck(n, ctxExpr)
n = walkexpr(n, init)
- case OCONV, OCONVNOP:
+ case ir.OCONV, ir.OCONVNOP:
n.Left = walkexpr(n.Left, init)
- if n.Op == OCONVNOP && checkPtr(Curfn, 1) {
+ if n.Op == ir.OCONVNOP && checkPtr(Curfn, 1) {
if n.Type.IsPtr() && n.Left.Type.IsUnsafePtr() { // unsafe.Pointer to *T
n = walkCheckPtrAlignment(n, init, nil)
break
}
}
param, result := rtconvfn(n.Left.Type, n.Type)
- if param == Txxx {
+ if param == types.Txxx {
break
}
- fn := basicnames[param] + "to" + basicnames[result]
+ fn := ir.BasicTypeNames[param] + "to" + ir.BasicTypeNames[result]
n = conv(mkcall(fn, types.Types[result], init, conv(n.Left, types.Types[param])), n.Type)
- case ODIV, OMOD:
+ case ir.ODIV, ir.OMOD:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
// rewrite complex div into function call.
et := n.Left.Type.Etype
- if isComplex[et] && n.Op == ODIV {
+ if isComplex[et] && n.Op == ir.ODIV {
t := n.Type
- n = mkcall("complex128div", types.Types[TCOMPLEX128], init, conv(n.Left, types.Types[TCOMPLEX128]), conv(n.Right, types.Types[TCOMPLEX128]))
+ n = mkcall("complex128div", types.Types[types.TCOMPLEX128], init, conv(n.Left, types.Types[types.TCOMPLEX128]), conv(n.Right, types.Types[types.TCOMPLEX128]))
n = conv(n, t)
break
}
// rewrite 64-bit div and mod on 32-bit architectures.
// TODO: Remove this code once we can introduce
// runtime calls late in SSA processing.
- if Widthreg < 8 && (et == TINT64 || et == TUINT64) {
- if n.Right.Op == OLITERAL {
+ if Widthreg < 8 && (et == types.TINT64 || et == types.TUINT64) {
+ if n.Right.Op == ir.OLITERAL {
// Leave div/mod by constant powers of 2 or small 16-bit constants.
// The SSA backend will handle those.
switch et {
- case TINT64:
+ case types.TINT64:
c := n.Right.Int64Val()
if c < 0 {
c = -c
if c != 0 && c&(c-1) == 0 {
break opswitch
}
- case TUINT64:
+ case types.TUINT64:
c := n.Right.Uint64Val()
if c < 1<<16 {
break opswitch
}
}
var fn string
- if et == TINT64 {
+ if et == types.TINT64 {
fn = "int64"
} else {
fn = "uint64"
}
- if n.Op == ODIV {
+ if n.Op == ir.ODIV {
fn += "div"
} else {
fn += "mod"
n = mkcall(fn, n.Type, init, conv(n.Left, types.Types[et]), conv(n.Right, types.Types[et]))
}
- case OINDEX:
+ case ir.OINDEX:
n.Left = walkexpr(n.Left, init)
// save the original node for bounds checking elision.
}
if t.IsArray() {
n.SetBounded(bounded(r, t.NumElem()))
- if base.Flag.LowerM != 0 && n.Bounded() && !Isconst(n.Right, constant.Int) {
+ if base.Flag.LowerM != 0 && n.Bounded() && !ir.IsConst(n.Right, constant.Int) {
base.Warn("index bounds check elided")
}
if smallintconst(n.Right) && !n.Bounded() {
base.Errorf("index out of bounds")
}
- } else if Isconst(n.Left, constant.String) {
+ } else if ir.IsConst(n.Left, constant.String) {
n.SetBounded(bounded(r, int64(len(n.Left.StringVal()))))
- if base.Flag.LowerM != 0 && n.Bounded() && !Isconst(n.Right, constant.Int) {
+ if base.Flag.LowerM != 0 && n.Bounded() && !ir.IsConst(n.Right, constant.Int) {
base.Warn("index bounds check elided")
}
if smallintconst(n.Right) && !n.Bounded() {
}
}
- if Isconst(n.Right, constant.Int) {
- if v := n.Right.Val(); constant.Sign(v) < 0 || doesoverflow(v, types.Types[TINT]) {
+ if ir.IsConst(n.Right, constant.Int) {
+ if v := n.Right.Val(); constant.Sign(v) < 0 || doesoverflow(v, types.Types[types.TINT]) {
base.Errorf("index out of bounds")
}
}
- case OINDEXMAP:
+ case ir.OINDEXMAP:
// Replace m[k] with *map{access1,assign}(maptype, m, &k)
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
if fast == mapslow {
// standard version takes key by reference.
// order.expr made sure key is addressable.
- key = nod(OADDR, key, nil)
+ key = ir.Nod(ir.OADDR, key, nil)
}
n = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)
} else {
if fast == mapslow {
// standard version takes key by reference.
// order.expr made sure key is addressable.
- key = nod(OADDR, key, nil)
+ key = ir.Nod(ir.OADDR, key, nil)
}
if w := t.Elem().Width; w <= zeroValSize {
}
n.Type = types.NewPtr(t.Elem())
n.MarkNonNil() // mapaccess1* and mapassign always return non-nil pointers.
- n = nod(ODEREF, n, nil)
+ n = ir.Nod(ir.ODEREF, n, nil)
n.Type = t.Elem()
n.SetTypecheck(1)
- case ORECV:
+ case ir.ORECV:
base.Fatalf("walkexpr ORECV") // should see inside OAS only
- case OSLICEHEADER:
+ case ir.OSLICEHEADER:
n.Left = walkexpr(n.Left, init)
n.List.SetFirst(walkexpr(n.List.First(), init))
n.List.SetSecond(walkexpr(n.List.Second(), init))
- case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
- checkSlice := checkPtr(Curfn, 1) && n.Op == OSLICE3ARR && n.Left.Op == OCONVNOP && n.Left.Left.Type.IsUnsafePtr()
+ case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
+ checkSlice := checkPtr(Curfn, 1) && n.Op == ir.OSLICE3ARR && n.Left.Op == ir.OCONVNOP && n.Left.Left.Type.IsUnsafePtr()
if checkSlice {
n.Left.Left = walkexpr(n.Left.Left, init)
} else {
n.Left = walkCheckPtrAlignment(n.Left, init, max)
}
if n.Op.IsSlice3() {
- if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
+ if max != nil && max.Op == ir.OCAP && samesafeexpr(n.Left, max.Left) {
// Reduce x[i:j:cap(x)] to x[i:j].
- if n.Op == OSLICE3 {
- n.Op = OSLICE
+ if n.Op == ir.OSLICE3 {
+ n.Op = ir.OSLICE
} else {
- n.Op = OSLICEARR
+ n.Op = ir.OSLICEARR
}
n = reduceSlice(n)
}
n = reduceSlice(n)
}
- case ONEW:
+ case ir.ONEW:
if n.Type.Elem().NotInHeap() {
base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type.Elem())
}
base.Fatalf("large ONEW with EscNone: %v", n)
}
r := temp(n.Type.Elem())
- r = nod(OAS, r, nil) // zero temp
+ r = ir.Nod(ir.OAS, r, nil) // zero temp
r = typecheck(r, ctxStmt)
init.Append(r)
- r = nod(OADDR, r.Left, nil)
+ r = ir.Nod(ir.OADDR, r.Left, nil)
r = typecheck(r, ctxExpr)
n = r
} else {
n = callnew(n.Type.Elem())
}
- case OADDSTR:
+ case ir.OADDSTR:
n = addstr(n, init)
- case OAPPEND:
+ case ir.OAPPEND:
// order should make sure we only see OAS(node, OAPPEND), which we handle above.
base.Fatalf("append outside assignment")
- case OCOPY:
+ case ir.OCOPY:
n = copyany(n, init, instrumenting && !base.Flag.CompilingRuntime)
// cannot use chanfn - closechan takes any, not chan any
- case OCLOSE:
+ case ir.OCLOSE:
fn := syslook("closechan")
fn = substArgTypes(fn, n.Left.Type)
n = mkcall1(fn, nil, init, n.Left)
- case OMAKECHAN:
+ case ir.OMAKECHAN:
// When size fits into int, use makechan instead of
// makechan64, which is faster and shorter on 32 bit platforms.
size := n.Left
fnname := "makechan64"
- argtype := types.Types[TINT64]
+ argtype := types.Types[types.TINT64]
// Type checking guarantees that TIDEAL size is positive and fits in an int.
// The case of size overflow when converting TUINT or TUINTPTR to TINT
// will be handled by the negative range checks in makechan during runtime.
- if size.Type.IsKind(TIDEAL) || size.Type.Size() <= types.Types[TUINT].Size() {
+ if size.Type.IsKind(types.TIDEAL) || size.Type.Size() <= types.Types[types.TUINT].Size() {
fnname = "makechan"
- argtype = types.Types[TINT]
+ argtype = types.Types[types.TINT]
}
n = mkcall1(chanfn(fnname, 1, n.Type), n.Type, init, typename(n.Type), conv(size, argtype))
- case OMAKEMAP:
+ case ir.OMAKEMAP:
t := n.Type
hmapType := hmap(t)
hint := n.Left
// var h *hmap
- var h *Node
+ var h *ir.Node
if n.Esc == EscNone {
// Allocate hmap on stack.
// var hv hmap
hv := temp(hmapType)
- zero := nod(OAS, hv, nil)
+ zero := ir.Nod(ir.OAS, hv, nil)
zero = typecheck(zero, ctxStmt)
init.Append(zero)
// h = &hv
- h = nod(OADDR, hv, nil)
+ h = ir.Nod(ir.OADDR, hv, nil)
// Allocate one bucket pointed to by hmap.buckets on stack if hint
// is not larger than BUCKETSIZE. In case hint is larger than
// BUCKETSIZE runtime.makemap will allocate the buckets on the heap.
// Maximum key and elem size is 128 bytes, larger objects
// are stored with an indirection. So max bucket size is 2048+eps.
- if !Isconst(hint, constant.Int) ||
+ if !ir.IsConst(hint, constant.Int) ||
constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(BUCKETSIZE)) {
// In case hint is larger than BUCKETSIZE runtime.makemap
// h.buckets = b
// }
- nif := nod(OIF, nod(OLE, hint, nodintconst(BUCKETSIZE)), nil)
+ nif := ir.Nod(ir.OIF, ir.Nod(ir.OLE, hint, nodintconst(BUCKETSIZE)), nil)
nif.SetLikely(true)
// var bv bmap
bv := temp(bmap(t))
- zero = nod(OAS, bv, nil)
+ zero = ir.Nod(ir.OAS, bv, nil)
nif.Nbody.Append(zero)
// b = &bv
- b := nod(OADDR, bv, nil)
+ b := ir.Nod(ir.OADDR, bv, nil)
// h.buckets = b
bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap
- na := nod(OAS, nodSym(ODOT, h, bsym), b)
+ na := ir.Nod(ir.OAS, nodSym(ir.ODOT, h, bsym), b)
nif.Nbody.Append(na)
nif = typecheck(nif, ctxStmt)
}
}
- if Isconst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(BUCKETSIZE)) {
+ if ir.IsConst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(BUCKETSIZE)) {
// Handling make(map[any]any) and
// make(map[any]any, hint) where hint <= BUCKETSIZE
// special allows for faster map initialization and
// Only need to initialize h.hash0 since
// hmap h has been allocated on the stack already.
// h.hash0 = fastrand()
- rand := mkcall("fastrand", types.Types[TUINT32], init)
+ rand := mkcall("fastrand", types.Types[types.TUINT32], init)
hashsym := hmapType.Field(4).Sym // hmap.hash0 see reflect.go:hmap
- a := nod(OAS, nodSym(ODOT, h, hashsym), rand)
+ a := ir.Nod(ir.OAS, nodSym(ir.ODOT, h, hashsym), rand)
a = typecheck(a, ctxStmt)
a = walkexpr(a, init)
init.Append(a)
// When hint fits into int, use makemap instead of
// makemap64, which is faster and shorter on 32 bit platforms.
fnname := "makemap64"
- argtype := types.Types[TINT64]
+ argtype := types.Types[types.TINT64]
// Type checking guarantees that TIDEAL hint is positive and fits in an int.
// See checkmake call in TMAP case of OMAKE case in OpSwitch in typecheck1 function.
// The case of hint overflow when converting TUINT or TUINTPTR to TINT
// will be handled by the negative range checks in makemap during runtime.
- if hint.Type.IsKind(TIDEAL) || hint.Type.Size() <= types.Types[TUINT].Size() {
+ if hint.Type.IsKind(types.TIDEAL) || hint.Type.Size() <= types.Types[types.TUINT].Size() {
fnname = "makemap"
- argtype = types.Types[TINT]
+ argtype = types.Types[types.TINT]
}
fn := syslook(fnname)
n = mkcall1(fn, n.Type, init, typename(n.Type), conv(hint, argtype), h)
}
- case OMAKESLICE:
+ case ir.OMAKESLICE:
l := n.Left
r := n.Right
if r == nil {
// if len < 0 { panicmakeslicelen() }
// panicmakeslicecap()
// }
- nif := nod(OIF, nod(OGT, conv(l, types.Types[TUINT64]), nodintconst(i)), nil)
- niflen := nod(OIF, nod(OLT, l, nodintconst(0)), nil)
+ nif := ir.Nod(ir.OIF, ir.Nod(ir.OGT, conv(l, types.Types[types.TUINT64]), nodintconst(i)), nil)
+ niflen := ir.Nod(ir.OIF, ir.Nod(ir.OLT, l, nodintconst(0)), nil)
niflen.Nbody.Set1(mkcall("panicmakeslicelen", nil, init))
nif.Nbody.Append(niflen, mkcall("panicmakeslicecap", nil, init))
nif = typecheck(nif, ctxStmt)
t = types.NewArray(t.Elem(), i) // [r]T
var_ := temp(t)
- a := nod(OAS, var_, nil) // zero temp
+ a := ir.Nod(ir.OAS, var_, nil) // zero temp
a = typecheck(a, ctxStmt)
init.Append(a)
- r := nod(OSLICE, var_, nil) // arr[:l]
+ r := ir.Nod(ir.OSLICE, var_, nil) // arr[:l]
r.SetSliceBounds(nil, l, nil)
r = conv(r, n.Type) // in case n.Type is named.
r = typecheck(r, ctxExpr)
len, cap := l, r
fnname := "makeslice64"
- argtype := types.Types[TINT64]
+ argtype := types.Types[types.TINT64]
// Type checking guarantees that TIDEAL len/cap are positive and fit in an int.
// The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
// will be handled by the negative range checks in makeslice during runtime.
- if (len.Type.IsKind(TIDEAL) || len.Type.Size() <= types.Types[TUINT].Size()) &&
- (cap.Type.IsKind(TIDEAL) || cap.Type.Size() <= types.Types[TUINT].Size()) {
+ if (len.Type.IsKind(types.TIDEAL) || len.Type.Size() <= types.Types[types.TUINT].Size()) &&
+ (cap.Type.IsKind(types.TIDEAL) || cap.Type.Size() <= types.Types[types.TUINT].Size()) {
fnname = "makeslice"
- argtype = types.Types[TINT]
+ argtype = types.Types[types.TINT]
}
- m := nod(OSLICEHEADER, nil, nil)
+ m := ir.Nod(ir.OSLICEHEADER, nil, nil)
m.Type = t
fn := syslook(fnname)
- m.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
+ m.Left = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
m.Left.MarkNonNil()
- m.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT]))
+ m.List.Set2(conv(len, types.Types[types.TINT]), conv(cap, types.Types[types.TINT]))
m = typecheck(m, ctxExpr)
m = walkexpr(m, init)
n = m
}
- case OMAKESLICECOPY:
+ case ir.OMAKESLICECOPY:
if n.Esc == EscNone {
base.Fatalf("OMAKESLICECOPY with EscNone: %v", n)
}
base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
}
- length := conv(n.Left, types.Types[TINT])
- copylen := nod(OLEN, n.Right, nil)
- copyptr := nod(OSPTR, n.Right, nil)
+ length := conv(n.Left, types.Types[types.TINT])
+ copylen := ir.Nod(ir.OLEN, n.Right, nil)
+ copyptr := ir.Nod(ir.OSPTR, n.Right, nil)
if !t.Elem().HasPointers() && n.Bounded() {
// When len(to)==len(from) and elements have no pointers:
// We do not check for overflow of len(to)*elem.Width here
// since len(from) is an existing checked slice capacity
// with same elem.Width for the from slice.
- size := nod(OMUL, conv(length, types.Types[TUINTPTR]), conv(nodintconst(t.Elem().Width), types.Types[TUINTPTR]))
+ size := ir.Nod(ir.OMUL, conv(length, types.Types[types.TUINTPTR]), conv(nodintconst(t.Elem().Width), types.Types[types.TUINTPTR]))
// instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
fn := syslook("mallocgc")
- sh := nod(OSLICEHEADER, nil, nil)
- sh.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, size, nodnil(), nodbool(false))
+ sh := ir.Nod(ir.OSLICEHEADER, nil, nil)
+ sh.Left = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, nodnil(), nodbool(false))
sh.Left.MarkNonNil()
sh.List.Set2(length, length)
sh.Type = t
s := temp(t)
- r := typecheck(nod(OAS, s, sh), ctxStmt)
+ r := typecheck(ir.Nod(ir.OAS, s, sh), ctxStmt)
r = walkexpr(r, init)
init.Append(r)
// instantiate memmove(to *any, frm *any, size uintptr)
fn = syslook("memmove")
fn = substArgTypes(fn, t.Elem(), t.Elem())
- ncopy := mkcall1(fn, nil, init, nod(OSPTR, s, nil), copyptr, size)
+ ncopy := mkcall1(fn, nil, init, ir.Nod(ir.OSPTR, s, nil), copyptr, size)
ncopy = typecheck(ncopy, ctxStmt)
ncopy = walkexpr(ncopy, init)
init.Append(ncopy)
} else { // Replace make+copy with runtime.makeslicecopy.
// instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
fn := syslook("makeslicecopy")
- s := nod(OSLICEHEADER, nil, nil)
- s.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[TUNSAFEPTR]))
+ s := ir.Nod(ir.OSLICEHEADER, nil, nil)
+ s.Left = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[types.TUNSAFEPTR]))
s.Left.MarkNonNil()
s.List.Set2(length, length)
s.Type = t
n = walkexpr(n, init)
}
- case ORUNESTR:
+ case ir.ORUNESTR:
a := nodnil()
if n.Esc == EscNone {
- t := types.NewArray(types.Types[TUINT8], 4)
- a = nod(OADDR, temp(t), nil)
+ t := types.NewArray(types.Types[types.TUINT8], 4)
+ a = ir.Nod(ir.OADDR, temp(t), nil)
}
// intstring(*[4]byte, rune)
- n = mkcall("intstring", n.Type, init, a, conv(n.Left, types.Types[TINT64]))
+ n = mkcall("intstring", n.Type, init, a, conv(n.Left, types.Types[types.TINT64]))
- case OBYTES2STR, ORUNES2STR:
+ case ir.OBYTES2STR, ir.ORUNES2STR:
a := nodnil()
if n.Esc == EscNone {
// Create temporary buffer for string on stack.
- t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
- a = nod(OADDR, temp(t), nil)
+ t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
+ a = ir.Nod(ir.OADDR, temp(t), nil)
}
- if n.Op == ORUNES2STR {
+ if n.Op == ir.ORUNES2STR {
// slicerunetostring(*[32]byte, []rune) string
n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
} else {
// slicebytetostring(*[32]byte, ptr *byte, n int) string
n.Left = cheapexpr(n.Left, init)
- ptr, len := n.Left.backingArrayPtrLen()
+ ptr, len := backingArrayPtrLen(n.Left)
n = mkcall("slicebytetostring", n.Type, init, a, ptr, len)
}
- case OBYTES2STRTMP:
+ case ir.OBYTES2STRTMP:
n.Left = walkexpr(n.Left, init)
if !instrumenting {
// Let the backend handle OBYTES2STRTMP directly
}
// slicebytetostringtmp(ptr *byte, n int) string
n.Left = cheapexpr(n.Left, init)
- ptr, len := n.Left.backingArrayPtrLen()
+ ptr, len := backingArrayPtrLen(n.Left)
n = mkcall("slicebytetostringtmp", n.Type, init, ptr, len)
- case OSTR2BYTES:
+ case ir.OSTR2BYTES:
s := n.Left
- if Isconst(s, constant.String) {
+ if ir.IsConst(s, constant.String) {
sc := s.StringVal()
// Allocate a [n]byte of the right size.
- t := types.NewArray(types.Types[TUINT8], int64(len(sc)))
- var a *Node
+ t := types.NewArray(types.Types[types.TUINT8], int64(len(sc)))
+ var a *ir.Node
if n.Esc == EscNone && len(sc) <= int(maxImplicitStackVarSize) {
- a = nod(OADDR, temp(t), nil)
+ a = ir.Nod(ir.OADDR, temp(t), nil)
} else {
a = callnew(t)
}
p := temp(t.PtrTo()) // *[n]byte
- init.Append(typecheck(nod(OAS, p, a), ctxStmt))
+ init.Append(typecheck(ir.Nod(ir.OAS, p, a), ctxStmt))
// Copy from the static string data to the [n]byte.
if len(sc) > 0 {
- as := nod(OAS,
- nod(ODEREF, p, nil),
- nod(ODEREF, convnop(nod(OSPTR, s, nil), t.PtrTo()), nil))
+ as := ir.Nod(ir.OAS,
+ ir.Nod(ir.ODEREF, p, nil),
+ ir.Nod(ir.ODEREF, convnop(ir.Nod(ir.OSPTR, s, nil), t.PtrTo()), nil))
as = typecheck(as, ctxStmt)
as = walkstmt(as)
init.Append(as)
}
// Slice the [n]byte to a []byte.
- n.Op = OSLICEARR
+ n.Op = ir.OSLICEARR
n.Left = p
n = walkexpr(n, init)
break
a := nodnil()
if n.Esc == EscNone {
// Create temporary buffer for slice on stack.
- t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
- a = nod(OADDR, temp(t), nil)
+ t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
+ a = ir.Nod(ir.OADDR, temp(t), nil)
}
// stringtoslicebyte(*32[byte], string) []byte
- n = mkcall("stringtoslicebyte", n.Type, init, a, conv(s, types.Types[TSTRING]))
+ n = mkcall("stringtoslicebyte", n.Type, init, a, conv(s, types.Types[types.TSTRING]))
- case OSTR2BYTESTMP:
+ case ir.OSTR2BYTESTMP:
// []byte(string) conversion that creates a slice
// referring to the actual string bytes.
// This conversion is handled later by the backend and
// for i, c := range []byte(string)
n.Left = walkexpr(n.Left, init)
- case OSTR2RUNES:
+ case ir.OSTR2RUNES:
a := nodnil()
if n.Esc == EscNone {
// Create temporary buffer for slice on stack.
- t := types.NewArray(types.Types[TINT32], tmpstringbufsize)
- a = nod(OADDR, temp(t), nil)
+ t := types.NewArray(types.Types[types.TINT32], tmpstringbufsize)
+ a = ir.Nod(ir.OADDR, temp(t), nil)
}
// stringtoslicerune(*[32]rune, string) []rune
- n = mkcall("stringtoslicerune", n.Type, init, a, conv(n.Left, types.Types[TSTRING]))
+ n = mkcall("stringtoslicerune", n.Type, init, a, conv(n.Left, types.Types[types.TSTRING]))
- case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
+ case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT, ir.OPTRLIT:
if isStaticCompositeLiteral(n) && !canSSAType(n.Type) {
// n can be directly represented in the read-only data section.
// Make direct reference to the static data. See issue 12841.
anylit(n, var_, init)
n = var_
- case OSEND:
+ case ir.OSEND:
n1 := n.Right
n1 = assignconv(n1, n.Left.Type.Elem(), "chan send")
n1 = walkexpr(n1, init)
- n1 = nod(OADDR, n1, nil)
+ n1 = ir.Nod(ir.OADDR, n1, nil)
n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, n.Left, n1)
- case OCLOSURE:
+ case ir.OCLOSURE:
n = walkclosure(n, init)
- case OCALLPART:
+ case ir.OCALLPART:
n = walkpartialcall(n, init)
}
if n.Type != t {
base.Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type)
}
- if n.Op == OLITERAL {
+ if n.Op == ir.OLITERAL {
n = typecheck(n, ctxExpr)
// Emit string symbol now to avoid emitting
// any concurrently during the backend.
updateHasCall(n)
if base.Flag.LowerW != 0 && n != nil {
- Dump("after walk expr", n)
+ ir.Dump("after walk expr", n)
}
base.Pos = lno
// markUsedIfaceMethod marks that an interface method is used in the current
// function. n is OCALLINTER node.
-func markUsedIfaceMethod(n *Node) {
+func markUsedIfaceMethod(n *ir.Node) {
ityp := n.Left.Left.Type
tsym := typenamesym(ityp).Linksym()
- r := obj.Addrel(Curfn.Func.lsym)
+ r := obj.Addrel(Curfn.Func.LSym)
r.Sym = tsym
// n.Left.Xoffset is the method index * Widthptr (the offset of code pointer
// in itab).
// If no such function is necessary, it returns (Txxx, Txxx).
func rtconvfn(src, dst *types.Type) (param, result types.EType) {
if thearch.SoftFloat {
- return Txxx, Txxx
+ return types.Txxx, types.Txxx
}
switch thearch.LinkArch.Family {
case sys.ARM, sys.MIPS:
if src.IsFloat() {
switch dst.Etype {
- case TINT64, TUINT64:
- return TFLOAT64, dst.Etype
+ case types.TINT64, types.TUINT64:
+ return types.TFLOAT64, dst.Etype
}
}
if dst.IsFloat() {
switch src.Etype {
- case TINT64, TUINT64:
- return src.Etype, TFLOAT64
+ case types.TINT64, types.TUINT64:
+ return src.Etype, types.TFLOAT64
}
}
case sys.I386:
if src.IsFloat() {
switch dst.Etype {
- case TINT64, TUINT64:
- return TFLOAT64, dst.Etype
- case TUINT32, TUINT, TUINTPTR:
- return TFLOAT64, TUINT32
+ case types.TINT64, types.TUINT64:
+ return types.TFLOAT64, dst.Etype
+ case types.TUINT32, types.TUINT, types.TUINTPTR:
+ return types.TFLOAT64, types.TUINT32
}
}
if dst.IsFloat() {
switch src.Etype {
- case TINT64, TUINT64:
- return src.Etype, TFLOAT64
- case TUINT32, TUINT, TUINTPTR:
- return TUINT32, TFLOAT64
+ case types.TINT64, types.TUINT64:
+ return src.Etype, types.TFLOAT64
+ case types.TUINT32, types.TUINT, types.TUINTPTR:
+ return types.TUINT32, types.TFLOAT64
}
}
}
- return Txxx, Txxx
+ return types.Txxx, types.Txxx
}
// TODO(josharian): combine this with its caller and simplify
-func reduceSlice(n *Node) *Node {
+func reduceSlice(n *ir.Node) *ir.Node {
low, high, max := n.SliceBounds()
- if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
+ if high != nil && high.Op == ir.OLEN && samesafeexpr(n.Left, high.Left) {
// Reduce x[i:len(x)] to x[i:].
high = nil
}
n.SetSliceBounds(low, high, max)
- if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil {
+ if (n.Op == ir.OSLICE || n.Op == ir.OSLICESTR) && low == nil && high == nil {
// Reduce x[:] to x.
if base.Debug.Slice > 0 {
base.Warn("slice: omit slice operation")
return n
}
-func ascompatee1(l *Node, r *Node, init *Nodes) *Node {
+func ascompatee1(l *ir.Node, r *ir.Node, init *ir.Nodes) *ir.Node {
// convas will turn map assigns into function calls,
// making it impossible for reorder3 to work.
- n := nod(OAS, l, r)
+ n := ir.Nod(ir.OAS, l, r)
- if l.Op == OINDEXMAP {
+ if l.Op == ir.OINDEXMAP {
return n
}
return convas(n, init)
}
-func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
+func ascompatee(op ir.Op, nl, nr []*ir.Node, init *ir.Nodes) []*ir.Node {
// check assign expression list to
// an expression list. called in
// expr-list = expr-list
nr[i1] = safeexpr(nr[i1], init)
}
- var nn []*Node
+ var nn []*ir.Node
i := 0
for ; i < len(nl); i++ {
if i >= len(nr) {
break
}
// Do not generate 'x = x' during return. See issue 4014.
- if op == ORETURN && samesafeexpr(nl[i], nr[i]) {
+ if op == ir.ORETURN && samesafeexpr(nl[i], nr[i]) {
continue
}
nn = append(nn, ascompatee1(nl[i], nr[i], init))
// cannot happen: caller checked that lists had same length
if i < len(nl) || i < len(nr) {
- var nln, nrn Nodes
+ var nln, nrn ir.Nodes
nln.Set(nl)
nrn.Set(nr)
- base.Fatalf("error in shape across %+v %v %+v / %d %d [%s]", nln, op, nrn, len(nl), len(nr), Curfn.funcname())
+ base.Fatalf("error in shape across %+v %v %+v / %d %d [%s]", nln, op, nrn, len(nl), len(nr), ir.FuncName(Curfn))
}
return nn
}
// fncall reports whether assigning an rvalue of type rt to an lvalue l might involve a function call.
-func fncall(l *Node, rt *types.Type) bool {
- if l.HasCall() || l.Op == OINDEXMAP {
+func fncall(l *ir.Node, rt *types.Type) bool {
+ if l.HasCall() || l.Op == ir.OINDEXMAP {
return true
}
if types.Identical(l.Type, rt) {
// check assign type list to
// an expression list. called in
// expr-list = func()
-func ascompatet(nl Nodes, nr *types.Type) []*Node {
+func ascompatet(nl ir.Nodes, nr *types.Type) []*ir.Node {
if nl.Len() != nr.NumFields() {
base.Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
}
- var nn, mm Nodes
+ var nn, mm ir.Nodes
for i, l := range nl.Slice() {
- if l.isBlank() {
+ if ir.IsBlank(l) {
continue
}
r := nr.Field(i)
if fncall(l, r.Type) {
tmp := temp(r.Type)
tmp = typecheck(tmp, ctxExpr)
- a := nod(OAS, l, tmp)
+ a := ir.Nod(ir.OAS, l, tmp)
a = convas(a, &mm)
mm.Append(a)
l = tmp
}
- res := nod(ORESULT, nil, nil)
+ res := ir.Nod(ir.ORESULT, nil, nil)
res.Xoffset = base.Ctxt.FixedFrameSize() + r.Offset
res.Type = r.Type
res.SetTypecheck(1)
- a := nod(OAS, l, res)
+ a := ir.Nod(ir.OAS, l, res)
a = convas(a, &nn)
updateHasCall(a)
if a.HasCall() {
- Dump("ascompatet ucount", a)
+ ir.Dump("ascompatet ucount", a)
base.Fatalf("ascompatet: too many function calls evaluating parameters")
}
}
// package all the arguments that match a ... T parameter into a []T.
-func mkdotargslice(typ *types.Type, args []*Node) *Node {
- var n *Node
+func mkdotargslice(typ *types.Type, args []*ir.Node) *ir.Node {
+ var n *ir.Node
if len(args) == 0 {
n = nodnil()
n.Type = typ
} else {
- n = nod(OCOMPLIT, nil, typenod(typ))
+ n = ir.Nod(ir.OCOMPLIT, nil, typenod(typ))
n.List.Append(args...)
n.SetImplicit(true)
}
// fixVariadicCall rewrites calls to variadic functions to use an
// explicit ... argument if one is not already present.
-func fixVariadicCall(call *Node) {
+func fixVariadicCall(call *ir.Node) {
fntype := call.Left.Type
if !fntype.IsVariadic() || call.IsDDD() {
return
call.SetIsDDD(true)
}
-func walkCall(n *Node, init *Nodes) {
+func walkCall(n *ir.Node, init *ir.Nodes) {
if n.Rlist.Len() != 0 {
return // already walked
}
walkexprlist(args, init)
// If this is a method call, add the receiver at the beginning of the args.
- if n.Op == OCALLMETH {
- withRecv := make([]*Node, len(args)+1)
+ if n.Op == ir.OCALLMETH {
+ withRecv := make([]*ir.Node, len(args)+1)
withRecv[0] = n.Left.Left
n.Left.Left = nil
copy(withRecv[1:], args)
// store that argument into a temporary variable,
// to prevent that calls from clobbering arguments already on the stack.
// When instrumenting, all arguments might require function calls.
- var tempAssigns []*Node
+ var tempAssigns []*ir.Node
for i, arg := range args {
updateHasCall(arg)
// Determine param type.
var t *types.Type
- if n.Op == OCALLMETH {
+ if n.Op == ir.OCALLMETH {
if i == 0 {
t = n.Left.Type.Recv().Type
} else {
if instrumenting || fncall(arg, t) {
// make assignment of fncall to tempAt
tmp := temp(t)
- a := nod(OAS, tmp, arg)
+ a := ir.Nod(ir.OAS, tmp, arg)
a = convas(a, init)
tempAssigns = append(tempAssigns, a)
// replace arg with temp
}
// generate code for print
-func walkprint(nn *Node, init *Nodes) *Node {
+func walkprint(nn *ir.Node, init *ir.Nodes) *ir.Node {
// Hoist all the argument evaluation up before the lock.
walkexprlistcheap(nn.List.Slice(), init)
// For println, add " " between elements and "\n" at the end.
- if nn.Op == OPRINTN {
+ if nn.Op == ir.OPRINTN {
s := nn.List.Slice()
- t := make([]*Node, 0, len(s)*2)
+ t := make([]*ir.Node, 0, len(s)*2)
for i, n := range s {
if i != 0 {
t = append(t, nodstr(" "))
// Collapse runs of constant strings.
s := nn.List.Slice()
- t := make([]*Node, 0, len(s))
+ t := make([]*ir.Node, 0, len(s))
for i := 0; i < len(s); {
var strs []string
- for i < len(s) && Isconst(s[i], constant.String) {
+ for i < len(s) && ir.IsConst(s[i], constant.String) {
strs = append(strs, s[i].StringVal())
i++
}
}
nn.List.Set(t)
- calls := []*Node{mkcall("printlock", nil, init)}
+ calls := []*ir.Node{mkcall("printlock", nil, init)}
for i, n := range nn.List.Slice() {
- if n.Op == OLITERAL {
+ if n.Op == ir.OLITERAL {
if n.Type == types.UntypedRune {
n = defaultlit(n, types.Runetype)
}
switch n.Val().Kind() {
case constant.Int:
- n = defaultlit(n, types.Types[TINT64])
+ n = defaultlit(n, types.Types[types.TINT64])
case constant.Float:
- n = defaultlit(n, types.Types[TFLOAT64])
+ n = defaultlit(n, types.Types[types.TFLOAT64])
}
}
- if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
- n = defaultlit(n, types.Types[TINT64])
+ if n.Op != ir.OLITERAL && n.Type != nil && n.Type.Etype == types.TIDEAL {
+ n = defaultlit(n, types.Types[types.TINT64])
}
n = defaultlit(n, nil)
nn.List.SetIndex(i, n)
- if n.Type == nil || n.Type.Etype == TFORW {
+ if n.Type == nil || n.Type.Etype == types.TFORW {
continue
}
- var on *Node
+ var on *ir.Node
switch n.Type.Etype {
- case TINTER:
+ case types.TINTER:
if n.Type.IsEmptyInterface() {
on = syslook("printeface")
} else {
on = syslook("printiface")
}
on = substArgTypes(on, n.Type) // any-1
- case TPTR:
+ case types.TPTR:
if n.Type.Elem().NotInHeap() {
on = syslook("printuintptr")
- n = nod(OCONV, n, nil)
- n.Type = types.Types[TUNSAFEPTR]
- n = nod(OCONV, n, nil)
- n.Type = types.Types[TUINTPTR]
+ n = ir.Nod(ir.OCONV, n, nil)
+ n.Type = types.Types[types.TUNSAFEPTR]
+ n = ir.Nod(ir.OCONV, n, nil)
+ n.Type = types.Types[types.TUINTPTR]
break
}
fallthrough
- case TCHAN, TMAP, TFUNC, TUNSAFEPTR:
+ case types.TCHAN, types.TMAP, types.TFUNC, types.TUNSAFEPTR:
on = syslook("printpointer")
on = substArgTypes(on, n.Type) // any-1
- case TSLICE:
+ case types.TSLICE:
on = syslook("printslice")
on = substArgTypes(on, n.Type) // any-1
- case TUINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINTPTR:
+ case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
if isRuntimePkg(n.Type.Sym.Pkg) && n.Type.Sym.Name == "hex" {
on = syslook("printhex")
} else {
on = syslook("printuint")
}
- case TINT, TINT8, TINT16, TINT32, TINT64:
+ case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64:
on = syslook("printint")
- case TFLOAT32, TFLOAT64:
+ case types.TFLOAT32, types.TFLOAT64:
on = syslook("printfloat")
- case TCOMPLEX64, TCOMPLEX128:
+ case types.TCOMPLEX64, types.TCOMPLEX128:
on = syslook("printcomplex")
- case TBOOL:
+ case types.TBOOL:
on = syslook("printbool")
- case TSTRING:
+ case types.TSTRING:
cs := ""
- if Isconst(n, constant.String) {
+ if ir.IsConst(n, constant.String) {
cs = n.StringVal()
}
switch cs {
on = syslook("printstring")
}
default:
- badtype(OPRINT, n.Type, nil)
+ badtype(ir.OPRINT, n.Type, nil)
continue
}
- r := nod(OCALL, on, nil)
+ r := ir.Nod(ir.OCALL, on, nil)
if params := on.Type.Params().FieldSlice(); len(params) > 0 {
t := params[0].Type
if !types.Identical(t, n.Type) {
- n = nod(OCONV, n, nil)
+ n = ir.Nod(ir.OCONV, n, nil)
n.Type = t
}
r.List.Append(n)
typecheckslice(calls, ctxStmt)
walkexprlist(calls, init)
- r := nod(OEMPTY, nil, nil)
+ r := ir.Nod(ir.OEMPTY, nil, nil)
r = typecheck(r, ctxStmt)
r = walkexpr(r, init)
r.Ninit.Set(calls)
return r
}
-func callnew(t *types.Type) *Node {
+func callnew(t *types.Type) *ir.Node {
dowidth(t)
- n := nod(ONEWOBJ, typename(t), nil)
+ n := ir.Nod(ir.ONEWOBJ, typename(t), nil)
n.Type = types.NewPtr(t)
n.SetTypecheck(1)
n.MarkNonNil()
// isReflectHeaderDataField reports whether l is an expression p.Data
// where p has type reflect.SliceHeader or reflect.StringHeader.
-func isReflectHeaderDataField(l *Node) bool {
- if l.Type != types.Types[TUINTPTR] {
+func isReflectHeaderDataField(l *ir.Node) bool {
+ if l.Type != types.Types[types.TUINTPTR] {
return false
}
var tsym *types.Sym
switch l.Op {
- case ODOT:
+ case ir.ODOT:
tsym = l.Left.Type.Sym
- case ODOTPTR:
+ case ir.ODOTPTR:
tsym = l.Left.Type.Elem().Sym
default:
return false
return tsym.Name == "SliceHeader" || tsym.Name == "StringHeader"
}
-func convas(n *Node, init *Nodes) *Node {
- if n.Op != OAS {
+func convas(n *ir.Node, init *ir.Nodes) *ir.Node {
+ if n.Op != ir.OAS {
base.Fatalf("convas: not OAS %v", n.Op)
}
defer updateHasCall(n)
return n
}
- if n.Left.isBlank() {
+ if ir.IsBlank(n.Left) {
n.Right = defaultlit(n.Right, nil)
return n
}
// be later use of an earlier lvalue.
//
// function calls have been removed.
-func reorder3(all []*Node) []*Node {
+func reorder3(all []*ir.Node) []*ir.Node {
// If a needed expression may be affected by an
// earlier assignment, make an early copy of that
// expression and use the copy instead.
- var early []*Node
+ var early []*ir.Node
- var mapinit Nodes
+ var mapinit ir.Nodes
for i, n := range all {
l := n.Left
// Save subexpressions needed on left side.
// Drill through non-dereferences.
for {
- if l.Op == ODOT || l.Op == OPAREN {
+ if l.Op == ir.ODOT || l.Op == ir.OPAREN {
l = l.Left
continue
}
- if l.Op == OINDEX && l.Left.Type.IsArray() {
+ if l.Op == ir.OINDEX && l.Left.Type.IsArray() {
l.Right = reorder3save(l.Right, all, i, &early)
l = l.Left
continue
default:
base.Fatalf("reorder3 unexpected lvalue %#v", l.Op)
- case ONAME:
+ case ir.ONAME:
break
- case OINDEX, OINDEXMAP:
+ case ir.OINDEX, ir.OINDEXMAP:
l.Left = reorder3save(l.Left, all, i, &early)
l.Right = reorder3save(l.Right, all, i, &early)
- if l.Op == OINDEXMAP {
+ if l.Op == ir.OINDEXMAP {
all[i] = convas(all[i], &mapinit)
}
- case ODEREF, ODOTPTR:
+ case ir.ODEREF, ir.ODOTPTR:
l.Left = reorder3save(l.Left, all, i, &early)
}
// replace *np with that temp.
// The result of reorder3save MUST be assigned back to n, e.g.
// n.Left = reorder3save(n.Left, all, i, early)
-func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
+func reorder3save(n *ir.Node, all []*ir.Node, i int, early *[]*ir.Node) *ir.Node {
if !aliased(n, all[:i]) {
return n
}
q := temp(n.Type)
- q = nod(OAS, q, n)
+ q = ir.Nod(ir.OAS, q, n)
q = typecheck(q, ctxStmt)
*early = append(*early, q)
return q.Left
// what's the outer value that a write to n affects?
// outer value means containing struct or array.
-func outervalue(n *Node) *Node {
+func outervalue(n *ir.Node) *ir.Node {
for {
switch n.Op {
- case OXDOT:
+ case ir.OXDOT:
base.Fatalf("OXDOT in walk")
- case ODOT, OPAREN, OCONVNOP:
+ case ir.ODOT, ir.OPAREN, ir.OCONVNOP:
n = n.Left
continue
- case OINDEX:
+ case ir.OINDEX:
if n.Left.Type != nil && n.Left.Type.IsArray() {
n = n.Left
continue
// Is it possible that the computation of r might be
// affected by assignments in all?
-func aliased(r *Node, all []*Node) bool {
+func aliased(r *ir.Node, all []*ir.Node) bool {
if r == nil {
return false
}
// Treat all fields of a struct as referring to the whole struct.
// We could do better but we would have to keep track of the fields.
- for r.Op == ODOT {
+ for r.Op == ir.ODOT {
r = r.Left
}
memwrite := false
for _, as := range all {
// We can ignore assignments to blank.
- if as.Left.isBlank() {
+ if ir.IsBlank(as.Left) {
continue
}
l := outervalue(as.Left)
- if l.Op != ONAME {
+ if l.Op != ir.ONAME {
memwrite = true
continue
}
default:
base.Fatalf("unexpected class: %v, %v", l, l.Class())
- case PAUTOHEAP, PEXTERN:
+ case ir.PAUTOHEAP, ir.PEXTERN:
memwrite = true
continue
- case PAUTO, PPARAM, PPARAMOUT:
+ case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
if l.Name.Addrtaken() {
memwrite = true
continue
// does the evaluation of n only refer to variables
// whose addresses have not been taken?
// (and no other memory)
-func varexpr(n *Node) bool {
+func varexpr(n *ir.Node) bool {
if n == nil {
return true
}
switch n.Op {
- case OLITERAL, ONIL:
+ case ir.OLITERAL, ir.ONIL:
return true
- case ONAME:
+ case ir.ONAME:
switch n.Class() {
- case PAUTO, PPARAM, PPARAMOUT:
+ case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
if !n.Name.Addrtaken() {
return true
}
return false
- case OADD,
- OSUB,
- OOR,
- OXOR,
- OMUL,
- ODIV,
- OMOD,
- OLSH,
- ORSH,
- OAND,
- OANDNOT,
- OPLUS,
- ONEG,
- OBITNOT,
- OPAREN,
- OANDAND,
- OOROR,
- OCONV,
- OCONVNOP,
- OCONVIFACE,
- ODOTTYPE:
+ case ir.OADD,
+ ir.OSUB,
+ ir.OOR,
+ ir.OXOR,
+ ir.OMUL,
+ ir.ODIV,
+ ir.OMOD,
+ ir.OLSH,
+ ir.ORSH,
+ ir.OAND,
+ ir.OANDNOT,
+ ir.OPLUS,
+ ir.ONEG,
+ ir.OBITNOT,
+ ir.OPAREN,
+ ir.OANDAND,
+ ir.OOROR,
+ ir.OCONV,
+ ir.OCONVNOP,
+ ir.OCONVIFACE,
+ ir.ODOTTYPE:
return varexpr(n.Left) && varexpr(n.Right)
- case ODOT: // but not ODOTPTR
+ case ir.ODOT: // but not ODOTPTR
// Should have been handled in aliased.
base.Fatalf("varexpr unexpected ODOT")
}
}
// is the name l mentioned in r?
-func vmatch2(l *Node, r *Node) bool {
+func vmatch2(l *ir.Node, r *ir.Node) bool {
if r == nil {
return false
}
switch r.Op {
// match each right given left
- case ONAME:
+ case ir.ONAME:
return l == r
- case OLITERAL, ONIL:
+ case ir.OLITERAL, ir.ONIL:
return false
}
// is any name mentioned in l also mentioned in r?
// called by sinit.go
-func vmatch1(l *Node, r *Node) bool {
+func vmatch1(l *ir.Node, r *ir.Node) bool {
// isolate all left sides
if l == nil || r == nil {
return false
}
switch l.Op {
- case ONAME:
+ case ir.ONAME:
switch l.Class() {
- case PPARAM, PAUTO:
+ case ir.PPARAM, ir.PAUTO:
break
default:
return vmatch2(l, r)
- case OLITERAL, ONIL:
+ case ir.OLITERAL, ir.ONIL:
return false
}
// paramstoheap returns code to allocate memory for heap-escaped parameters
// and to copy non-result parameters' values from the stack.
-func paramstoheap(params *types.Type) []*Node {
- var nn []*Node
+func paramstoheap(params *types.Type) []*ir.Node {
+ var nn []*ir.Node
for _, t := range params.Fields().Slice() {
- v := asNode(t.Nname)
+ v := ir.AsNode(t.Nname)
if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
v = nil
}
}
if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
- nn = append(nn, walkstmt(nod(ODCL, v, nil)))
- if stackcopy.Class() == PPARAM {
- nn = append(nn, walkstmt(typecheck(nod(OAS, v, stackcopy), ctxStmt)))
+ nn = append(nn, walkstmt(ir.Nod(ir.ODCL, v, nil)))
+ if stackcopy.Class() == ir.PPARAM {
+ nn = append(nn, walkstmt(typecheck(ir.Nod(ir.OAS, v, stackcopy), ctxStmt)))
}
}
}
// The generated code is added to Curfn's Enter list.
func zeroResults() {
for _, f := range Curfn.Type.Results().Fields().Slice() {
- v := asNode(f.Nname)
+ v := ir.AsNode(f.Nname)
if v != nil && v.Name.Param.Heapaddr != nil {
// The local which points to the return value is the
// thing that needs zeroing. This is already handled
// by a Needzero annotation in plive.go:livenessepilogue.
continue
}
- if v.isParamHeapCopy() {
+ if isParamHeapCopy(v) {
// TODO(josharian/khr): Investigate whether we can switch to "continue" here,
// and document more in either case.
// In the review of CL 114797, Keith wrote (roughly):
v = v.Name.Param.Stackcopy
}
// Zero the stack location containing f.
- Curfn.Func.Enter.Append(nodl(Curfn.Pos, OAS, v, nil))
+ Curfn.Func.Enter.Append(ir.NodAt(Curfn.Pos, ir.OAS, v, nil))
}
}
// returnsfromheap returns code to copy values for heap-escaped parameters
// back to the stack.
-func returnsfromheap(params *types.Type) []*Node {
- var nn []*Node
+func returnsfromheap(params *types.Type) []*ir.Node {
+ var nn []*ir.Node
for _, t := range params.Fields().Slice() {
- v := asNode(t.Nname)
+ v := ir.AsNode(t.Nname)
if v == nil {
continue
}
- if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class() == PPARAMOUT {
- nn = append(nn, walkstmt(typecheck(nod(OAS, stackcopy, v), ctxStmt)))
+ if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class() == ir.PPARAMOUT {
+ nn = append(nn, walkstmt(typecheck(ir.Nod(ir.OAS, stackcopy, v), ctxStmt)))
}
}
base.Pos = lno
}
-func vmkcall(fn *Node, t *types.Type, init *Nodes, va []*Node) *Node {
- if fn.Type == nil || fn.Type.Etype != TFUNC {
+func vmkcall(fn *ir.Node, t *types.Type, init *ir.Nodes, va []*ir.Node) *ir.Node {
+ if fn.Type == nil || fn.Type.Etype != types.TFUNC {
base.Fatalf("mkcall %v %v", fn, fn.Type)
}
base.Fatalf("vmkcall %v needs %v args got %v", fn, n, len(va))
}
- r := nod(OCALL, fn, nil)
+ r := ir.Nod(ir.OCALL, fn, nil)
r.List.Set(va)
if fn.Type.NumResults() > 0 {
r = typecheck(r, ctxExpr|ctxMultiOK)
return r
}
-func mkcall(name string, t *types.Type, init *Nodes, args ...*Node) *Node {
+func mkcall(name string, t *types.Type, init *ir.Nodes, args ...*ir.Node) *ir.Node {
return vmkcall(syslook(name), t, init, args)
}
-func mkcall1(fn *Node, t *types.Type, init *Nodes, args ...*Node) *Node {
+func mkcall1(fn *ir.Node, t *types.Type, init *ir.Nodes, args ...*ir.Node) *ir.Node {
return vmkcall(fn, t, init, args)
}
-func conv(n *Node, t *types.Type) *Node {
+func conv(n *ir.Node, t *types.Type) *ir.Node {
if types.Identical(n.Type, t) {
return n
}
- n = nod(OCONV, n, nil)
+ n = ir.Nod(ir.OCONV, n, nil)
n.Type = t
n = typecheck(n, ctxExpr)
return n
// convnop converts node n to type t using the OCONVNOP op
// and typechecks the result with ctxExpr.
-func convnop(n *Node, t *types.Type) *Node {
+func convnop(n *ir.Node, t *types.Type) *ir.Node {
if types.Identical(n.Type, t) {
return n
}
- n = nod(OCONVNOP, n, nil)
+ n = ir.Nod(ir.OCONVNOP, n, nil)
n.Type = t
n = typecheck(n, ctxExpr)
return n
// byteindex converts n, which is byte-sized, to an int used to index into an array.
// We cannot use conv, because we allow converting bool to int here,
// which is forbidden in user code.
-func byteindex(n *Node) *Node {
+func byteindex(n *ir.Node) *ir.Node {
// We cannot convert from bool to int directly.
// While converting from int8 to int is possible, it would yield
// the wrong result for negative values.
// Reinterpreting the value as an unsigned byte solves both cases.
- if !types.Identical(n.Type, types.Types[TUINT8]) {
- n = nod(OCONV, n, nil)
- n.Type = types.Types[TUINT8]
+ if !types.Identical(n.Type, types.Types[types.TUINT8]) {
+ n = ir.Nod(ir.OCONV, n, nil)
+ n.Type = types.Types[types.TUINT8]
n.SetTypecheck(1)
}
- n = nod(OCONV, n, nil)
- n.Type = types.Types[TINT]
+ n = ir.Nod(ir.OCONV, n, nil)
+ n.Type = types.Types[types.TINT]
n.SetTypecheck(1)
return n
}
-func chanfn(name string, n int, t *types.Type) *Node {
+func chanfn(name string, n int, t *types.Type) *ir.Node {
if !t.IsChan() {
base.Fatalf("chanfn %v", t)
}
return fn
}
-func mapfn(name string, t *types.Type) *Node {
+func mapfn(name string, t *types.Type) *ir.Node {
if !t.IsMap() {
base.Fatalf("mapfn %v", t)
}
return fn
}
-func mapfndel(name string, t *types.Type) *Node {
+func mapfndel(name string, t *types.Type) *ir.Node {
if !t.IsMap() {
base.Fatalf("mapfn %v", t)
}
return mapslow
}
-func writebarrierfn(name string, l *types.Type, r *types.Type) *Node {
+func writebarrierfn(name string, l *types.Type, r *types.Type) *ir.Node {
fn := syslook(name)
fn = substArgTypes(fn, l, r)
return fn
}
-func addstr(n *Node, init *Nodes) *Node {
+func addstr(n *ir.Node, init *ir.Nodes) *ir.Node {
// order.expr rewrote OADDSTR to have a list of strings.
c := n.List.Len()
if n.Esc == EscNone {
sz := int64(0)
for _, n1 := range n.List.Slice() {
- if n1.Op == OLITERAL {
+ if n1.Op == ir.OLITERAL {
sz += int64(len(n1.StringVal()))
}
}
// Don't allocate the buffer if the result won't fit.
if sz < tmpstringbufsize {
// Create temporary buffer for result string on stack.
- t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
- buf = nod(OADDR, temp(t), nil)
+ t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
+ buf = ir.Nod(ir.OADDR, temp(t), nil)
}
}
// build list of string arguments
- args := []*Node{buf}
+ args := []*ir.Node{buf}
for _, n2 := range n.List.Slice() {
- args = append(args, conv(n2, types.Types[TSTRING]))
+ args = append(args, conv(n2, types.Types[types.TSTRING]))
}
var fn string
// large numbers of strings are passed to the runtime as a slice.
fn = "concatstrings"
- t := types.NewSlice(types.Types[TSTRING])
- slice := nod(OCOMPLIT, nil, typenod(t))
+ t := types.NewSlice(types.Types[types.TSTRING])
+ slice := ir.Nod(ir.OCOMPLIT, nil, typenod(t))
if prealloc[n] != nil {
prealloc[slice] = prealloc[n]
}
slice.List.Set(args[1:]) // skip buf arg
- args = []*Node{buf, slice}
+ args = []*ir.Node{buf, slice}
slice.Esc = EscNone
}
cat := syslook(fn)
- r := nod(OCALL, cat, nil)
+ r := ir.Nod(ir.OCALL, cat, nil)
r.List.Set(args)
r = typecheck(r, ctxExpr)
r = walkexpr(r, init)
return r
}
-func walkAppendArgs(n *Node, init *Nodes) {
+func walkAppendArgs(n *ir.Node, init *ir.Nodes) {
walkexprlistsafe(n.List.Slice(), init)
// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
// s
//
// l2 is allowed to be a string.
-func appendslice(n *Node, init *Nodes) *Node {
+func appendslice(n *ir.Node, init *ir.Nodes) *ir.Node {
walkAppendArgs(n, init)
l1 := n.List.First()
l2 = cheapexpr(l2, init)
n.List.SetSecond(l2)
- var nodes Nodes
+ var nodes ir.Nodes
// var s []T
s := temp(l1.Type)
- nodes.Append(nod(OAS, s, l1)) // s = l1
+ nodes.Append(ir.Nod(ir.OAS, s, l1)) // s = l1
elemtype := s.Type.Elem()
// n := len(s) + len(l2)
- nn := temp(types.Types[TINT])
- nodes.Append(nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), nod(OLEN, l2, nil))))
+ nn := temp(types.Types[types.TINT])
+ nodes.Append(ir.Nod(ir.OAS, nn, ir.Nod(ir.OADD, ir.Nod(ir.OLEN, s, nil), ir.Nod(ir.OLEN, l2, nil))))
// if uint(n) > uint(cap(s))
- nif := nod(OIF, nil, nil)
- nuint := conv(nn, types.Types[TUINT])
- scapuint := conv(nod(OCAP, s, nil), types.Types[TUINT])
- nif.Left = nod(OGT, nuint, scapuint)
+ nif := ir.Nod(ir.OIF, nil, nil)
+ nuint := conv(nn, types.Types[types.TUINT])
+ scapuint := conv(ir.Nod(ir.OCAP, s, nil), types.Types[types.TUINT])
+ nif.Left = ir.Nod(ir.OGT, nuint, scapuint)
// instantiate growslice(typ *type, []any, int) []any
fn := syslook("growslice")
fn = substArgTypes(fn, elemtype, elemtype)
// s = growslice(T, s, n)
- nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn)))
+ nif.Nbody.Set1(ir.Nod(ir.OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn)))
nodes.Append(nif)
// s = s[:n]
- nt := nod(OSLICE, s, nil)
+ nt := ir.Nod(ir.OSLICE, s, nil)
nt.SetSliceBounds(nil, nn, nil)
nt.SetBounded(true)
- nodes.Append(nod(OAS, s, nt))
+ nodes.Append(ir.Nod(ir.OAS, s, nt))
- var ncopy *Node
+ var ncopy *ir.Node
if elemtype.HasPointers() {
// copy(s[len(l1):], l2)
- nptr1 := nod(OSLICE, s, nil)
+ nptr1 := ir.Nod(ir.OSLICE, s, nil)
nptr1.Type = s.Type
- nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
+ nptr1.SetSliceBounds(ir.Nod(ir.OLEN, l1, nil), nil, nil)
nptr1 = cheapexpr(nptr1, &nodes)
nptr2 := l2
- Curfn.Func.setWBPos(n.Pos)
+ Curfn.Func.SetWBPos(n.Pos)
// instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
fn := syslook("typedslicecopy")
fn = substArgTypes(fn, l1.Type.Elem(), l2.Type.Elem())
- ptr1, len1 := nptr1.backingArrayPtrLen()
- ptr2, len2 := nptr2.backingArrayPtrLen()
- ncopy = mkcall1(fn, types.Types[TINT], &nodes, typename(elemtype), ptr1, len1, ptr2, len2)
+ ptr1, len1 := backingArrayPtrLen(nptr1)
+ ptr2, len2 := backingArrayPtrLen(nptr2)
+ ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, typename(elemtype), ptr1, len1, ptr2, len2)
} else if instrumenting && !base.Flag.CompilingRuntime {
// rely on runtime to instrument:
// copy(s[len(l1):], l2)
// l2 can be a slice or string.
- nptr1 := nod(OSLICE, s, nil)
+ nptr1 := ir.Nod(ir.OSLICE, s, nil)
nptr1.Type = s.Type
- nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
+ nptr1.SetSliceBounds(ir.Nod(ir.OLEN, l1, nil), nil, nil)
nptr1 = cheapexpr(nptr1, &nodes)
nptr2 := l2
- ptr1, len1 := nptr1.backingArrayPtrLen()
- ptr2, len2 := nptr2.backingArrayPtrLen()
+ ptr1, len1 := backingArrayPtrLen(nptr1)
+ ptr2, len2 := backingArrayPtrLen(nptr2)
fn := syslook("slicecopy")
fn = substArgTypes(fn, ptr1.Type.Elem(), ptr2.Type.Elem())
- ncopy = mkcall1(fn, types.Types[TINT], &nodes, ptr1, len1, ptr2, len2, nodintconst(elemtype.Width))
+ ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, ptr1, len1, ptr2, len2, nodintconst(elemtype.Width))
} else {
// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
- nptr1 := nod(OINDEX, s, nod(OLEN, l1, nil))
+ nptr1 := ir.Nod(ir.OINDEX, s, ir.Nod(ir.OLEN, l1, nil))
nptr1.SetBounded(true)
- nptr1 = nod(OADDR, nptr1, nil)
+ nptr1 = ir.Nod(ir.OADDR, nptr1, nil)
- nptr2 := nod(OSPTR, l2, nil)
+ nptr2 := ir.Nod(ir.OSPTR, l2, nil)
- nwid := cheapexpr(conv(nod(OLEN, l2, nil), types.Types[TUINTPTR]), &nodes)
- nwid = nod(OMUL, nwid, nodintconst(elemtype.Width))
+ nwid := cheapexpr(conv(ir.Nod(ir.OLEN, l2, nil), types.Types[types.TUINTPTR]), &nodes)
+ nwid = ir.Nod(ir.OMUL, nwid, nodintconst(elemtype.Width))
// instantiate func memmove(to *any, frm *any, length uintptr)
fn := syslook("memmove")
// isAppendOfMake reports whether n is of the form append(x , make([]T, y)...).
// isAppendOfMake assumes n has already been typechecked.
-func isAppendOfMake(n *Node) bool {
+func isAppendOfMake(n *ir.Node) bool {
if base.Flag.N != 0 || instrumenting {
return false
}
base.Fatalf("missing typecheck: %+v", n)
}
- if n.Op != OAPPEND || !n.IsDDD() || n.List.Len() != 2 {
+ if n.Op != ir.OAPPEND || !n.IsDDD() || n.List.Len() != 2 {
return false
}
second := n.List.Second()
- if second.Op != OMAKESLICE || second.Right != nil {
+ if second.Op != ir.OMAKESLICE || second.Right != nil {
return false
}
// The care of overflow of the len argument to make will be handled by an explicit check of int(len) < 0 during runtime.
y := second.Left
- if !Isconst(y, constant.Int) && y.Type.Size() > types.Types[TUINT].Size() {
+ if !ir.IsConst(y, constant.Int) && y.Type.Size() > types.Types[types.TUINT].Size() {
return false
}
// }
// }
// s
-func extendslice(n *Node, init *Nodes) *Node {
+func extendslice(n *ir.Node, init *ir.Nodes) *ir.Node {
// isAppendOfMake made sure all possible positive values of l2 fit into an uint.
// The case of l2 overflow when converting from e.g. uint to int is handled by an explicit
// check of l2 < 0 at runtime which is generated below.
- l2 := conv(n.List.Second().Left, types.Types[TINT])
+ l2 := conv(n.List.Second().Left, types.Types[types.TINT])
l2 = typecheck(l2, ctxExpr)
n.List.SetSecond(l2) // walkAppendArgs expects l2 in n.List.Second().
l1 := n.List.First()
l2 = n.List.Second() // re-read l2, as it may have been updated by walkAppendArgs
- var nodes []*Node
+ var nodes []*ir.Node
// if l2 >= 0 (likely happens), do nothing
- nifneg := nod(OIF, nod(OGE, l2, nodintconst(0)), nil)
+ nifneg := ir.Nod(ir.OIF, ir.Nod(ir.OGE, l2, nodintconst(0)), nil)
nifneg.SetLikely(true)
// else panicmakeslicelen()
// s := l1
s := temp(l1.Type)
- nodes = append(nodes, nod(OAS, s, l1))
+ nodes = append(nodes, ir.Nod(ir.OAS, s, l1))
elemtype := s.Type.Elem()
// n := len(s) + l2
- nn := temp(types.Types[TINT])
- nodes = append(nodes, nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), l2)))
+ nn := temp(types.Types[types.TINT])
+ nodes = append(nodes, ir.Nod(ir.OAS, nn, ir.Nod(ir.OADD, ir.Nod(ir.OLEN, s, nil), l2)))
// if uint(n) > uint(cap(s))
- nuint := conv(nn, types.Types[TUINT])
- capuint := conv(nod(OCAP, s, nil), types.Types[TUINT])
- nif := nod(OIF, nod(OGT, nuint, capuint), nil)
+ nuint := conv(nn, types.Types[types.TUINT])
+ capuint := conv(ir.Nod(ir.OCAP, s, nil), types.Types[types.TUINT])
+ nif := ir.Nod(ir.OIF, ir.Nod(ir.OGT, nuint, capuint), nil)
// instantiate growslice(typ *type, old []any, newcap int) []any
fn := syslook("growslice")
fn = substArgTypes(fn, elemtype, elemtype)
// s = growslice(T, s, n)
- nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn)))
+ nif.Nbody.Set1(ir.Nod(ir.OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn)))
nodes = append(nodes, nif)
// s = s[:n]
- nt := nod(OSLICE, s, nil)
+ nt := ir.Nod(ir.OSLICE, s, nil)
nt.SetSliceBounds(nil, nn, nil)
nt.SetBounded(true)
- nodes = append(nodes, nod(OAS, s, nt))
+ nodes = append(nodes, ir.Nod(ir.OAS, s, nt))
// lptr := &l1[0]
l1ptr := temp(l1.Type.Elem().PtrTo())
- tmp := nod(OSPTR, l1, nil)
- nodes = append(nodes, nod(OAS, l1ptr, tmp))
+ tmp := ir.Nod(ir.OSPTR, l1, nil)
+ nodes = append(nodes, ir.Nod(ir.OAS, l1ptr, tmp))
// sptr := &s[0]
sptr := temp(elemtype.PtrTo())
- tmp = nod(OSPTR, s, nil)
- nodes = append(nodes, nod(OAS, sptr, tmp))
+ tmp = ir.Nod(ir.OSPTR, s, nil)
+ nodes = append(nodes, ir.Nod(ir.OAS, sptr, tmp))
// hp := &s[len(l1)]
- hp := nod(OINDEX, s, nod(OLEN, l1, nil))
+ hp := ir.Nod(ir.OINDEX, s, ir.Nod(ir.OLEN, l1, nil))
hp.SetBounded(true)
- hp = nod(OADDR, hp, nil)
- hp = convnop(hp, types.Types[TUNSAFEPTR])
+ hp = ir.Nod(ir.OADDR, hp, nil)
+ hp = convnop(hp, types.Types[types.TUNSAFEPTR])
// hn := l2 * sizeof(elem(s))
- hn := nod(OMUL, l2, nodintconst(elemtype.Width))
- hn = conv(hn, types.Types[TUINTPTR])
+ hn := ir.Nod(ir.OMUL, l2, nodintconst(elemtype.Width))
+ hn = conv(hn, types.Types[types.TUINTPTR])
clrname := "memclrNoHeapPointers"
hasPointers := elemtype.HasPointers()
if hasPointers {
clrname = "memclrHasPointers"
- Curfn.Func.setWBPos(n.Pos)
+ Curfn.Func.SetWBPos(n.Pos)
}
- var clr Nodes
+ var clr ir.Nodes
clrfn := mkcall(clrname, nil, &clr, hp, hn)
clr.Append(clrfn)
if hasPointers {
// if l1ptr == sptr
- nifclr := nod(OIF, nod(OEQ, l1ptr, sptr), nil)
+ nifclr := ir.Nod(ir.OIF, ir.Nod(ir.OEQ, l1ptr, sptr), nil)
nifclr.Nbody = clr
nodes = append(nodes, nifclr)
} else {
// ...
// }
// s
-func walkappend(n *Node, init *Nodes, dst *Node) *Node {
+func walkappend(n *ir.Node, init *ir.Nodes, dst *ir.Node) *ir.Node {
if !samesafeexpr(dst, n.List.First()) {
n.List.SetFirst(safeexpr(n.List.First(), init))
n.List.SetFirst(walkexpr(n.List.First(), init))
return n
}
- var l []*Node
+ var l []*ir.Node
ns := temp(nsrc.Type)
- l = append(l, nod(OAS, ns, nsrc)) // s = src
+ l = append(l, ir.Nod(ir.OAS, ns, nsrc)) // s = src
na := nodintconst(int64(argc)) // const argc
- nx := nod(OIF, nil, nil) // if cap(s) - len(s) < argc
- nx.Left = nod(OLT, nod(OSUB, nod(OCAP, ns, nil), nod(OLEN, ns, nil)), na)
+ nx := ir.Nod(ir.OIF, nil, nil) // if cap(s) - len(s) < argc
+ nx.Left = ir.Nod(ir.OLT, ir.Nod(ir.OSUB, ir.Nod(ir.OCAP, ns, nil), ir.Nod(ir.OLEN, ns, nil)), na)
fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
- nx.Nbody.Set1(nod(OAS, ns,
+ nx.Nbody.Set1(ir.Nod(ir.OAS, ns,
mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
- nod(OADD, nod(OLEN, ns, nil), na))))
+ ir.Nod(ir.OADD, ir.Nod(ir.OLEN, ns, nil), na))))
l = append(l, nx)
- nn := temp(types.Types[TINT])
- l = append(l, nod(OAS, nn, nod(OLEN, ns, nil))) // n = len(s)
+ nn := temp(types.Types[types.TINT])
+ l = append(l, ir.Nod(ir.OAS, nn, ir.Nod(ir.OLEN, ns, nil))) // n = len(s)
- nx = nod(OSLICE, ns, nil) // ...s[:n+argc]
- nx.SetSliceBounds(nil, nod(OADD, nn, na), nil)
+ nx = ir.Nod(ir.OSLICE, ns, nil) // ...s[:n+argc]
+ nx.SetSliceBounds(nil, ir.Nod(ir.OADD, nn, na), nil)
nx.SetBounded(true)
- l = append(l, nod(OAS, ns, nx)) // s = s[:n+argc]
+ l = append(l, ir.Nod(ir.OAS, ns, nx)) // s = s[:n+argc]
ls = n.List.Slice()[1:]
for i, n := range ls {
- nx = nod(OINDEX, ns, nn) // s[n] ...
+ nx = ir.Nod(ir.OINDEX, ns, nn) // s[n] ...
nx.SetBounded(true)
- l = append(l, nod(OAS, nx, n)) // s[n] = arg
+ l = append(l, ir.Nod(ir.OAS, nx, n)) // s[n] = arg
if i+1 < len(ls) {
- l = append(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))) // n = n + 1
+ l = append(l, ir.Nod(ir.OAS, nn, ir.Nod(ir.OADD, nn, nodintconst(1)))) // n = n + 1
}
}
//
// Also works if b is a string.
//
-func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
+func copyany(n *ir.Node, init *ir.Nodes, runtimecall bool) *ir.Node {
if n.Left.Type.Elem().HasPointers() {
- Curfn.Func.setWBPos(n.Pos)
+ Curfn.Func.SetWBPos(n.Pos)
fn := writebarrierfn("typedslicecopy", n.Left.Type.Elem(), n.Right.Type.Elem())
n.Left = cheapexpr(n.Left, init)
- ptrL, lenL := n.Left.backingArrayPtrLen()
+ ptrL, lenL := backingArrayPtrLen(n.Left)
n.Right = cheapexpr(n.Right, init)
- ptrR, lenR := n.Right.backingArrayPtrLen()
+ ptrR, lenR := backingArrayPtrLen(n.Right)
return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), ptrL, lenL, ptrR, lenR)
}
// n.Right can be a slice or string.
n.Left = cheapexpr(n.Left, init)
- ptrL, lenL := n.Left.backingArrayPtrLen()
+ ptrL, lenL := backingArrayPtrLen(n.Left)
n.Right = cheapexpr(n.Right, init)
- ptrR, lenR := n.Right.backingArrayPtrLen()
+ ptrR, lenR := backingArrayPtrLen(n.Right)
fn := syslook("slicecopy")
fn = substArgTypes(fn, ptrL.Type.Elem(), ptrR.Type.Elem())
n.Right = walkexpr(n.Right, init)
nl := temp(n.Left.Type)
nr := temp(n.Right.Type)
- var l []*Node
- l = append(l, nod(OAS, nl, n.Left))
- l = append(l, nod(OAS, nr, n.Right))
+ var l []*ir.Node
+ l = append(l, ir.Nod(ir.OAS, nl, n.Left))
+ l = append(l, ir.Nod(ir.OAS, nr, n.Right))
- nfrm := nod(OSPTR, nr, nil)
- nto := nod(OSPTR, nl, nil)
+ nfrm := ir.Nod(ir.OSPTR, nr, nil)
+ nto := ir.Nod(ir.OSPTR, nl, nil)
- nlen := temp(types.Types[TINT])
+ nlen := temp(types.Types[types.TINT])
// n = len(to)
- l = append(l, nod(OAS, nlen, nod(OLEN, nl, nil)))
+ l = append(l, ir.Nod(ir.OAS, nlen, ir.Nod(ir.OLEN, nl, nil)))
// if n > len(frm) { n = len(frm) }
- nif := nod(OIF, nil, nil)
+ nif := ir.Nod(ir.OIF, nil, nil)
- nif.Left = nod(OGT, nlen, nod(OLEN, nr, nil))
- nif.Nbody.Append(nod(OAS, nlen, nod(OLEN, nr, nil)))
+ nif.Left = ir.Nod(ir.OGT, nlen, ir.Nod(ir.OLEN, nr, nil))
+ nif.Nbody.Append(ir.Nod(ir.OAS, nlen, ir.Nod(ir.OLEN, nr, nil)))
l = append(l, nif)
// if to.ptr != frm.ptr { memmove( ... ) }
- ne := nod(OIF, nod(ONE, nto, nfrm), nil)
+ ne := ir.Nod(ir.OIF, ir.Nod(ir.ONE, nto, nfrm), nil)
ne.SetLikely(true)
l = append(l, ne)
fn := syslook("memmove")
fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
- nwid := temp(types.Types[TUINTPTR])
- setwid := nod(OAS, nwid, conv(nlen, types.Types[TUINTPTR]))
+ nwid := temp(types.Types[types.TUINTPTR])
+ setwid := ir.Nod(ir.OAS, nwid, conv(nlen, types.Types[types.TUINTPTR]))
ne.Nbody.Append(setwid)
- nwid = nod(OMUL, nwid, nodintconst(nl.Type.Elem().Width))
+ nwid = ir.Nod(ir.OMUL, nwid, nodintconst(nl.Type.Elem().Width))
call := mkcall1(fn, nil, init, nto, nfrm, nwid)
ne.Nbody.Append(call)
return nlen
}
-func eqfor(t *types.Type) (n *Node, needsize bool) {
+func eqfor(t *types.Type) (n *ir.Node, needsize bool) {
// Should only arrive here with large memory or
// a struct/array containing a non-memory field/element.
// Small memory is handled inline, and single non-memory
return n, true
case ASPECIAL:
sym := typesymprefix(".eq", t)
- n := newname(sym)
+ n := NewName(sym)
setNodeNameFunc(n)
- n.Type = functype(nil, []*Node{
+ n.Type = functype(nil, []*ir.Node{
anonfield(types.NewPtr(t)),
anonfield(types.NewPtr(t)),
- }, []*Node{
- anonfield(types.Types[TBOOL]),
+ }, []*ir.Node{
+ anonfield(types.Types[types.TBOOL]),
})
return n, false
}
// The result of walkcompare MUST be assigned back to n, e.g.
// n.Left = walkcompare(n.Left, init)
-func walkcompare(n *Node, init *Nodes) *Node {
- if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != ONIL && n.Right.Op != ONIL {
+func walkcompare(n *ir.Node, init *ir.Nodes) *ir.Node {
+ if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != ir.ONIL && n.Right.Op != ir.ONIL {
return walkcompareInterface(n, init)
}
// Handle both == and !=.
eq := n.Op
- andor := OOROR
- if eq == OEQ {
- andor = OANDAND
+ andor := ir.OOROR
+ if eq == ir.OEQ {
+ andor = ir.OANDAND
}
// Check for types equal.
// For empty interface, this is:
// l.tab == type(r)
// For non-empty interface, this is:
// l.tab != nil && l.tab._type == type(r)
- var eqtype *Node
- tab := nod(OITAB, l, nil)
+ var eqtype *ir.Node
+ tab := ir.Nod(ir.OITAB, l, nil)
rtyp := typename(r.Type)
if l.Type.IsEmptyInterface() {
- tab.Type = types.NewPtr(types.Types[TUINT8])
+ tab.Type = types.NewPtr(types.Types[types.TUINT8])
tab.SetTypecheck(1)
- eqtype = nod(eq, tab, rtyp)
+ eqtype = ir.Nod(eq, tab, rtyp)
} else {
- nonnil := nod(brcom(eq), nodnil(), tab)
- match := nod(eq, itabType(tab), rtyp)
- eqtype = nod(andor, nonnil, match)
+ nonnil := ir.Nod(brcom(eq), nodnil(), tab)
+ match := ir.Nod(eq, itabType(tab), rtyp)
+ eqtype = ir.Nod(andor, nonnil, match)
}
// Check for data equal.
- eqdata := nod(eq, ifaceData(n.Pos, l, r.Type), r)
+ eqdata := ir.Nod(eq, ifaceData(n.Pos, l, r.Type), r)
// Put it all together.
- expr := nod(andor, eqtype, eqdata)
+ expr := ir.Nod(andor, eqtype, eqdata)
n = finishcompare(n, expr, init)
return n
}
// instead, and arrange for the constant
// operand to be the first argument.
l, r := n.Left, n.Right
- if r.Op == OLITERAL {
+ if r.Op == ir.OLITERAL {
l, r = r, l
}
- constcmp := l.Op == OLITERAL && r.Op != OLITERAL
+ constcmp := l.Op == ir.OLITERAL && r.Op != ir.OLITERAL
var fn string
var paramType *types.Type
if constcmp {
fn = "libfuzzerTraceConstCmp1"
}
- paramType = types.Types[TUINT8]
+ paramType = types.Types[types.TUINT8]
case 2:
fn = "libfuzzerTraceCmp2"
if constcmp {
fn = "libfuzzerTraceConstCmp2"
}
- paramType = types.Types[TUINT16]
+ paramType = types.Types[types.TUINT16]
case 4:
fn = "libfuzzerTraceCmp4"
if constcmp {
fn = "libfuzzerTraceConstCmp4"
}
- paramType = types.Types[TUINT32]
+ paramType = types.Types[types.TUINT32]
case 8:
fn = "libfuzzerTraceCmp8"
if constcmp {
fn = "libfuzzerTraceConstCmp8"
}
- paramType = types.Types[TUINT64]
+ paramType = types.Types[types.TUINT64]
default:
base.Fatalf("unexpected integer size %d for %v", t.Size(), t)
}
init.Append(mkcall(fn, nil, init, tracecmpArg(l, paramType, init), tracecmpArg(r, paramType, init)))
}
return n
- case TARRAY:
+ case types.TARRAY:
// We can compare several elements at once with 2/4/8 byte integer compares
inline = t.NumElem() <= 1 || (issimple[t.Elem().Etype] && (t.NumElem() <= 4 || t.Elem().Width*t.NumElem() <= maxcmpsize))
- case TSTRUCT:
+ case types.TSTRUCT:
inline = t.NumComponents(types.IgnoreBlankFields) <= 4
}
cmpl := n.Left
- for cmpl != nil && cmpl.Op == OCONVNOP {
+ for cmpl != nil && cmpl.Op == ir.OCONVNOP {
cmpl = cmpl.Left
}
cmpr := n.Right
- for cmpr != nil && cmpr.Op == OCONVNOP {
+ for cmpr != nil && cmpr.Op == ir.OCONVNOP {
cmpr = cmpr.Left
}
}
fn, needsize := eqfor(t)
- call := nod(OCALL, fn, nil)
- call.List.Append(nod(OADDR, cmpl, nil))
- call.List.Append(nod(OADDR, cmpr, nil))
+ call := ir.Nod(ir.OCALL, fn, nil)
+ call.List.Append(ir.Nod(ir.OADDR, cmpl, nil))
+ call.List.Append(ir.Nod(ir.OADDR, cmpr, nil))
if needsize {
call.List.Append(nodintconst(t.Width))
}
res := call
- if n.Op != OEQ {
- res = nod(ONOT, res, nil)
+ if n.Op != ir.OEQ {
+ res = ir.Nod(ir.ONOT, res, nil)
}
n = finishcompare(n, res, init)
return n
}
// inline: build boolean expression comparing element by element
- andor := OANDAND
- if n.Op == ONE {
- andor = OOROR
+ andor := ir.OANDAND
+ if n.Op == ir.ONE {
+ andor = ir.OOROR
}
- var expr *Node
- compare := func(el, er *Node) {
- a := nod(n.Op, el, er)
+ var expr *ir.Node
+ compare := func(el, er *ir.Node) {
+ a := ir.Nod(n.Op, el, er)
if expr == nil {
expr = a
} else {
- expr = nod(andor, expr, a)
+ expr = ir.Nod(andor, expr, a)
}
}
cmpl = safeexpr(cmpl, init)
continue
}
compare(
- nodSym(OXDOT, cmpl, sym),
- nodSym(OXDOT, cmpr, sym),
+ nodSym(ir.OXDOT, cmpl, sym),
+ nodSym(ir.OXDOT, cmpr, sym),
)
}
} else {
var convType *types.Type
switch {
case remains >= 8 && combine64bit:
- convType = types.Types[TINT64]
+ convType = types.Types[types.TINT64]
step = 8 / t.Elem().Width
case remains >= 4 && combine32bit:
- convType = types.Types[TUINT32]
+ convType = types.Types[types.TUINT32]
step = 4 / t.Elem().Width
case remains >= 2 && combine16bit:
- convType = types.Types[TUINT16]
+ convType = types.Types[types.TUINT16]
step = 2 / t.Elem().Width
default:
step = 1
}
if step == 1 {
compare(
- nod(OINDEX, cmpl, nodintconst(i)),
- nod(OINDEX, cmpr, nodintconst(i)),
+ ir.Nod(ir.OINDEX, cmpl, nodintconst(i)),
+ ir.Nod(ir.OINDEX, cmpr, nodintconst(i)),
)
i++
remains -= t.Elem().Width
} else {
elemType := t.Elem().ToUnsigned()
- cmplw := nod(OINDEX, cmpl, nodintconst(i))
+ cmplw := ir.Nod(ir.OINDEX, cmpl, nodintconst(i))
cmplw = conv(cmplw, elemType) // convert to unsigned
cmplw = conv(cmplw, convType) // widen
- cmprw := nod(OINDEX, cmpr, nodintconst(i))
+ cmprw := ir.Nod(ir.OINDEX, cmpr, nodintconst(i))
cmprw = conv(cmprw, elemType)
cmprw = conv(cmprw, convType)
// For code like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
// ssa will generate a single large load.
for offset := int64(1); offset < step; offset++ {
- lb := nod(OINDEX, cmpl, nodintconst(i+offset))
+ lb := ir.Nod(ir.OINDEX, cmpl, nodintconst(i+offset))
lb = conv(lb, elemType)
lb = conv(lb, convType)
- lb = nod(OLSH, lb, nodintconst(8*t.Elem().Width*offset))
- cmplw = nod(OOR, cmplw, lb)
- rb := nod(OINDEX, cmpr, nodintconst(i+offset))
+ lb = ir.Nod(ir.OLSH, lb, nodintconst(8*t.Elem().Width*offset))
+ cmplw = ir.Nod(ir.OOR, cmplw, lb)
+ rb := ir.Nod(ir.OINDEX, cmpr, nodintconst(i+offset))
rb = conv(rb, elemType)
rb = conv(rb, convType)
- rb = nod(OLSH, rb, nodintconst(8*t.Elem().Width*offset))
- cmprw = nod(OOR, cmprw, rb)
+ rb = ir.Nod(ir.OLSH, rb, nodintconst(8*t.Elem().Width*offset))
+ cmprw = ir.Nod(ir.OOR, cmprw, rb)
}
compare(cmplw, cmprw)
i += step
}
}
if expr == nil {
- expr = nodbool(n.Op == OEQ)
+ expr = nodbool(n.Op == ir.OEQ)
// We still need to use cmpl and cmpr, in case they contain
// an expression which might panic. See issue 23837.
t := temp(cmpl.Type)
- a1 := nod(OAS, t, cmpl)
+ a1 := ir.Nod(ir.OAS, t, cmpl)
a1 = typecheck(a1, ctxStmt)
- a2 := nod(OAS, t, cmpr)
+ a2 := ir.Nod(ir.OAS, t, cmpr)
a2 = typecheck(a2, ctxStmt)
init.Append(a1, a2)
}
return n
}
-func tracecmpArg(n *Node, t *types.Type, init *Nodes) *Node {
+func tracecmpArg(n *ir.Node, t *types.Type, init *ir.Nodes) *ir.Node {
// Ugly hack to avoid "constant -1 overflows uintptr" errors, etc.
- if n.Op == OLITERAL && n.Type.IsSigned() && n.Int64Val() < 0 {
+ if n.Op == ir.OLITERAL && n.Type.IsSigned() && n.Int64Val() < 0 {
n = copyexpr(n, n.Type, init)
}
return conv(n, t)
}
-func walkcompareInterface(n *Node, init *Nodes) *Node {
+func walkcompareInterface(n *ir.Node, init *ir.Nodes) *ir.Node {
n.Right = cheapexpr(n.Right, init)
n.Left = cheapexpr(n.Left, init)
eqtab, eqdata := eqinterface(n.Left, n.Right)
- var cmp *Node
- if n.Op == OEQ {
- cmp = nod(OANDAND, eqtab, eqdata)
+ var cmp *ir.Node
+ if n.Op == ir.OEQ {
+ cmp = ir.Nod(ir.OANDAND, eqtab, eqdata)
} else {
- eqtab.Op = ONE
- cmp = nod(OOROR, eqtab, nod(ONOT, eqdata, nil))
+ eqtab.Op = ir.ONE
+ cmp = ir.Nod(ir.OOROR, eqtab, ir.Nod(ir.ONOT, eqdata, nil))
}
return finishcompare(n, cmp, init)
}
-func walkcompareString(n *Node, init *Nodes) *Node {
+func walkcompareString(n *ir.Node, init *ir.Nodes) *ir.Node {
// Rewrite comparisons to short constant strings as length+byte-wise comparisons.
- var cs, ncs *Node // const string, non-const string
+ var cs, ncs *ir.Node // const string, non-const string
switch {
- case Isconst(n.Left, constant.String) && Isconst(n.Right, constant.String):
+ case ir.IsConst(n.Left, constant.String) && ir.IsConst(n.Right, constant.String):
// ignore; will be constant evaluated
- case Isconst(n.Left, constant.String):
+ case ir.IsConst(n.Left, constant.String):
cs = n.Left
ncs = n.Right
- case Isconst(n.Right, constant.String):
+ case ir.IsConst(n.Right, constant.String):
cs = n.Right
ncs = n.Left
}
// Our comparison below assumes that the non-constant string
// is on the left hand side, so rewrite "" cmp x to x cmp "".
// See issue 24817.
- if Isconst(n.Left, constant.String) {
+ if ir.IsConst(n.Left, constant.String) {
cmp = brrev(cmp)
}
combine64bit = thearch.LinkArch.RegSize >= 8
}
- var and Op
+ var and ir.Op
switch cmp {
- case OEQ:
- and = OANDAND
- case ONE:
- and = OOROR
+ case ir.OEQ:
+ and = ir.OANDAND
+ case ir.ONE:
+ and = ir.OOROR
default:
// Don't do byte-wise comparisons for <, <=, etc.
// They're fairly complicated.
if len(s) > 0 {
ncs = safeexpr(ncs, init)
}
- r := nod(cmp, nod(OLEN, ncs, nil), nodintconst(int64(len(s))))
+ r := ir.Nod(cmp, ir.Nod(ir.OLEN, ncs, nil), nodintconst(int64(len(s))))
remains := len(s)
for i := 0; remains > 0; {
if remains == 1 || !canCombineLoads {
cb := nodintconst(int64(s[i]))
- ncb := nod(OINDEX, ncs, nodintconst(int64(i)))
- r = nod(and, r, nod(cmp, ncb, cb))
+ ncb := ir.Nod(ir.OINDEX, ncs, nodintconst(int64(i)))
+ r = ir.Nod(and, r, ir.Nod(cmp, ncb, cb))
remains--
i++
continue
var convType *types.Type
switch {
case remains >= 8 && combine64bit:
- convType = types.Types[TINT64]
+ convType = types.Types[types.TINT64]
step = 8
case remains >= 4:
- convType = types.Types[TUINT32]
+ convType = types.Types[types.TUINT32]
step = 4
case remains >= 2:
- convType = types.Types[TUINT16]
+ convType = types.Types[types.TUINT16]
step = 2
}
- ncsubstr := nod(OINDEX, ncs, nodintconst(int64(i)))
+ ncsubstr := ir.Nod(ir.OINDEX, ncs, nodintconst(int64(i)))
ncsubstr = conv(ncsubstr, convType)
csubstr := int64(s[i])
// Calculate large constant from bytes as sequence of shifts and ors.
// Like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
// ssa will combine this into a single large load.
for offset := 1; offset < step; offset++ {
- b := nod(OINDEX, ncs, nodintconst(int64(i+offset)))
+ b := ir.Nod(ir.OINDEX, ncs, nodintconst(int64(i+offset)))
b = conv(b, convType)
- b = nod(OLSH, b, nodintconst(int64(8*offset)))
- ncsubstr = nod(OOR, ncsubstr, b)
+ b = ir.Nod(ir.OLSH, b, nodintconst(int64(8*offset)))
+ ncsubstr = ir.Nod(ir.OOR, ncsubstr, b)
csubstr |= int64(s[i+offset]) << uint8(8*offset)
}
csubstrPart := nodintconst(csubstr)
// Compare "step" bytes as once
- r = nod(and, r, nod(cmp, csubstrPart, ncsubstr))
+ r = ir.Nod(and, r, ir.Nod(cmp, csubstrPart, ncsubstr))
remains -= step
i += step
}
}
}
- var r *Node
- if n.Op == OEQ || n.Op == ONE {
+ var r *ir.Node
+ if n.Op == ir.OEQ || n.Op == ir.ONE {
// prepare for rewrite below
n.Left = cheapexpr(n.Left, init)
n.Right = cheapexpr(n.Right, init)
eqlen, eqmem := eqstring(n.Left, n.Right)
// quick check of len before full compare for == or !=.
// memequal then tests equality up to length len.
- if n.Op == OEQ {
+ if n.Op == ir.OEQ {
// len(left) == len(right) && memequal(left, right, len)
- r = nod(OANDAND, eqlen, eqmem)
+ r = ir.Nod(ir.OANDAND, eqlen, eqmem)
} else {
// len(left) != len(right) || !memequal(left, right, len)
- eqlen.Op = ONE
- r = nod(OOROR, eqlen, nod(ONOT, eqmem, nil))
+ eqlen.Op = ir.ONE
+ r = ir.Nod(ir.OOROR, eqlen, ir.Nod(ir.ONOT, eqmem, nil))
}
} else {
// sys_cmpstring(s1, s2) :: 0
- r = mkcall("cmpstring", types.Types[TINT], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING]))
- r = nod(n.Op, r, nodintconst(0))
+ r = mkcall("cmpstring", types.Types[types.TINT], init, conv(n.Left, types.Types[types.TSTRING]), conv(n.Right, types.Types[types.TSTRING]))
+ r = ir.Nod(n.Op, r, nodintconst(0))
}
return finishcompare(n, r, init)
// The result of finishcompare MUST be assigned back to n, e.g.
// n.Left = finishcompare(n.Left, x, r, init)
-func finishcompare(n, r *Node, init *Nodes) *Node {
+func finishcompare(n, r *ir.Node, init *ir.Nodes) *ir.Node {
r = typecheck(r, ctxExpr)
r = conv(r, n.Type)
r = walkexpr(r, init)
}
// return 1 if integer n must be in range [0, max), 0 otherwise
-func bounded(n *Node, max int64) bool {
+func bounded(n *ir.Node, max int64) bool {
if n.Type == nil || !n.Type.IsInteger() {
return false
}
}
switch n.Op {
- case OAND, OANDNOT:
+ case ir.OAND, ir.OANDNOT:
v := int64(-1)
switch {
case smallintconst(n.Left):
v = n.Left.Int64Val()
case smallintconst(n.Right):
v = n.Right.Int64Val()
- if n.Op == OANDNOT {
+ if n.Op == ir.OANDNOT {
v = ^v
if !sign {
v &= 1<<uint(bits) - 1
return true
}
- case OMOD:
+ case ir.OMOD:
if !sign && smallintconst(n.Right) {
v := n.Right.Int64Val()
if 0 <= v && v <= max {
}
}
- case ODIV:
+ case ir.ODIV:
if !sign && smallintconst(n.Right) {
v := n.Right.Int64Val()
for bits > 0 && v >= 2 {
}
}
- case ORSH:
+ case ir.ORSH:
if !sign && smallintconst(n.Right) {
v := n.Right.Int64Val()
if v > int64(bits) {
}
// usemethod checks interface method calls for uses of reflect.Type.Method.
-func usemethod(n *Node) {
+func usemethod(n *ir.Node) {
t := n.Left.Type
// Looking for either of:
}
if res1 == nil {
- if p0.Type.Etype != TINT {
+ if p0.Type.Etype != types.TINT {
return
}
} else {
if s := res0.Type.Sym; s != nil && s.Name == "Method" && isReflectPkg(s.Pkg) {
Curfn.Func.SetReflectMethod(true)
// The LSym is initialized at this point. We need to set the attribute on the LSym.
- Curfn.Func.lsym.Set(obj.AttrReflectMethod, true)
+ Curfn.Func.LSym.Set(obj.AttrReflectMethod, true)
}
}
-func usefield(n *Node) {
+func usefield(n *ir.Node) {
if objabi.Fieldtrack_enabled == 0 {
return
}
default:
base.Fatalf("usefield %v", n.Op)
- case ODOT, ODOTPTR:
+ case ir.ODOT, ir.ODOTPTR:
break
}
if n.Sym == nil {
Curfn.Func.FieldTrack[sym] = struct{}{}
}
-func candiscardlist(l Nodes) bool {
+func candiscardlist(l ir.Nodes) bool {
for _, n := range l.Slice() {
if !candiscard(n) {
return false
return true
}
-func candiscard(n *Node) bool {
+func candiscard(n *ir.Node) bool {
if n == nil {
return true
}
return false
// Discardable as long as the subpieces are.
- case ONAME,
- ONONAME,
- OTYPE,
- OPACK,
- OLITERAL,
- ONIL,
- OADD,
- OSUB,
- OOR,
- OXOR,
- OADDSTR,
- OADDR,
- OANDAND,
- OBYTES2STR,
- ORUNES2STR,
- OSTR2BYTES,
- OSTR2RUNES,
- OCAP,
- OCOMPLIT,
- OMAPLIT,
- OSTRUCTLIT,
- OARRAYLIT,
- OSLICELIT,
- OPTRLIT,
- OCONV,
- OCONVIFACE,
- OCONVNOP,
- ODOT,
- OEQ,
- ONE,
- OLT,
- OLE,
- OGT,
- OGE,
- OKEY,
- OSTRUCTKEY,
- OLEN,
- OMUL,
- OLSH,
- ORSH,
- OAND,
- OANDNOT,
- ONEW,
- ONOT,
- OBITNOT,
- OPLUS,
- ONEG,
- OOROR,
- OPAREN,
- ORUNESTR,
- OREAL,
- OIMAG,
- OCOMPLEX:
+ case ir.ONAME,
+ ir.ONONAME,
+ ir.OTYPE,
+ ir.OPACK,
+ ir.OLITERAL,
+ ir.ONIL,
+ ir.OADD,
+ ir.OSUB,
+ ir.OOR,
+ ir.OXOR,
+ ir.OADDSTR,
+ ir.OADDR,
+ ir.OANDAND,
+ ir.OBYTES2STR,
+ ir.ORUNES2STR,
+ ir.OSTR2BYTES,
+ ir.OSTR2RUNES,
+ ir.OCAP,
+ ir.OCOMPLIT,
+ ir.OMAPLIT,
+ ir.OSTRUCTLIT,
+ ir.OARRAYLIT,
+ ir.OSLICELIT,
+ ir.OPTRLIT,
+ ir.OCONV,
+ ir.OCONVIFACE,
+ ir.OCONVNOP,
+ ir.ODOT,
+ ir.OEQ,
+ ir.ONE,
+ ir.OLT,
+ ir.OLE,
+ ir.OGT,
+ ir.OGE,
+ ir.OKEY,
+ ir.OSTRUCTKEY,
+ ir.OLEN,
+ ir.OMUL,
+ ir.OLSH,
+ ir.ORSH,
+ ir.OAND,
+ ir.OANDNOT,
+ ir.ONEW,
+ ir.ONOT,
+ ir.OBITNOT,
+ ir.OPLUS,
+ ir.ONEG,
+ ir.OOROR,
+ ir.OPAREN,
+ ir.ORUNESTR,
+ ir.OREAL,
+ ir.OIMAG,
+ ir.OCOMPLEX:
break
// Discardable as long as we know it's not division by zero.
- case ODIV, OMOD:
- if n.Right.Op == OLITERAL && constant.Sign(n.Right.Val()) != 0 {
+ case ir.ODIV, ir.OMOD:
+ if n.Right.Op == ir.OLITERAL && constant.Sign(n.Right.Val()) != 0 {
break
}
return false
// Discardable as long as we know it won't fail because of a bad size.
- case OMAKECHAN, OMAKEMAP:
- if Isconst(n.Left, constant.Int) && constant.Sign(n.Left.Val()) == 0 {
+ case ir.OMAKECHAN, ir.OMAKEMAP:
+ if ir.IsConst(n.Left, constant.Int) && constant.Sign(n.Left.Val()) == 0 {
break
}
return false
// Difficult to tell what sizes are okay.
- case OMAKESLICE:
+ case ir.OMAKESLICE:
return false
- case OMAKESLICECOPY:
+ case ir.OMAKESLICECOPY:
return false
}
// The result of wrapCall MUST be assigned back to n, e.g.
// n.Left = wrapCall(n.Left, init)
-func wrapCall(n *Node, init *Nodes) *Node {
+func wrapCall(n *ir.Node, init *ir.Nodes) *ir.Node {
if n.Ninit.Len() != 0 {
walkstmtlist(n.Ninit.Slice())
init.AppendNodes(&n.Ninit)
}
- isBuiltinCall := n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER
+ isBuiltinCall := n.Op != ir.OCALLFUNC && n.Op != ir.OCALLMETH && n.Op != ir.OCALLINTER
// Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
if !isBuiltinCall && n.IsDDD() {
last := n.List.Len() - 1
- if va := n.List.Index(last); va.Op == OSLICELIT {
+ if va := n.List.Index(last); va.Op == ir.OSLICELIT {
n.List.Set(append(n.List.Slice()[:last], va.List.Slice()...))
n.SetIsDDD(false)
}
}
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
- origArgs := make([]*Node, n.List.Len())
- t := nod(OTFUNC, nil, nil)
+ origArgs := make([]*ir.Node, n.List.Len())
+ t := ir.Nod(ir.OTFUNC, nil, nil)
for i, arg := range n.List.Slice() {
s := lookupN("a", i)
- if !isBuiltinCall && arg.Op == OCONVNOP && arg.Type.IsUintptr() && arg.Left.Type.IsUnsafePtr() {
+ if !isBuiltinCall && arg.Op == ir.OCONVNOP && arg.Type.IsUintptr() && arg.Left.Type.IsUnsafePtr() {
origArgs[i] = arg
arg = arg.Left
n.List.SetIndex(i, arg)
if origArg == nil {
continue
}
- arg := nod(origArg.Op, args[i], nil)
+ arg := ir.Nod(origArg.Op, args[i], nil)
arg.Type = origArg.Type
args[i] = arg
}
- call := nod(n.Op, nil, nil)
+ call := ir.Nod(n.Op, nil, nil)
if !isBuiltinCall {
- call.Op = OCALL
+ call.Op = ir.OCALL
call.Left = n.Left
call.SetIsDDD(n.IsDDD())
}
typecheckslice(fn.Nbody.Slice(), ctxStmt)
xtop = append(xtop, fn)
- call = nod(OCALL, nil, nil)
+ call = ir.Nod(ir.OCALL, nil, nil)
call.Left = fn.Func.Nname
call.List.Set(n.List.Slice())
call = typecheck(call, ctxStmt)
// type syntax expression n.Type.
// The result of substArgTypes MUST be assigned back to old, e.g.
// n.Left = substArgTypes(n.Left, t1, t2)
-func substArgTypes(old *Node, types_ ...*types.Type) *Node {
- n := old.copy()
+func substArgTypes(old *ir.Node, types_ ...*types.Type) *ir.Node {
+ n := ir.Copy(old)
for _, t := range types_ {
dowidth(t)
// isRuneCount reports whether n is of the form len([]rune(string)).
// These are optimized into a call to runtime.countrunes.
-func isRuneCount(n *Node) bool {
- return base.Flag.N == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES
+func isRuneCount(n *ir.Node) bool {
+ return base.Flag.N == 0 && !instrumenting && n.Op == ir.OLEN && n.Left.Op == ir.OSTR2RUNES
}
-func walkCheckPtrAlignment(n *Node, init *Nodes, count *Node) *Node {
+func walkCheckPtrAlignment(n *ir.Node, init *ir.Nodes, count *ir.Node) *ir.Node {
if !n.Type.IsPtr() {
base.Fatalf("expected pointer type: %v", n.Type)
}
}
n.Left = cheapexpr(n.Left, init)
- init.Append(mkcall("checkptrAlignment", nil, init, convnop(n.Left, types.Types[TUNSAFEPTR]), typename(elem), conv(count, types.Types[TUINTPTR])))
+ init.Append(mkcall("checkptrAlignment", nil, init, convnop(n.Left, types.Types[types.TUNSAFEPTR]), typename(elem), conv(count, types.Types[types.TUINTPTR])))
return n
}
var walkCheckPtrArithmeticMarker byte
-func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
+func walkCheckPtrArithmetic(n *ir.Node, init *ir.Nodes) *ir.Node {
// Calling cheapexpr(n, init) below leads to a recursive call
// to walkexpr, which leads us back here again. Use n.Opt to
// prevent infinite loops.
// TODO(mdempsky): Make stricter. We only need to exempt
// reflect.Value.Pointer and reflect.Value.UnsafeAddr.
switch n.Left.Op {
- case OCALLFUNC, OCALLMETH, OCALLINTER:
+ case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
return n
}
- if n.Left.Op == ODOTPTR && isReflectHeaderDataField(n.Left) {
+ if n.Left.Op == ir.ODOTPTR && isReflectHeaderDataField(n.Left) {
return n
}
// "It is valid both to add and to subtract offsets from a
// pointer in this way. It is also valid to use &^ to round
// pointers, usually for alignment."
- var originals []*Node
- var walk func(n *Node)
- walk = func(n *Node) {
+ var originals []*ir.Node
+ var walk func(n *ir.Node)
+ walk = func(n *ir.Node) {
switch n.Op {
- case OADD:
+ case ir.OADD:
walk(n.Left)
walk(n.Right)
- case OSUB, OANDNOT:
+ case ir.OSUB, ir.OANDNOT:
walk(n.Left)
- case OCONVNOP:
+ case ir.OCONVNOP:
if n.Left.Type.IsUnsafePtr() {
n.Left = cheapexpr(n.Left, init)
- originals = append(originals, convnop(n.Left, types.Types[TUNSAFEPTR]))
+ originals = append(originals, convnop(n.Left, types.Types[types.TUNSAFEPTR]))
}
}
}
n = cheapexpr(n, init)
- slice := mkdotargslice(types.NewSlice(types.Types[TUNSAFEPTR]), originals)
+ slice := mkdotargslice(types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
slice.Esc = EscNone
- init.Append(mkcall("checkptrArithmetic", nil, init, convnop(n, types.Types[TUNSAFEPTR]), slice))
+ init.Append(mkcall("checkptrArithmetic", nil, init, convnop(n, types.Types[types.TUNSAFEPTR]), slice))
// TODO(khr): Mark backing store of slice as dead. This will allow us to reuse
// the backing store for multiple calls to checkptrArithmetic.
// checkPtr reports whether pointer checking should be enabled for
// function fn at a given level. See debugHelpFooter for defined
// levels.
-func checkPtr(fn *Node, level int) bool {
- return base.Debug.Checkptr >= level && fn.Func.Pragma&NoCheckPtr == 0
+func checkPtr(fn *ir.Node, level int) bool {
+ return base.Debug.Checkptr >= level && fn.Func.Pragma&ir.NoCheckPtr == 0
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gc
+package ir
type bitset8 uint8
// Code generated by "stringer -type=Class"; DO NOT EDIT.
-package gc
+package ir
import "strconv"
// for debugging purposes. The code is customized for Node graphs
// and may be used for an alternative view of the node structure.
-package gc
+package ir
import (
- "cmd/compile/internal/base"
- "cmd/compile/internal/types"
- "cmd/internal/src"
"fmt"
"io"
"os"
"reflect"
"regexp"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
)
// dump is like fdump but prints to stderr.
-func dump(root interface{}, filter string, depth int) {
- fdump(os.Stderr, root, filter, depth)
+func DumpAny(root interface{}, filter string, depth int) {
+ FDumpAny(os.Stderr, root, filter, depth)
}
// fdump prints the structure of a rooted data structure
// rather than their type; struct fields with zero values or
// non-matching field names are omitted, and "…" means recursion
// depth has been reached or struct fields have been omitted.
-func fdump(w io.Writer, root interface{}, filter string, depth int) {
+func FDumpAny(w io.Writer, root interface{}, filter string, depth int) {
if root == nil {
fmt.Fprintln(w, "nil")
return
return
case *types.Node:
- x = reflect.ValueOf(asNode(v))
+ x = reflect.ValueOf(AsNode(v))
}
switch x.Kind() {
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gc
+package ir
import (
"bytes"
- "cmd/compile/internal/base"
- "cmd/compile/internal/types"
- "cmd/internal/src"
"fmt"
"go/constant"
"io"
"strings"
"sync"
"unicode/utf8"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
)
// A FmtFlag value is a set of flags (or 0).
// *types.Sym, *types.Type, and *Node types use the flags below to set the format mode
const (
- FErr fmtMode = iota
+ FErr FmtMode = iota
FDbg
FTypeId
FTypeIdName // same as FTypeId, but use package name instead of prefix
// %- v type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
// update returns the results of applying f to mode.
-func (f FmtFlag) update(mode fmtMode) (FmtFlag, fmtMode) {
+func (f FmtFlag) update(mode FmtMode) (FmtFlag, FmtMode) {
switch {
case f&FmtSign != 0:
mode = FDbg
return f, mode
}
-var goopnames = []string{
+var OpNames = []string{
OADDR: "&",
OADD: "+",
OADDSTR: "+",
return fmt.Sprintf("%#v", o)
}
-func (o Op) format(s fmt.State, verb rune, mode fmtMode) {
+func (o Op) format(s fmt.State, verb rune, mode FmtMode) {
switch verb {
case 'v':
o.oconv(s, fmtFlag(s, verb), mode)
}
}
-func (o Op) oconv(s fmt.State, flag FmtFlag, mode fmtMode) {
+func (o Op) oconv(s fmt.State, flag FmtFlag, mode FmtMode) {
if flag&FmtSharp != 0 || mode != FDbg {
- if int(o) < len(goopnames) && goopnames[o] != "" {
- fmt.Fprint(s, goopnames[o])
+ if int(o) < len(OpNames) && OpNames[o] != "" {
+ fmt.Fprint(s, OpNames[o])
return
}
}
fmt.Fprint(s, o.String())
}
-type fmtMode int
+type FmtMode int
type fmtNode struct {
x *Node
- m fmtMode
+ m FmtMode
}
func (f *fmtNode) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) }
type fmtOp struct {
x Op
- m fmtMode
+ m FmtMode
}
func (f *fmtOp) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) }
type fmtType struct {
x *types.Type
- m fmtMode
+ m FmtMode
}
func (f *fmtType) Format(s fmt.State, verb rune) { typeFormat(f.x, s, verb, f.m) }
type fmtSym struct {
x *types.Sym
- m fmtMode
+ m FmtMode
}
func (f *fmtSym) Format(s fmt.State, verb rune) { symFormat(f.x, s, verb, f.m) }
type fmtNodes struct {
x Nodes
- m fmtMode
+ m FmtMode
}
func (f *fmtNodes) Format(s fmt.State, verb rune) { f.x.format(s, verb, f.m) }
-func (n *Node) Format(s fmt.State, verb rune) { n.format(s, verb, FErr) }
-func (o Op) Format(s fmt.State, verb rune) { o.format(s, verb, FErr) }
+func (n *Node) Format(s fmt.State, verb rune) {
+ FmtNode(n, s, verb)
+}
+
+func FmtNode(n *Node, s fmt.State, verb rune) {
+ n.format(s, verb, FErr)
+}
+
+func (o Op) Format(s fmt.State, verb rune) { o.format(s, verb, FErr) }
// func (t *types.Type) Format(s fmt.State, verb rune) // in package types
// func (y *types.Sym) Format(s fmt.State, verb rune) // in package types { y.format(s, verb, FErr) }
func (n Nodes) Format(s fmt.State, verb rune) { n.format(s, verb, FErr) }
-func (m fmtMode) Fprintf(s fmt.State, format string, args ...interface{}) {
+func (m FmtMode) Fprintf(s fmt.State, format string, args ...interface{}) {
m.prepareArgs(args)
fmt.Fprintf(s, format, args...)
}
-func (m fmtMode) Sprintf(format string, args ...interface{}) string {
+func (m FmtMode) Sprintf(format string, args ...interface{}) string {
m.prepareArgs(args)
return fmt.Sprintf(format, args...)
}
-func (m fmtMode) Sprint(args ...interface{}) string {
+func (m FmtMode) Sprint(args ...interface{}) string {
m.prepareArgs(args)
return fmt.Sprint(args...)
}
-func (m fmtMode) prepareArgs(args []interface{}) {
+func (m FmtMode) prepareArgs(args []interface{}) {
for i, arg := range args {
switch arg := arg.(type) {
case Op:
}
}
-func (n *Node) format(s fmt.State, verb rune, mode fmtMode) {
+func (n *Node) format(s fmt.State, verb rune, mode FmtMode) {
switch verb {
case 'v', 'S', 'L':
- n.nconv(s, fmtFlag(s, verb), mode)
+ nconvFmt(n, s, fmtFlag(s, verb), mode)
case 'j':
- n.jconv(s, fmtFlag(s, verb))
+ jconvFmt(n, s, fmtFlag(s, verb))
default:
fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)
var EscFmt func(n *Node, short bool) string
// *Node details
-func (n *Node) jconv(s fmt.State, flag FmtFlag) {
+func jconvFmt(n *Node, s fmt.State, flag FmtFlag) {
short := flag&FmtShort != 0
// Useful to see which nodes in an AST printout are actually identical
fmt.Fprintf(s, " l(%s%d)", pfx, n.Pos.Line())
}
- if !short && n.Xoffset != BADWIDTH {
+ if !short && n.Xoffset != types.BADWIDTH {
fmt.Fprintf(s, " x(%d)", n.Xoffset)
}
}
}
-func vconv(v constant.Value, flag FmtFlag) string {
+func FmtConst(v constant.Value, flag FmtFlag) string {
if flag&FmtSharp == 0 && v.Kind() == constant.Complex {
real, imag := constant.Real(v), constant.Imag(v)
s%~ %%g
*/
-func symfmt(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode fmtMode) {
+func symfmt(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode FmtMode) {
if flag&FmtShort == 0 {
switch mode {
case FErr: // This is for the user
- if s.Pkg == builtinpkg || s.Pkg == localpkg {
+ if s.Pkg == BuiltinPkg || s.Pkg == LocalPkg {
b.WriteString(s.Name)
return
}
// If the name was used by multiple packages, display the full path,
- if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
+ if s.Pkg.Name != "" && NumImport[s.Pkg.Name] > 1 {
fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name)
return
}
b.WriteString(s.Name)
}
-var basicnames = []string{
- TINT: "int",
- TUINT: "uint",
- TINT8: "int8",
- TUINT8: "uint8",
- TINT16: "int16",
- TUINT16: "uint16",
- TINT32: "int32",
- TUINT32: "uint32",
- TINT64: "int64",
- TUINT64: "uint64",
- TUINTPTR: "uintptr",
- TFLOAT32: "float32",
- TFLOAT64: "float64",
- TCOMPLEX64: "complex64",
- TCOMPLEX128: "complex128",
- TBOOL: "bool",
- TANY: "any",
- TSTRING: "string",
- TNIL: "nil",
- TIDEAL: "untyped number",
- TBLANK: "blank",
+var BasicTypeNames = []string{
+ types.TINT: "int",
+ types.TUINT: "uint",
+ types.TINT8: "int8",
+ types.TUINT8: "uint8",
+ types.TINT16: "int16",
+ types.TUINT16: "uint16",
+ types.TINT32: "int32",
+ types.TUINT32: "uint32",
+ types.TINT64: "int64",
+ types.TUINT64: "uint64",
+ types.TUINTPTR: "uintptr",
+ types.TFLOAT32: "float32",
+ types.TFLOAT64: "float64",
+ types.TCOMPLEX64: "complex64",
+ types.TCOMPLEX128: "complex128",
+ types.TBOOL: "bool",
+ types.TANY: "any",
+ types.TSTRING: "string",
+ types.TNIL: "nil",
+ types.TIDEAL: "untyped number",
+ types.TBLANK: "blank",
}
var fmtBufferPool = sync.Pool{
},
}
-func tconv(t *types.Type, flag FmtFlag, mode fmtMode) string {
+func tconv(t *types.Type, flag FmtFlag, mode FmtMode) string {
buf := fmtBufferPool.Get().(*bytes.Buffer)
buf.Reset()
defer fmtBufferPool.Put(buf)
// flag and mode control exactly what is printed.
// Any types x that are already in the visited map get printed as @%d where %d=visited[x].
// See #16897 before changing the implementation of tconv.
-func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited map[*types.Type]int) {
+func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode FmtMode, visited map[*types.Type]int) {
if off, ok := visited[t]; ok {
// We've seen this type before, so we're trying to print it recursively.
// Print a reference to it instead.
return
}
- if t.Sym.Pkg == localpkg && t.Vargen != 0 {
+ if t.Sym.Pkg == LocalPkg && t.Vargen != 0 {
b.WriteString(mode.Sprintf("%v·%d", t.Sym, t.Vargen))
return
}
return
}
- if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
+ if int(t.Etype) < len(BasicTypeNames) && BasicTypeNames[t.Etype] != "" {
var name string
switch t {
case types.UntypedBool:
case types.UntypedComplex:
name = "untyped complex"
default:
- name = basicnames[t.Etype]
+ name = BasicTypeNames[t.Etype]
}
b.WriteString(name)
return
defer delete(visited, t)
switch t.Etype {
- case TPTR:
+ case types.TPTR:
b.WriteByte('*')
switch mode {
case FTypeId, FTypeIdName:
}
tconv2(b, t.Elem(), 0, mode, visited)
- case TARRAY:
+ case types.TARRAY:
b.WriteByte('[')
b.WriteString(strconv.FormatInt(t.NumElem(), 10))
b.WriteByte(']')
tconv2(b, t.Elem(), 0, mode, visited)
- case TSLICE:
+ case types.TSLICE:
b.WriteString("[]")
tconv2(b, t.Elem(), 0, mode, visited)
- case TCHAN:
+ case types.TCHAN:
switch t.ChanDir() {
case types.Crecv:
b.WriteString("<-chan ")
}
}
- case TMAP:
+ case types.TMAP:
b.WriteString("map[")
tconv2(b, t.Key(), 0, mode, visited)
b.WriteByte(']')
tconv2(b, t.Elem(), 0, mode, visited)
- case TINTER:
+ case types.TINTER:
if t.IsEmptyInterface() {
b.WriteString("interface {}")
break
}
b.WriteByte('}')
- case TFUNC:
+ case types.TFUNC:
if flag&FmtShort != 0 {
// no leading func
} else {
tconv2(b, t.Results(), 0, mode, visited)
}
- case TSTRUCT:
+ case types.TSTRUCT:
if m := t.StructType().Map; m != nil {
mt := m.MapType()
// Format the bucket struct for map[x]y as map.bucket[x]y.
b.WriteByte('}')
}
- case TFORW:
+ case types.TFORW:
b.WriteString("undefined")
if t.Sym != nil {
b.WriteByte(' ')
sconv2(b, t.Sym, 0, mode)
}
- case TUNSAFEPTR:
+ case types.TUNSAFEPTR:
b.WriteString("unsafe.Pointer")
- case Txxx:
+ case types.Txxx:
b.WriteString("Txxx")
default:
// Don't know how to handle - fall back to detailed prints.
}
// Statements which may be rendered with a simplestmt as init.
-func stmtwithinit(op Op) bool {
+func StmtWithInit(op Op) bool {
switch op {
case OIF, OFOR, OFORUNTIL, OSWITCH:
return true
return false
}
-func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
+func stmtFmt(n *Node, s fmt.State, mode FmtMode) {
// some statements allow for an init, but at most one,
// but we may have an arbitrary number added, eg by typecheck
// and inlining. If it doesn't fit the syntax, emit an enclosing
// block starting with the init statements.
// if we can just say "for" n->ninit; ... then do so
- simpleinit := n.Ninit.Len() == 1 && n.Ninit.First().Ninit.Len() == 0 && stmtwithinit(n.Op)
+ simpleinit := n.Ninit.Len() == 1 && n.Ninit.First().Ninit.Len() == 0 && StmtWithInit(n.Op)
// otherwise, print the inits as separate statements
complexinit := n.Ninit.Len() != 0 && !simpleinit && (mode != FErr)
// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
- extrablock := complexinit && stmtwithinit(n.Op)
+ extrablock := complexinit && StmtWithInit(n.Op)
if extrablock {
fmt.Fprint(s, "{")
}
}
-var opprec = []int{
+var OpPrec = []int{
OALIGNOF: 8,
OAPPEND: 8,
OBYTES2STR: 8,
OEND: 0,
}
-func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
+func exprFmt(n *Node, s fmt.State, prec int, mode FmtMode) {
for n != nil && n.Implicit() && (n.Op == ODEREF || n.Op == OADDR) {
n = n.Left
}
return
}
- nprec := opprec[n.Op]
+ nprec := OpPrec[n.Op]
if n.Op == OTYPE && n.Sym != nil {
nprec = 8
}
case OLITERAL: // this is a bit of a mess
if mode == FErr {
if n.Orig != nil && n.Orig != n {
- n.Orig.exprfmt(s, prec, mode)
+ exprFmt(n.Orig, s, prec, mode)
return
}
if n.Sym != nil {
fmt.Fprintf(s, "'\\U%08x'", uint64(x))
}
} else {
- fmt.Fprint(s, vconv(n.Val(), fmtFlag(s, 'v')))
+ fmt.Fprint(s, FmtConst(n.Val(), fmtFlag(s, 'v')))
}
if needUnparen {
mode.Fprintf(s, "%v:%v", n.Sym, n.Left)
case OCALLPART:
- n.Left.exprfmt(s, nprec, mode)
+ exprFmt(n.Left, s, nprec, mode)
if n.Right == nil || n.Right.Sym == nil {
fmt.Fprint(s, ".<nil>")
return
mode.Fprintf(s, ".%0S", n.Right.Sym)
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
- n.Left.exprfmt(s, nprec, mode)
+ exprFmt(n.Left, s, nprec, mode)
if n.Sym == nil {
fmt.Fprint(s, ".<nil>")
return
mode.Fprintf(s, ".%0S", n.Sym)
case ODOTTYPE, ODOTTYPE2:
- n.Left.exprfmt(s, nprec, mode)
+ exprFmt(n.Left, s, nprec, mode)
if n.Right != nil {
mode.Fprintf(s, ".(%v)", n.Right)
return
mode.Fprintf(s, ".(%v)", n.Type)
case OINDEX, OINDEXMAP:
- n.Left.exprfmt(s, nprec, mode)
+ exprFmt(n.Left, s, nprec, mode)
mode.Fprintf(s, "[%v]", n.Right)
case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
- n.Left.exprfmt(s, nprec, mode)
+ exprFmt(n.Left, s, nprec, mode)
fmt.Fprint(s, "[")
low, high, max := n.SliceBounds()
if low != nil {
- fmt.Fprint(s, low.modeString(mode))
+ fmt.Fprint(s, modeString(low, mode))
}
fmt.Fprint(s, ":")
if high != nil {
- fmt.Fprint(s, high.modeString(mode))
+ fmt.Fprint(s, modeString(high, mode))
}
if n.Op.IsSlice3() {
fmt.Fprint(s, ":")
if max != nil {
- fmt.Fprint(s, max.modeString(mode))
+ fmt.Fprint(s, modeString(max, mode))
}
}
fmt.Fprint(s, "]")
mode.Fprintf(s, "%#v(%.v)", n.Op, n.List)
case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
- n.Left.exprfmt(s, nprec, mode)
+ exprFmt(n.Left, s, nprec, mode)
if n.IsDDD() {
mode.Fprintf(s, "(%.v...)", n.List)
return
if n.Left != nil && n.Left.Op == n.Op {
fmt.Fprint(s, " ")
}
- n.Left.exprfmt(s, nprec+1, mode)
+ exprFmt(n.Left, s, nprec+1, mode)
// Binary
case OADD,
OSEND,
OSUB,
OXOR:
- n.Left.exprfmt(s, nprec, mode)
+ exprFmt(n.Left, s, nprec, mode)
mode.Fprintf(s, " %#v ", n.Op)
- n.Right.exprfmt(s, nprec+1, mode)
+ exprFmt(n.Right, s, nprec+1, mode)
case OADDSTR:
for i, n1 := range n.List.Slice() {
if i != 0 {
fmt.Fprint(s, " + ")
}
- n1.exprfmt(s, nprec, mode)
+ exprFmt(n1, s, nprec, mode)
}
case ODDD:
mode.Fprintf(s, "...")
}
}
-func (n *Node) nodefmt(s fmt.State, flag FmtFlag, mode fmtMode) {
+func nodeFmt(n *Node, s fmt.State, flag FmtFlag, mode FmtMode) {
t := n.Type
// We almost always want the original.
}
if flag&FmtLong != 0 && t != nil {
- if t.Etype == TNIL {
+ if t.Etype == types.TNIL {
fmt.Fprint(s, "nil")
} else if n.Op == ONAME && n.Name.AutoTemp() {
mode.Fprintf(s, "%v value", t)
// TODO inlining produces expressions with ninits. we can't print these yet.
- if opprec[n.Op] < 0 {
- n.stmtfmt(s, mode)
+ if OpPrec[n.Op] < 0 {
+ stmtFmt(n, s, mode)
return
}
- n.exprfmt(s, 0, mode)
+ exprFmt(n, s, 0, mode)
}
-func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
+func nodeDumpFmt(n *Node, s fmt.State, flag FmtFlag, mode FmtMode) {
recur := flag&FmtShort == 0
if recur {
if n.Op == ODCLFUNC && n.Func != nil && n.Func.Dcl != nil && len(n.Func.Dcl) != 0 {
indent(s)
// The dcls for a func or closure
- mode.Fprintf(s, "%v-dcl%v", n.Op, asNodes(n.Func.Dcl))
+ mode.Fprintf(s, "%v-dcl%v", n.Op, AsNodes(n.Func.Dcl))
}
if n.List.Len() != 0 {
indent(s)
}
// "%S" suppresses qualifying with package
-func symFormat(s *types.Sym, f fmt.State, verb rune, mode fmtMode) {
+func symFormat(s *types.Sym, f fmt.State, verb rune, mode FmtMode) {
switch verb {
case 'v', 'S':
fmt.Fprint(f, sconv(s, fmtFlag(f, verb), mode))
}
}
-func smodeString(s *types.Sym, mode fmtMode) string { return sconv(s, 0, mode) }
+func smodeString(s *types.Sym, mode FmtMode) string { return sconv(s, 0, mode) }
// See #16897 before changing the implementation of sconv.
-func sconv(s *types.Sym, flag FmtFlag, mode fmtMode) string {
+func sconv(s *types.Sym, flag FmtFlag, mode FmtMode) string {
if flag&FmtLong != 0 {
panic("linksymfmt")
}
return types.InternString(buf.Bytes())
}
-func sconv2(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode fmtMode) {
+func sconv2(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode FmtMode) {
if flag&FmtLong != 0 {
panic("linksymfmt")
}
symfmt(b, s, flag, mode)
}
-func fldconv(b *bytes.Buffer, f *types.Field, flag FmtFlag, mode fmtMode, visited map[*types.Type]int, funarg types.Funarg) {
+func fldconv(b *bytes.Buffer, f *types.Field, flag FmtFlag, mode FmtMode, visited map[*types.Type]int, funarg types.Funarg) {
if f == nil {
b.WriteString("<T>")
return
// Take the name from the original.
if mode == FErr {
- s = origSym(s)
+ s = OrigSym(s)
}
if s != nil && f.Embedded == 0 {
if funarg != types.FunargNone {
- name = asNode(f.Nname).modeString(mode)
+ name = modeString(AsNode(f.Nname), mode)
} else if flag&FmtLong != 0 {
name = mode.Sprintf("%0S", s)
if !types.IsExported(name) && flag&FmtUnsigned == 0 {
// "%L" print definition, not name
// "%S" omit 'func' and receiver from function types, short type names
-func typeFormat(t *types.Type, s fmt.State, verb rune, mode fmtMode) {
+func typeFormat(t *types.Type, s fmt.State, verb rune, mode FmtMode) {
switch verb {
case 'v', 'S', 'L':
fmt.Fprint(s, tconv(t, fmtFlag(s, verb), mode))
}
}
-func (n *Node) String() string { return fmt.Sprint(n) }
-func (n *Node) modeString(mode fmtMode) string { return mode.Sprint(n) }
+func (n *Node) String() string { return fmt.Sprint(n) }
+func modeString(n *Node, mode FmtMode) string { return mode.Sprint(n) }
// "%L" suffix with "(type %T)" where possible
// "%+S" in debug mode, don't recurse, no multiline output
-func (n *Node) nconv(s fmt.State, flag FmtFlag, mode fmtMode) {
+func nconvFmt(n *Node, s fmt.State, flag FmtFlag, mode FmtMode) {
if n == nil {
fmt.Fprint(s, "<N>")
return
switch mode {
case FErr:
- n.nodefmt(s, flag, mode)
+ nodeFmt(n, s, flag, mode)
case FDbg:
dumpdepth++
- n.nodedump(s, flag, mode)
+ nodeDumpFmt(n, s, flag, mode)
dumpdepth--
default:
}
}
-func (l Nodes) format(s fmt.State, verb rune, mode fmtMode) {
+func (l Nodes) format(s fmt.State, verb rune, mode FmtMode) {
switch verb {
case 'v':
l.hconv(s, fmtFlag(s, verb), mode)
}
// Flags: all those of %N plus '.': separate with comma's instead of semicolons.
-func (l Nodes) hconv(s fmt.State, flag FmtFlag, mode fmtMode) {
+func (l Nodes) hconv(s fmt.State, flag FmtFlag, mode FmtMode) {
if l.Len() == 0 && mode == FDbg {
fmt.Fprint(s, "<nil>")
return
}
for i, n := range l.Slice() {
- fmt.Fprint(s, n.modeString(mode))
+ fmt.Fprint(s, modeString(n, mode))
if i+1 < l.Len() {
fmt.Fprint(s, sep)
}
}
}
-func dumplist(s string, l Nodes) {
+func DumpList(s string, l Nodes) {
fmt.Printf("%s%+v\n", s, l)
}
-func fdumplist(w io.Writer, s string, l Nodes) {
+func FDumpList(w io.Writer, s string, l Nodes) {
fmt.Fprintf(w, "%s%+v\n", s, l)
}
}
return ""
}
+
+// numImport tracks how often a package with a given name is imported.
+// It is used to provide a better error message (by using the package
+// path to disambiguate) if a package that appears multiple times with
+// the same name appears in an error message.
+var NumImport = make(map[string]int)
+
+func InstallTypeFormats() {
+ types.Sconv = func(s *types.Sym, flag, mode int) string {
+ return sconv(s, FmtFlag(flag), FmtMode(mode))
+ }
+ types.Tconv = func(t *types.Type, flag, mode int) string {
+ return tconv(t, FmtFlag(flag), FmtMode(mode))
+ }
+ types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
+ symFormat(sym, s, verb, FmtMode(mode))
+ }
+ types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
+ typeFormat(t, s, verb, FmtMode(mode))
+ }
+}
+
+// Line returns n's position as a string. If n has been inlined,
+// it uses the outermost position where n has been inlined.
+func Line(n *Node) string {
+ return base.FmtPos(n.Pos)
+}
--- /dev/null
+// 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 ir
+
+import "cmd/compile/internal/types"
+
+var LocalPkg *types.Pkg // package being compiled
+
+// builtinpkg is a fake package that declares the universe block.
+var BuiltinPkg *types.Pkg
// “Abstract” syntax representation.
-package gc
+package ir
import (
+ "go/constant"
+ "sort"
+ "strings"
+ "unsafe"
+
"cmd/compile/internal/base"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/src"
- "go/constant"
- "sort"
)
// A Node is a single node in the syntax tree.
base.Fatalf("have Opt")
}
if n.Op == OLITERAL {
- assertRepresents(n.Type, v)
+ AssertValidTypeForConst(n.Type, v)
}
n.SetHasVal(true)
n.E = &v
// mayBeShared reports whether n may occur in multiple places in the AST.
// Extra care must be taken when mutating such a node.
-func (n *Node) mayBeShared() bool {
+func MayBeShared(n *Node) bool {
switch n.Op {
case ONAME, OLITERAL, ONIL, OTYPE:
return true
}
// funcname returns the name (without the package) of the function n.
-func (n *Node) funcname() string {
+func FuncName(n *Node) string {
if n == nil || n.Func == nil || n.Func.Nname == nil {
return "<nil>"
}
// This differs from the compiler's internal convention where local functions lack a package
// because the ultimate consumer of this is a human looking at an IDE; package is only empty
// if the compilation package is actually the empty string.
-func (n *Node) pkgFuncName() string {
+func PkgFuncName(n *Node) string {
var s *types.Sym
if n == nil {
return "<nil>"
FieldTrack map[*types.Sym]struct{}
DebugInfo *ssa.FuncDebug
- lsym *obj.LSym
+ LSym *obj.LSym
Inl *Inline
Pragma PragmaFlag // go:xxx function annotations
flags bitset16
- numDefers int // number of defer calls in the function
- numReturns int // number of explicit returns in the function
+ NumDefers int // number of defer calls in the function
+ NumReturns int // number of explicit returns in the function
// nwbrCalls records the LSyms of functions called by this
// function for go:nowritebarrierrec analysis. Only filled in
// if nowritebarrierrecCheck != nil.
- nwbrCalls *[]nowritebarrierrecCallSym
+ NWBRCalls *[]SymAndPos
}
// An Inline holds fields used for function bodies that can be inlined.
func (f *Func) SetInstrumentBody(b bool) { f.flags.set(funcInstrumentBody, b) }
func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
-func (f *Func) setWBPos(pos src.XPos) {
+func (f *Func) SetWBPos(pos src.XPos) {
if base.Debug.WB != 0 {
base.WarnfAt(pos, "write barrier")
}
type Nodes struct{ slice *[]*Node }
// asNodes returns a slice of *Node as a Nodes value.
-func asNodes(s []*Node) Nodes {
+func AsNodes(s []*Node) Nodes {
return Nodes{&s}
}
// inspect invokes f on each node in an AST in depth-first order.
// If f(n) returns false, inspect skips visiting n's children.
-func inspect(n *Node, f func(*Node) bool) {
+func Inspect(n *Node, f func(*Node) bool) {
if n == nil || !f(n) {
return
}
- inspectList(n.Ninit, f)
- inspect(n.Left, f)
- inspect(n.Right, f)
- inspectList(n.List, f)
- inspectList(n.Nbody, f)
- inspectList(n.Rlist, f)
+ InspectList(n.Ninit, f)
+ Inspect(n.Left, f)
+ Inspect(n.Right, f)
+ InspectList(n.List, f)
+ InspectList(n.Nbody, f)
+ InspectList(n.Rlist, f)
}
-func inspectList(l Nodes, f func(*Node) bool) {
+func InspectList(l Nodes, f func(*Node) bool) {
for _, n := range l.Slice() {
- inspect(n, f)
+ Inspect(n, f)
}
}
// nodeQueue is a FIFO queue of *Node. The zero value of nodeQueue is
// a ready-to-use empty queue.
-type nodeQueue struct {
+type NodeQueue struct {
ring []*Node
head, tail int
}
// empty reports whether q contains no Nodes.
-func (q *nodeQueue) empty() bool {
+func (q *NodeQueue) Empty() bool {
return q.head == q.tail
}
// pushRight appends n to the right of the queue.
-func (q *nodeQueue) pushRight(n *Node) {
+func (q *NodeQueue) PushRight(n *Node) {
if len(q.ring) == 0 {
q.ring = make([]*Node, 16)
} else if q.head+len(q.ring) == q.tail {
// popLeft pops a node from the left of the queue. It panics if q is
// empty.
-func (q *nodeQueue) popLeft() *Node {
- if q.empty() {
+func (q *NodeQueue) PopLeft() *Node {
+ if q.Empty() {
panic("dequeue empty")
}
n := q.ring[q.head%len(q.ring)]
sort.Slice(res, func(i, j int) bool { return less(res[i], res[j]) })
return res
}
+
+func Nod(op Op, nleft, nright *Node) *Node {
+ return NodAt(base.Pos, op, nleft, nright)
+}
+
+func NodAt(pos src.XPos, op Op, nleft, nright *Node) *Node {
+ var n *Node
+ switch op {
+ case ODCLFUNC:
+ var x struct {
+ n Node
+ f Func
+ }
+ n = &x.n
+ n.Func = &x.f
+ n.Func.Decl = n
+ case ONAME:
+ base.Fatalf("use newname instead")
+ case OLABEL, OPACK:
+ var x struct {
+ n Node
+ m Name
+ }
+ n = &x.n
+ n.Name = &x.m
+ default:
+ n = new(Node)
+ }
+ n.Op = op
+ n.Left = nleft
+ n.Right = nright
+ n.Pos = pos
+ n.Xoffset = types.BADWIDTH
+ n.Orig = n
+ return n
+}
+
+// newnamel returns a new ONAME Node associated with symbol s at position pos.
+// The caller is responsible for setting n.Name.Curfn.
+func NewNameAt(pos src.XPos, s *types.Sym) *Node {
+ if s == nil {
+ base.Fatalf("newnamel nil")
+ }
+
+ var x struct {
+ n Node
+ m Name
+ p Param
+ }
+ n := &x.n
+ n.Name = &x.m
+ n.Name.Param = &x.p
+
+ n.Op = ONAME
+ n.Pos = pos
+ n.Orig = n
+
+ n.Sym = s
+ return n
+}
+
+// The Class of a variable/function describes the "storage class"
+// of a variable or function. During parsing, storage classes are
+// called declaration contexts.
+type Class uint8
+
+//go:generate stringer -type=Class
+const (
+ Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
+ PEXTERN // global variables
+ PAUTO // local variables
+ PAUTOHEAP // local variables or parameters moved to heap
+ PPARAM // input arguments
+ PPARAMOUT // output results
+ PFUNC // global functions
+
+ // Careful: Class is stored in three bits in Node.flags.
+ _ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
+)
+
+type PragmaFlag int16
+
+const (
+ // Func pragmas.
+ Nointerface PragmaFlag = 1 << iota
+ Noescape // func parameters don't escape
+ Norace // func must not have race detector annotations
+ Nosplit // func should not execute on separate stack
+ Noinline // func should not be inlined
+ NoCheckPtr // func should not be instrumented by checkptr
+ CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
+ UintptrEscapes // pointers converted to uintptr escape
+
+ // Runtime-only func pragmas.
+ // See ../../../../runtime/README.md for detailed descriptions.
+ Systemstack // func must run on system stack
+ Nowritebarrier // emit compiler error instead of write barrier
+ Nowritebarrierrec // error on write barrier in this or recursive callees
+ Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
+
+ // Runtime and cgo type pragmas
+ NotInHeap // values of this type must not be heap allocated
+
+ // Go command pragmas
+ GoBuildPragma
+)
+
+type SymAndPos struct {
+ Sym *obj.LSym // LSym of callee
+ Pos src.XPos // line of call
+}
+
+func AsNode(n *types.Node) *Node { return (*Node)(unsafe.Pointer(n)) }
+
+func AsTypesNode(n *Node) *types.Node { return (*types.Node)(unsafe.Pointer(n)) }
+
+var BlankNode *Node
+
+// origSym returns the original symbol written by the user.
+func OrigSym(s *types.Sym) *types.Sym {
+ if s == nil {
+ return nil
+ }
+
+ if len(s.Name) > 1 && s.Name[0] == '~' {
+ switch s.Name[1] {
+ case 'r': // originally an unnamed result
+ return nil
+ case 'b': // originally the blank identifier _
+ // TODO(mdempsky): Does s.Pkg matter here?
+ return BlankNode.Sym
+ }
+ return s
+ }
+
+ if strings.HasPrefix(s.Name, ".anon") {
+ // originally an unnamed or _ name (see subr.go: structargs)
+ return nil
+ }
+
+ return s
+}
+
+// SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max].
+// n must be a slice expression. max is nil if n is a simple slice expression.
+func (n *Node) SliceBounds() (low, high, max *Node) {
+ if n.List.Len() == 0 {
+ return nil, nil, nil
+ }
+
+ switch n.Op {
+ case OSLICE, OSLICEARR, OSLICESTR:
+ s := n.List.Slice()
+ return s[0], s[1], nil
+ case OSLICE3, OSLICE3ARR:
+ s := n.List.Slice()
+ return s[0], s[1], s[2]
+ }
+ base.Fatalf("SliceBounds op %v: %v", n.Op, n)
+ return nil, nil, nil
+}
+
+// SetSliceBounds sets n's slice bounds, where n is a slice expression.
+// n must be a slice expression. If max is non-nil, n must be a full slice expression.
+func (n *Node) SetSliceBounds(low, high, max *Node) {
+ switch n.Op {
+ case OSLICE, OSLICEARR, OSLICESTR:
+ if max != nil {
+ base.Fatalf("SetSliceBounds %v given three bounds", n.Op)
+ }
+ s := n.List.Slice()
+ if s == nil {
+ if low == nil && high == nil {
+ return
+ }
+ n.List.Set2(low, high)
+ return
+ }
+ s[0] = low
+ s[1] = high
+ return
+ case OSLICE3, OSLICE3ARR:
+ s := n.List.Slice()
+ if s == nil {
+ if low == nil && high == nil && max == nil {
+ return
+ }
+ n.List.Set3(low, high, max)
+ return
+ }
+ s[0] = low
+ s[1] = high
+ s[2] = max
+ return
+ }
+ base.Fatalf("SetSliceBounds op %v: %v", n.Op, n)
+}
+
+// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
+// o must be a slicing op.
+func (o Op) IsSlice3() bool {
+ switch o {
+ case OSLICE, OSLICEARR, OSLICESTR:
+ return false
+ case OSLICE3, OSLICE3ARR:
+ return true
+ }
+ base.Fatalf("IsSlice3 op %v", o)
+ return false
+}
+
+func IsConst(n *Node, ct constant.Kind) bool {
+ return ConstType(n) == ct
+}
+
+// Int64Val returns n as an int64.
+// n must be an integer or rune constant.
+func (n *Node) Int64Val() int64 {
+ if !IsConst(n, constant.Int) {
+ base.Fatalf("Int64Val(%v)", n)
+ }
+ x, ok := constant.Int64Val(n.Val())
+ if !ok {
+ base.Fatalf("Int64Val(%v)", n)
+ }
+ return x
+}
+
+// CanInt64 reports whether it is safe to call Int64Val() on n.
+func (n *Node) CanInt64() bool {
+ if !IsConst(n, constant.Int) {
+ return false
+ }
+
+ // if the value inside n cannot be represented as an int64, the
+ // return value of Int64 is undefined
+ _, ok := constant.Int64Val(n.Val())
+ return ok
+}
+
+// Uint64Val returns n as an uint64.
+// n must be an integer or rune constant.
+func (n *Node) Uint64Val() uint64 {
+ if !IsConst(n, constant.Int) {
+ base.Fatalf("Uint64Val(%v)", n)
+ }
+ x, ok := constant.Uint64Val(n.Val())
+ if !ok {
+ base.Fatalf("Uint64Val(%v)", n)
+ }
+ return x
+}
+
+// BoolVal returns n as a bool.
+// n must be a boolean constant.
+func (n *Node) BoolVal() bool {
+ if !IsConst(n, constant.Bool) {
+ base.Fatalf("BoolVal(%v)", n)
+ }
+ return constant.BoolVal(n.Val())
+}
+
+// StringVal returns the value of a literal string Node as a string.
+// n must be a string constant.
+func (n *Node) StringVal() string {
+ if !IsConst(n, constant.String) {
+ base.Fatalf("StringVal(%v)", n)
+ }
+ return constant.StringVal(n.Val())
+}
+
+// rawcopy returns a shallow copy of n.
+// Note: copy or sepcopy (rather than rawcopy) is usually the
+// correct choice (see comment with Node.copy, below).
+func (n *Node) RawCopy() *Node {
+ copy := *n
+ return ©
+}
+
+// sepcopy returns a separate shallow copy of n, with the copy's
+// Orig pointing to itself.
+func SepCopy(n *Node) *Node {
+ copy := *n
+ copy.Orig = ©
+ return ©
+}
+
+// copy returns shallow copy of n and adjusts the copy's Orig if
+// necessary: In general, if n.Orig points to itself, the copy's
+// Orig should point to itself as well. Otherwise, if n is modified,
+// the copy's Orig node appears modified, too, and then doesn't
+// represent the original node anymore.
+// (This caused the wrong complit Op to be used when printing error
+// messages; see issues #26855, #27765).
+func Copy(n *Node) *Node {
+ copy := *n
+ if n.Orig == n {
+ copy.Orig = ©
+ }
+ return ©
+}
+
+// isNil reports whether n represents the universal untyped zero value "nil".
+func IsNil(n *Node) bool {
+ // Check n.Orig because constant propagation may produce typed nil constants,
+ // which don't exist in the Go spec.
+ return n.Orig.Op == ONIL
+}
+
+func IsBlank(n *Node) bool {
+ if n == nil {
+ return false
+ }
+ return n.Sym.IsBlank()
+}
+
+// IsMethod reports whether n is a method.
+// n must be a function or a method.
+func IsMethod(n *Node) bool {
+ return n.Type.Recv() != nil
+}
+
+func (n *Node) Typ() *types.Type {
+ return n.Type
+}
+
+func (n *Node) StorageClass() ssa.StorageClass {
+ switch n.Class() {
+ case PPARAM:
+ return ssa.ClassParam
+ case PPARAMOUT:
+ return ssa.ClassParamOut
+ case PAUTO:
+ return ssa.ClassAuto
+ default:
+ base.Fatalf("untranslatable storage class for %v: %s", n, n.Class())
+ return 0
+ }
+}
// Code generated by "stringer -type=Op -trimprefix=O"; DO NOT EDIT.
-package gc
+package ir
import "strconv"
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gc
+package ir
import (
"reflect"
--- /dev/null
+// 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 ir
+
+import (
+ "go/constant"
+ "math"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/types"
+)
+
+func ConstType(n *Node) constant.Kind {
+ if n == nil || n.Op != OLITERAL {
+ return constant.Unknown
+ }
+ return n.Val().Kind()
+}
+
+// ValueInterface returns the constant value stored in n as an interface{}.
+// It returns int64s for ints and runes, float64s for floats,
+// and complex128s for complex values.
+func ConstValue(n *Node) interface{} {
+ switch v := n.Val(); v.Kind() {
+ default:
+ base.Fatalf("unexpected constant: %v", v)
+ panic("unreachable")
+ case constant.Bool:
+ return constant.BoolVal(v)
+ case constant.String:
+ return constant.StringVal(v)
+ case constant.Int:
+ return Int64Val(n.Type, v)
+ case constant.Float:
+ return Float64Val(v)
+ case constant.Complex:
+ return complex(Float64Val(constant.Real(v)), Float64Val(constant.Imag(v)))
+ }
+}
+
+// int64Val returns v converted to int64.
+// Note: if t is uint64, very large values will be converted to negative int64.
+func Int64Val(t *types.Type, v constant.Value) int64 {
+ if t.IsUnsigned() {
+ if x, ok := constant.Uint64Val(v); ok {
+ return int64(x)
+ }
+ } else {
+ if x, ok := constant.Int64Val(v); ok {
+ return x
+ }
+ }
+ base.Fatalf("%v out of range for %v", v, t)
+ panic("unreachable")
+}
+
+func Float64Val(v constant.Value) float64 {
+ if x, _ := constant.Float64Val(v); !math.IsInf(x, 0) {
+ return x + 0 // avoid -0 (should not be needed, but be conservative)
+ }
+ base.Fatalf("bad float64 value: %v", v)
+ panic("unreachable")
+}
+
+func AssertValidTypeForConst(t *types.Type, v constant.Value) {
+ if !ValidTypeForConst(t, v) {
+ base.Fatalf("%v does not represent %v", t, v)
+ }
+}
+
+func ValidTypeForConst(t *types.Type, v constant.Value) bool {
+ switch v.Kind() {
+ case constant.Unknown:
+ return OKForConst[t.Etype]
+ case constant.Bool:
+ return t.IsBoolean()
+ case constant.String:
+ return t.IsString()
+ case constant.Int:
+ return t.IsInteger()
+ case constant.Float:
+ return t.IsFloat()
+ case constant.Complex:
+ return t.IsComplex()
+ }
+
+ base.Fatalf("unexpected constant kind: %v", v)
+ panic("unreachable")
+}
+
+// nodlit returns a new untyped constant with value v.
+func NewLiteral(v constant.Value) *Node {
+ n := Nod(OLITERAL, nil, nil)
+ if k := v.Kind(); k != constant.Unknown {
+ n.Type = idealType(k)
+ n.SetVal(v)
+ }
+ return n
+}
+
+func idealType(ct constant.Kind) *types.Type {
+ switch ct {
+ case constant.String:
+ return types.UntypedString
+ case constant.Bool:
+ return types.UntypedBool
+ case constant.Int:
+ return types.UntypedInt
+ case constant.Float:
+ return types.UntypedFloat
+ case constant.Complex:
+ return types.UntypedComplex
+ }
+ base.Fatalf("unexpected Ctype: %v", ct)
+ return nil
+}
+
+var OKForConst [types.NTYPE]bool
"cmd/compile/internal/base"
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
case *obj.LSym:
wantreg = "SB"
gc.AddAux(&p.From, v)
- case *gc.Node:
+ case *ir.Node:
wantreg = "SP"
gc.AddAux(&p.From, v)
case nil:
"cmd/compile/internal/base"
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
case *obj.LSym:
wantreg = "SB"
gc.AddAux(&p.From, v)
- case *gc.Node:
+ case *ir.Node:
wantreg = "SP"
gc.AddAux(&p.From, v)
case nil:
import (
"cmd/compile/internal/base"
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
p.To.Reg = v.Reg()
}
- case *obj.LSym, *gc.Node:
+ case *obj.LSym, *ir.Node:
p := s.Prog(ppc64.AMOVD)
p.From.Type = obj.TYPE_ADDR
p.From.Reg = v.Args[0].Reg()
import (
"cmd/compile/internal/base"
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/obj"
case *obj.LSym:
wantreg = "SB"
gc.AddAux(&p.From, v)
- case *gc.Node:
+ case *ir.Node:
wantreg = "SP"
gc.AddAux(&p.From, v)
case nil:
import (
"cmd/compile/internal/base"
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
switch v.Aux.(type) {
case *obj.LSym:
gc.AddAux(&p.From, v)
- case *gc.Node:
+ case *ir.Node:
p.From.Reg = v.Args[0].Reg()
gc.AddAux(&p.From, v)
default:
"cmd/compile/internal/arm",
"cmd/compile/internal/arm64",
"cmd/compile/internal/gc",
+ "cmd/compile/internal/ir",
"cmd/compile/internal/logopt",
"cmd/compile/internal/mips",
"cmd/compile/internal/mips64",